multi cluster sender

This commit is contained in:
Cloud Wu
2019-03-20 17:56:39 +08:00
parent 1d4308f33a
commit 000fa2be3a
4 changed files with 119 additions and 61 deletions

View File

@@ -2,15 +2,24 @@ local skynet = require "skynet"
local clusterd local clusterd
local cluster = {} local cluster = {}
local sender = {}
local function get_sender(t, node)
local c = skynet.call(clusterd, "lua", "sender", node)
t[node] = c
return c
end
setmetatable(sender, { __index = get_sender } )
function cluster.call(node, address, ...) function cluster.call(node, address, ...)
-- skynet.pack(...) will free by cluster.core.packrequest -- skynet.pack(...) will free by cluster.core.packrequest
return skynet.call(clusterd, "lua", "req", node, address, skynet.pack(...)) return skynet.call(sender[node], "lua", "req", address, skynet.pack(...))
end end
function cluster.send(node, address, ...) function cluster.send(node, address, ...)
-- push is the same with req, but no response -- push is the same with req, but no response
skynet.send(clusterd, "lua", "push", node, address, skynet.pack(...)) skynet.send(sender[node], "lua", "push", address, skynet.pack(...))
end end
function cluster.open(port) function cluster.open(port)
@@ -45,7 +54,7 @@ function cluster.register(name, addr)
end end
function cluster.query(node, name) function cluster.query(node, name)
return skynet.call(clusterd, "lua", "req", node, 0, skynet.pack(name)) return skynet.call(sender[node], "lua", "req", 0, skynet.pack(name))
end end
skynet.init(function() skynet.init(function()

View File

@@ -1,4 +1,5 @@
local skynet = require "skynet" local skynet = require "skynet"
require "skynet.manager"
local sc = require "skynet.socketchannel" local sc = require "skynet.socketchannel"
local socket = require "skynet.socket" local socket = require "skynet.socket"
local cluster = require "skynet.cluster.core" local cluster = require "skynet.cluster.core"
@@ -6,6 +7,7 @@ local cluster = require "skynet.cluster.core"
local config_name = skynet.getenv "cluster" local config_name = skynet.getenv "cluster"
local node_address = {} local node_address = {}
local node_session = {} local node_session = {}
local node_sender = {}
local command = {} local command = {}
local config = {} local config = {}
local nodename = cluster.nodename() local nodename = cluster.nodename()
@@ -40,13 +42,20 @@ local function open_channel(t, key)
local succ, err, c local succ, err, c
if address then if address then
local host, port = string.match(address, "([^:]+):(.*)$") local host, port = string.match(address, "([^:]+):(.*)$")
c = sc.channel { c = node_sender[key]
host = host, if c == nil then
port = tonumber(port), c = skynet.newservice "clustersender"
response = read_response, if node_sender[key] then
nodelay = true, -- double check
} skynet.kill(c)
succ, err = pcall(c.connect, c, true) c = node_sender[key]
else
node_sender[key] = c
end
end
succ = pcall(skynet.call, c, "lua", "changenode", host, port)
if succ then if succ then
t[key] = c t[key] = c
ct.channel = c ct.channel = c
@@ -120,56 +129,8 @@ function command.listen(source, addr, port)
skynet.ret(skynet.pack(nil)) skynet.ret(skynet.pack(nil))
end end
local function send_request(source, node, addr, msg, sz) function command.sender(source, node)
local session = node_session[node] or 1 skynet.ret(skynet.pack(node_channel[node]))
-- msg is a local pointer, cluster.packrequest will free it
local request, new_session, padding = cluster.packrequest(addr, session, msg, sz)
node_session[node] = new_session
-- node_channel[node] may yield or throw error
local c = node_channel[node]
local tracetag = skynet.tracetag()
if tracetag then
if tracetag:sub(1,1) ~= "(" then
-- add nodename
local newtag = string.format("(%s-%s-%d)%s", nodename, node, session, tracetag)
skynet.tracelog(tracetag, string.format("session %s", newtag))
tracetag = newtag
end
skynet.tracelog(tracetag, string.format("cluster %s", node))
c:request(cluster.packtrace(tracetag))
end
return c:request(request, session, padding)
end
function command.req(...)
local ok, msg = pcall(send_request, ...)
if ok then
if type(msg) == "table" then
skynet.ret(cluster.concat(msg))
else
skynet.ret(msg)
end
else
skynet.error(msg)
skynet.response()(false)
end
end
function command.push(source, node, addr, msg, sz)
local session = node_session[node] or 1
local request, new_session, padding = cluster.packpush(addr, session, msg, sz)
if padding then -- is multi push
node_session[node] = new_session
end
-- node_channel[node] may yield or throw error
local c = node_channel[node]
c:request(request, nil, padding)
-- notice: push may fail where the channel is disconnected or broken.
end end
local proxy = {} local proxy = {}

View File

@@ -22,11 +22,12 @@ skynet.forward_type( forward_map ,function()
if n then if n then
address = n address = n
end end
local sender = skynet.call(clusterd, "lua", "sender", node)
skynet.dispatch("system", function (session, source, msg, sz) skynet.dispatch("system", function (session, source, msg, sz)
if session == 0 then if session == 0 then
skynet.send(clusterd, "lua", "push", node, address, msg, sz) skynet.send(clusterd, "lua", "push", node, address, msg, sz)
else else
skynet.ret(skynet.rawcall(clusterd, "lua", skynet.pack("req", node, address, msg, sz))) skynet.ret(skynet.rawcall(sender, "lua", skynet.pack("req", address, msg, sz)))
end end
end) end)
end) end)

87
service/clustersender.lua Normal file
View File

@@ -0,0 +1,87 @@
local skynet = require "skynet"
local sc = require "skynet.socketchannel"
local socket = require "skynet.socket"
local cluster = require "skynet.cluster.core"
local ignoreret = skynet.ignoreret
local channel
local session = 1
local command = {}
local function send_request(addr, msg, sz)
-- msg is a local pointer, cluster.packrequest will free it
local current_session = session
local request, new_session, padding = cluster.packrequest(addr, session, msg, sz)
session = new_session
-- node_channel[node] may yield or throw error
local tracetag = skynet.tracetag()
if tracetag then
if tracetag:sub(1,1) ~= "(" then
-- add nodename
local newtag = string.format("(%s-%s-%d)%s", nodename, node, session, tracetag)
skynet.tracelog(tracetag, string.format("session %s", newtag))
tracetag = newtag
end
skynet.tracelog(tracetag, string.format("cluster %s", node))
channel:request(cluster.packtrace(tracetag))
end
return channel:request(request, current_session, padding)
end
function command.req(...)
local ok, msg = pcall(send_request, ...)
if ok then
if type(msg) == "table" then
skynet.ret(cluster.concat(msg))
else
skynet.ret(msg)
end
else
skynet.error(msg)
skynet.response()(false)
end
end
function command.push(addr, msg, sz)
local request, new_session, padding = cluster.packpush(addr, session, msg, sz)
if padding then -- is multi push
session = new_session
end
-- node_channel[node] may yield or throw error
channel:request(request, nil, padding)
end
local function read_response(sock)
local sz = socket.header(sock:read(2))
local msg = sock:read(sz)
return cluster.unpackresponse(msg) -- session, ok, data, padding
end
function command.changenode(host, port)
local c = sc.channel {
host = host,
port = tonumber(port),
response = read_response,
nodelay = true,
}
succ, err = pcall(c.connect, c, true)
if succ then
channel = c
skynet.ret(skynet.pack(nil))
else
skynet.response()(false)
end
end
skynet.start(function()
skynet.dispatch("lua", function(session , source, cmd, ...)
local f = assert(command[cmd])
f(...)
end)
end)