1. 摘要
Redis作为目前最流行的键值对存储数据库,有着丰富的数据结构支持,在民生、金融、游戏、直播等诸多领域都有广泛的应用,大大提升了开发者的开发效率。今天我们主要介绍Redis在游戏开发中的几个典型应用场景:用户数据缓存、持久化功能的消息队列、乐观锁功能。
2. 典型应用场景
下面我们一一来介绍上述几个场景下是如何应用Redis的。
2.1 Redis作为DB的缓存
通常来说,每个注册的用户在后台数据库中都会保留一些和这个用户关联的信息,譬如说用户名、加密后的密码、昵称等等,然后用户在玩游戏的过程中也会产生一些关键的数据,需要在数据库中永久保存,譬如对于MMORPG
类型的游戏来说,可能需要保存用户当前的装备、金钱、充值的点数
等等信息,这些数据如果丢失会带来非常严重的问题。
随着业务的发展,注册的用户可能会越来越多,达到了亿级别,这个时候如果每个用户登录的请求,查询/修改个人游戏数据的请求都落到后端的数据库上,数据库的性能肯定是跟不上的,必然会导致比较糟糕的用户体验,这个时候我们自然就想到了缓存。
缓存是一种基于时间或空间局部性原理,以较小的成本带来较大数据访问速度提升的通用手段。在整个计算机体系中处处可见,大到大型网站的构建,小到cpu访存。
注册用户1亿
的游戏,也许日活是1千万
,如果我们能把这1千万的用户信息放到Redis中缓存起来,90%以上
的请求都直接是纯内存访问,势必会带来很大的性能提升。
上面是一个典型的Redis作为数据库缓存的架构,应用在读Cache(Redis)失效时,会访问数据库,然后把读到的数据同时写一份在Redis中,如果Redis内存满了,会基于一定的淘汰策略部分数据,下次访问同一份数据就可以直接读Redis了,这样Redis中就可以一直保存最近一段时间的热点数据。
上面只画了一个Redis节点,如果业务是构建在云上的,数据规模不大,缓存中的数据通常也可以容忍丢失,那么阿里云目前推出的单节点版Redis是一个性价比很高的选择。如果数据规模比较大,可以考虑集群形态的Redis,基于阿里云单节点集群版Redis,我们无需自己处理数据分片,可以像使用主从版一样使用集群版Redis,提升开发效率。
2.2 基于Redis实现带持久化功能的消息队列
生产者消费者模型是非常常用的编程模型,在游戏中也有大量的应用。譬如说用户在游戏中购买了一件虚拟物品,相当于产生了一个订单,订单相关的信息保存在了Redis的list中,另外一个负责处理订单的模块会从list中取出订单信息,然后做响应处理,简化的模型如下,
模块A
lpush user_oder_list "user1_order1 info"
(integer) 1
lpush user_oder_list "user1_order2 info"
(integer) 2
lpush user_oder_list "user2_order3 info"
(integer) 3
模块B
rpop user_oder_list
"user1_order1 info"
处理订单
rpop user_oder_list
"user1_order2 info"
处理订单
rpop user_oder_list
"user2_order3 info"
处理订单
如果在处理的过程中出现了Redis实例挂掉或所在机器宕机的情况,我们也无需担心,Redis提供了持久化的功能,当Redis重启之后会重新加载本地的数据恢复用户订单队列。阿里云Redis提供了双副本的主从和集群形态,除了会开启AOF持久化
,我们还会在主Redis故障时自动进行切换
,最大程度保证服务的可用性以及用户业务的稳定性。
2.3 基于Redis的乐观锁
在游戏开发中,我们有时需要实现乐观锁功能,乐观锁在数据竞争概率比较小的情况下会带来比较大的性能提升。memcached
中有cas
命令,用来实现check-and-set
这样功能。Redis中我们可以基于Multi/EXEC/WATCH
操作来实现类似的功能。
被WATCH的键会被监视,并且在事务执行前会去感知键的值是否发生了变化。如果有至少一个被监视的键在EXEC执行之前被修改了,那么整个事务都会被取消。
假如有一个用户使用购买的点数,兑换了一部分游戏内的金币,通常的操作如下,
curr_point = GET user1_point
curr_gold = GET user1_gold
curr_point -= x
curr_gold += x*100
SET user1_point curr_point
SET user1_gold curr_gold
在单个Redis客户端执行上述命令的时候没有问题,但是如果用户做了多次兑换,然后有多个Redis客户端同时在执行上述逻辑,那么用户的数据就错乱了。那如果基于Redis的WATCH和MULTI/EXEC机制,我们可以这么做,
WATCH
curr_point = GET user1_point
curr_gold = GET user1_gold
curr_point -= x
curr_gold += x*100
MULTI
SET user1_point curr_point
SET user1_gold curr_gold
EXEC
这样如果在执行EXEC之前,user1_point和user1_gold这两个key的值发生了变化,那么事务就会失败,否则事务执行成功。对于业务来说,就是不断的去重试上述逻辑,直到成功,这也是为什么数据冲突概率小的时候,性能很好,因为基本相当于无锁,所以称之为乐观锁。
3. 总结
Redis在游戏开发中的应用,远不止上述三个场景,我们还可以基于Redis来实现分布式锁、用户排行榜、共同关注、共同喜好、二度好友、发布订阅
等等功能,后面我们会分享更多和Redis行业应用相关的文章,敬请期待。