31

skynet 版的 cache server 改进

 4 years ago
source link: https://blog.codingnow.com/2020/02/skynet_cache_server_refine.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

去年我实现的 Unity cache server 的替代品 已经逐渐在公司内部取代 Unity 官方的版本。反应还不错,性能,可维护性以及稳定性都超过官方版本。

最近疫情严重,公司安排所有人员在家办公,今天是开工第三天。前两天比较混乱,毕竟在家办公的决定是在假期中间做出的,并没有预先准备,我们的这个 cacheserver 也在第一天受到了极大的考验,暴露出一个问题,好在只是内存用量预警,并没有出任何差错。我花了一天多的时间排查和解决问题,感觉这是一个极好的案例,值得记录一下。

周一复工那一天,公司内网的 cache server 服务器突然内存使用量峰值超过了 20G ,接近硬件配置的 32G ,SA 预警。好在不久以后就回落,并稳定下来。

这个服务器是基于 skynet 编写的,一开始只有 200 行左右的一个单一 lua 文件,非常简单。我认为设计和实现都是清晰可靠的。设计的时候就考虑过大用户量大数据量的应用场景(我们在生产环境运行的这个服务器实际管理数据已经超过了 800G),最多会有几百用户的并发。重新实现的原因是因为原版占用内存太多,所以内存使用量本来就是设计的主要考量因素。

我没有采用一个连接一个 agent 的方案,而是使用了固定数量的 agent ,用简单的负载均衡方法把外部连接分摊进去。

另外,还加了一个几十行的 C 模块,用来绕过 lua 虚拟机直接发送大文件。因为,如果把文件读入 Lua 虚拟机后,会增加额外的内存以及 gc 的负担。skynet 提供了 C API ,直接从 C 层打开读取本地文件并从网络发送走更直接高效。

考虑到大数据文件可能很大,在 C 模块里,我还特地按 4K 一个数据块的处理,并没有把大文件一次读入内存。

结合实际情况,我猜测了内存峰值出现的原因:大量数据积压在 skynet 内部的待发送队列中。

这是 skynet 当初设计的一个权衡下的结果。skynet 的网络发送 api 被设计成非阻塞,原子性,且在连接没有断开时一定发送成功的。这样可以方面业务层使用。业务层不用像使用 posix 标准 send 那样,还要检查返回值,看真的发送了多少字节。

而 skynet 的大多数应用场景,重头在业务处理,而不是 IO 消耗,一般不会出现 IO 积压的情况。但 cacheserver 这个业务不同,是典型的重 IO 环境。虽然通讯协议是串行的,一个一个文件处理,但客户端却可以一次性提交很多文件请求,每个请求都只有几十个字节,但回应的文件却可以很大。加上发送 api 是非阻塞的,这样就会导致大量待发送的数据进入 skynet 的网络层。

为什么这半年一直没有出现问题呢?因为我们一直是在速度很快的内网使用这个服务器(也是官方推荐的使用方法)。而且使用是渐进的,不会突然请求很多文件。而这次,大量同事在家办公,使用 vpn 连入内网,连接速度很慢。在第一天,家中的开发环境是全新的,需要全量拉所有的资源数据。种种因素加起来,在高并发高数据量的情况下,问题就暴露了出来。

其实这个问题之前也有人遇到过, 见这个 issue 。只是我虽然帮别人解决了需求,自己并未实践此类业务。解决方法并不复杂,使用 socket.warning 设置回调即可。当发送缓冲区过载,skynet 会发送一个 warning 消息给发送服务,告知缓冲区太长;这个时候业务应该停止发送数据(或进一步的测试一下带宽,限制流量),等到缓冲区清空(同样也会收到消息),再继续发送。

值得注意的是,如果加入 socket.warning 消息的监控,就不能再在 C 库函数中发送整个数据文件了。因为,如果文件过大,在发送的过程中,是没有机会处理新的消息,并挂起发送过程的。

我的修改方案是给 C 的发送函数增加了 offset 选项,并可以返回已经发送的字节数。当一次发送量超过一个阙值后,就中断返回。由 lua 调用方来决策是否应该挂起等待,或继续发送。最终添加了几十行代码就解决了这次的问题。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK