49

在试验ZeroMQ Push/Pull(他们所说的Pipeline)套接字类型时,我很难理解这种模式的实用性。它被称为“负载平衡器”。

给定单个服务器向多个工作人员发送任务,Push/Pull 将在所有客户端之间平均分配任务。3 个客户端和 30 个任务,每个客户端获得 10 个任务:client1 获得任务 1、4、7、... client2、2、5、...等等。很公平。字面上地。

然而,在实践中,任务复杂性或客户端计算资源(或可用性)通常是非均匀混合的,那么这种模式就会被严重破坏。所有任务似乎都是提前安排好的,服务器不知道客户端的进度,甚至不知道它们是否可用。如果 client1 宕机,它的剩余任务不会发送给其他客户端,而是为 client1 排队。如果 client1 仍然关闭,则永远不会处理这些任务。相反,如果客户端处理其任务的速度更快,则它不会获得更多任务并保持空闲状态,因为它们仍然为其他客户端安排。

使用REQ/REP是一种可能的解决方案;然后只将任务分配给可用资源。

所以我错过了什么吗?如何Push/Pull有效使用?有没有办法使用这种套接字类型来处理客户端、任务等的不对称性?

谢谢!

这是一个简单的 Python 示例:

# server

import zmq
import time

context = zmq.Context()
socket = context.socket(zmq.PUSH)
#socket = context.socket(zmq.REP)   # uncomment for Req/Rep

socket.bind("tcp://127.0.0.1:5555")

i = 0
time.sleep(1)   # naive wait for clients to arrive

while True:
  #msg = socket.recv()    # uncomment for Req/Rep
  socket.send(chr(i))
  i += 1 
  if i == 100:
    break

time.sleep(10)   # naive wait for tasks to drain

.

# client

import zmq
import time
import sys

context = zmq.Context()

socket = context.socket(zmq.PULL)
#socket = context.socket(zmq.REQ)    # uncomment for Req/Rep

socket.connect("tcp://127.0.0.1:5555")

delay = float(sys.argv[1])

while True:
  #socket.send('')     # uncomment for Req/Rep
  message = socket.recv()
  print "recv:", ord(message)
  time.sleep(delay)

在命令行上启动 3 个带有延迟参数的客户端(即 1、1 和 0.1),然后启动服务器,看看所有任务是如何均匀分布的。然后杀死其中一个客户端以查看其剩余任务未得到处理。

取消注释指示将其切换到Req/Rep类型套接字的行并观察更有效的负载平衡器。

4

1 回答 1

67

它不是负载均衡器,这是在 0MQ 文档中停留了一段时间的错误解释。要进行负载平衡,您必须从工作人员那里获取有关其可用性的一些信息。PUSH 与 DEALER 一样,是循环分配器。它的原始速度和简单性很有用。您不需要任何类型的喋喋不休,只需将任务泵入管道,它们就会以网络可以处理的速度尽快发送给所有可用的工作人员。

当您执行大量的小任务,并且工作人员不经常出入时,该模式很有用。该模式不适用于需要时间完成的大型任务,因为您需要一个仅将新任务发送给可用工作人员的队列。它还受到反模式的影响,如果客户端发送许多任务然后工作人员连接,第一个工作人员将获取 1,000 条左右的消息,而其他工作人员仍在忙于连接。

您可以通过多种方式制作自己的高级路由。查看指南中的 LRU 模式:在此,工作人员明确告诉代理“准备好”。您还可以进行基于信用的流量控制,这就是我在任何实际负载平衡情况下都会做的事情。它是 LRU 模式的推广。见http://hintjens.com/blog:15

于 2012-09-21T09:44:55.227 回答