关于监听同步模块的封装

为啥需要封装一个监听同步模块?

使用skynet开发功能,由于是actor模型,难免会遇到一个服务需要依赖另一个服务的数据的情况,解决这个问题常见的方案有:

  1. 封装一个c模块,用于共享数据
    优点

    • API使用简单,get set 即可。
    • 节省内存。

    缺点

    • 编码难度大,风险高,需要处理好多线程编码问题。
    • 需要加读写锁,读取性能不一定高。
    • lua调用c,没有直接访问lua快。
  2. 要用的时候去查询
    优点:

    • 实现简单,简单call调用即可。

    缺点

    • 对于过于频繁的请求,并不是一个很好的方案。
    • 查询数据量大时,对性能有影响。(频繁的打包,解包,生成临时的lua表,增加lua gc 负担)
  3. watch_syn监听同步机制
    优点

    • 实现难度适中。
    • API调用简单。
    • 数据本地持有,访问迅速。
    • 更新通知,无需频繁请求。

    缺点

    • 如果是频繁更新的数据,效果与第二方案没有多大差异。

使用案例

skynet的share_datad.lua

我学习到使用这种机制,是通过翻看share_datad的源码,share_data通过监听同步机制来实现对共享配置的热更。

skynet_flycontriner_mgr.lua

skynet_fly使用这种方式,通知热更后服务地址的变更。

skynet_flymonitor_exit.lua

skynet_fly使用这种方式,监听服务退出。

skynet_fly_demomonitor_exit.lua

skynet_fly_demo使用这种方式,通知密钥变更。

所以说,这种机制开发中,挺常用的,所有就打算写一个通用模块,以便以后使用直接引入即可,不需要去关心实现rpc的细节了。

实现思路

基本定义

监听同步机制中分为两个角色,发布者订阅者,在代码中,我把他们分别称为server,client,server只有1个,client可以有多个,server可以发布多个key-value值,
client也可以监听多个key-value值,其中key是string,value,可以是string,number,bool,nil,table。client可以有多个,但是同一个服务里只有一个对应server的访问实例,因为server是以client服务地址为key记录来访,通常一个订阅者也不需要创建2个以上发布者访问实例。

机制链路

  1. server首先注册key-value,生成对应版本号为1。
  2. clientC2S 监听key,传递版本号首次为空。
  3. serverS2C 接收到key,如果不是首次访问或者版本号不一致返回最新结果,版本号一直暂时不回复(client会挂起等待)。
  4. serverS2C 当需要发布新值时,通知所有的监听的client

通过以上步骤完成对数据的同步。

API

测试

skynetfly源码地址


关于监听同步模块的封装
https://huahua132.github.io/2024/01/28/skynet_fly_ss/watch_syn/
作者
huahua132
发布于
2024年1月28日
许可协议