欢乐西游通用缓存系统设计—应用Redis

2024-05-09 16:08

本文主要是介绍欢乐西游通用缓存系统设计—应用Redis,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、需求背景:

       欢乐西游是一款手机卡牌游戏,采用分区分服架构,目前已经登录手Q和微信平台。有些全区玩法需要使用到离线玩家数据:1、天梯PVP系统(按竞技积分匹配全区玩家,包括离线玩家)2、大闹天宫(按战斗力匹配全区玩家,包括离线玩家)

       欢乐西采用TcaplusKV方式存储玩家数据,数据读写以角色gid作为key进行,因此通过积分或者战斗力的方式匹配玩家将会非常麻烦。以天梯系统为例,为了通过竞技积分查找玩家,需要Cache玩家离线数据并且建立以积分作为数据索引的数据结构,方便通过竞技积分找出符合要求的角色。PVP玩法都是全区级的,因此Cache数据应该在大区级,便于不同的gamesvr访问。

二、缓存设计关键点:

1、 数据持久化。如果进程coredump或者服务器down机怎么办?缓存数据怎么恢复,是否需要通过数据上报机制来重建缓存?

2、 数据量。一个大区缓存数据量级有多少?能否做到缓存在一台机器还是数据分片在不同机器?

3、 性能问题。缓存全区数据,百万级,能否保证业务需要的读写和匹配性能?

4、 数据结构设计。竞技积分匹配(1000分为例),需要匹配900~1100范围玩家,并且整体匹配满足密度分布,比如[900,920]玩家分布占[900,1100]范围50%的数量,那么从整体来看,匹配到[900,920]的角色要占50%的概率。如何设计数据结构,能够方便管理缓存数据并且能够很好支持匹配规则?

5、 可扩展性。缓存数据数据管理应该具备一定通用和扩展性,例如后续大闹天宫通过战斗力来匹配玩家,扩展新的字段和结构。

三、缓存数据结构设计:

       按积分分段管理缓存数据,例如每20分一个积分段,所有符合当前积分段的玩家放在一起。最终呈现的数据结构如下:

  

       当需要匹配[900,1100]角色时,1、计算出匹配范围涉及到的具体积分段  2、计算出每个积分段人数,再根据每个积分段人数比例算出对应积分段的匹配概率  3、通过概率计算匹配最终落在哪个积分段。

       上面是一个比较通用的匹配算法,但欢乐西游天梯匹配规则更复杂,他会首先从积分段总共匹配200(匹配人数符合积分段人数比例分布),再根据这200人等级和自己等级差按概率分布再匹配。具体细节不在赘述,但总体思想如上描述。

四、架构设计方案一:

       游戏自己实现MatchSvrcache玩家离线数据,实现匹配逻辑。使用共享内存方式存储cache数据,保证不停机更新后数据不丢失。

优缺点分析:

1、自己实现一个MatchSvr的缓存系统,会增加开发工作量和复杂度。

2、等级段100+个,每个等级段角色数不固定,用链表来维护增大实现难度。同时,在匹配对手中,需要随机匹配也会增大链表操作的复杂度,查找和删除需要遍历链表,性能低。

3MatchSvr缓存数据落地磁盘,保证停机后的数据恢复。磁盘落地可以每天晚上开个线程一条一条写磁盘,整个开发量较大。或者使用mmap映射磁盘文件到内存,定时msync同步内存脏数据到磁盘,但这样内存固定,如果以后加字段或新增系统会非常麻烦。

4、扩展性不够好,没有一个通用的缓存系统,新系统需要额外开发。

五、架构设计方案二:

       针对方案一,其实可以将匹配逻辑和缓存数据分离,解耦合。缓存数据层是一个通用的存储和数据管理方案,后续新增字段和数据都能非常方便扩展,常驻进程,修改少,稳定,支持数据持久化。匹配逻辑层用于读写缓存数据并且应用各种匹配规则,无状态服务,即使匹配逻辑修改,只需要更新逻辑层。

       我们采用开源的Redis作为缓存数据层,提供高效数据管理和持久化功能。Redis是一款开源的、高性能的key-value存储。Redis 和其他很多 key-value 数据库的不同之处在于, Redis 不仅支持简单的字符串键值对,它还提供了一系列数据结构类型值, 比如列表、哈希、集合和有序集, 并在这些数据结构类型上定义了一套强大的 API 。通过对不同类型的值进行操作, Redis 可以很轻易地完成其他只支持字符串键值对的 key-value 数据库很难(或者无法)完成的任务。例如天梯系统一个积分段对应一个集合,在redis层,key就是积分段,value就是集合,可以方便查找删除等操作。

Redis 分别提供了 RDB  AOF 两种持久化模式。在 Redis 运行时, RDB 程序将当前内存中的数据库快照保存到磁盘文件中 Redis 重启动时,RDB 程序可以通过载入 RDB 文件来还原数据库的状态。

Redis提供通用的数据缓存服务,服务各个需要的子模块。这个进程类似mysql,只需要启动一次,以后不再启停。CacheProxy使用tapp多线程模式,每个线程同步访问redis。经测试,基本数据接口操作本机2.5W/s,跨机器3500/s。因此,CacheProxy3~5个线程同步访问不会有任何性能问题。当然,使用cacheproxy能够保证和redis部署在同一台机器上。

优点:

1、 Redis 不仅支持简单的字符串键值对,它的Value还支持列表、哈希、集合和有序集, 并在这些数据结构类型上定义了一套强大的 API  在具体应用时,key是一个具体积分段,value就是积分段下所有角色数据组成的集合,Redis底层实现用hashmap方式,集合元素可以动态增加,查找删除都是O(1)时间复杂度。因此可以很轻易解决方案一12点。

2、 Redis支持RDB持久化模式,通过配置,可以定期将全量数据写到磁盘文件中。Redisfork一个子进程,由子进程完成写磁盘的工作。

3、 提供通用的Cache数据服务,拥有较好的扩展性,后续新增系统都可以来使用

4、 节省开发工作,不需要重复实现各种数据结构管理,数据落地等模块。

5 Redis提供强大的客户端,可以方便查看各种数据和key,便于开发测试和运维,而且还有很多脚本工具,便于后期数据分析。

一些思考:

      独立一个CacheProxy进程?

     最早的想法是直接通过interface来访问Redis服务,但可能会有两个缺点:

     1、 Interface作为world<=>zone, zone<=>zone之间的公共纽带,作用日益加重。Interface直接影响到天梯系统、帮派系统、登录踢人、idip请求、邮件体力通知、公告等。为了保证interface本身作为消息转发的简单和稳定,将redis客户端api访问独立出来会安全许多

     2、 Redis客户端访问Redis服务采用多线程同步方式。如果interfaceRedis不在同一个机器,将会极大影响同步访问性能(具体参照上面数据,性能瓶颈在网络io层。按照目前的服务器部署,world层会使用一台机器,interfaceredis分布在一台机器肯定不会影响访问性能,但以后可能会将interface部署到不同机器,保证interface容灾。

      同步还是异步访问redis

异步访问优点:

1、性能非常高。单线程简单读写压测显示,异步20W+/s, 同步2.5W/s

2、异步访问基本不受跨机器影响,瓶颈在redis自身数据处理速度。

但异步相比同步,也有些缺点:

1、异步api本身教复杂,需要用到libevent或者libev库事件机制驱动。 

2、异步api会使业务流程变得非常复杂。例如天梯系统更新一个玩家积分,涉及到更新玩家积分数据、从原来积分段删除、添加到新的积分段三个步骤,每个步骤都需要回调处理。而且cacheproxy本身无状态,不希望有数据缓存来支持回调处理。

综上:使用同步接口已经拥有非常高的性能,而且使用cacheproxy能够保证和redis部署在同一台机器,性能完全满足业务需求。同时,同步接口api极为简单,上述更新玩家积分的3个操作,都可以当成本地直接完成,业务流程很清晰。

六、运行流程:

l  上报竞技积分

l  匹配对手

七、压测性能:

Cacheproxy采用多线程同步方式,在v8.2机型压测(816G内存),缓存数据1000W,内存占用2G,按上述实际综合业务场景压测数据如下:

Cacheproxy线程数

上报积分/s

Cacheproxy单线程cpu占用

Redis Cpu占用

1

0.89W

47%

42%

2

1.62W

41%

58%

3

2.38W

38%

76%

4

2.72W

31%

84%

5

2.56W

26%

81%

6

2.46W

22%

72%

7

2.29W

15%

66%

15

1.95W

7%

58%

 

Cacheproxy线程数

匹配数/s

Cacheproxy单线程cpu占用

Redis Cpu占用

1

3030

31%

62%

2

4370

22%

84%

3

4500

16%

85%

4

5050

15%

86%

5

5100

12%

86%

6

5700

11%

88%

7

5700

10%

88%

15

5000

4%

82%

综上:cacheproxy线程并发4~5个性能最好。当线程数较少时,同步访问瓶颈在网络IO层。当线程数过多时,由于cpu8核,其他线程会抢占Rediscpu资源,导致Redis本身数据处理减慢。

八、运营数据:

欢乐西游是分区架构,redis服务部署在每个大区,cacheproxy并发5个线程,以191太上老君大区为例:

注册用户:50W

Redis内存占用:100M

Redis RDB备份文件:28M

Pvp竞技上报+匹配峰值:44 * 5 =220/s (tnm2每分钟统计峰值44/s,瞬间峰值按5倍算)

CacheproxyRedis cpu占用在1%左右,基本可以忽略。

以下是一些性能截图:

九、容灾:

       根据业务场景需求,pvp缓存数据不是十分关键的数据,哪怕全部丢失也可以自动上报,重新建立缓存数据。

       因此Redis采用RDB模式备份数据,每天全量备份一次到本地磁盘,并拷贝一份到其他机器。即使Redis挂了或者整个机器down机,也能通过加载RDB文件非常方便的恢复数据。哪怕恢复的数据是老的,对于玩家也是毫无感知。

       如果整个world机器down机,gamesvr层在一定时间收不到心跳包也会将world层置为超时。这时匹配流程会转入匹配机器人,玩家还是能进行竞技玩法,提供一定程度有损服务。直到world机器恢复,匹配流程将自动切换回正常模式。

十、其他:

       总体而言,匹配逻辑层和数据层分离,数据层采用redis具有良好的扩展性,数据管理、持久化、高性能都能非常好的满足业务需求。后续的大闹天宫系统,通过战斗力匹配离线玩家,也使用类似的方式,1天时间就完成整个数据上报和匹配流程,极大简化了开发流程。

       当然,Redis还有非常丰富的功能,集群管理、AOF备份等机制,我们只是用到其中很小的一部分功能,满足业务需求并具有一定扩展性就可以,关键是能够方便部署,不需要额外的机器资源成本和运维成本。

       使用Redis经验不多,希望大家多多指正。  

这篇关于欢乐西游通用缓存系统设计—应用Redis的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/973849

相关文章

nginx -t、nginx -s stop 和 nginx -s reload 命令的详细解析(结合应用场景)

《nginx-t、nginx-sstop和nginx-sreload命令的详细解析(结合应用场景)》本文解析Nginx的-t、-sstop、-sreload命令,分别用于配置语法检... 以下是关于 nginx -t、nginx -s stop 和 nginx -s reload 命令的详细解析,结合实际应

golang程序打包成脚本部署到Linux系统方式

《golang程序打包成脚本部署到Linux系统方式》Golang程序通过本地编译(设置GOOS为linux生成无后缀二进制文件),上传至Linux服务器后赋权执行,使用nohup命令实现后台运行,完... 目录本地编译golang程序上传Golang二进制文件到linux服务器总结本地编译Golang程序

Python通用唯一标识符模块uuid使用案例详解

《Python通用唯一标识符模块uuid使用案例详解》Pythonuuid模块用于生成128位全局唯一标识符,支持UUID1-5版本,适用于分布式系统、数据库主键等场景,需注意隐私、碰撞概率及存储优... 目录简介核心功能1. UUID版本2. UUID属性3. 命名空间使用场景1. 生成唯一标识符2. 数

Linux系统性能检测命令详解

《Linux系统性能检测命令详解》本文介绍了Linux系统常用的监控命令(如top、vmstat、iostat、htop等)及其参数功能,涵盖进程状态、内存使用、磁盘I/O、系统负载等多维度资源监控,... 目录toppsuptimevmstatIOStatiotopslabtophtopdstatnmon

Knife4j+Axios+Redis前后端分离架构下的 API 管理与会话方案(最新推荐)

《Knife4j+Axios+Redis前后端分离架构下的API管理与会话方案(最新推荐)》本文主要介绍了Swagger与Knife4j的配置要点、前后端对接方法以及分布式Session实现原理,... 目录一、Swagger 与 Knife4j 的深度理解及配置要点Knife4j 配置关键要点1.Spri

PostgreSQL的扩展dict_int应用案例解析

《PostgreSQL的扩展dict_int应用案例解析》dict_int扩展为PostgreSQL提供了专业的整数文本处理能力,特别适合需要精确处理数字内容的搜索场景,本文给大家介绍PostgreS... 目录PostgreSQL的扩展dict_int一、扩展概述二、核心功能三、安装与启用四、字典配置方法

Python中re模块结合正则表达式的实际应用案例

《Python中re模块结合正则表达式的实际应用案例》Python中的re模块是用于处理正则表达式的强大工具,正则表达式是一种用来匹配字符串的模式,它可以在文本中搜索和匹配特定的字符串模式,这篇文章主... 目录前言re模块常用函数一、查看文本中是否包含 A 或 B 字符串二、替换多个关键词为统一格式三、提

Redis出现中文乱码的问题及解决

《Redis出现中文乱码的问题及解决》:本文主要介绍Redis出现中文乱码的问题及解决,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1. 问题的产生2China编程. 问题的解决redihttp://www.chinasem.cns数据进制问题的解决中文乱码问题解决总结

Java MQTT实战应用

《JavaMQTT实战应用》本文详解MQTT协议,涵盖其发布/订阅机制、低功耗高效特性、三种服务质量等级(QoS0/1/2),以及客户端、代理、主题的核心概念,最后提供Linux部署教程、Sprin... 目录一、MQTT协议二、MQTT优点三、三种服务质量等级四、客户端、代理、主题1. 客户端(Clien

Redis的持久化之RDB和AOF机制详解

《Redis的持久化之RDB和AOF机制详解》:本文主要介绍Redis的持久化之RDB和AOF机制,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录概述RDB(Redis Database)核心原理触发方式手动触发自动触发AOF(Append-Only File)核