RPC整個過程涉及四類對象:客戶端、客戶端代理、服務端和服務端代理。RPC要求客戶端和服務端之間約定好調用接口和傳輸格式(如JSON,Xml等),客戶端在調用該接口時,由客戶端的代理對象負責對調用的參數(包括調用的函數名和參數等信息)進行格式轉換,使之符合約定的傳輸格式,並經過網絡傳送至服務端。數據傳輸至服務端後,交由服務端代理對象進行格式解碼,獲取調用的接口和參數,最後調用服務端對象相應的方法獲取結果並返回客戶端。服務端的服務地址發佈到ConfigServer,並推送給客戶端,各類配置和規則信息經過Diamond發佈訂閱,服務的基本信息採集到Redis中。java
這張圖是解釋RPC註冊中心經典的圖,圖中的ConfigServer能夠看作是一個內存數據庫,它主要有兩個功能:linux
這裏須要注意的是:真正發起遠程調用是在消費者端和服務端生產者端和ConfigServer沒有直接關係,實際的RPC是一個點對點的過程,經過TCP進行通訊。spring
常見I/O模型數據庫
用戶進程實際上是須要不斷的主動詢問kernel數據好了沒有。由於須要不斷地輪詢,這消耗了大量的CPU的資源。編程
select本質上是經過設置或者檢查存放fd標誌位的數據結構來進行下一步處理。這樣所帶來的缺點是:windows
對socket進行掃描時是線性掃描,即採用輪詢的方法,效率較低:
當套接字比較多的時候,每次select()都要經過遍歷FD_SETSIZE個Socket來完成調度,無論哪一個Socket是活躍的,都遍歷一遍。這會浪費不少CPU時間。若是能給套接字註冊某個回調函數,當他們活躍時,自動完成相關操做,那就避免了輪詢,這正是epoll與kqueue作的。後端
須要維護一個用來存放大量fd的數據結構,這樣會使得用戶空間和內核空間在傳遞該結構時複製開銷大數組
poll本質上和select沒有區別,它將用戶傳入的數組拷貝到內核空間,而後查詢每一個fd對應的設備狀態,若是設備就緒則在設備等待隊列中加入一項並繼續遍歷,若是遍歷完全部fd後沒有發現就緒設備,則掛起當前進程,直到設備就緒或者主動超時,被喚醒後它又要再次遍歷fd。這個過程經歷了屢次無謂的遍歷。服務器
它沒有最大鏈接數的限制,緣由是它是基於鏈表來存儲的,可是一樣有一個缺點:網絡
大量的fd的數組被總體複製於用戶態和內核地址空間之間,而無論這樣的複製是否是有意義。 2. poll還有一個特色是「水平觸發」,若是報告了fd後,沒有被處理,那麼下次poll時會再次報告該fd。
epoll支持水平觸發和邊緣觸發,最大的特色在於邊緣觸發,它只告訴進程哪些fd剛剛變爲就需態,而且只會通知一次。還有一個特色是,epoll使用「事件」的就緒通知方式,經過epoll_ctl註冊fd,一旦該fd就緒,內核就會採用相似callback的回調機制來激活該fd,epoll_wait即可以收到通知。
Java從1.4開始提供了NIO工具包,支持用 I/O複用模型來進行網絡編程。其模式圖:
這種模型與信號驅動模型的主要區別是:信號驅動I/O由內核通知咱們什麼時候能夠開始一個I/O操做,而異步I/O模型由內核通知咱們I/O操做什麼時候已經完成.
JDK1.7 升級了NIO 類庫,升級後的NIO類庫被稱爲NIO2.0。java也正是提供了異步文件I/O操做,同時提供了與UNIX網絡編程事件驅動I/O對應的AIO。
Netty4的beta3加了AIO了,可是到beta9又被去了,做者的意思是測試下來AIO性能不如NIO,因此不必用,在Linux上NIO的實現自己就是epoll,使用jdk的AIO沒有意義,在windows上jdk的AIO實現是IOCP,這種狀況下使用AIO是比poll的性能高的,可是netty的服務器通常是在linux上,因此拋棄windows沒啥大不了,windows最多作個客戶端,用nio也就夠了。