PHP redis会话处理程序-更改服务器数量

eni9jsuy  于 7个月前  发布在  Redis
关注(0)|答案(1)|浏览(61)

我使用phpredis作为会话处理程序(https://github.com/phpredis/phpredis)。我当前的连接字符串如下所示:

session.save_path = "tcp://10.0.1.11:7005?weight=1&timeout=0.2&persistent=1&read_timeout=0.5,
tcp://10.0.1.12:7005?weight=1&timeout=0.2&persistent=1&read_timeout=0.5"

字符串
但我需要添加更多的redis服务器和移动它们之间的现有会话。
我的新连接字符串看起来像这样:

session.save_path = "tcp://10.0.1.11:7005?weight=1&timeout=0.2&persistent=1&read_timeout=0.5,
tcp://10.0.1.12:7005?weight=1&timeout=0.2&persistent=1&read_timeout=0.5,
tcp://10.0.1.13:7005?weight=1&timeout=0.2&persistent=1&read_timeout=0.5,
tcp://10.0.1.14:7005?weight=1&timeout=0.2&persistent=1&read_timeout=0.5,
tcp://10.0.1.15:7005?weight=1&timeout=0.2&persistent=1&read_timeout=0.5"


因此,将有3个以上的服务器和会话分布的关键将改变与服务器的数量。
我如何将现有的会话从旧服务器移动到新服务器,然后将每个会话都放在正确的服务器上?有没有现有的工具可以做到这一点?有人有类似的问题,并有现成的解决方案吗?

f4t66c6m

f4t66c6m1#

我已经准备好了php脚本,可以将所有会话迁移到新的服务器,同时保留与phpredis会话处理程序使用相同的布局。它支持Redis和Redis->migrate()或手动Redis->dump()和Redis->restore()。也许它对有同样问题的人有用。

<?php
class RedisPoolMember {
    public Redis $redis_sock;
    public string $hostname;
    public int $port;
    public int $weight;
    public $next;

    public function __construct(string $hostname, int $port, int $weight) {
        $this->redis_sock = new Redis(); 
        $this->redis_sock->connect($hostname, $port);
        $this->weight = $weight;
        $this->hostname = $hostname;
        $this->port = $port;
        $this->next = null;
    }
}

class RedisPool {
    public $totalWeight = 0;
    public $count = 0;
    public $head = null;
    public $lock_status;

    public function add(string $hostname, int $port, int $weight) {
        
        $rpm = new RedisPoolMember($hostname, $port, $weight);
        $rpm->next = $this->head;
        $this->head = $rpm;

        $this->totalWeight += $weight;
        $this->count++;
    }
    
    public function get(string $key): ?RedisPoolMember {
        $pos = unpack("L", substr($key, 0, 4))[1]; // Assuming a little-endian order
        $pos %= $this->totalWeight;

        $rpm = $this->head;

        for ($i = 0; $i < $this->totalWeight;) {
            if ($pos >= $i && $pos < $i + $rpm->weight) {
                return $rpm;
            }
            $i += $rpm->weight;
            $rpm = $rpm->next;
        }

        return null;
    }
}

function saveKeyPool(RedisPool &$pool, string $sessionPrefix, string $key, $value) {
    $sid = substr($key, strlen($sessionPrefix));
    $rpm = $pool->get($sid);
    $rpm->redis_sock->restore($key, $value);
}

function readKeyPool(RedisPool &$pool, string $sessionPrefix, string $key) {
    $sid = substr($key, strlen($sessionPrefix));
    $rpm = $pool->get($sid);
    return $rpm->redis_sock->dump($key);
}

function migrateKey(RedisPool &$oldPool, RedisPool &$newPool, string $sessionPrefix, string $key) {
    echo('.');
    $sid = substr($key, strlen($sessionPrefix));
    $rpmOld = $oldPool->get($sid);
    $rpmNew = $newPool->get($sid);
    //echo("Migrate key $key to {$rpmNew->hostname}:{$rpmNew->port}\n");
    $rpmOld->redis_sock->migrate($rpmNew->hostname, $rpmNew->port, $key, 0, 0, true, true);
}

function getKeyDestinationRpm(RedisPool &$newPool, string $sessionPrefix, string $key) {
    $sid = substr($key, strlen($sessionPrefix));
    $rpmNew = $newPool->get($sid);
    return $rpmNew->hostname.':'.$rpmNew->port;
}

function processBatch(Redis &$oldRedis, array &$batch) {
    foreach($batch as $server=>$keys) {
        $server = explode(':', $server);
        $oldRedis->migrate($server[0], $server[1], $keys, 0, 0, true, true);
    }
}

$sessionPrefix = 'PHPREDIS_SESSION:';
$oldRedisServers = [['hostname'=>'10.0.1.11', 'port'=>7005], ['hostname'=>'10.0.1.12', 'port'=>7005]];

$redisPoolOld = new RedisPool();
$redisPoolOld->add('10.0.1.11', 7005, 1);
$redisPoolOld->add('10.0.1.12', 7005, 1);

$redisPoolNew = new RedisPool();
$redisPoolNew->add('10.0.1.11', 7010, 1);
$redisPoolNew->add('10.0.1.11', 7011, 1);
$redisPoolNew->add('10.0.1.11', 7012, 1);
$redisPoolNew->add('10.0.1.11', 7013, 1);
$redisPoolNew->add('10.0.1.11', 7014, 1);
$redisPoolNew->add('10.0.1.11', 7015, 1);
$redisPoolNew->add('10.0.1.12', 7010, 1);
$redisPoolNew->add('10.0.1.12', 7011, 1);
$redisPoolNew->add('10.0.1.12', 7012, 1);
$redisPoolNew->add('10.0.1.12', 7013, 1);
$redisPoolNew->add('10.0.1.12', 7014, 1);
$redisPoolNew->add('10.0.1.12', 7015, 1);

foreach($oldRedisServers as $redisServerData) {
    $oldRedis = new Redis();
    $oldRedis->connect($redisServerData['hostname'], $redisServerData['port']);
    $count = 0;
    // Get all keys
    $it = NULL;
    do {
        // Use scan to get the next batch of keys and update the iterator
        $arr_keys = $oldRedis->scan($it, '*', 1000);
        $batch = [];
        if ($arr_keys !== FALSE) {
            foreach ($arr_keys as $str_key) {
                //migrateKey($redisPoolOld, $redisPoolNew, $sessionPrefix, $str_key);
                $batch[getKeyDestinationRpm($redisPoolNew, $sessionPrefix, $str_key)] []= $str_key;
            }
        }
        processBatch($oldRedis, $batch);
        $count += 1000;
        echo("\n{$redisServerData['hostname']}:{$redisServerData['port']} - $count migrated\n"); //1000 records mark
    } while ($it > 0);
}

//test functions
//$key = 'PHPREDIS_SESSION:d09d7358fa84cf68455fee3564e126a5';
//$value = readKeyPool($redisPoolOld, $sessionPrefix, $key);
//saveKeyPool($redisPoolNew, $sessionPrefix, $key, $value);
//migrateKey($redisPoolOld, $redisPoolNew, $sessionPrefix, $key);
//var_dump(readKeyPool($redisPoolOld, $sessionPrefix, 'PHPREDIS_SESSION:d09d7358fa84cf68455fee3564e126a5'));
?>

字符串

相关问题