skynet框架:跨进程组播实现方案

存在业务场景,从单点进程(source)批量向集群内其他节点(target)推送消息,目标节点数量可能达三位数。

提供一个实现方案:

  1. target上开启进程内的组播服务,只负责当前节点的组播推送业务;服务支持接收其他节点的通知消息(目标服务只在所在节点内的组播服务上做订阅等操作,由该组播服务负责管理);
  2. source进程构造组播消息包,做一次循环将消息发送到所有目标节点(这里只是寻常的remote send,multicast消息类型不是必须的,最常用的lua消息类型足够使用);
  3. target上的组播服务将数据包pack成multicast消息类型转发到所有目标订阅服务;

一段代码说明下:

-- source service
for _, skynet_node in ipairs(get_target_nodes()) do
	cluster.send(skynet_node, "multicastd", "lua", "remote_publish", channel, msg)
end

-- multicastd
local subscribes = {
	-- channel = {
	-- 		service,
  -- 		...
	-- },
	-- ...
}

local MULTICAST_CMD = {
	publish = function(channel, msg)
		for service in pairs(subscribes[channel]) do
			skynet.send(service, "multicast", msg)
		end
	end,
    subscribe = function(...)
    	...
    end,
    newchannel = function(...) 
        ...
    end,
    ...
}

local LUA_CMD = {
	remote_publish = function(...)
		local channel, msg = unpack(...)
		MULTICAST_CMD.publish(channel, msg)
	end
}

function init_service()
	...
	skynet.dispatch("lua", function(_, _, cmd, ...)
		LUA_CMD[cmd](...)
	end)
end
skynet.start(init_service)

-- target service
function init_service()
	...
	skynet.dispatch("multicast", function(...)
		...
	end)
end
skynet.start(init_service)

上述方案中multicastd服务核心只做一个事情:当收到组播通知时,将消息推送到订阅的所有服务中去。这个组播通知可以来自包括服务所在节点内的任何集群内节点,我们常常是把channel id跟某个业务玩法绑定,所有节点约定这个id,target service订阅这个channel后,关联的这个玩法(可能跑在当前或其他节点)有组播需求时,会通知到关心该消息的所有target service。

可以看出,方案并没有区分local channel和remote channel。这里发起组播请求的总是单点玩法节点,而multicastd服务只是作为目标节点,等待组播通知,这里通知消息使用的消息类型也并不是multicastd。我们的业务,广播的需求场景基本是从单点节点单向发出,所有目标节点作为接收方进行接收处理。

posted @ 2024-03-23 14:23  linxx-  阅读(65)  评论(0编辑  收藏  举报