本文目录导读:

- 方案一:基于 Redis 存储 Session(推荐)
- 方案二:使用 Memcached(适合高并发读)
- 方案三:使用数据库存储 Session(适合小规模)
- 方案四:使用 Memcache(已过时,不推荐)
- 关键点与注意事项
- 扩展:结合 JWT 实现无状态认证(更彻底方案)
在ThinkPHP项目中实现分布式Session共享,是解决多台服务器负载均衡时用户登录状态不一致问题的关键,以下是几种主流的实现方案及具体代码示例:
基于 Redis 存储 Session(推荐)
这是最常用且性能最优的方案,利用 Redis 的高性能和持久化特性。
环境准备
确保服务器已安装 Redis 扩展(phpredis 或 predis)。
修改配置文件 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(已过时,不推荐)
关键点与注意事项
-
Cookie 域名一致性
确保所有服务器部署在同一域名下,session.cookie_domain设置为顶级域名,如.example.com。 -
负载均衡策略
即使使用共享存储,建议配置ip_hash或uri_hash负载均衡策略,减少跨服务器 Session 切换频率,提升性能。 -
Session 前缀隔离
多个应用共用同一个 Redis 时,使用不同的前缀进行隔离,如app1_和app2_。 -
过期时间设置
设置合理的expire时间,并确保 Redis 的maxmemory足够。 -
数据一致性
Session 中存放大对象或复杂数据结构,建议序列化存储,ThinkPHP 默认使用serialize。 -
故障转移
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。