7 月的工作平淡无奇,除了 X 系统由借鉴 A 游戏改成借鉴 B 游戏,就没什么了,还是谈点别的吧。

最近看了 《游戏服务器端究竟解决了什么问题》,推荐给大家。作者关于烂框架的分析很有趣,框架定义角色时,不恰当的角色划分,会引起额外的复杂度,作者文章中后部分有分析。

作者对服务器消息流通的分析,相当见功力。游戏的服务器端,可以抽象的看成消息的生产者和消费者的集合。每一个生产者 / 消费者,就是一个服务。skynet 的优势,在于提供了服务这个封装,一组功能相对独立的逻辑,可以组合在一个服务内,通过 skynet 转发通信,为其他服务提供相应功能。常见的消息生产者,包括和客户端通信、解包的 gate 模块,skynet 提供的 timer 定时驱动。服务就是对这些消息进行响应,并通过和其他服务的互动,完成自己的功能。

在这个基础上,作者抽取出了消息 pattern 这个概念。常见的模式有 C->Gate->S, S->Gate->C, S->Gate->C。相对的,因为服务的存在,作者还引入了额外的 MQ,来处理服务间的通讯问题。同理,有 Service->MQ->Service, Service->MQ->Service

对于玩家存档的问题,作者抽象了一个数据服务来做这个事情。对应于烂框架的 DB 代理进程,只能用跟项目高度相关的 API 进行数据读取,数据服务提供了更高层的功能:剥离游戏服务状态。剥离状态后,从 skynet 的角度看,所有 agent、service,都是做一些简单的计算、比较、排序,最后数据都会存到数据服务上。这样的好处是,剥离了状态的 skynet,随便挂,不会丢数据,对用户透明。这个思路非常棒,但是进程间通讯的代价比 skynet 内服务间通讯要大,怎么避免服务间通讯引起频繁的数据服务通讯,是一个值得思考的问题。

作者对我启发最大的地方,是文末推荐的那篇 《The Log》,作者是 LinkedIn 团队的开发成员。写 Log 是一件非常简单和入门的事,看完 the log,却发现一直忽视了对 log 这种数据流的视角。文章字里行间,还透着点日志式数据库的意味。这篇文章比较长,核心思路是 Table 和 Change Log 是可以相互转化的,一个 Table 反映了当前的状态,而 Log 则记录了 Table 一路以来的状态转换。那么,只要有 Log,其实 Table 不再重要,因为只要我回放 Log,最终就可以得到 Table。** 这是一个有状态到无状态的转化 **!然后 Log 这一块可以交给成熟的中间件处理,LinkdedIn 是透过卡夫卡(Kafka)来完成的。消费者的消费速度慢?不要紧,无状态服务可以无限水平扩展。消息产生了消息链?没关系,丢回到 Log 中,下个周期再处理,完美!

顺便推荐一篇对 The Log 的引用文章,来自于 Yelp 团队:《billions of messages a day》, 里面对利用 Log 进行解耦作了更深入的剖析,对兼容 Log 格式变更也有自己的解决办法,有空可以看看