1. 單線程java
時間回到十幾年前,那時主流的CPU都仍是單核(除了商用高性能的小機),CPU的核心頻率是機器最重要的指標之一。react
在編程領域當時比較流行的是單線程編程,對於CPU密集型的應用程序而言,頻繁的經過多線程進行協做和搶佔時間片反而會下降性能。c++
2. 多線程編程
隨着硬件性能的提高,CPU的核數愈來愈越多,不少服務器標配已經達到32或64核。經過多線程併發編程,能夠充分利用多核CPU的處理能力,提高系統的處理效率和併發性能。後端
從2005年開始,隨着多核處理器的逐步普及,多線程併發編程也逐漸流行起來,用戶能夠經過 new Thread()的方式建立新的線程。安全
根據不一樣的語言多線程之間的同步、協做、建立和銷燬等工做都須要用戶本身處理。因爲建立和銷燬線程是個相對比較重量級的操做,所以,這種原始的多線程編程效率和性能都不高。服務器
3. 線程池網絡
爲了提高多線程編程的效率和性能,下降用戶開發難度。JDK1.5推出了java.util.concurrent併發編程包。在併發編程類庫中,提供了線程池、線程安全容器、原子類等新的類庫,極大的提高了Java多線程編程的效率,下降了開發難度。若是使用c/c++這些就須要本身實現,固然對線程的理解也會更深刻。多線程
從JDK1.5開始,基於線程池的併發編程已經成爲Java多核編程的主流。架構
4. Reactor模型
不管是C++仍是Java編寫的網絡框架,大多數都是基於Reactor模式進行設計和開發,Reactor模式基於事件驅動,特別適合處理海量的I/O事件。
4.1 單線程模型
Reactor單線程模型,指的是全部的IO操做都在同一個NIO線程上面完成,NIO線程的職責以下:
1)做爲NIO服務端,接收客戶端的TCP鏈接;
2)做爲NIO客戶端,向服務端發起TCP鏈接;
3)讀取通訊對端的請求或者應答消息;
4)向通訊對端發送消息請求或者應答消息。
Reactor單線程模型示意圖以下所示:
圖1-1 Reactor單線程模型
因爲Reactor模式使用的是異步非阻塞IO,全部的IO操做都不會致使阻塞,理論上一個線程能夠獨立處理全部IO相關的操做。從架構層面看,一個NIO線程確實能夠完成其承擔的職責。例如,經過Acceptor類接收客戶端的TCP鏈接請求消息,鏈路創建成功以後,經過Dispatch將對應的ByteBuffer派發到指定的Handler上進行消息解碼。用戶線程能夠經過消息編碼經過NIO線程將消息發送給客戶端。
對於一些小容量應用場景,可使用單線程模型。可是對於高負載、大併發的應用場景卻不合適,主要緣由以下:
1) 一個NIO線程同時處理成百上千的鏈路,性能上沒法支撐,即使NIO線程的CPU負荷達到100%,也沒法知足海量消息的編碼、解碼、讀取和發送;
2) 當NIO線程負載太重以後,處理速度將變慢,這會致使大量客戶端鏈接超時,超時以後每每會進行重發,這更加劇了NIO線程的負載,最終會致使大量消息積壓和處理超時,成爲系統的性能瓶頸;
3)可靠性問題:一旦NIO線程意外跑飛,或者進入死循環,會致使整個系統通訊模塊不可用,不能接收和處理外部消息,形成節點故障。
爲了解決這些問題,演進出了Reactor多線程模型,下面咱們一塊兒學習下Reactor多線程模型。
4.2 多線程模型
Rector多線程模型與單線程模型最大的區別就是有一組NIO線程處理IO操做,它的原理圖以下:
圖1-2 Reactor多線程模型
Reactor多線程模型的特色:
1) 有專門一個NIO線程-Acceptor線程用於監聽服務端,接收客戶端的TCP鏈接請求;
2) 網絡IO操做-讀、寫等由一個NIO線程池負責,線程池能夠採用標準的JDK線程池實現,它包含一個任務隊列和N個可用的線程,由這些NIO線程負責消息的讀取、解碼、編碼和發送;
3) 1個NIO線程能夠同時處理N條鏈路,可是1個鏈路只對應1個NIO線程,防止發生併發操做問題。
在絕大多數場景下,Reactor多線程模型均可以知足性能需求;可是,在極個別特殊場景中,一個NIO線程負責監聽和處理全部的客戶端鏈接可能會存在性能問題。例如併發百萬客戶端鏈接,或者服務端須要對客戶端握手進行安全認證,可是認證自己很是損耗性能。在這類場景下,單獨一個Acceptor線程可能會存在性能不足問題,爲了解決性能問題,產生了第三種Reactor線程模型-主從Reactor多線程模型。
4.3 主從多線程模型
主從Reactor線程模型的特色是:服務端用於接收客戶端鏈接的再也不是個1個單獨的NIO線程,而是一個獨立的NIO線程池。Acceptor接收到客戶端TCP鏈接請求處理完成後(可能包含接入認證等),將新建立的SocketChannel註冊到IO線程池(sub reactor線程池)的某個IO線程上,由它負責SocketChannel的讀寫和編解碼工做。Acceptor線程池僅僅只用於客戶端的登錄、握手和安全認證,一旦鏈路創建成功,就將鏈路註冊到後端subReactor線程池的IO線程上,由IO線程負責後續的IO操做。
它的線程模型以下圖所示:
圖1-3 主從Reactor多線程模型
利用主從NIO線程模型,能夠解決1個服務端監聽線程沒法有效處理全部客戶端鏈接的性能不足問題。
它的工做流程總結以下:
從主線程池中隨機選擇一個Reactor線程做爲Acceptor線程,用於綁定監聽端口,接收客戶端鏈接;
Acceptor線程接收客戶端鏈接請求以後建立新的SocketChannel,將其註冊到主線程池的其它Reactor線程上,由其負責接入認證、IP黑白名單過濾、握手等操做;
步驟2完成以後,業務層的鏈路正式創建,將SocketChannel從主線程池的Reactor線程的多路複用器上摘除,從新註冊到Sub線程池的線程上,用於處理I/O的讀寫操做。