zeromq总结
2019獨角獸企業重金招聘Python工程師標準>>>
下面解釋一下zeromq常用的幾種網絡pattern:
1)?request-reply
就是一般的C/S架構中,client與server之間一問一答的通信模式,比如最經典的echo服務.需要注意的是,client發送一個request,server必須有一個回應.?這個pattern并不是什么亮點,下面亮點來了.
2)?publish-subscribe
server端作為publish端,而任何連接到服務端的client都會成為subscribe端.也就是說,server端會把當前的所有需要publish出去的消息全部發送到當前連接上去的client上.
3)?push-pull
server端作為push端,而client端作為pull端.如果有多個client端同時連接到這個server,則服務器會在內部做一個負載均衡,采用平均分配的算法,將所有的消息均衡發布到client端上.
看上去,很稀松平常?接下來亮點真的來了.
2),3)兩種模式中,無論是server端還是client端在啟動時?都是不知道client實際數量的,這就意味著,一個使用zeromq搭建的服務,可以進行”熱更新”.
考慮如下一種場景.一個server端做為一組服務器集群最上層的一個proxy,起到負載均衡的作用,將請求按照它下面對應服務器集群依次派發到不同的?client端進行處理.某個時刻可能處理的機器只有2臺,而隨著負載越來越大,可能需要3臺機器了,這個時候如果使用zeromq的push-pull?搭建的proxy端,則可以不用對之前搭建的server,client端進行停機,只需要新啟動一個client連接上去,proxy層就會自動根據當前的機器分配平均派發任務了.cool.?實際上,這些模式并不是什么新東西,只不過zeromq為使用者做了一個封裝,而不是像libevent,ACE等還局限在網絡層部分的封裝,它關注的是通信層,通信模式等.
個人感覺,zeromq部分解決?了erlang所要解決的問題:在多臺機器中通信,派發任務等,是分布式通信的利器,但是局限于語言的限制,它沒有辦法做的跟erlang一樣的完善(erlang已經可以算的上一個簡易微型的OS了),但是許多的時候,似乎只使用這一部分功能也就足夠了.?zeromq的代碼量,截至到我目前閱讀的2.0.10-stable版本,也只有不到2W行代碼.提供出去的API也極為簡單,但是內部的實現比較”繞”,zeromq是我閱讀過的項目中少數的非常需要依賴調試工具跟進代碼才能看懂代碼流程的項目,同時代碼中類的繼承層次也比較多,閱讀起來并不像它提供的API那樣簡單直白.后續會對其中的一些難點做一些分析.
3?ZeroMQ?的模式
在需要并行化處理數據的時候,采用消息隊列通訊的方式來協作,比采用共享狀態的方式要好的多。Erlang?,Go?都使用這一手段來讓并行任務之間協同工作。
最近讀完了?ZeroMQ?的?Guide。寫的很不錯。前幾年一直有做類似的工作,但是自己總結的不好。而?ZeroMQ?把消息通訊方面的模式總結的很不錯。
ZeroMQ?并不是一個對?socket?的封裝,不能用它去實現已有的網絡協議。它有自己的模式,不同于更底層的點對點通訊模式。它有比?tcp?協議更高一級的協議。(當然?ZeroMQ?不一定基于?TCP?協議,它也可以用于進程間和進程內通訊。)它改變了通訊都基于一對一的連接這個假設。
ZeroMQ?把通訊的需求看成四類。其中一類是一對一結對通訊,用來支持傳統的?TCP?socket?模型,但并不推薦使用。常用的通訊模式只有三類。
1.?請求回應模型。由請求端發起請求,并等待回應端回應請求。從請求端來看,一定是一對對收發配對的;反之,在回應端一定是發收對。請求端和回應端都可以是?1:N?的模型。通常把?1?認為是?server?,N?認為是?Client?。ZeroMQ?可以很好的支持路由功能(實現路由功能的組件叫作?Device),把?1:N?擴展為?N:M?(只需要加入若干路由節點)。從這個模型看,更底層的端點地址是對上層隱藏的。每個請求都隱含有回應地址,而應用則不關心它。
2.?發布訂閱模型。這個模型里,發布端是單向只發送數據的,且不關心是否把全部的信息都發送給訂閱端。如果發布端開始發布信息的時候,訂閱端尚未連接上來,這些信息直接丟棄。不過一旦訂閱端連接上來,中間會保證沒有信息丟失。同樣,訂閱端則只負責接收,而不能反饋。如果發布端和訂閱端需要交互(比如要確認訂閱者是否已經連接上),則使用額外的?socket?采用請求回應模型滿足這個需求。
3.?管道模型。這個模型里,管道是單向的,從?PUSH?端單向的向?PULL?端單向的推送數據流。
任何分布式,并行的需求,都可以用這三種模型組合起來解決問題。ZeroMQ?只專注和解決了消息通訊這一基本問題,干的非常漂亮。
基于定義好的模型,我們可以看到,api?可以實現的非常簡單易用。我們不再需要?bind/listen/accept?來架設服務器,因為這個模型天然是?1:N?而不是?1:1?的,不需要為每個通道保留一個句柄。我們也不必在意?server?是否先啟動(bind),而后才能讓?client?工作起來(connect)。
這以上模型中,關注的是通訊雙方的職責,而不是實現的方式:監聽端口還是連接對方端口。對于復雜的多進程協同工作的系統,?不必糾結于進程啟動的次序(在我前幾年設計的系統中,啟動腳本寫起來就非常麻煩)。
使用?ZeroMQ?不必在意底層實現是使用短連接還是長連接方式。ZeroMQ?中的?Transient?(短暫)?和?Durable?(持久)?socket?也并非區別于實現層是否保持了?tcp?連接。而是概念上的不同。對于?Durable?socket?,其生命期可以長于一個進程的生命期,即使進程退出,再次啟動后依舊可以維持繼續之前的?socket?。當然,這并不是幫助你挽救你的程序因出錯而崩潰的。它只是提出這個模式,讓你根據設計需要可以實現。對于?ZeroMQ?,如有需求(若內存有限),甚至把數據傳輸的?buffer?放到磁盤上。
對于網絡游戲,我覺得基于?ZeroMQ?來架構服務器非常合適。對于玩家?Client?-?Server?部分倒不必使用?ZeroMQ?,而可以寫一個前端程序,比如前些年寫過的一篇?blog?中提到的連接服務器依然適用。這個連接服務器對內的服務集群則可以用?ZeroMQ?的協議通訊。
4?開發注意事項
4.1?zmq_msg_copy()?和?memcpy()區別
zmq_msg_copy()?和?memcpy()的作用是不一樣的,zmq應該有自定義的數據塊結構,zmq_msg_copy會把原有的成員對應的在目標msg的成員賦值。其中,指針不是深拷貝,ZMQ數據塊是共享指針,ZMQ數據塊上有引用計數器。?
zmq效率很高,而且是很小的開發包。zmq同時封裝了TCP?UDP?和UNIX?DOMAIN?socket等。Zmq負責管理連接和消息收、發、緩沖等。zmq沒有單獨的隊列對象,zmq隊列都是內部需要緩沖需要發送出去的但還沒能發出去的消息,或者收到其他隊列發過來的消息,用戶還沒取消息時zmq先緩存消息。?
如果和對端的鏈路連接出問題,zmq會先在本地保存,但對無限保存緩沖消息的話總有內存上的限制的。?
zmq的connect一次后,鏈路的維護zmq內部有處理。就是說發了一次包后,長時間才發第二次,這樣的情況也支持。zmq負責管理鏈路連接,connect調用后其實底層真實的連接可能還沒建立的,zmq會自動嘗試連接。就是說connct一次就可以了,然后就算鏈路斷了,再send它也會重新連接。?
4.3?req/resp網絡模式
這種模式下,server接收了一條req,必須要回復一個resp才能進入下一輪的監聽,否則,沒回復就進入下一輪監聽會出現錯誤。
轉載于:https://my.oschina.net/zhangjie830621/blog/350827
總結
- 上一篇: 一个能从别人的观念来看事情,能了解别人心
- 下一篇: mysql Table 'plugi