swoole内多进程并发redis和mysql出现请求返回数据串包问题bug解决
swoole内多进程并发redis和mysql出现请求返回数据串包问题bug解决
问题:
swoole实现tcp服务时,在并发情况下,不同进程下的redis和db的请求数据返回出现串包混乱问题
出现原因:
swoole tcp服务启动前调用了 mysql 和 redis 查询配置信息,并把连接对象实例化缓存起来了,然后在后续tcp启动前没有清理这些实例化的连接,导致多个work进程之间共享了这些启动前实例化的连接实例,从而在不同进程间并发处理请求时请求返回数据串包返回异常。
问题解决前代码:
# tcp服务启动代码
defineGameServer($serverId);
// 此处未清理连接实例
$tcp = new \Dragonica\Game\Socket\GameServer(SELF_IP, GAME_LISTEN_PRIVATE_PORT, $config, $serverId);
$tcp->init();
$tcp->startServer();
defineGameServer()
{
# 查询配置信息,调用了
# c_redis_db
# c_mysql_db
}
# redis&myqsl部分代码:
class c_redis_db
{
private static $instancesLocal = array();
private static $instancesRemote = array();
static function getRedisInstance($db = self::DEFAULT_DB, $reconnect = false)
{
if ($reconnect || !array_key_exists($db, self::$instancesLocal))
$redis = self::connect(ACCOUNT_REDIS_SERVER, ACCOUNT_REDIS_PORT, $db);
self::$instancesLocal[$db] = $redis;
} else {
$redis = self::$instancesLocal[$db];
}
return $redis;
}
}
# mysql部分代码
class c_mysql_db
{
private $mysql;
var $host;
var $port;
var $user;
var $pwd;
var $db;
private $connected = false;
private $error;
private $inTran;
static $instances = array();
static function DBConnect($type = self::GAME_DB)
{
if (!array_key_exists($type, self::$instances)) {
$instance = new c_mysql_db($db['host'], $db['port'], $db['user'], $db['pwd'], $db['db']);
self::$instances[$type] = $instance;
}
$instance = self::$instances[$type];
$instance->connect();
return $instance;
}
}
问题解决后代码:
# tcp服务启动代码
defineGameServer($serverId);
******* 新加代码 START********
c_redis_db_account::clearInstance();
c_redis_db::clearInstance();
c_mysql_db::clearInstance();
******* 新加代码 END ********
..........
..........
# redis&myqsl部分代码:
class c_redis_db
{
...........
static function clearInstance() {
foreach (self::$instancesLocal as $local){
try {
$local->close();
showLog('close redis account local', true);
} catch (\Exception $e) {
showLog("redis close error account local;", true);
}
}
foreach (self::$instancesRemote as $remote){
try {
$remote->close();
showLog('close redis account remote', true);
} catch (\Exception $e) {
showLog("redis close error account remote;", true);
}
}
self::$instancesLocal = array();
self::$instancesRemote = array();
}
}
# mysql部分代码
class c_mysql_db
{
.............
static function clearInstance() {
foreach(self::$instances as $instance) {
$instance->mysql->close();
$instance->connected = false;
}
self::$instances = array();
}
}
本作品采用《CC 协议》,转载必须注明作者和本文链接
推荐文章: