ThinkPHP项目分布式Session共享

wen PHP项目 3

本文目录导读:

ThinkPHP项目分布式Session共享

  1. 方案一:基于 Redis 存储 Session(推荐)
  2. 方案二:使用 Memcached(适合高并发读)
  3. 方案三:使用数据库存储 Session(适合小规模)
  4. 方案四:使用 Memcache(已过时,不推荐)
  5. 关键点与注意事项
  6. 扩展:结合 JWT 实现无状态认证(更彻底方案)

在ThinkPHP项目中实现分布式Session共享,是解决多台服务器负载均衡时用户登录状态不一致问题的关键,以下是几种主流的实现方案及具体代码示例:


基于 Redis 存储 Session(推荐)

这是最常用且性能最优的方案,利用 Redis 的高性能和持久化特性。

环境准备

确保服务器已安装 Redis 扩展(phpredispredis)。

修改配置文件 config/session.php

<?php
// config/session.php
return [
    // 其他配置...
    'type'           => 'redis', // 使用 Redis 驱动
    'prefix'         => 'think_', // Session 前缀
    'auto_start'     => true,    // 自动开启
    'expire'         => 3600,    // 过期时间(秒)
    // Redis 连接配置
    'host'           => '127.0.0.1', // Redis 服务器地址
    'port'           => 6379,        // Redis 端口
    'password'       => '',          // Redis 密码(可空)
    'select'         => 0,           // 选择的数据库
    'timeout'        => 5,           // 连接超时时间
    'persistent'     => false,       // 是否长连接
    'session_name'   => 'PHPSESSID', // Session Cookie 名称
];

config/database.php 中配置(如果需要)

如果你使用 think\cache\driver\Redis,确保缓存配置正确:

// config/cache.php
'stores' => [
    // 其他缓存...
    'redis' => [
        'type'   => 'redis',
        'host'   => '127.0.0.1',
        'port'   => 6379,
        'password' => '',
        'select' => 0,
        'timeout' => 5,
        'persistent' => false,
    ],
],

测试是否生效

写一个测试控制器,写入和读取 Session:

// application/index/controller/Test.php
namespace app\index\controller;
use think\Controller;
class Test extends Controller
{
    public function setSession()
    {
        session('user_id', 123);
        session('username', 'admin');
        return 'Session 已写入!';
    }
    public function getSession()
    {
        $user_id = session('user_id');
        $username = session('username');
        return "用户ID:{$user_id},用户名:{$username}";
    }
}

访问不同服务器(通过负载均衡分发),测试 Session 是否一致。


使用 Memcached(适合高并发读)

Memcached 适合读多写少的场景,配置方式类似。

修改 config/session.php

'type' => 'memcached',
'host' => '127.0.0.1',
'port' => 11211,
'expire' => 3600,

使用数据库存储 Session(适合小规模)

适用于没有 Redis 但有多台服务器的情况,但性能较差(数据库压力大)。

创建 Session 表

CREATE TABLE `think_session` (
  `session_id` varchar(255) NOT NULL,
  `session_data` text NOT NULL,
  `session_expire` int(11) NOT NULL,
  PRIMARY KEY (`session_id`),
  KEY `session_expire` (`session_expire`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

修改配置

'type' => 'database',
'table' => 'think_session',
'database' => 'db_config', // 数据库连接配置(通常默认)

使用 Memcache(已过时,不推荐)


关键点与注意事项

  1. Cookie 域名一致性
    确保所有服务器部署在同一域名下,session.cookie_domain 设置为顶级域名,如 .example.com

  2. 负载均衡策略
    即使使用共享存储,建议配置 ip_hashuri_hash 负载均衡策略,减少跨服务器 Session 切换频率,提升性能。

  3. Session 前缀隔离
    多个应用共用同一个 Redis 时,使用不同的前缀进行隔离,如 app1_app2_

  4. 过期时间设置
    设置合理的 expire 时间,并确保 Redis 的 maxmemory 足够。

  5. 数据一致性
    Session 中存放大对象或复杂数据结构,建议序列化存储,ThinkPHP 默认使用 serialize

  6. 故障转移
    Redis 是单点,建议使用 Redis 集群或哨兵模式,避免单点故障导致所有 Session 丢失。


扩展:结合 JWT 实现无状态认证(更彻底方案)

对于高并发、微服务架构,可以完全抛弃 Session,改用 JWT(JSON Web Token)实现无状态认证:

// 使用 Firebase/JWT 库
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
// 生成 Token
$payload = [
    'user_id' => 123,
    'username' => 'admin',
    'exp' => time() + 3600 * 2
];
$token = JWT::encode($payload, env('jwt_secret'), 'HS256');
// 验证 Token
try {
    $decoded = JWT::decode($token, new Key(env('jwt_secret'), 'HS256'));
    $user_id = $decoded->user_id;
} catch (\Exception $e) {
    // Token 无效
}

JWT 方案优势:

  • 无需共享存储,天然分布式友好
  • 减轻服务器内存压力
  • 适合移动端、API 场景

方案 适用场景 优点 缺点
Redis 大多数场景 高性能、持久化、支持复杂结构 需要维护 Redis 服务
Memcached 读多写少 内存速度快 重启丢失、数据可能丢失
Database 小规模 部署简单 数据库压力大、性能差
JWT 微服务、API 无状态、高度可扩展 无法服务端主动失效

推荐方案:使用 Redis 作为 Session 共享存储,这是 PHP 项目最成熟、最常用的方案,如果预算有限且规模不大,可以使用数据库方案,对于追求现代架构的项目,建议直接使用 JWT。

抱歉,评论功能暂时关闭!