skynet框架:全服广播业务
存在业务场景,对当前在线玩家发送消息通知。
这里将消息生产的服务称为source,目标玩家服务称为target。对单个玩家使用独立的lua虚拟机进行代理,称为agent,承载agent的节点称为user。
区分source和target是否存在于相同的skynet节点:
如果处于相同的节点,那么只是单服内进行一次进程内广播的操作,所有单服的广播同步进行(场景一);
如果处在不同的节点,那么source为外部节点上的服务,此时,需要将消息派发到当前存在的所有user单服上,即跨进程广播方案(场景二)
下面讨论几个问题:
-
单次广播操作是否稳定可靠
我们将业务上的广播动作(单服内)看做一次遍历所有agent发送消息的同步操作:
function CMD.broadcast()
for _, addr in ipairs(online_agents) do
skynet.send(addr, "broadcast", cmd)
end
end
对于上述场景一二,广播的消息量级是相同的,那么我们只讨论在单服上做一次广播是否安全。一次广播的消息总数量是单服当前登录中的玩家数量,即当前存在的agent数量。这里需要评估的点在于:
(1)瞬间产出的消息量级是否可控;(2)单次广播的CPU占用时间;
对于滚服架构,绝大多数的业务实现在相同的skynet进程上,单服容纳的agent上限不高(相对大服架构而言),我们认为单次广播生产的消息数量可控,占用CPU的时间也在可控范围,不会造成内存暴涨和卡顿问题;
对于大服架构,我们将非单独玩家的逻辑独立出来跑在公共进程上,为user释放出更多系统资源。大服架构下单台服(user)的承载上限更高,瞬间产出的消息可能引起内存较大波动,此时source服务处于分发广播消息的动作上,如果有后续的消息(比如另一个发起广播的请求)到来,可能会造成消息处理的卡顿延迟,source服务繁忙中。
事实上,业务上我们对在线玩家的广播动作,很多时候是在0点跨天5点跨天(比如玩法的阶段切换通知),此时批量的广播请求同时发起进行,上述的卡顿延迟现象会比较明显。
-
优化全服广播
上面提到的全服广播带来的性能压力,讨论记录以下几个处理思路:
(1)内存压力:通过提高单服机器硬件配置;卡顿延迟问题:扩展单点source服务为批量服务,为每个广播请求分配一个source服务进行处理,提高并发性能;
(2)组播方案代替;大部分情况下,在线的玩家只在指定场景下关心这个广播消息,比如主场景下需要实时刷新玩法入口的信息,但在其他玩法场景内并不需要接收到这个消息(进入主场景时通过请求回应的方式获取此时的数据进行更新),针对此类业务场景,可以使用组播的实现方案代替全服的广播:我们抽象出各类scene,对source服务实现支持区分scene消息推送,通过订阅的方式标记关心scene内关联的组播消息,当source发起组播请求时(此时消息携带scene信息),只发送给订阅了该消息的target,实现更精准的消息推送;
(3)客户端定时请求刷新;这里是异步代替同步的思路。业务开发上服务器避免全服广播的动作,由客户端定时请求获取数据更新。将单个广播动作变成多个请求回应的动作,通过skynet的消息队列异步消费。这里消息的数量并没有减少,服务器会在瞬间接收到所有在线玩家的请求,但此时agent的消息队列、source的消息队列会进行调度,发挥出skynet的协调能力。
本文来自博客园,作者:linxx-,转载请注明原文链接:https://www.cnblogs.com/linxx-/p/18091050