相较于“懒惰的”做了些许扩展,适当的挽救那个“死等”的败笔~
[img]https://github.com/imatix/zguide/raw/master/images/fig58.png[/img]
恰如图所示,在消费者与服务者中加了一个中间件,做了一个请求的分发工作(尽管不是那么智能),避免了每次总是在等待不靠谱的worker服务。
中间的均衡队列:
workers:
[color=red]注意:[/color]这里语言是lua。
这种模型理论上来说,已经相当靠谱了,好吧,路由还不够智能~
(未完待续)
[img]https://github.com/imatix/zguide/raw/master/images/fig58.png[/img]
恰如图所示,在消费者与服务者中加了一个中间件,做了一个请求的分发工作(尽管不是那么智能),避免了每次总是在等待不靠谱的worker服务。
中间的均衡队列:
require"zmq"
require"zmq.poller"
require"zhelpers"
require"zmsg"
local tremove = table.remove
local MAX_WORKERS = 100
s_version_assert (2, 1)
-- Prepare our context and sockets
local context = zmq.init(1)
local frontend = context:socket(zmq.XREP)
local backend = context:socket(zmq.XREP)
frontend:bind("tcp://*:5555"); -- For clients
backend:bind("tcp://*:5556"); -- For workers
-- Queue of available workers
local worker_queue = {}
local is_accepting = false
local poller = zmq.poller(2)
local function frontend_cb()
-- Now get next client request, route to next worker
local msg = zmsg.recv (frontend)
-- Dequeue a worker from the queue.
local worker = tremove(worker_queue, 1)
msg:wrap(worker, "")
msg:send(backend)
if (#worker_queue == 0) then
-- stop accepting work from clients, when no workers are available.
poller:remove(frontend)
is_accepting = false
end
end
-- Handle worker activity on backend
poller:add(backend, zmq.POLLIN, function()
local msg = zmsg.recv(backend)
-- Use worker address for LRU routing
worker_queue[#worker_queue + 1] = msg:unwrap()
-- start accepting client requests, if we are not already doing so.
if not is_accepting then
is_accepting = true
poller:add(frontend, zmq.POLLIN, frontend_cb)
end
-- Forward message to client if it's not a READY
if (msg:address() ~= "READY") then
msg:send(frontend)
end
end)
-- start poller's event loop
poller:start()
-- We never exit the main loop
workers:
require"zmq"
require"zmsg"
math.randomseed(os.time())
local context = zmq.init(1)
local worker = context:socket(zmq.REQ)
-- Set random identity to make tracing easier
local identity = string.format("%04X-%04X", randof (0x10000), randof (0x10000))
worker:setopt(zmq.IDENTITY, identity)
worker:connect("tcp://localhost:5556")
-- Tell queue we're ready for work
printf ("I: (%s) worker ready\n", identity)
worker:send("READY")
local cycles = 0
while true do
local msg = zmsg.recv (worker)
-- Simulate various problems, after a few cycles
cycles = cycles + 1
if (cycles > 3 and randof (5) == 0) then
printf ("I: (%s) simulating a crash\n", identity)
break
elseif (cycles > 3 and randof (5) == 0) then
printf ("I: (%s) simulating CPU overload\n", identity)
s_sleep (5000)
end
printf ("I: (%s) normal reply - %s\n",
identity, msg:body())
s_sleep (1000) -- Do some heavy work
msg:send(worker)
end
worker:close()
context:term()
[color=red]注意:[/color]这里语言是lua。
这种模型理论上来说,已经相当靠谱了,好吧,路由还不够智能~
(未完待续)