
恰如图所示,在消费者与服务者中加了一个中间件,做了一个请求的分发工作(尽管不是那么智能),避免了每次总是在等待不靠谱的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()
注意:这里语言是lua。
这种模型理论上来说,已经相当靠谱了,好吧,路由还不够智能~
(未完待续)