优化数据存储
优化匹配队列
不知道童鞋们有没有发现我们的游戏现在有一个问题,就是当某个player_id
发起匹配后,一直在匹配中,这时候刷新了网页重新进入游戏,在还没有按匹配按钮的时候,如果服务端匹配成功了,就会自动进入到游戏。
这是因为我们的匹配队列现在用的是一个List
结构,当客户端连接断开后,并没有把player_id
弹出。而且目前的逻辑也没有做player_id
唯一性检测,有可能匹配队列中会存在重复的player_id
。
解决这个问题的办法有很多,赵童鞋选择的是将List
改为Set
。
做题时间
- 修改
DataCenter
中匹配队列的数据结构为Set
。 - 增加删除匹配队列中某个
player_id
的方法,当客户端断开时调用该方法删除玩家。
DataCenter
类:
<?php
...
class DataCenter
{
...
public static function getPlayerWaitListLen()
{
$key = self::PREFIX_KEY . ":player_wait_list";
return self::redis()->sCard($key);
}
public static function pushPlayerToWaitList($playerId)
{
$key = self::PREFIX_KEY . ":player_wait_list";
self::redis()->sAdd($key, $playerId);
}
public static function popPlayerFromWaitList()
{
$key = self::PREFIX_KEY . ":player_wait_list";
return self::redis()->sPop($key);
}
public static function delPlayerFromWaitList($playerId)
{
$key = self::PREFIX_KEY . ":player_wait_list";
self::redis()->sRem($key, $playerId);
}
...
public static function delPlayerInfo($playerFd)
{
...
self::delPlayerFromWaitList($playerId);
}
...
}
得益于我们对key
的良好管理,并不需要修改Logic
中的代码,仅仅是改了一下Redis
的调用方法就解决了。
多个Key合并
如果童鞋们在开发中时常观察Redis
的Key
值的话,就会发现随着游戏的开发,里面的Key
越来越多了。
127.0.0.1:6379> keys *
1) "game:player_room_id:player_869"
2) "game:player_room_id:player_141"
3) "game:player_room_id:player_853"
4) "game:player_room_id:player_253"
5) "game:player_rank"
6) "game:online_player"
7) "game:player_id:105"
8) "game:player_room_id:player_235"
9) "game:player_fd:player_964"
10) "game:player_room_id:player_264"
11) "game:player_room_id:player_636"
...
仅仅是随便测试了几下,就会产生一大堆Key
值,部分Key
还是有着关系的,如player_room_id
、player_fd
等,他们都是关于同一个玩家的,我们可以对这一类Key
进行合并。
做题时间
- 使用
Hash
结构合并多个Key
到player_info
中。
DataCenter
类:
<?php
...
class DataCenter
{
...
public static function setPlayerRoomId($playerId, $roomId)
{
$key = self::PREFIX_KEY . ':player_info';
$field = 'room_id:' . $playerId;
self::redis()->hSet($key, $field, $roomId);
}
public static function getPlayerRoomId($playerId)
{
$key = self::PREFIX_KEY . ':player_info';
$field = 'room_id:' . $playerId;
return self::redis()->hGet($key, $field);
}
public static function delPlayerRoomId($playerId)
{
$key = self::PREFIX_KEY . ':player_info';
$field = 'room_id:' . $playerId;
self::redis()->hDel($key, $field);
}
public static function getPlayerFd($playerId)
{
$key = self::PREFIX_KEY . ':player_info';
$field = 'player_fd:' . $playerId;
return self::redis()->hGet($key, $field);
}
public static function setPlayerFd($playerId, $playerFd)
{
$key = self::PREFIX_KEY . ':player_info';
$field = 'player_fd:' . $playerId;
self::redis()->hSet($key, $field, $playerFd);
}
public static function delPlayerFd($playerId)
{
$key = self::PREFIX_KEY . ':player_info';
$field = 'player_fd:' . $playerId;
self::redis()->hDel($key, $field);
}
public static function getPlayerId($playerFd)
{
$key = self::PREFIX_KEY . ':player_info';
$field = 'player_id:' . $playerFd;
return self::redis()->hGet($key, $field);
}
public static function setPlayerId($playerFd, $playerId)
{
$key = self::PREFIX_KEY . ':player_info';
$field = 'player_id:' . $playerFd;
self::redis()->hSet($key, $field, $playerId);
}
public static function delPlayerId($playerFd)
{
$key = self::PREFIX_KEY . ':player_info';
$field = 'player_id:' . $playerFd;
self::redis()->hDel($key, $field);
}
...
public static function initDataCenter()
{
//清空匹配队列
$key = self::PREFIX_KEY . ':player_wait_list';
self::redis()->del($key);
//清空在线玩家
$key = self::PREFIX_KEY . ':online_player';
self::redis()->del($key);
//清空玩家信息
$key = self::PREFIX_KEY . ':player_info';
self::redis()->del($key);
}
...
}
重启游戏并进行游玩,我们再来看一下Redis
的情况。
127.0.0.1:6379> keys *
1) "game:player_info"
2) "game:player_wait_list"
3) "game:online_player"
本章对应Github Commit
:扩展三:优化数据存储