簡體   English   中英

PUB-SUB 的 ZMQ 延遲(慢速訂閱者)

[英]ZMQ latency with PUB-SUB (slow subscriber)

我發現了很多關於類似主題的問題,但它們並沒有幫助我解決我的問題。

使用 :

  • Linux Ubuntu 14.04
  • 蟒蛇 3.4
  • zmq : 4.0.4 // pyZMQ 14.3.1

TL; 博士

即使設置了 HWM,ZMQ SUB 套接字中的接收器隊列也在無限增長。 當訂閱者比發布者慢時會發生這種情況。 我能做些什么來防止它?

背景

我在人機交互領域工作。 我們有一個龐大的代碼庫來控制鼠標光標,這類事情。 我想在幾個模塊中“打破它”,與 ZMQ 通信。 它必須具有盡可能小的延遲,但丟棄(丟失)消息並不那么重要。

另一個有趣的方面是可以在節點之間添加“間諜”。 因此,PUB/SUB 插座似乎是最合適的。

像這樣的事情:

+----------+                +-----------+                 +------------+
|          | PUB            |           |  PUB            |            |
|  Input   | +----+------>  |  Filter   |  +----+------>  |   Output   |
|          |      |     SUB |           |       |     SUB |            |
+----------+      v         +-----------+       v         +------------+
               +-----+                       +-----+                   
               |Spy 1|                       |Spy 2|                   
               +-----+                       +-----+       

問題

一切正常,除非我們添加間諜。 如果我們添加一個間諜來做“繁重的事情”,比如使用 matplotlib 進行實時可視化,我們會注意到繪圖中的延遲增加。 IE :在上圖中,過濾器和輸出速度很快,沒有看到延遲,但在 Spy 2 上,運行 20 分鍾后延遲可以達到 10 分鍾(!!)

看起來接收器上的隊列無限增長。 我們調查了 ZMQ 的高水位線 (HWM) 功能,將其設置為低以丟棄舊消息,但沒有任何改變。

最少的代碼

建築學 :

+------------+                +-------------+
|            |  PUB           |             |
|   sender   | -------------> |  receiver   |
|            |             SUB|             |
+------------+                +-------------+

接收器是一個慢速接收器(在第一張圖中充當間諜)

代碼 :

發件人.py

import time
import zmq

ctx = zmq.Context()

sender = ctx.socket(zmq.PUB)
sender.setsockopt(zmq.SNDBUF, 256)
sender.set_hwm(10)
sender.bind('tcp://127.0.0.1:1500')

print(zmq.zmq_version()) ## 4.0.4
print(zmq.__version__) ## 14.3.1
print(sender.get_hwm()) ## 10

i = 0
while True:
    mess = "{} {}".format(i, time.time())
    sender.send_string(mess)
    print("Send : {}".format(mess))
    i+= 1

接收器.py:

import time
import zmq

ctx = zmq.Context()
front_end = ctx.socket(zmq.SUB)

front_end.set_hwm(1)
front_end.setsockopt(zmq.RCVBUF, 8)

front_end.setsockopt_string(zmq.SUBSCRIBE, '')
front_end.connect('tcp://127.0.0.1:1500')

print(zmq.zmq_version()) ## 4.0.4
print(zmq.__version__) ## 14.3.1
print(front_end.get_hwm()) ## 1

while True:
    mess = front_end.recv_string()
    i, t = mess.split(" ")
    mess = "{} {}".format(i, time.time() - float(t))
    print("received : {}".format(mess))
    time.sleep(1)  # slow

我不認為這是 ZMQ Pub/Sub 的正常行為。 我試圖在接收器、訂閱者和兩者中設置 HWM,但沒有任何改變。

我錯過了什么?

Edit :

當我解釋我的問題時,我認為我沒有說清楚。 我做了一個移動鼠標光標的實現。 輸入是在 ZMQ 中以 200Hz 發送的鼠標光標位置(使用.sleep( 1.0 / 200 ) ),完成了一些處理並更新了鼠標光標位置(在我的最小示例中沒有此睡眠)。

一切都很順利,即使當我發射間諜時也是如此。 盡管如此,間諜的延遲越來越大(因為處理速度緩慢)。 延遲不會出現在光標中,位於“管道”的末尾。

我認為問題來自排隊消息的緩慢訂閱者

在我的例子中,如果我們殺死發送者並讓接收者活着,消息將繼續顯示,直到顯示所有(?)提交的消息。

間諜正在繪制光標的位置以提供一些反饋,有這樣的滯后仍然很不方便......我只是想得到最后發送的消息,這就是我試圖降低HWM的原因。

缺少更好的實時設計/驗證

ZeroMQ 是一個強大的消息傳遞層。

也就是說,檢查它在原始while True:每秒真正發送多少消息while True: killer-loop

測量它。 設計基於事實,而不是感覺。

事實很重要。

start_CLK = time.time()                                    # .SET _CLK
time.sleep( 0.001)                                         # .NOP avoid DIV/0!
i = 0                                                      # .SET CTR
while True:                                                # .LOOP
    sender.send_string( "{} {}".format( i, time.time() ) ) # .SND ZMQ-PUB 
    print i / ( time.time() - start_CLK )                  # .GUI perf [msg/sec]
    i+= 1                                                  # .INC CTR

ZeroMQ 盡最大努力在計划中填充該雪崩。

它非常擅長這一點。

你的 [ Filter ] + [ Spy1 ] + [ Output ] + [ Spy2 ] 管道處理,端到端,

  • 更快,包括 .send() + .recv_string() 開銷都比 [ Input ]-sender

或者

  • 成為主要的阻塞病態元素,導致內部 PUB/SUB 隊列增長,增長,增長

這個隊列鏈問題可以通過另一種架構設計來解決。

需要重新思考的事情:

  1. 對 [ Filter ].send() cadency 進行子采樣(交錯因子取決於您控制下的實時過程的穩定性問題——無論是 1 毫秒(順便說一句,O/S 計時​​器分辨率,因此沒有量子物理學實驗)可以使用 COTS O/S 計時​​器控制 :o) ),雙向語音流為 10 毫秒,TV/GUI 流為 50 毫秒,鍵盤事件流為 300 毫秒等)

  2. 在線v/s離線后處理/可視化(你注意到一個沉重的matplotlib處理,你通常承擔大約 800 - 1600 - 3600 毫秒的開銷,即使在簡單的 2D 圖形上 - 在決定改變 PUB/SUB 之前測量它- < proc1 >-PUB/SUB-< proc2 > 處理架構(您已經注意到,< spy2 > 會導致 < proc2 >-PUB-feeding 和發送開銷的增長出現問題)。

  3. 線程數與執行它們的本地主機內核數 - 從本地主機 ip 來看,所有進程都駐留在同一個本地主機上。 加上為每個 ZMQ.Context 添加 + 一個線程,加上審查 Python GIL 鎖定開銷,如果所有線程都是從同一個 Python 解釋器實例化的......阻塞會增加。 阻塞很痛。 更好的分布式架構可以改善這些性能方面。 但是,首先回顧 [1] 和 [2]

nb調用了 20 分鍾的處理管道延遲(實時系統 TimeDOMAIN skew)延遲非常委婉

來自http://zguide.zeromq.org/page:all#toc50

當您的套接字達到其 HWM 時,它將根據套接字類型阻止或丟棄數據。 PUB 和 ROUTER 套接字在到達它們的 HWM 時將丟棄數據,而其他套接字類型將阻塞。 通過 inproc 傳輸,發送方和接收方共享相同的緩沖區,因此真正的 HWM 是雙方設置的 HWM 之和。

所以 SUB 套接字不會真正丟棄舊消息。 你可以用路由器做一些技巧來實現一個掉線的訂閱者,或者考慮一種可以滿足元素緩慢的設計。 Zero 的好處之一是您的許多核心代碼可以保持不變,並且您可能會在處理套接字的包裝器周圍移動。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM