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

相关文章

CSS中的Static、Relative、Absolute、Fixed、Sticky的应用与详细对比

《CSS中的Static、Relative、Absolute、Fixed、Sticky的应用与详细对比》CSS中的position属性用于控制元素的定位方式,不同的定位方式会影响元素在页面中的布... css 中的 position 属性用于控制元素的定位方式,不同的定位方式会影响元素在页面中的布局和层叠关

SpringBoot3应用中集成和使用Spring Retry的实践记录

《SpringBoot3应用中集成和使用SpringRetry的实践记录》SpringRetry为SpringBoot3提供重试机制,支持注解和编程式两种方式,可配置重试策略与监听器,适用于临时性故... 目录1. 简介2. 环境准备3. 使用方式3.1 注解方式 基础使用自定义重试策略失败恢复机制注意事项

Redis Cluster模式配置

《RedisCluster模式配置》:本文主要介绍RedisCluster模式配置,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录分片 一、分片的本质与核心价值二、分片实现方案对比 ‌三、分片算法详解1. ‌范围分片(顺序分片)‌2. ‌哈希分片3. ‌虚

Springboot整合Redis主从实践

《Springboot整合Redis主从实践》:本文主要介绍Springboot整合Redis主从的实例,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录前言原配置现配置测试LettuceConnectionFactory.setShareNativeConnect

Redis过期删除机制与内存淘汰策略的解析指南

《Redis过期删除机制与内存淘汰策略的解析指南》在使用Redis构建缓存系统时,很多开发者只设置了EXPIRE但却忽略了背后Redis的过期删除机制与内存淘汰策略,下面小编就来和大家详细介绍一下... 目录1、简述2、Redis http://www.chinasem.cn的过期删除策略(Key Expir

基于Python实现一个简单的题库与在线考试系统

《基于Python实现一个简单的题库与在线考试系统》在当今信息化教育时代,在线学习与考试系统已成为教育技术领域的重要组成部分,本文就来介绍一下如何使用Python和PyQt5框架开发一个名为白泽题库系... 目录概述功能特点界面展示系统架构设计类结构图Excel题库填写格式模板题库题目填写格式表核心数据结构

Linux系统中的firewall-offline-cmd详解(收藏版)

《Linux系统中的firewall-offline-cmd详解(收藏版)》firewall-offline-cmd是firewalld的一个命令行工具,专门设计用于在没有运行firewalld服务的... 目录主要用途基本语法选项1. 状态管理2. 区域管理3. 服务管理4. 端口管理5. ICMP 阻断

MyBatis设计SQL返回布尔值(Boolean)的常见方法

《MyBatis设计SQL返回布尔值(Boolean)的常见方法》这篇文章主要为大家详细介绍了MyBatis设计SQL返回布尔值(Boolean)的几种常见方法,文中的示例代码讲解详细,感兴趣的小伙伴... 目录方案一:使用COUNT查询存在性(推荐)方案二:条件表达式直接返回布尔方案三:存在性检查(EXI

Python使用Tkinter打造一个完整的桌面应用

《Python使用Tkinter打造一个完整的桌面应用》在Python生态中,Tkinter就像一把瑞士军刀,它没有花哨的特效,却能快速搭建出实用的图形界面,作为Python自带的标准库,无需安装即可... 目录一、界面搭建:像搭积木一样组合控件二、菜单系统:给应用装上“控制中枢”三、事件驱动:让界面“活”

Windows 系统下 Nginx 的配置步骤详解

《Windows系统下Nginx的配置步骤详解》Nginx是一款功能强大的软件,在互联网领域有广泛应用,简单来说,它就像一个聪明的交通指挥员,能让网站运行得更高效、更稳定,:本文主要介绍W... 目录一、为什么要用 Nginx二、Windows 系统下 Nginx 的配置步骤1. 下载 Nginx2. 解压