多併發系統架構的一些優化思路

多併發是網站的基本要求,大型網站的併發量甚至會達到數萬,單臺服務器的併發用戶也會達到數百,例如淘寶的雙十一、商務網站的促銷活動。

 

一、多少線程合適

 

多併發又可以分爲CPU密集型和IO密集型。

1CPU密集型即需要非常多的CPU計算資源,如有多顆CPU核心,可以讓每一顆CPU都參與計算,從而不浪費服務器資源,CPU密集型的典型例子,例如文件排序、圖形搜索、動態規劃等需要複雜的科學計算的情況,CPU密集型需要減少線程數,減少線程的上下文切換導致的資源損耗。

2IO密集型即需要大量的數據讀寫,例如網絡傳輸、數據庫讀寫等,大部分的網站、企業應用系統都屬於IO密集型,當發生IO讀寫的時候,由於IO操作時間很長(受限於硬盤的讀寫速度和網絡傳輸速度),線程會處於等待狀態,此時CPU空閒,這時CPU可以調度其他線程進行處理,IO密集型需要增加線程數,這樣在IO處理的時候,可以去做其他事情,以提高併發量。

 

對於多併發,目前主要採用多進程和多線程兩種模式,例如一臺服務器上有多個應用服務器,然後多個應用服務器接收多個線程併發執行,因爲線程之間的切換也有成本,所以也有觀點認爲應該採用多進程的模式。總之,進程數和線程數應該要根據實際情況進行綜合選擇。

 

那麼,到底啓動多少線程合適呢?根據以上分析,線程數應該和CPU核心數量成正比,而和IO阻塞時間成反比,因此有兩個公式可供參考:

 

1線程數=[任務執行時間/(任務執行時間-IO等待時間)] * CPU內核數

 

  

 

2線程數 = CPU核心數/(1-阻塞係數)

   這個阻塞係數一般爲0.8~0.9之間,也可以取0.8或者0.9

 

如果是CPU密集型,則線程數不超過CPU內核,如果是IO密集型,則應該增加線程數,提高併發量。

 

當發現系統運行慢的時候,不是盲目去加CPU加內存或者加硬盤,應該充分了解系統資源的使用情況,從而決定如何升級系統配置,例如在Linux環境下用TOP指令觀察CPU、硬盤的使用情況:

   Tasks: 29 total, 1 running, 28 sleeping,0 stopped, 0 zombie
    Cpu(s): 0.3% us, 1.0% sy, 0.0% ni, 98.7%id, 0.0% wa, 0.0% hi, 0.0% si


0.3% us反應CPU使用情況,0.0% wa 則大致體現出當前的磁盤io請求是否頻繁。如果 wa的數量比較大,說明等待輸入輸出的的io比較多,另外還可以通過交互命令H瞭解各個線程對CPU的使用情況。

 

Mysql中還可以通過show processlist命令查看高導致磁盤頻繁讀寫的查詢語句。

 

二、多層次連接池

 

從以上分析,線程也不應***,而且線程之間的切換需要成本,而且線程數過多,對資源搶佔卻不釋放,會出現死鎖的情況,在數據庫操作中經常會碰到這樣情況。所以應該通過連接池,控制線程數量,並減少線程之間的切換,對於一個多層次的網站結構,有Web服務器、應用服務器、緩存服務器、數據庫服務器。

 

可以在不同服務器之間通過多個連接池進行互聯,從而控制併發數和線程資源。

 

wKioL1ax1y-R4EUeAADwUEpT9FE467.png

 


三、異步消息實現高併發

 

     在不使用消息隊列的情況,所以請求都是併發操作,會對數據庫造成很大的壓力,也導致系統響應能力下降。

 

使用消息隊列,則用戶可以馬上得到響應,數據寫入消息隊列,由消費者從隊列獲取數據,異步寫入數據,從而提高用戶響應速度。如果消息隊列滿,則可以即使反饋給用戶等待,而不是導致系統崩潰,該做法體現在淘寶雙十一活動的前10分鐘,當時用戶併發操作量激增,如果沒有使用消息隊列,則系統崩潰,使用消息隊列從而實現併發高峯的削平,消息隊列也可以應用於公交車到站提醒、促銷等多用戶高併發的場景。

  

    當前主要的消息隊列有:IBM MQRabbitMQActiveMQ等。

 

四、使用集羣提高併發處理能力

 

  使用負載均衡可以將併發訪問分散到多臺服務器上處理,避免單臺服務器壓力過大,提高系統響應能力。

   可以採用重定向負載均衡、DNS負載均衡、反向代理負載均衡、IP負載均衡等模式

 

 

五、多線程模式下的線程安全

 

併發線程,容易產生線程衝突,因此需要解決線程安全問題

 

1、講對象設計爲無狀態,這樣不會出現狀態不一致情況,例如Servlet就是無狀態,因此是線程安全

 

2、使用ThreadLocal的局部對象,這樣可以減少線程之間併發操作對象

 

3、併發使用鎖,通過鎖實現順序操作,避免併發修改,但是鎖會帶來系統性能的下降,javaconcurrent包下的ConcurrentHashMap、ConcurrentLinkedQueue和CopyOnWriteArrayList等等,都是線程安全的。




除此之外,還可以考慮採用更爲複雜的分佈式結構:分佈式服務,例如SOA,分佈式緩存,例如memcache、redis等,網絡上的加速,例如CDN等,硬件上的升級,例如固態硬盤等。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章