zeroMQ初体验-24.可靠性-简单的海盗模式

相较于“懒惰的”做了些许扩展,适当的挽救那个“死等”的败笔~



恰如图所示,在消费者与服务者中加了一个中间件,做了一个请求的分发工作(尽管不是那么智能),避免了每次总是在等待不靠谱的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。

这种模型理论上来说,已经相当靠谱了,好吧,路由还不够智能~

(未完待续)


你可能感兴趣的:(工作,中间件,socket,OS,lua)