zmq一些擴展模式 客戶端服務器 一對多 多對多問題 訂閱模式的擴展等

級聯模式

通常,一個節點,即可以作爲 Server,同時也能作爲 Client,通過 PipeLine 模型中的 Worker,他向上連接着任務分發,向下連接着結果蒐集的 Sink 機器。因此,我們可以藉助這種特性,豐富的擴展原有的三種模式。例如,一個代理 Publisher,作爲一個內網的 Subscriber 接受信息,同時將信息,轉發到外網,其結構圖
在這裏插入圖片描述
多個服務器
ZMQ 和 Socket 的區別在於,前者支持N:M的連接,而後者則只是1:1的連接,那麼一個 Client 連接多個 Server 的情況是怎樣的呢

ZMQ 的N:1的連接情況:(一對多)

在這裏插入圖片描述
我們假設 Client 有 R1,R2,R3,R4四個任務,我們只需要一個 ZMQ 的 Socket,就可以連接四個服務,他能夠自動均衡的分配任務。如圖所示,R1,R4自動分配到了節點A,R2到了B,R3到了C。

N:M的連接(多對多)

如圖:
在這裏插入圖片描述
我們通過一箇中間結點(Broker)來進行負載均衡的功能。我們通過代碼瞭解,其中的 Client 實際基礎的zmq.REQ模式,而 Server 端的不同是,他不需要監聽端口,而是需要連接 Broker 的端口,接受需要處理的信息。所以,我們重點閱讀 Broker 的代碼:

client.py

import zmq,time

#  Prepare our context and sockets
context = zmq.Context()
socket = context.socket(zmq.REQ)
socket.connect("tcp://localhost:5559")

#  Do 10 requests, waiting each time for a response
for request in range(1,11):
    time.sleep(2)
    socket.send(b"Hello")
    message = socket.recv()
    print("Received reply %s [%s]" % (request, message))

Broker.py

import zmq,time

# Prepare our context and sockets
context = zmq.Context()
frontend = context.socket(zmq.ROUTER)
backend = context.socket(zmq.DEALER)
frontend.bind("tcp://*:5559")
backend.bind("tcp://*:5560")

# Initialize poll set
poller = zmq.Poller()
poller.register(frontend, zmq.POLLIN)
poller.register(backend, zmq.POLLIN)

# Switch messages between sockets
while True:
    socks = dict(poller.poll())   #輪詢器 循環接收

    if socks.get(frontend) == zmq.POLLIN:
        message = frontend.recv_multipart()
        backend.send_multipart(message)

    if socks.get(backend) == zmq.POLLIN:
        message = backend.recv_multipart()
        frontend.send_multipart(message)

server.py

import zmq

context = zmq.Context()
socket = context.socket(zmq.REP)
socket.connect("tcp://localhost:5560")

while True:
    message = socket.recv()
    print("Received request: %s" % message)
    socket.send(b"World")

同時我們可以開多個客戶端可多個服務端來同時進行,Broker.py可以根據收到消息的不同來進行相應的處理返回給對方
Broker 監聽了兩個端口,接受從多個 Client 端發送過來的數據,並將數據,轉發給 Server。在 Broker 中,我們監聽了兩個端口,使用了兩個 Socket,那麼對於多個 Socket 的情況,我們是不需要通過輪詢的方式去處理數據的,在之前,我們可以使用 libevent 實現,異步的信息處理和傳輸。而現在,我們只需要使用 ZMQ 的$poll->poll 以實現多個 Socket 的異步處理。

擴展 ZMQ 的訂閱者模式

當我們將 WEB 代碼部署到集羣上的時候,如果需要實時的將最新的配置信息,主動的推送到各個機器節點。在此過程中,我們一定要保證,各個節點收到的信息的一致性和正確性,如果使用 HTTP,由於他的無狀態性,我們無法保證信息的一致性,當然,你可以使用 HTTP 來實現,只是更復雜,ZMQ是更好的選擇
我們使用 ZMQ 的信息訂閱模式。在普通模式中,我們注意到,對於後來的加入節點,始終會丟失在他加入之前,已經發送的信息(Slow joiner)。我們可以開啓另外一個 ZMQ 的通信通道,用於報告當前節點的情況(節點的身份、準備狀態等),保證所有的節點都連接完成之後再開始推送消息,其結構如圖所示:
在這裏插入圖片描述
使用 Request-Reply 連接來確認所有的節點連接完畢
Sub代碼:

import time
import zmq

def main():
    context = zmq.Context()
    #創建接收訂閱消息的連接
    subscriber = context.socket(zmq.SUB)
    subscriber.connect('tcp://localhost:5561')
    #設置接收的連接頭
    subscriber.setsockopt(zmq.SUBSCRIBE, b'')
  
    time.sleep(1)
    #創建用來確認用戶連接是否足夠的連接
    syncclient = context.socket(zmq.REQ)
    syncclient.connect('tcp://localhost:5562')
    #發送確認連接的消息 並接受`在這裏插入代碼片`
    syncclient.send(b'')
    syncclient.recv()
    
    nbr = 0
    while True:
        msg = subscriber.recv()
        if msg == b'END':
            break
            nbr += 1
            print ('Received %d updates' % nbr)

if __name__ == '__main__':
    main()

pub代碼:

import zmq

# 確認節點數目達到要求
SUBSCRIBERS_EXPECTED = 10

def main():
    context = zmq.Context()
    # 創建用來發送需要的消息的連接
    publisher = context.socket(zmq.PUB)
    publisher.sndhwm = 1100000  # 設置高水位標記
    publisher.bind('tcp://*:5561')
    # 創建用來確認用戶數量是否足夠的連接
    syncservice = context.socket(zmq.REP)
    syncservice.bind('tcp://*:5562')
    subscribers = 0

    # 判斷此時的連接數 不夠的話繼續接收並連接
    while subscribers < SUBSCRIBERS_EXPECTED:
        msg = syncservice.recv()
        syncservice.send(b'')
        subscribers += 1
        print("+1 subscriber (%i/%i)" % (subscribers, SUBSCRIBERS_EXPECTED))
   #當連接數量足夠了開始發佈消息
    for i in range(1000000):
        publisher.send(b'Rhubarb')
    publisher.send(b'END')


if __name__ == '__main__':
    main()

如果使用TCP連接並且訂閱者是慢速的,那麼消息將在發佈方排隊;可以使用高水位標記(High-Water Marks,HWM)來定義緩衝區的大小,在ZeroMQ v2.x版本中HWM默認是無限制的,而在v3.x中默認情況下它是1000。對於PUB套接字,當到達HWM時,將丟棄數據。設置HWM參數:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章