zeromq用來怎麼玩?
最近看了一本書《ZeroMQ:雲時代極速消息通信庫》,作者說那是更好用的socket,但感覺用起來相比其他穩定的網路庫沒有更簡單,因為本身有一定的消息格式,所以主要用於集群內部,但是集群內部都可以用自己喜歡的庫,因此覺得要使用zeromq的話需要投資一定學習時間並且看不到特別優勢。。。請問應該怎麼正確地玩zeromq?有沒有非用一種消息隊列不可的項目?
2015-03-19
最近也在學ZeroMQ,先列一些前輩們的學習心得吧:
RabbitMQ, ZeroMQ, Kafka 是一個層級的東西嗎, 相互之間有哪些優缺點? - 消息隊列 新世紀通訊函式庫 (這篇是繁體的,我用firefox的一個插件「同文堂」轉換一下看。)
然後這裡說一下自己的一些體會:
1. 首先弄明白0MQ中的「socket」和傳統意義上socket的一些差異。
我認為ZeroMQ不能算作單純的socket庫,它應該算是一個messaging library,一個「輕量級」的消息隊列庫(這裡所說的「輕量級」是與過去一些企業級的消息隊列對比而言的)。正如我前面列出的兩個大神所說的:socket只是表現形式,而通信模式才是其本質。
也就是說,在學0MQ的時候,不要把0MQ中的socket和系統本身的socket弄混。我們可以看看zmq_socket的文檔:
zmq_socket(3) (zguide告訴我們,這份文檔要時不時的拿出來要多讀幾遍)
注意,每一種不同類型的「socket」,都有自己的消息模式。這其中包括該類型套接字可以和哪些套接字連接到一起工作啊(Compatible peer sockets)、消息傳遞的方向啊(Direction)、消息收發模式啊(Send/receive pattern)、還有Outgoing routing和Incoming routing用到的一些調度演算法啊(比如:Round-robin、Fair-queued,這些調度演算法在操作系統課程中應該會有涉及)。當我們創建一個0MQ套接字後,我們實際上得到的是一個加了各種特效的「socket」。
上面一段話,我意在說明,0MQ中的「socket」沒那麼簡單。借用@Dirk Chang答案中「模式」一詞,0MQ實際上是把一些在實踐中總結出來的消息通信模型封裝成不同類型的套接字,以供我們使用。
我認為,這個帖子中很好地闡明了0MQ中「socket」的含義:
zeromq - Does PyZMQ handle creating threads for each new client connection?
2. 我剛學0MQ的時候總是糾結於「客戶端」、「服務端」的概念。比如REQ-REP模式中,究竟哪一端該作為客戶端,那一端作為服務端呢?
實際上,這也算是個小誤區吧!因為我們不是在用傳統TCP中的Server-client。
在傳統TCP中的Server-client中,server要先啟動,然後bind到一個埠,等待client調用connect連接它。
而0MQ中調用zmq_bind和調用zmq_connect的雙方沒有那麼嚴格的先後順序。這也是0MQ有趣的特性之一。直接引用zguide的中的文字吧:
To create a connection between two nodes, you use zmq_bind() in one node and zmq_connect() in the other. As a general rule of thumb, the node that does zmq_bind() is a "server", sitting on a well-known network address, and the node which does zmq_connect() is a "client", with unknown or arbitrary network addresses. Thus we say that we "bind a socket to an endpoint" and "connect a socket to an endpoint", the endpoint being that well-known network address.
Many architectures follow some kind of client/server model, where the server is the component that is most static, and the clients are the components that are most dynamic, i.e., they come and go the most. There are sometimes issues of addressing: servers will be visible to clients, but not necessarily vice versa. So mostly it"s obvious which node should be doing zmq_bind() (the server) and which should be doing zmq_connect() (the client). It also depends on the kind of sockets you"re using, with some exceptions for unusual network architectures.
簡而言之,這段話實際上在講,在0MQ中,我們會用它提供的套接字構建一個messaging topology,我們通常認為server端應該是這個topology中比較穩定的組件,由這些比較穩定的組件來調用zmq_bind,而client則是比較動態的部分,它們來來去去,所以我們通常會調用zmq_connect將它們連接到這個topology中比較穩定的部分。比如,在0MQ中,我們會接觸到messaging broker的概念,通常messaging broker會調用zmq_bind,作為服務端存在。
3. 0MQ的一些特點
(1) 速度快
ZeroMQ的第一個特點就是速度快,這篇帖子中大致給了我們一個這樣的概念:
4 款消息隊列軟體產品大比拼
(2) 靈活
首先,再推薦一位大嬸的博客:
遠程調用服務(RPC)和消息(Message Queue)對比及其適用/不適用場合_Pragmatistic Guy
0MQ提供的都是一些基本組件,它允許我們自己搭建自己的messaging topology。所以說,0MQ是很靈活的。
本答案的第二個鏈接中提到,傳統的消息隊列中有一個「中央集權式」的messaging broker,該messaging broker通常會負責消息在各個節點之間的傳輸。而0MQ呢,用zguide中的話講,就是:decentralized。你看,0MQ並不要求你的messaging topology中央必須是一個message broker(這個message broker可能作為消息的存儲、轉發中心)。在一些簡單的通信模型中,省去message broker確實為我們省去了很多工作。而且我們也無需為message broker專門搭建一個伺服器。
我們也許會問,如果缺少了message broker,那麼未及發送/接受的消息會不會丟失呢?不同擔心。因為通常情況下,0MQ中一些套接字本身自帶一個buffer,會把這些消息先存下來。
但是ZeroMQ的去中心化不代表完完全全的去中心化。我認為,ZMQ把建立message broker的自由交給了我們。這樣,我們可以在有需要的時候建立一個proxy,來簡化網路的複雜性和維護城北。zguide中講到的The Dynamic Discovery Problem、Shared Queue其實都是在教我們在不同場景下應該怎樣建立一個broker來降低網路的複雜性而提升其靈活性。
而且,對於一個複雜的消息拓撲,「各自為政」(見:新世紀通訊函式庫)會可能需要在加入新的節點時重新配置消息拓撲(這會在什麼情況下發生,具體可以參考zguide中在介紹The Dynamic Discovery Problem、Shared Queue時引入的例子)。
zguide中描述The Dynamic Discovery Problem這個問題時,拿PUB-SUB模式來舉例,說明了使用中間件可以降低兩兩互聯網路的維護成本。中間件的引入使網路更加靈活,因而增加新的節點更加簡單。如果不採用中間件,則每次增加新的節點時(比如增加一個新的PUB節點),要重新配置該新節點和現有其他節點之間的關係(比如,把剛才新增的PUB節點和所有現有的SUB節點相連)。
再引用一段zguide中的文字:
You might wonder, if all networks eventually get large enough to need intermediaries, why don"t we simply have a message broker in place for all applications? For beginners, it"s a fair compromise. Just always use a star topology, forget about performance, and things will usually work. However, message brokers are greedy things; in their role as central intermediaries, they become too complex, too stateful, and eventually a problem.
我們通過往網路中加入中間件的方法來降低網路的複雜性,這是一個比較普遍的需求。然而ZMQ並沒有因該需求的普遍性而在庫中內置形如message borker這樣的中間件。該段話闡述了ZMQ這樣做的原因:中間件本身是違背ZMQ「去中心化」的設計思想的,而且中間件會變得很複雜。所以,ZMQ把構建中間件的自由給了我們。而且,用ZMQ實現形如message broker這樣的消息中間件並不複雜。
通過上面這些討論,可以看出ZeroMQ極其靈活性(而我們要很好地掌握這種靈活性,需要花些功夫:了解最基本的消息模式、了解彼此之間如何組合起來構建更複雜的消息傳遞網路拓撲。)
(3) 方便
上面提到,0MQ中socket被加了各種特效,所以,我們要實現一些功能的時候,比如:並發、load-balancing,我們需要做的是使用正確的套接字及構建正確的messaging topology。
4. 我認為使用0MQ能帶來的好處(實際上,這段主要得益於公司的一位前輩的指導)
(1) 跨語言變得簡單。
假設,我們有一個模塊是用C++實現的,需要提供給另外一個C#/Java/Python/……應用來調用,過去我們可能會使用「C#嵌入C++」/「Java內嵌C++」形如這樣的黑科技來實現。但是呢,現在,我們可以用0MQ來實現這種通信。因為0MQ為各種主流語言都提供了bindings。
(2) 模塊間的解耦
這裡提一下阿里做的RocketMQ。而且,看一下這個issue:
從開發團隊獲取最新文檔,查看哪些用戶在使用RocketMQ · Issue #1 · alibaba/RocketMQ · GitHub
我們可以看到,很多人拿RocketMQ來做模塊間的解耦。
PS:阿里還提供了和阿里雲結合的RocketMQ。
(3) 插件化
假設我們在實現一個數據採集、處理系統。數據的處理可能會有多步(比如:A、B、C步),通過0MQ我們可以把每一步處理工作都寫成一個模塊,類似於插件。這樣,傳給一個平台的數據可能只需要經過A、C兩步,傳給另一個平台的可能需要A、B、C三步。各個步驟之間通過0MQ傳輸數據。這樣,當我們想增加新的處理步驟的時候,只需要再寫個模塊,並加入處理流程就行了。
(4) 並行、負載均衡
0MQ的並行、負載均衡都已經存在於其基因中了。
zguide中有這麼一段文字:
Multithreading with ZeroMQ
To make utterly perfect MT programs (and I mean that literally), we don"t need mutexes, locks, or any other form of inter-thread communication except messages sent across ZeroMQ sockets.
If you"ve spent years learning tricks to make your MT code work at all, let alone rapidly, with locks and semaphores and critical sections, you will be disgusted when you realize it was all for nothing. If there"s one lesson we"ve learned from 30+ years of concurrent programming, it is: just don"t share state. It"s like two drunkards trying to share a beer. It doesn"t matter if they"re good buddies. Sooner or later, they"re going to get into a fight. And the more drunkards you add to the table, the more they fight each other over the beer. The tragic majority of MT applications look like drunken bar fights.
我認為,值得深思。
你看,學了0MQ,我們的程序設計思路(思考模式)在發生著變化。
5. 一些八卦
github上libzmq的第一貢獻者:
Contributors to zeromq/libzmq · GitHub
是這位大嬸:
sustrik · GitHub
而zguide的作者,以及libzmq目前主要維護者,是這位大嬸(iMatix CEO):
hintjens (Pieter Hintjens) · GitHub
據不負責任傳言,他們本是一家,後來意見發生分歧,前者就出走,另立項目:Crossroads I/O:
ZeroMQ vs Crossroads I/O
後來,Crossroads I/O掛掉之後,前者重寫一個項目:nanomsg/nanomsg · GitHub。
這個PPT透露出了個中八卦,以及zeromq和nanomsg之間的一些差別(其中提到0MQ中「0」的奧義):
Nanomsg: ZeroMQ done right
裡邊插入了奇怪的照片。
還有一個有趣的問題是,sustrik曾說當年選用C++實現libzmq是一個「美麗的」錯誤(「美麗的」是我加的)
為什麼我希望用C而不是C++來實現ZeroMQ Why should I have written ZeroMQ in C, not C++ (part I)
所以你看,nanomsg就是用C實現的了。
另,nanocat貌似不錯。
不過不知道nanomsg示例是否豐富、文檔是否全。相信學了ZeroMQ,nanomsg也很容易上手。
6. 一些資源
(1) zguide
官網上的http://zguide.zeromq.org/page:all只是文檔
imatix/zguide · GitHub
裡面有各種語言的示例。
(2) zguide-cn
這是國內的大嬸翻譯的,不過好久沒更新了。如果一些術語實在不知道啥意思,不妨翻閱一下,和英文版的zguide對比閱讀。
anjuke/zguide-cn · GitHub
(3)
ZeroMQ (豆瓣)
這本書的第一部分就是zguide中的內容,第二部分更偏向實踐應用。
(4)
網路編程 - kaka11的專欄
ZeroMQ源碼分析。orz。
2016-08-29T17:17+08:00
nanomsg 1.0 版已發布。
2016-10-14T13:28+08:00
知乎專欄
Pieter Hintjens 最終選擇了安樂死。R.I.P.
2017-04-09T13:22:29+08:00
《代碼的未來》最後一節講了 ZeroMQ。
----
用過一段時間,基本上只用到了發布發布訂閱(見鬼,linux 下搜狗打不出yue,還是個bug),用這個玩意兒實現了一個簡單的應用框架,不同的功能模塊通過zmq進行數據的共享,還挺方便的。
如果使用發布訂閱,高水位是一個非常隱晦的設置參數(發布者的接收高水位必須大於接收者的訂閱數量,否則接收方會收不到,非常坑爹,文檔沒有任何地方提到這個特性,猜測是高版本下,將過濾放在發布方導致的,因為在內部處理中訂閱方要發送訂閱信息給發布方)再有一個不好就是 context 的概念,及其噁心,作者估計也被噁心的夠嗆,所以才在 nanomsg 中去掉了這一概念,封裝的更加友好了。
熱切期待 nanomsg 不想再用zmq 了。
建議也了解一下原作者新重新實現的nanomsg
http://nanomsg.org/documentation.html
你就說不比哪個網路庫簡單吧
我用ROTER、DEALER模式實現了一個使用訂閱發布模式的消息匯流排……通過特地通訊協議,還能定向推送消息……並且支持多個消息匯流排之間互相訂閱……總之就是一個很自由的通訊框架了……
當然,訂閱發布的邏輯是自己實現的…定義了一種很原始的通訊協議實現的……
怎麼說呢…經過一次不嚴謹的測試,竟然比原生的訂閱發布效率要高……(當然,很不嚴謹。區域網內100台機器訂閱相同的消息,進行三維模型的運動同步顯示……)
嗯,基本上還是挺不錯的,就是之前沒優化消息,網路佔用率100%了……
通道到模式的思考方式的變化
zeromq我學了兩個晚上用起來了,現在還有子服務在用...跑了兩年多了...
當然我只是用了request/reply這一種模式,其他的按照sample試了下而以...沒深入過推薦閱讀: