Sessions共享技术设计

概述

分布式session是实现分布式部署的前提, 当前项目因为历史缘由未实现分布式session, 可是因为在kubernets中部署多个pod时, 负载均衡的调用链太长, 致使会话不能保持, 因此迫切须要分布式session.php

实现方案

a. 修改配置文件php.ini

直接在PHP中配置, 或者在代码中集成git

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

b. 代码中动态设置

ini_set("session.save_handler", "redis");
ini_set("session.save_path", "tcp://127.0.0.1:6379");

c. 实现SessionHandlerInterface接口

php提供了SessionHandlerInterface接口, 按照此接口进行implements, 便可完成session共享。github

/**
 * @see http://php.net/manual/zh/class.sessionhandlerinterface.php
 */
SessionHandlerInterface {
    abstract public bool close ( void )
    abstract public bool destroy ( string $session_id )
    abstract public int gc ( int $maxlifetime )
    abstract public bool open ( string $save_path , string $session_name )
    abstract public string read ( string $session_id )
    abstract public bool write ( string $session_id , string $session_data )
}

/**
 * @see http://php.net/manual/zh/class.sessionhandler.php
 */
MySessionHandler implements SessionHandlerInterface , SessionIdInterface {
    public bool close ( void )
    public string create_sid ( void )
    public bool destroy ( string $session_id )
    public int gc ( int $maxlifetime )
    public bool open ( string $save_path , string $session_name )
    public string read ( string $session_id )
    public bool write ( string $session_id , string $session_data )
}

如上是PHP文档中对此interface的描述, 下面介绍下迅速过一下涉及到的几个方法:redis

方法 说明
open 方法用于基于文件的session存储系统, 该方法中可不放置任何代码,能够将其置为空方法。
close 和open 方法同样,也能够被忽略,对大多数驱动而言都用不到该方法。
read 应该返回与给定$sessionId, 相匹配的session数据的字符串版本。
write 应该讲给定$data 写到持久化存储系统相应的$sessionId destroy 从持久化存储中移除 $sessionId 对应的数据。
gc 方法销毁大于给定 $lifetime 的全部session数据,对自己拥有过时机制的系统如 MemcachedRedis 而言,该方法能够留空。

实现完成后使用session_set_save_handler完成session驱动的注册数据库

$handler = new MySessionHandler();
session_set_save_handler($handler, true);
// 下面这行代码能够防止使用对象做为会话保存管理器时可能引起的非预期行为
register_shutdown_function('session_write_close');

session_start();
// 如今可使用 $_SESSION 保存以及获取数据了
Warning: 在脚本执行完毕以后, PHP内部会清除对象, 因此有可能不调用 writeclose回调函数, 这样可能会引起非预期的行为, 因此当使用对象做为会话保存管理器时, 须要经过注册 shutdown回调函数来规避风险。一般,你能够经过调用 register_shutdown_function()函数来注册 session_write_close()回调函数

d. 自定义session驱动

可经过memcachedredisdb等实现分布式session,考虑先实现redis session驱动浏览器

<?php

//自定义interface
interface SessionInterface {
    public function set($key, $value, $expire);
    public function get($key);
    public function del($key);
    public function has($key);
    public function all();
} 

class RedisSession implements SessionInterface {

}

咱们知道通常状况下cookie中存储着session id, 因此实现自定义session, 须要一些配置, 配置以下:缓存

参数 默认值 选项 描述
sess.driver files files/database/redis/memcached/custom 使用的存储 session 的驱动
sess.cookie_name my_session [A-Za-z_-] characters only session cookie 的名称
sess.expiration 7200 (2 hours) Time in seconds (integer) 你但愿 session 持续的秒数 若是你但愿 session 不过时(直到浏览器关闭),将其设置为 0
sess.save_path NULL None 指定存储位置,取决于使用的存储 session 的驱动
sess.time_to_update 300 Time in seconds (integer) 该选项用于控制过多久将从新生成一个新 session ID 设置为 0 将禁用 session ID 的从新生成
sess.regenerate_destroy FALSE TRUE/FALSE (boolean) 当自动从新生成 session ID 时,是否销毁老的 session ID 对应的数据 若是设置为 FALSE ,数据以后将自动被垃圾回收器删除

使用时, $_SESSION 的操做改成 RedisSession 类操做.安全

例如:cookie

$_SESSION['aa'] = 123; 改成 RedisSession::set('aa', 123);
echo $_SESSION['aa']; 改成 echo RedisSession::get('aa');session

redis驱动实现

Warning: 因为Redis没有锁机制, 这个驱动的锁是经过一个保持300s的值来模拟的。

Redis 是一种存储引擎,一般用于缓存,并因为他的高性能而流行起来,这可能也正是你使用 Redis 驱动的缘由。

缺点是它并不像关系型数据库那样广泛,须要你的系统中安装了 phpredis 这个 PHP 扩展,它并非 PHP 程序自带的。 可能的状况是,你使用 Redis 驱动的缘由是你已经很是熟悉 Redis 了而且你使用它还有其余的目的。

固然不想安装phpredis客户端时, 能承受必定的性能损失, 可以使用predis包

https://github.com/nrk/predis

和文件驱动和数据库驱动同样,你必须经过 sess.save_path 参数来配置存储 session 的位置。 这里的格式有些不一样,同时也要复杂一点,这在 phpredis 扩展的 README 文件中有很好的解释,连接以下:
https://github.com/phpredis/p...

Warning: 这里的 Session 类并无真的用到 'redis' 的 session.save_handler , 只是 采用了它的路径的格式而已。

注意事项

a. 浏览器A标签脚本执行过程当中,打开B标签访问同一个脚本,会被pending,直到A执行完毕。

缘由该脚本执行了session_start(),而php session_start()后对该session的写入是排他的,只有当脚本执行结束或显式执行session_destroy()才能释放session文件锁。

b. 自定义session驱动并非那么简单, 须要用到不少知识来正确的实现它。

你不只要知道session通常的工做原理,并且要知道它在PHP中如何实现的,还要知道它的内部存储机制是如何工做的,如何去处理并发,如何去避免死锁(不能去掉锁),以及如何处理潜在的安全问题

相关文章
相关标签/搜索