本文目录导读:

- 基于Redis的Session共享(最常用)
- 使用Memcached
- 数据库存储(MySQL/PostgreSQL)
- 基于数据库的分布式Session中间件
- 使用框架自带的Session中间件(以Laravel为例)
- 实现JWT Token替代Session(无状态方案)
- 高可用Redis集群配置
- 最佳实践建议
对于PHP项目的分布式Session共享同步,主要有以下几种成熟的解决方案:
基于Redis的Session共享(最常用)
配置方式
// php.ini 配置
session.save_handler = redis
session.save_path = "tcp://127.0.0.1:6379?auth=password&database=0"
// 或者在代码中设置
ini_set('session.save_handler', 'redis');
ini_set('session.save_path', 'tcp://127.0.0.1:6379');
使用Predis或PhpRedis客户端
// 使用Predis
composer require predis/predis
// Session配置
$redis = new Predis\Client([
'scheme' => 'tcp',
'host' => '127.0.0.1',
'port' => 6379,
'password' => 'your_password'
]);
session_set_save_handler(
function() use ($redis) { return true; }, // open
function() use ($redis) { return true; }, // close
function($session_id) use ($redis) { // read
return $redis->get("session:$session_id") ?: '';
},
function($session_id, $data) use ($redis) { // write
$redis->setex("session:$session_id", 3600, $data);
return true;
},
function($session_id) use ($redis) { // destroy
$redis->del("session:$session_id");
return true;
},
function($maxlifetime) use ($redis) { // gc
return true;
}
);
使用Memcached
// php.ini配置
session.save_handler = memcached
session.save_path = "127.0.0.1:11211"
// 或者代码中配置
$memcached = new Memcached();
$memcached->addServer('127.0.0.1', 11211);
session_set_save_handler(new SessionHandlerInterface() {
// 实现相应方法
}, true);
数据库存储(MySQL/PostgreSQL)
CREATE TABLE sessions (
session_id VARCHAR(128) PRIMARY KEY,
data TEXT,
last_accessed TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
expire_at TIMESTAMP
);
CREATE INDEX idx_expire ON sessions(expire_at);
class DatabaseSessionHandler implements SessionHandlerInterface {
private $db;
public function open($savePath, $sessionName) {
$this->db = new PDO('mysql:host=localhost;dbname=test', 'user', 'pass');
return true;
}
public function read($sessionId) {
$stmt = $this->db->prepare("SELECT data FROM sessions WHERE session_id = ?");
$stmt->execute([$sessionId]);
return $stmt->fetchColumn() ?: '';
}
public function write($sessionId, $data) {
$stmt = $this->db->prepare(
"REPLACE INTO sessions (session_id, data, last_accessed, expire_at)
VALUES (?, ?, NOW(), DATE_ADD(NOW(), INTERVAL 1 HOUR))"
);
return $stmt->execute([$sessionId, $data]);
}
public function destroy($sessionId) {
$stmt = $this->db->prepare("DELETE FROM sessions WHERE session_id = ?");
return $stmt->execute([$sessionId]);
}
public function gc($maxlifetime) {
$stmt = $this->db->prepare("DELETE FROM sessions WHERE last_accessed < DATE_SUB(NOW(), INTERVAL ? SECOND)");
return $stmt->execute([$maxlifetime]);
}
}
基于数据库的分布式Session中间件
使用专门的Session管理中间件
// 使用Laravel框架的Redis驱动
// config/session.php
'driver' => 'redis',
'connection' => 'session',
'lifetime' => 120,
// config/database.php
'redis' => [
'client' => 'predis',
'options' => [
'cluster' => 'redis',
],
'clusters' => [
'session' => [
[
'host' => 'redis-node1',
'password' => 'pass',
'port' => 6379,
],
[
'host' => 'redis-node2',
'password' => 'pass',
'port' => 6379,
],
],
],
],
使用框架自带的Session中间件(以Laravel为例)
// Laravel 中的Session配置 SESSION_DRIVER=redis SESSION_CONNECTION=session // 或使用database驱动 SESSION_DRIVER=database SESSION_LIFETIME=120 // 创建sessions表 php artisan session:table php artisan migrate
实现JWT Token替代Session(无状态方案)
// 使用firebase/php-jwt
composer require firebase/php-jwt
class JwtAuth {
private $key = 'your-secret-key';
public function generateToken($userId) {
$payload = [
'iat' => time(),
'exp' => time() + 3600,
'user_id' => $userId,
'roles' => ['admin', 'editor']
];
return JWT::encode($payload, $this->key);
}
public function validateToken($token) {
try {
$decoded = JWT::decode($token, new Key($this->key, 'HS256'));
return (array) $decoded;
} catch (Exception $e) {
return null;
}
}
}
高可用Redis集群配置
// 使用Redis Sentinel
'session' => [
'sentinels' => [
'tcp://sentinel1:26379',
'tcp://sentinel2:26379',
'tcp://sentinel3:26379',
],
'options' => [
'replication' => 'sentinel',
'service' => 'mymaster',
'parameters' => [
'password' => 'redis_password',
],
],
],
// 或者使用Redis Cluster
'session' => [
'cluster' => 'redis',
'clusters' => [
'default' => [
[
'host' => 'redis-node1',
'port' => 6379,
],
// ...更多节点
],
],
],
最佳实践建议
选择合适的方案
- 中小规模:单机Redis足够
- 大规模高并发:Redis Cluster + Sentinel
- 无需高可用:Memcached适合纯缓存
- 业务复杂:JWT替代Session
Session数据优化
// 只存储必要的数据
$_SESSION = [
'user_id' => 123,
'username' => 'john',
'role' => 'admin'
]; // 避免存储大量数据
// 设置合理的过期时间
ini_set('session.gc_maxlifetime', 3600); // 1小时
ini_set('session.cookie_lifetime', 3600);
安全性考虑
// 使用HTTPS
ini_set('session.cookie_secure', 1);
// 设置HttpOnly
ini_set('session.cookie_httponly', 1);
// 使用SameSite
ini_set('session.cookie_samesite', 'Lax');
// 定期刷新Session ID
session_regenerate_id(true);
监控和故障转移
// Redis连接池配置
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$redis->setOption(Redis::OPT_SERIALIZER, Redis::SERIALIZER_PHP);
// 健康检查
try {
$redis->ping();
} catch (Exception $e) {
// 切换到备用Redis
$backupRedis = new Redis();
$backupRedis->connect('backup-redis', 6379);
}
选择方案时要根据项目的实际规模、团队技术栈和运维能力来决定,对于大多数项目,Redis + 自定义Session处理器是最平衡的选择。