关于增加skynet_fly orm_table_m 可热更服务

前言

因为orm在多个服务持有的时候,没法保证一致性,所有需要把orm封装到独立服务中,其他服务通过rpc调用,为了使用便利性,封装了通用的orm可热更服务orm_table_m.lua和rpc调用模块orm_table_client.lua

orm_table_m.lua

转入的config需要提供一个配置项orm_plug,它是lua模块文件。需要提供init,call两个方法。

  • init() 方法需要创建出orm对象并且返回。
  • call(func_name,…) 方法提供一系列rpc调用的方法。

热更处理

当orm热更时,orm_table_m.lua会立即调用保存接口,确保数据全部同步到对应的数据库中,这个过程没有完成,新的服务都不会调用收到start回调,也不会收到服务地址变更的推送,这样就保证了数据只有一个服务持有保证数据一致性。强制保存过程中,如果操作失败会一直尝试,直到成功保证数据不丢失。通常操作失败是连接异常或者数据库挂壁了。

call操作调用

其他服务调用orm服务时,可能orm服务正在热更,旧服务不再提供服务了,就需要通知rpc客户端,转移调用。

1
2
3
4
5
6
7
8
9
10
11
12
13
function CMD.call(func_name,...)
if G_ISCLOSE then
return true
end

return false, queue(g_orm_plug.call, func_name, ...)
end

function CMD.herald_exit()
G_ISCLOSE = true

queue(g_orm_obj.save_change_now,g_orm_obj)
end

只需要在确定下线以后,通知move转移调用。

orm_table_client.lua

简化调用

正常热更模块的rpc调用如下:

1
2
local client = contriner_client:new("orm_table_m","player")
client:mod_call('call',"doing_same", arg1, arg2)

为了简化调用,使用元表封装一层。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
local mt = {__index = function(t,k)
t[k] = function(self,...)
t._client = t._client or contriner_client:new("orm_table_m",t._orm_name)
local ret = nil
--尝试 5 次,还不成功,那肯定是数据库挂逼了或者热更后执行保存比较耗时
for i = 1,5 do
ret = {t._client:mod_call("call", k, ...)}
local is_move = ret[1]
if not is_move then
return select(2,tunpack(ret))
end
skynet.yield()
end
end
return t[k]
end}

之后调用方式如下:

1
2
3
4
local client = orm_table_client:new("player")
client:doing_same(arg1, arg2)
--或者
orm_table_client:instance("player"):doing_same(arg1, arg2)

封装的目的除了简化调用,还有一个作用就是,对接特殊处理

特殊处理

因为热更过程中,旧服务不再提供服务,会返回move的结果,此时仅仅需要重试就行了。因为contriner_client默认使用了服务切换。

特殊情况

因为旧服务被替代之后,无法再进行服务切换,所以它的消息会一直发给旧服务。(如果放开这个限制,就会出现AB问题),比如旧服务访问的函数,在最新的版本被删除了。或者函数调用的参数做了调整了,都会导致调用出错。暂时想不到很完美的方案解决这个问题。只能旧服务不能访问orm可以接受的情况下,可以用热更,其他情况只能停服更新了。

示例

orm

总结

完善了orm系统。

skynetfly源码地址


关于增加skynet_fly orm_table_m 可热更服务
https://huahua132.github.io/2023/12/24/skynet_fly_ss/orm_table_m/
作者
huahua132
发布于
2023年12月24日
许可协议