在不注销用户的情况下将会话从 memcached 迁移到 redis laravel

Migrate session from memcached to redis without logging users out in laravel

我们目前正在使用 Memcached 来存储 Laravel 的基于 cookie 的会话,但希望在整个会话和缓存中使用 Redis 来保持一致性。

有没有办法在不注销用户的情况下将所有用户会话从 Memcached 迁移到 Redis?

下面是如何进行这种迁移的示例。试试看:

<?php

$host = '127.0.0.1';
$port = null;
$oldPrefix = 'sess_';
$newPrefix = 'sess_';
$sessionDir = '/var/lib/php/session/';
$m = new \Redis();
$m->connect($host, $port);
// $m = new \Memcached();
// $m->addServer($host, $port);
$sessions = scandir($sessionDir);
if (!$sessions) {
    die('nothing to migrate');
}
foreach ($sessions as $s) {
    if (in_array($s, ['.', '..'])) {
        continue;
    }
    $sessionName = str_replace($oldPrefix, '', $s);
    $sessionContents = file_get_contents($sessionDir.$s);
    if (!$m->set($newPrefix.$sessionName, $sessionContents)) {
        die(sprintf('Could not migrate session %s'.PHP_EOL, $newPrefix.$sessionName));
    }
    echo '.';
}
die(PHP_EOL);

但我猜 hat 用户将被注销。

我能够在不注销用户的情况下迁移会话。我为此创建了一个 artisan 命令:

<?php
namespace App\Console\Commands;
use \Memcached;
use \Redis;
use Illuminate\Console\Command;
class MigrateSessionToRedis extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'migrate:session';
    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Migrate sessions from Memcached to Redis';
    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct() #NOSONAR
    {
        parent::__construct();
    }
    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        $this->info('Starting session migration..');
        $memcached = new Memcached();
        $memcached->addServer(env('MEMCACHED_HOST'), 11211);
        $sessions = $this->getMemcachedKeys(env('MEMCACHED_HOST'));
        if (! is_array($sessions)) {
            $this->error('Could not retrieve sessions from Memcached');
            exit(1);
        }
        foreach ($sessions as $session) {
            $value = $memcached->get($session);
            if ($value) {
                $object = unserialize($value);
                $valueForRedis = serialize(serialize($object));
                // Set session in Redis with session expiry lifetime
                Redis::set("{$session}", $valueForRedis, 'EX', config('session.lifetime'));
            }
        }
        $this->info('Finished session migration.');
    }
    /**
    * Get all memcached keys. Special function because getAllKeys() is broken since memcached 1.4.23.
    * Should only be needed on php 5.6
    *
    * cleaned up version of code found on whosebug.com by Maduka Jayalath
    *
    * @return array|int - all retrieved keys (or negative number on error)
    */
    private function getMemcachedKeys($host = '127.0.0.1', $port = 11211) #NOSONAR
    {
        $mem = @fsockopen($host, $port);
        if ($mem === false) {
            return -1;
        }
        // retrieve distinct slab
        $r = @fwrite($mem, 'stats items' . chr(10));
        if ($r === false) {
            return -2;
        }
        $slab = [];
        while (($l = @fgets($mem, 1024)) !== false) {
            // finished?
            $l = trim($l);
            if ($l == 'END') {
                break;
            }
            $m = [];
            // <STAT items:22:evicted_nonzero 0>
            $r = preg_match('/^STAT\sitems\:(\d+)\:/', $l, $m);
            if ($r != 1) {
                return -3;
            }
            $a_slab = $m[1];
            if (!array_key_exists($a_slab, $slab)) {
                $slab[$a_slab] = [];
            }
        }
        reset($slab);
        foreach ($slab as $a_slab_key => &$a_slab) {
            $r = @fwrite($mem, 'stats cachedump ' . $a_slab_key . ' 100' . chr(10));
            if ($r === false) {
                return -4;
            }
            while (($l = @fgets($mem, 1024)) !== false) {
                // finished?
                $l = trim($l);
                if ($l == 'END') {
                    break;
                }
                $m = [];
                // ITEM 42 [118 b; 1354717302 s]
                $r = preg_match('/^ITEM\s([^\s]+)\s/', $l, $m);
                if ($r != 1) {
                    return -5;
                }
                $a_key = $m[1];
                $a_slab[] = $a_key;
            }
        }
        // close the connection
        @fclose($mem);
        unset($mem);
        $keys = [];
        reset($slab);
        foreach ($slab as &$a_slab) {
            reset($a_slab);
            foreach ($a_slab as &$a_key) {
                $keys[] = $a_key;
            }
        }
        unset($slab);
        return $keys;
    }
}

希望对大家有帮助。