欢乐西游通用缓存系统设计—应用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

相关文章

Redis分片集群的实现

《Redis分片集群的实现》Redis分片集群是一种将Redis数据库分散到多个节点上的方式,以提供更高的性能和可伸缩性,本文主要介绍了Redis分片集群的实现,具有一定的参考价值,感兴趣的可以了解一... 目录1. Redis Cluster的核心概念哈希槽(Hash Slots)主从复制与故障转移2.

Python FastAPI+Celery+RabbitMQ实现分布式图片水印处理系统

《PythonFastAPI+Celery+RabbitMQ实现分布式图片水印处理系统》这篇文章主要为大家详细介绍了PythonFastAPI如何结合Celery以及RabbitMQ实现简单的分布式... 实现思路FastAPI 服务器Celery 任务队列RabbitMQ 作为消息代理定时任务处理完整

Linux系统中卸载与安装JDK的详细教程

《Linux系统中卸载与安装JDK的详细教程》本文详细介绍了如何在Linux系统中通过Xshell和Xftp工具连接与传输文件,然后进行JDK的安装与卸载,安装步骤包括连接Linux、传输JDK安装包... 目录1、卸载1.1 linux删除自带的JDK1.2 Linux上卸载自己安装的JDK2、安装2.1

Python中随机休眠技术原理与应用详解

《Python中随机休眠技术原理与应用详解》在编程中,让程序暂停执行特定时间是常见需求,当需要引入不确定性时,随机休眠就成为关键技巧,下面我们就来看看Python中随机休眠技术的具体实现与应用吧... 目录引言一、实现原理与基础方法1.1 核心函数解析1.2 基础实现模板1.3 整数版实现二、典型应用场景2

Python Dash框架在数据可视化仪表板中的应用与实践记录

《PythonDash框架在数据可视化仪表板中的应用与实践记录》Python的PlotlyDash库提供了一种简便且强大的方式来构建和展示互动式数据仪表板,本篇文章将深入探讨如何使用Dash设计一... 目录python Dash框架在数据可视化仪表板中的应用与实践1. 什么是Plotly Dash?1.1

使用Java实现通用树形结构构建工具类

《使用Java实现通用树形结构构建工具类》这篇文章主要为大家详细介绍了如何使用Java实现通用树形结构构建工具类,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录完整代码一、设计思想与核心功能二、核心实现原理1. 数据结构准备阶段2. 循环依赖检测算法3. 树形结构构建4. 搜索子

Redis 中的热点键和数据倾斜示例详解

《Redis中的热点键和数据倾斜示例详解》热点键是指在Redis中被频繁访问的特定键,这些键由于其高访问频率,可能导致Redis服务器的性能问题,尤其是在高并发场景下,本文给大家介绍Redis中的热... 目录Redis 中的热点键和数据倾斜热点键(Hot Key)定义特点应对策略示例数据倾斜(Data S

Android Kotlin 高阶函数详解及其在协程中的应用小结

《AndroidKotlin高阶函数详解及其在协程中的应用小结》高阶函数是Kotlin中的一个重要特性,它能够将函数作为一等公民(First-ClassCitizen),使得代码更加简洁、灵活和可... 目录1. 引言2. 什么是高阶函数?3. 高阶函数的基础用法3.1 传递函数作为参数3.2 Lambda

Linux系统之主机网络配置方式

《Linux系统之主机网络配置方式》:本文主要介绍Linux系统之主机网络配置方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、查看主机的网络参数1、查看主机名2、查看IP地址3、查看网关4、查看DNS二、配置网卡1、修改网卡配置文件2、nmcli工具【通用

Linux系统之dns域名解析全过程

《Linux系统之dns域名解析全过程》:本文主要介绍Linux系统之dns域名解析全过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、dns域名解析介绍1、DNS核心概念1.1 区域 zone1.2 记录 record二、DNS服务的配置1、正向解析的配置