网络IO发展历程:BIO、NIO、多路复用器、epoll
網絡側IO,通過網絡來通信(偏向內核方面)
C10K問題:http://www.kegel.com/c10k.html#frameworks
BIO NIO 多路復用器
什么是NIO
操作系統角度:NIO表示非阻塞IO,nonblocking;
JDK角度:N表示New IO(要掌握nonblocking,channel,buffer,selector),內存、文件系統
要想明白JDK的NIO,要先明白操作系統的NIO
今天講一些詞匯:同步、異步、阻塞、非阻塞
1、OS
程序不能直接訪問內核,用戶程序想要調用內核的方法,需要使用int 80中斷,CPU從用戶態切換到內核態。操作系統給內核暴露了幾百個系統調用syscall。
IDT:中斷描述符表,記錄0~255中斷號,在BIOS就加載了,內核進行callback,比如int 0x80,這里的80是中斷號
GDT:全局描述符表。
關于中斷的概念:使用晶振(將直流電流轉換為…打點),實現CPU的時間分片。中斷分為軟中斷(多個進程的切換,讓他們看似同時在執行)、硬件中斷(接受鍵盤、鼠標輸入)。進程想要訪問硬件,需要觸發int 0x80中斷
宏觀并行、微觀串行
新版圖:
舉例
來看一段簡單的可以進行網絡通信的java代碼(JDK1.4),來說明計算機的通信是怎么完成的
抓取程序和內核之間的系統調用,追蹤每一個線程,并輸出到一個文件中:
strace用來監控指定的程序(字節碼)發生了哪些系統調用
運行后生成的輸出文件:
JVM是C語言開發的,跑在操作系統之上,進行了系統調用。
下面是輸出了java代碼在內核中實際進行的系統調用:
2541行的3就是java代碼中 new 出的ServerSocket(),在3上綁定了端口號
最后一行看到accept(3,證明調用被阻塞了
使用tail一直盯著這個輸出,同時:開一個窗口,建立連接、發數據
使用nc手工建立一個新的連接:
查看輸出:
recv(5,是再一次阻塞,
再用客戶端 隨意輸入一些數據,再查看輸出:
查看server端的端口監聽
關于文件描述符:linux一切皆文件
文件描述符3:用來代表監聽
文件描述符3,4:一個是ipv4,一個是ipv6
(補充)使用jps命令可以查看java線程號12855
建立客戶端連接之后,fd文件描述符里面多出一個5,代表新建立的這個連接:
上述這種情況,如果一個客戶端連接之后一直不發數據,會一直阻塞。別人無法連接進來。
那么,如何實現能夠接受多個客戶端?
傳統的BIO模型:讓一個連接對應一個線程,每新開一個連接,就給它新開一個線程。
弊端:線程過多
如何解決C10K問題?
C10K問題:用戶態和內核態之間頻繁切換。CPU在一個時間片只能處理一個程序(線程),線程具有獨立的棧,當線程過多時,調度的時候成本較高。
問題的本質:因為阻塞(BIO)。為了解決阻塞,才開啟的多線程。想解決這個問題,從內核的角度考慮,可以考慮讓系統調用得到的文件描述符3,5變成非阻塞。
解決問題的思路:將阻塞變為不阻塞。這種功能應該在內核實現,而不是用程序實現。
不要受到一些文章的影響,簡單的用“加機器”的方式解決問題。
將單擊性能已經壓榨到極限時,再考慮加機器,分布式/用集群。
我們看內核的系統調用:
內核有一種非阻塞模式:在accept(3,中空轉,要么返回client的描述符,要么返回-1
使用了NIO的新代碼:
(補充代碼圖)
用了NIO的api,不能在JDK1.4中使用。可以在JDK1.8中使用。
ss.configBlocking(false);設置非阻塞
后面用一個循環,每一次循環中,如果沒有連接,則打印null;如果有連接,則打印端口號。這樣
運行后,看循環輸出的null可以判斷,沒有進入阻塞狀態
accept一直都是-1,沒有阻塞。代表沒有連接。
連接進來一個客戶端之后:
用一個線程可以接受很多客戶端。(NIO:NonBlocking)
NIO的存在的問題
放大:
C10K當并發量很大的時候,文件描述符會很多,每循環一次,都要調用一次recv系統調用(復雜度O(n)),進行用戶態到內核態的切換,切換時性能損耗大。
縮小:
當C10K只有1個C發來了數據,只使用到了1個有用的系統調用,剩余n-1次的監聽都是無效的->技術選型失敗。(架構師進行技術選型:要懂原理)
如何解決:多路復用
多路復用
多條路復用了一次調用得到具體的到來情況
實現方式:內核
允許程序去調用內核,來監控更多的客戶端,直到一個或多個文件描述符是可用的狀態,再返回。減少了用戶態、內核態的無用切換。
select多路復用器返回給程序一個list,告訴程序哪些可以讀取,然后程序要自己讀取。這是同步模型。
如果程序自己讀取,程序在IO上的模型就叫同步模型。
如果程序把讀取的過程交給內核,自己做自己的事情,叫異步模型。
多路復用的問題:如果有很多長連接,內核每次都要給程序傳遞很多連接對象
解決方式:epoll
epoll
Epoll也是多路復用器。它不負責讀取IO,只關心返回結果。Epoll是Event poll,把有數據這個事件通知給程序,還需要程序自己取讀取數據。
man epoll查看命令幫助文檔
epoll_create, epoll_ctl, epoll_wait
監控redis用的是哪種系統調用
netty是同步IO,異步計算
總結
以上是生活随笔為你收集整理的网络IO发展历程:BIO、NIO、多路复用器、epoll的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 技术人员究竟应该如何保持快速学习的能力?
- 下一篇: 【ElasticSearch】使用Doc