20180702-行军队列持久化问题

在做SLG项目时,有一个非常重要的问题,行军队列。

之所以把行军队列管理单独提出来,是因为行军里,包含了玩家战斗过程中的关键信息,也可以说所有数据,至少也是对数据的引用,该行军队列数据一旦出现问题,后果非常严重。


行军信息直接存储在二级存储器,也就是服务器的内存数据中,服务器一旦宕机,或者维护重启,所有的行军数据都将不复存在。但是行军包含的数据,在战斗运算中被修改,在整个时序图中,也不是固定不变的,这就导致如果将行军数据直接存储在持久化存储层,会导致io开销,而对游戏服务器来说,所谓的性能瓶颈,很少出现在CPU上,通常都在IIO上,无论是磁盘IO还是网络IO。


mysql这种强事物型数据库不满足对于快速读取写入的需求,mongo是以空间换时间,将数据块放在内存中,在内存中完成数据改写再由独立的线程回写进磁盘。直觉上分析mongo的存取速度会快于mysql,但是注意一下,服务器部署时,数据库都是独立部署在另外的服务器上,每一条对数据的读写命令,都需要跨越整个网络协议栈,从应用层,到传输层,到网络层,再到链路层,再由网卡发送出去,每一层都包含了解包和拆包过程,而且网络层用的是tcp,数据包需要确认包来确定下一次的tcp窗口,这又将导致延迟等待。


暂时先不考虑重新封装mongo,将mongo修改为异步处理,因为这么干会导致业务层更复杂的数据不一致问题。


接下来考虑redis和memcached这样的内存型nosql数据库,redis包含了aof和raf两种数据写入磁盘机制,就算redis挂掉也依然能保证数据的可用,而且redis的string类型数据,最大可以存储512M的大小,初步看满足了安全性的要求。但是注意一点,redis是单线程回调机制的,对CPU的利用其实是不高的。memcached是纯内存型的k-v数据库,内部是hash,内存的管理方式倒是用了比较能减少内存碎片的chrunk机制,而redis开辟了很大一块内存用来做内存池。此外,redis还是可以部署集群,一个master节点有两个cluster节点用来辅助存储数据。

这里有篇文章用来分析更进一步的分析读写性能  https://www.douban.com/note/609353706/

memcached的读写要优于redis。

这里就需要做一个权衡,数据的安全性,读写的性能,单节点的稳定性,对集群的支持,这些都需要考虑。

暂时选用redis,因为安全性实在是不可忽视,但在应用在业务中之前,需要做一些单元测试和性能测试来验证可行性。

其实在这里,可以将redis单独封装出来,接口其实是从业务上抽象出来的,一般是增删改查,通常所说的CRUD,这么做可以让中间件更通用一些,其他相似的业务可以复用代码。

而在业务层面,其中非常重要的一点,就是在重启服务器时,要将中间件的数据全部立即加载进去。


这种方案存在一个问题,redis的缓存存在失效时间,六种清理策略,也是在超出最大使用内存后,按照哪种规则清理。但是行军队列却不能对失效时间做预估,例如玩家向一座堡垒行军,这个时间是基于距离和兵的速度,预先做猜测会导致在不该清理的时候被清理。

并且,问题不止这么简单,在行军队列中,大量依赖于时间的事件机制,在重启的时候,服务器内存中的数据丢失,而且,之前已经绑定的事件也会丢失。

这么想会让事情复杂,将需求结构化,核心的目标是在服务器宕机重启的时候,依然能恢复到重启之前的状态。

猜你喜欢

转载自blog.csdn.net/adofsauron/article/details/80882570