Skynet
12 篇关于 sharedata 的使用
最近上了全节点热更配置表。起因是有一次热更配置表时没有覆盖全节点,导致数据不一致而 traceback,中断了一个重要流程。由于读表服务和目标服务的相关性比较隐蔽,热更 review 时没能发现这个问题,于是决定后续所有配置表都采用全节点热更。 全节点热更上线后,发现内存会持续增长,多次热更后尤为明显。同事排查后发现是 sharedata 服务的内存一直在涨,应该是旧配置表没有释放导致的。这件事比较复杂,搞清楚后很容易又忘了,决定写篇博客记录一下。 为什么要有 sharedata 各服务的配置内 …
最近上了全节点热更配置表。起因是有一次热更配置表时没有覆盖全节点,导致数据不一致而 traceback,中断了一个重要流程。由于读表服务和目标服务的相关性比较隐蔽,热更 review 时没能发现这个问题,于是决定后续所有配置表都采用全节点热更。 全节点热更上线后,发现内存会持续增长,多次热更后尤为明显。同事排查后发现是 sharedata 服务的内存一直在涨,应该是旧配置表没有释放导致的。这件事比较复杂,搞清楚后很容易又忘了,决定写篇博客记录一下。 为什么要有 sharedata 各服务的配置内 …
当lua_sharedata碰上上限
最近在使用sharedata共享配置表的时候遇到了问题,报了stack overflow,最小复现的例子贴在这里了。之前因为忙,没有细读过sharedata 的代码,这次事故正好临急抱佛脚读一遍,匆忙记点笔记,以后好回忆起来。sharedata是为了不同服务之间共享配置表而诞生的,通过sharedata接口拿到的是一个 c 的代理对象,并不直接持有配置表本身。正是通过这个代理,实现了配置表的无感热更,以及服务之间的配置内存共享。对于字符串来说,这个C代理持有的并不是字符串本身,而是一个索引,指向 …
最近在使用sharedata共享配置表的时候遇到了问题,报了stack overflow,最小复现的例子贴在这里了。之前因为忙,没有细读过sharedata 的代码,这次事故正好临急抱佛脚读一遍,匆忙记点笔记,以后好回忆起来。sharedata是为了不同服务之间共享配置表而诞生的,通过sharedata接口拿到的是一个 c 的代理对象,并不直接持有配置表本身。正是通过这个代理,实现了配置表的无感热更,以及服务之间的配置内存共享。对于字符串来说,这个C代理持有的并不是字符串本身,而是一个索引,指向 …
项目上线啦
历时 3 年半,项目终于上线啦,打开 tig 翻到仓库的开头,看看提交历史,还是有点感慨的,实在没想到要花这么久。简单聊点线上问题吧 这次上线最刺激的是,开服前半小时,发现昨晚压测的服务器崩掉了,原因是聊天服务内存太大导致 OOM。于是用 memlimit 紧急止血,出问题的方法挂到模块上方便后续线上热更,然后打包,重启,紧赶慢赶在开服前几分钟搞完,提前开服错峰。真的非常非常刺激,当然,线上也没有出现这个问题,我们压测的例子相对比较极端,一大堆人每 30 秒集体跳场景,注册场景聊天的地方又做了锁 …
历时 3 年半,项目终于上线啦,打开 tig 翻到仓库的开头,看看提交历史,还是有点感慨的,实在没想到要花这么久。简单聊点线上问题吧 这次上线最刺激的是,开服前半小时,发现昨晚压测的服务器崩掉了,原因是聊天服务内存太大导致 OOM。于是用 memlimit 紧急止血,出问题的方法挂到模块上方便后续线上热更,然后打包,重启,紧赶慢赶在开服前几分钟搞完,提前开服错峰。真的非常非常刺激,当然,线上也没有出现这个问题,我们压测的例子相对比较极端,一大堆人每 30 秒集体跳场景,注册场景聊天的地方又做了锁 …
首次付费测
游戏终于走到了付费测试阶段啦,头几天遇到了一些奇奇怪怪的问题,记录一下 首先是内存问题,压测没有测到反复登录的情况,线上发现内存占用逐渐上升,到了一个玩家 40M 的惊人水平。正想着手查哪个模块耗的内存多,涛神下来讨论问题,让我先看一下 uniqtask 的返回,结果好家伙,基本上每个 agent 服务上都挂了 400 多个协程在上面,review 下代码发现每个协程都拿着一个角色,导致内存没法释放。兹事体大,没有立即解决挂起的协程了,先热更修复这个代码的问题,然后降低 agent 的复用次数, …
游戏终于走到了付费测试阶段啦,头几天遇到了一些奇奇怪怪的问题,记录一下 首先是内存问题,压测没有测到反复登录的情况,线上发现内存占用逐渐上升,到了一个玩家 40M 的惊人水平。正想着手查哪个模块耗的内存多,涛神下来讨论问题,让我先看一下 uniqtask 的返回,结果好家伙,基本上每个 agent 服务上都挂了 400 多个协程在上面,review 下代码发现每个协程都拿着一个角色,导致内存没法释放。兹事体大,没有立即解决挂起的协程了,先热更修复这个代码的问题,然后降低 agent 的复用次数, …
压测周
最近一周做压测,发现了几个 skynet 使用上的问题,记录一下 目前的进程大概分成 center、login 和 room 三种,login 用来承接玩家连接,做一些单机玩法,center 做一些玩家间的附带玩法,比如公会、排行榜,room 处理房间相关的战斗逻辑和 aoi 剪裁 首先发现的问题是建公会相关的。压测的时候居然不是 center 进程挂了,而是 login 进程先挂掉了,公会服务负载还比较低;还附带副作用:建立的公会多了,就再也起不了服务器,center 一定会在启动的时候挂掉。 …
最近一周做压测,发现了几个 skynet 使用上的问题,记录一下 目前的进程大概分成 center、login 和 room 三种,login 用来承接玩家连接,做一些单机玩法,center 做一些玩家间的附带玩法,比如公会、排行榜,room 处理房间相关的战斗逻辑和 aoi 剪裁 首先发现的问题是建公会相关的。压测的时候居然不是 center 进程挂了,而是 login 进程先挂掉了,公会服务负载还比较低;还附带副作用:建立的公会多了,就再也起不了服务器,center 一定会在启动的时候挂掉。 …
Skynet 广播优化小记
最近和 QC 同学共建一套自动化压测的框架,希望能够确定游戏的性能基线,通过自动化定期回顾,看看有没有引入性能劣化的代码。压测过程中,发现广播性能不够强,搞的清明假期也在家想问题,写篇博客记录一下 为了让房间服务能腾出手专心处理战斗相关内容,我们针对性的改进了打包和广播,分离到一个与房间 1 比 1 配置的 sidecar 服务上去,期待能多利用一个核的算力来实现。在维持客户端链接的 login 节点,我们也做了类似 Skynet 的 cluster 模块的优化,拆分开一个 gate 和多个 …
最近和 QC 同学共建一套自动化压测的框架,希望能够确定游戏的性能基线,通过自动化定期回顾,看看有没有引入性能劣化的代码。压测过程中,发现广播性能不够强,搞的清明假期也在家想问题,写篇博客记录一下 为了让房间服务能腾出手专心处理战斗相关内容,我们针对性的改进了打包和广播,分离到一个与房间 1 比 1 配置的 sidecar 服务上去,期待能多利用一个核的算力来实现。在维持客户端链接的 login 节点,我们也做了类似 Skynet 的 cluster 模块的优化,拆分开一个 gate 和多个 …
使用 jemalloc 的潜在问题
今天读到一篇 关于 Firefox 内存优化的文章 ,里面提到使用 jemalloc 时遇到的一个小问题,不知道有没有现成的 API 可以统计,回头看看。 Jemalloc 是用来减少内存碎片化导致的内存损失的。内存碎片化是指可用内存被分成了一片片碎片,虽然总量够用,但是无法按需求分出指定大小的块。操作系统是按页(page)进行内存管理的,每页被浪费的内存会成为空洞;另外,部分释放回来的内存会在已分配内存间形成碎片,比较大的内存申请也塞不进去碎片里,导致内存损失 [Page1, [3 …
今天读到一篇 关于 Firefox 内存优化的文章 ,里面提到使用 jemalloc 时遇到的一个小问题,不知道有没有现成的 API 可以统计,回头看看。 Jemalloc 是用来减少内存碎片化导致的内存损失的。内存碎片化是指可用内存被分成了一片片碎片,虽然总量够用,但是无法按需求分出指定大小的块。操作系统是按页(page)进行内存管理的,每页被浪费的内存会成为空洞;另外,部分释放回来的内存会在已分配内存间形成碎片,比较大的内存申请也塞不进去碎片里,导致内存损失 [Page1, [3 …
Skynet require 的更新
最近升级项目依赖的中间件,中间件组的同学强力推荐(打发XD)我去看看 skynet.require 的修改,很有趣,而且是其中一个比较大的不兼容改动,我重新看了 Skynet 的代码 确实比以前更好用了,这里简单分享一下 服务启动的时候,往往会用到 sharedata 服务来全局共享一份数据表。sharedata 服务的 API 初始化时会使用 skynet.call 来调用 sharedata 服务,因为 call 最终会调用 yield,而 require 是一个 C 实现的函数,无法在其中 …
最近升级项目依赖的中间件,中间件组的同学强力推荐(打发XD)我去看看 skynet.require 的修改,很有趣,而且是其中一个比较大的不兼容改动,我重新看了 Skynet 的代码 确实比以前更好用了,这里简单分享一下 服务启动的时候,往往会用到 sharedata 服务来全局共享一份数据表。sharedata 服务的 API 初始化时会使用 skynet.call 来调用 sharedata 服务,因为 call 最终会调用 yield,而 require 是一个 C 实现的函数,无法在其中 …
一些吐槽
感觉被周六加班榨干了,累的不想写博客。非常佩服其他同事,996 还看不出来有啥异样的,太强了。。3 月 4 月连续加班后,5 月终于可以放松一下,不用加班了。五一假期陪老婆回了老家,过了愉快的 5 天,后面补班就非常累了。。。 上月月底请新同学帮忙做了一次压测,发现了一处内存泄漏。我们战斗部分的代码是仿照 ECS 的方式写的,按帧驱动系统更新,但是怪物死亡的时候没处理好,AI 停止后有可能又重新加上 tag,导致场景里只有几百个怪,实际却有几千个 AI 在跑。用 CPU 火焰图看就是 AI 部分 …
感觉被周六加班榨干了,累的不想写博客。非常佩服其他同事,996 还看不出来有啥异样的,太强了。。3 月 4 月连续加班后,5 月终于可以放松一下,不用加班了。五一假期陪老婆回了老家,过了愉快的 5 天,后面补班就非常累了。。。 上月月底请新同学帮忙做了一次压测,发现了一处内存泄漏。我们战斗部分的代码是仿照 ECS 的方式写的,按帧驱动系统更新,但是怪物死亡的时候没处理好,AI 停止后有可能又重新加上 tag,导致场景里只有几百个怪,实际却有几千个 AI 在跑。用 CPU 火焰图看就是 AI 部分 …
skynet.call 调用
上次 写了一篇文章讲 skynet.send,最近想起一个 call 的问题,流程跟 skynet.send 差不多,再记录一下 虽然官方 wiki 并没有记录,但是 skynet.call 一个不存在的服务,并不会报错的,最神奇的是当你真的起了同名的服务,这个服务就真的能收到这条消息。skynet.call 本质上还是 skynet.send,只是 send 完以后将 session 号和 coroutine 记下来,然后自己调用 yield 将控制权交还给 skynet。按上篇文章所述,给一 …
上次 写了一篇文章讲 skynet.send,最近想起一个 call 的问题,流程跟 skynet.send 差不多,再记录一下 虽然官方 wiki 并没有记录,但是 skynet.call 一个不存在的服务,并不会报错的,最神奇的是当你真的起了同名的服务,这个服务就真的能收到这条消息。skynet.call 本质上还是 skynet.send,只是 send 完以后将 session 号和 coroutine 记下来,然后自己调用 yield 将控制权交还给 skynet。按上篇文章所述,给一 …
skynet 火焰图的新方法
最近 子熏同学 搞定了新的抓取火焰图的方法,他觉得改动有点多,不方便开源出来,不过我觉得思路很好,写篇文章记录一下 skynet 自带的魔改版 Lua,即使 Lua 代码在死循环,也能通过 gm 指令让 vm 停下来,看看出事的地方是哪里。这是通过引入 lua_checksig_ 来实现的。在 lvm.c 里,重点的几个 OPCODE: OP_JMP, OP_CALL, OP_TAILCALL, OP_FORLOOP 都会调用 lua_checksig 进行检查,如果设置了开关,就会通过 …
最近 子熏同学 搞定了新的抓取火焰图的方法,他觉得改动有点多,不方便开源出来,不过我觉得思路很好,写篇文章记录一下 skynet 自带的魔改版 Lua,即使 Lua 代码在死循环,也能通过 gm 指令让 vm 停下来,看看出事的地方是哪里。这是通过引入 lua_checksig_ 来实现的。在 lvm.c 里,重点的几个 OPCODE: OP_JMP, OP_CALL, OP_TAILCALL, OP_FORLOOP 都会调用 lua_checksig 进行检查,如果设置了开关,就会通过 …
skynet 中隐藏的单点服务 : Harbor
昨晚和同事一起看 skynet 的代码,对于 skynet 实现的按名字发送消息比较好奇,走读了一下代码,特意写篇文章记录一下 Skynet 服务间通信,比较常用的是 skynet.send,该接口在 skynet/lualib/skynet.lua 中,实现则是 skynet.core 模块的 send 方法。skynet.core 是 skynet 提供给 lua 的一个 so,代码在 skynet/lualib-src/lua-skynet.c,它用了一个巧妙的注册办法 …
昨晚和同事一起看 skynet 的代码,对于 skynet 实现的按名字发送消息比较好奇,走读了一下代码,特意写篇文章记录一下 Skynet 服务间通信,比较常用的是 skynet.send,该接口在 skynet/lualib/skynet.lua 中,实现则是 skynet.core 模块的 send 方法。skynet.core 是 skynet 提供给 lua 的一个 so,代码在 skynet/lualib-src/lua-skynet.c,它用了一个巧妙的注册办法 …