天天看點

[架構] ZeroMQ 深度探索(一)

最初認識 ZeroMQ 是被它的名号所吸引,最近在一個高性能中間件的項目中用到了 ZeroMQ,對這個号稱“史上最快的消息隊列”有了更深層次的了解。如果我們僅僅把 ZeroMQ 看作是一個消息隊列,那就完全搞錯了,ZeroMQ 是一套智能傳輸層協定,它不僅為開發者提供了強大的開發包,還包含了一套很棒的通信協定的實作,更值得一提是,它對分布式系統開發有着相當獨到的見解,絕對值得我們好好學習。ZeroMQ 的最終目标是加入 Linux 核心,目前 ZeroMQ 已經出現在 YUM 中,相信 ZeroMQ 的未來會越來越美好!

ZeroMQ 特點介紹

1、支援高并發的異步 Socket 架構

2、協定比 TCP 更快、适用于大型叢集和分布式計算

3、提供多種消息傳遞機制,如 inproc/IPC/TCP/multicast 等

4、内置豐富的組合模式,可用于簡化大型分步式計算架構

5、提供異步 I/O 模式,适用于可擴充的多核應用開發

6、擁有活躍的開發者社群提供技術支援,發展相當迅速

7、支援超過 30 種的程式設計語言,如 C/C++/Java/.NET/Python/PHP 等

8、良好的跨平台性,支援多種 OS,如 Linux/Windows/OS X 等

9、擁有 iMatix 公司的商業級别支援,卻是完全免費的

ZeroMQ 設計哲學

綜合來說,ZeroMQ 的設計哲學在于“權衡”兩字,其實 ZeroMQ 的名字就展現了這一點。“Zero”表示從零開始,也就是從無到有;ZeroMQ 不提供現成的安裝套件(比如broker),這也意味着使用者必須自己來建構需要的套件,這種做法各有利弊;“利”在于使用者可以自由的構造屬于自己的分布式系統,而“弊”則在于門檻比較高,對于不熟悉程式設計的使用者來說就麻煩大了。不過,相比與通過功能疊代來實作複雜需求的方案來說,ZeroMQ 更傾向于從根本上解決問題,這也正展現了 ZeroMQ 創始人 Pieter Hintjens 的設計哲學。

ZeroMQ 面向使用者

ZeroMQ 是為那些對大型分布式系統感興趣的開發者們而生的!假如你熟悉 C 語言,那麼使用 ZeroMQ 将是件非常享受的事情,因為 ZeroMQ 開發包中已經包含了非常豐富的 C 語言的使用範例,有經驗的開發者可以快速入手。使用 ZeroMQ 可以為我們節省下大量的編碼時間,當然在此之前,我們需要把 ZeroMQ 的基礎知識和用法了解透徹,否則誤用或者錯用的話,後果将是“很嚴重”的!接下來,我們開始學習 ZeroMQ 的基礎知識。

ZeroMQ 學前必讀

ZeroMQ 究竟是什麼?也許我們應該先“大肆吹噓”一番,但這顯然是毫無意義的,也不是我們技術人員的本色。簡單來說,ZeroMQ 是一個更小、更快、更簡單的智能傳輸層協定,它可以幫助我們簡化原本非常複雜的事情,實際上,這也就是當初設計 ZeroMQ 時的初衷。

今天,我們的世界變得越來越複雜,我們使用的軟體也在随着人類社會的變化而演變。可以預見到的是,未來的軟體系統将會變得越來越龐大,就像人類的大腦一樣,錯綜複雜;這個時候,我們必須得把問題分解開來,逐個擊破,否則,軟體最終隻能變成可怕的巨獸,把一切都搞砸。分而治之,講的就是這個道理,這也就是我們需要分布式系統的原因。

在分布式系統中,代碼之間需要通信,此時我們就必須使用網絡、協定、線程這些工具來實作;然而,現實情況是,即使我們已經擁有了這些工具,但實作起來仍然非常費功夫。目前業界可用的網絡協定比較有限,比如 TCP/UDP/HTTP/Websocket 等;這些協定要麼太複雜,要麼太笨重,也許我們會抱怨道,難道沒有其他的選擇了嗎?ZeroMQ 是否會是我們期待的答案?下面,讓我們回到兩個最基本的問題上,一是如何實作代碼之間需要通信,二是如何讓通信變得更簡單高效。

ZeroMQ HelloWorld

接下來,我們先從一個最簡單的例子,即 HelloWorld 項目講起。這就是網絡請求中最基本的“請求-響應”模式(Request-Reply),用戶端往服務端發送“Hello”,服務端回應“World”,如圖1-1。

[架構] ZeroMQ 深度探索(一)

以下是 HelloWorld 項目的服務端代碼(hwserver.c),熟悉 Socket 程式設計的同學應該很容易了解其中的文法,即使用 TCP 協定,監聽 5555 端口,然後不停地接受、列印并傳回資訊,每次處理後停止 1 秒。

// Hello World server

#include <zmq.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>

int main (void)
{
    // Socket to talk to clients
    void *context = zmq_ctx_new ();
    void *responder = zmq_socket (context, ZMQ_REP);
    int rc = zmq_bind (responder, "tcp://*:5555");
    assert (rc == 0);

    while (1) {
        char buffer [10];
        zmq_recv (responder, buffer, 10, 0);
        printf ("Received Hello\n");
        zmq_send (responder, "World", 5, 0);
        sleep (1); // Do some 'work'
    }
    return 0;
}
           

以下是 HelloWorld 項目的用戶端代碼(hwclient.c),邏輯也很簡單,向服務端連續發送 10 條消息,接受并列印傳回資訊。

// Hello World client
#include <zmq.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>

int main (void)
{
    printf ("Connecting to hello world server…\n");
    void *context = zmq_ctx_new ();
    void *requester = zmq_socket (context, ZMQ_REQ);
    zmq_connect (requester, "tcp://localhost:5555");

    int request_nbr;
    for (request_nbr = 0; request_nbr != 10; request_nbr++) {
        char buffer [10];
        printf ("Sending Hello %d…\n", request_nbr);
        zmq_send (requester, "Hello", 5, 0);
        zmq_recv (requester, buffer, 10, 0);
        printf ("Received World %d\n", request_nbr);
    }
    zmq_close (requester);
    zmq_ctx_destroy (context);
    return 0;
}
           

服務端代碼的運作結果如圖1-2。

[架構] ZeroMQ 深度探索(一)

用戶端代碼的運作結果如圖1-3。

[架構] ZeroMQ 深度探索(一)

運作結果很容易了解,這就是一個标準的“請求-響應”模式的例子。從中我們可以看到使用 ZeroMQ 的類庫實作起來還是很簡單的,和基礎 Socket 庫的用法差不多,實作的功能也差不了多少,但是事實是否如此呢?在下一篇《 ZeroMQ 深度探索(二)》中我們将深入讨論這個問題,未完待續...

TIP:建議大家使用 3.2 以上的版本進行開發。以後所有的的例子都是基于 C 語言的。所有的示例代碼可以通過“git clone --depth=1 git://github.com/imatix/zguide.git”擷取。

繼續閱讀