面试题答案
一键面试数据结构设计
- 按照游戏模式存储排行榜:
- 对于每个游戏模式,使用一个 Redis Sorted Set 来存储玩家的排行榜信息。例如,假设游戏模式有
game_mode_1
,game_mode_2
等,Sorted Set 的 key 可以设计为leaderboard:game_mode_1
,leaderboard:game_mode_2
等。 - Sorted Set 中的 member 为玩家 ID,score 为玩家在该游戏模式下的得分。这样通过 Sorted Set 的有序特性,可以很方便地获取玩家的排名。
- 对于每个游戏模式,使用一个 Redis Sorted Set 来存储玩家的排行榜信息。例如,假设游戏模式有
- 按分组存储玩家排名:
- 对于按照等级划分的分组(假设等级有
level_1
,level_2
等),为每个分组创建一个 Sorted Set。例如,leaderboard:level_1:game_mode_1
,leaderboard:level_1:game_mode_2
等。同样,member 为玩家 ID,score 为玩家在对应游戏模式下的得分。
- 对于按照等级划分的分组(假设等级有
操作逻辑
- 更新排行榜:
- 当玩家在某个游戏模式下有新的得分时,使用
ZADD
命令更新对应的 Sorted Set。例如,对于game_mode_1
,如果玩家player_1
有新得分new_score
,执行ZADD leaderboard:game_mode_1 new_score player_1
。 - 同时,要更新该玩家所属分组的 Sorted Set。假设
player_1
属于level_1
分组,执行ZADD leaderboard:level_1:game_mode_1 new_score player_1
。
- 当玩家在某个游戏模式下有新的得分时,使用
- 查询玩家排名:
- 查询玩家在某个游戏模式下的总排名,使用
ZRANK
命令。例如,查询player_1
在game_mode_1
中的排名,执行ZRANK leaderboard:game_mode_1 player_1
。 - 查询玩家在其所属分组中的排名,同样使用
ZRANK
命令。例如,查询player_1
在level_1
分组的game_mode_1
中的排名,执行ZRANK leaderboard:level_1:game_mode_1 player_1
。
- 查询玩家在某个游戏模式下的总排名,使用
应对高并发场景下的数据一致性问题
- 使用 Redis 事务:
- 在更新排行榜时,可以使用 Redis 的 MULTI 和 EXEC 命令组成事务。例如:
MULTI ZADD leaderboard:game_mode_1 new_score player_1 ZADD leaderboard:level_1:game_mode_1 new_score player_1 EXEC
- 这样可以保证这两个操作要么都执行成功,要么都不执行,避免部分更新导致的数据不一致。
- 乐观锁机制:
- 在更新数据前,先获取当前玩家的得分,例如使用
ZSCORE
命令获取player_1
在leaderboard:game_mode_1
中的得分old_score
。 - 在更新时,通过
WATCH
命令监控该 Sorted Set。例如:
WATCH leaderboard:game_mode_1 MULTI ZADD leaderboard:game_mode_1 new_score player_1 ZADD leaderboard:level_1:game_mode_1 new_score player_1 EXEC
- 如果在
WATCH
之后,leaderboard:game_mode_1
被其他客户端修改,EXEC
命令会返回nil
,表示事务执行失败,此时需要重新获取数据并再次尝试更新。
- 在更新数据前,先获取当前玩家的得分,例如使用
- 读写分离与缓存:
- 对于读操作,可以采用读写分离的策略,使用多个从节点来分担读压力。对于频繁查询的排名信息,可以在应用层设置本地缓存,减少对 Redis 的直接查询次数。例如,使用 Memcached 或者应用内的内存缓存(如 Python 的
functools.lru_cache
等)来缓存玩家排名。这样在高并发读场景下,可以快速从缓存中获取数据,提高响应速度。同时,需要注意缓存的更新策略,当排行榜数据发生变化时,及时更新缓存数据,以保证数据的一致性。
- 对于读操作,可以采用读写分离的策略,使用多个从节点来分担读压力。对于频繁查询的排名信息,可以在应用层设置本地缓存,减少对 Redis 的直接查询次数。例如,使用 Memcached 或者应用内的内存缓存(如 Python 的