4

我们正在考虑将我们的 php 会话数据移动到 redis。

设置看起来很简单。只需在 php.ini 中设置以下内容并重新启动 apache。应该都设置好了:

session.save_handler = redis
session.save_path = "tcp://host1:6379"

如果可能的话,我希望我们的用户不要注意到迁移。是否可以在不丢失任何现有会话数据的情况下将会话数据移动到 redis?

4

5 回答 5

7

目前没有针对您所要求的开箱即用的解决方案,但为此任务编写自定义脚本实际上相当简单。

本质上,phpredis 将会话数据以字符串形式存储在 redis 中,键名格式如下:PHPREDIS_SESSION:$sessionid,其中$sessionid是会话的 php id,可通过 检索session_id()。会话数据被“编码”为 php-session 序列化变量(与常见的 php 序列化/反序列化格式略有不同,请参阅session_encode)。

既然我们知道了这一点,那么迁移存储在文件中的会话数据有两种可能性:

  • 遍历每个会话文件(实际路径session.save_path在您的 php.ini 中设置),读取数据并将其写回 redis。文件本身存储会话数据的 php-session 序列化表示,这意味着内容可以直接复制到 redis,并且文件名具有以下模式:sess_$sessionid$sessionid 是,你猜对了,id 你'将要用于您的 redis 密钥。

  • 通过暂时保留基于文件的会话来逐步迁移数据,但在使用会话数据时实时填充 redis,直到存储在 redis 中的会话数量看起来足以进行切换。这可以通过执行以下操作来实现:

    $redis->set("PHPREDIS_SESSION:".session_id(), session_encode());

    就在每个脚本结束之前。此方法可能会增加一点开销,具体取决于会话中的数据量以及 session_encode 的工作方式。

于 2012-10-03T15:01:15.163 回答
3

刚刚在 bash 中创建了这样一个脚本并添加到我的仓库中。

https://github.com/renasboy/php-redis-migrate-sessions

于 2013-02-15T10:52:57.350 回答
2

可能,是的,容易,不是那么多。

AFAIK,phpredis 没有迁移脚本,因此您必须自己编写一个。您可能想查看Cm_RedisSession 的脚本,该脚本对该 redis 模块执行类似操作。

于 2012-09-29T12:50:52.047 回答
2

如果你使用 symfony,你可以使用如下命令:

yml 配置:

parameters:
    redis_address: "localhost"
    project_name : "ACME_"

snc_redis:
    clients:
        default:
            type: predis
            alias: default
            dsn: redis://%redis_address%
            logging: '%kernel.debug%'
        session:
            type: predis
            alias: session
            dsn: redis://%redis_address%/1
            logging: true
    session:
        client: session
        prefix: '%project_name%PHPREDIS_SESSION'
        ttl: 7776000 # 90 days

symfony 命令:

<?php

// Command:  app/console acme:migrate:session:files:to:redis --env=dev
namespace Acme\AppBundle\Command;

use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
use Symfony\Component\Finder\Finder;

class MigrateSessionFilesToRedisCommand extends ContainerAwareCommand {

protected $env;

protected function configure() {
    $this->setName('acme:migrate:session:files:to:redis')
        ->setDescription("Migrate Session Files To Redis")
        ->setHelp("Migrate Session Files To Redis");
}


protected function execute(InputInterface $input, OutputInterface $output) {

    $sessionPath = realpath( sprintf('%s%s', $this->getContainer()->getParameter('kernel.root_dir'), '/sessions') );
    $prefix      = 'ACME_PHPREDIS_SESSION';

    $redis = $this->getContainer()->get('snc_redis.session');

    $finder = new Finder();
    $finder->files()->in($sessionPath);

    foreach ($finder as $file) {

        $realPath = $file->getRealpath();

        $sessionId = str_replace( 'sess_', '', $file->getRelativePathname() );
        $redis->append( sprintf('%s:%s', $prefix, $sessionId) , file_get_contents( $realPath ) );
    }

}

}

注意:将“ACME”替换为您的项目 ID/名称,并设置存储文件的正确会话路径。

于 2016-06-17T11:40:23.927 回答
1

这是我将会话数据导入 redis 的超级简单脚本:

#!/bin/bash


export REDISCLI_AUTH=my-supper-strong-password-4-redis-server
TTL=$(( 24 * 3600 ))

for i in sess_*; do
    ex=$(( $(date +%s) - $(stat -c %Y "$i") + $TTL ))
    k="PHPREDIS_SESSION:${i:5}"
    v=$(cat "$i")

    echo "SET $k of len:${#v} EX $ex"
    redis-cli SET "$k" "$v" EX $ex
done

我没有彻底测试它,所以请谨慎使用。

于 2019-07-04T10:23:20.457 回答