Sessions共享技术设计

概述

分布式session是实现分布式部署的前提, 当前项目由于历史原因未实现分布式session, 但是由于在kubernets中部署多个pod时, 负载均衡的调用链太长, 导致会话不能保持, 所以迫切需要分布式session.

实现方案

a. 修改配置文件php.ini

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


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共享。

/**
 * @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的描述, 下面介绍下迅速过一下涉及到的几个方法:

方法 说明
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 类操作.

例如:

$_SESSION[‘aa‘] = 123; 改为 RedisSession::set(‘aa‘, 123);
echo $_SESSION[‘aa‘]; 改为 echo RedisSession::get(‘aa‘);

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中如何实现的,还要知道它的内部存储机制是如何工作的,如何去处理并发,如何去避免死锁(不能去掉锁),以及如何处理潜在的安全问题

原文地址:https://segmentfault.com/a/1190000016054843

原文地址:https://www.cnblogs.com/lalalagq/p/9974966.html

时间: 2024-11-09 00:57:16

Sessions共享技术设计的相关文章

tomcat+memcached实现sessions共享

以前公司就用到这个.也简单写过一个文档.后来发现写的不够详细以至于别人看到我的文档.总是不知所措.这次利用空闲时间写一份详细的.共享给各位刚接触这个技术的小伙伴!!! 实验环境:虚拟机centOS6.6_x89_64  Minal模式 软件版本:apache-tomcat-7.0.64.tar.gz jdk-7u45-linux-x64.tar.gz libevent-2.0.21-stable.tar.gz memcached-1.4.21.tar.gz 以及和tomcat版本相对经的jar包

生产要不要开启MySQL查询缓存

一.前言在当今的各种系统中,缓存是对系统性能优化的重要手段.MySQL Query Cache(MySQL查询缓存)在MySQL Server中是默认打开的,但是网上各种资料以及有经验的DBA都建议生产环境中把MySQL Query Cache关闭.按道理,MySQL Server默认打开,是鼓励用户使用缓存,但是大拿们却建议关闭此功能,并且国内各个云厂商提供的MySQL云服务中默认都是关闭这个功能,这是为什么?他们在使用中遇到了什么坑?本文将会从以下几方面来详解MySQL Query Cach

ANSI_common-lisp

前言 本书的目的是快速及全面的教你 Common Lisp 的有关知识.它实际上包含两本书.前半部分用大量的例子来解释 Common Lisp 里面重要的概念.后半部分是一个最新 Common Lisp 辞典,涵盖了所有 ANSI Common Lisp 的操作符. 这本书面向的读者 ANSI Common Lisp 这本书适合学生或者是专业的程序员去读.本书假设读者阅读前没有 Lisp 的相关知识.有别的程序语言的编程经验也许对读本书有帮助,但也不是必须的.本书从解释 Lisp 中最基本的概念

Terracotta+Tomcat+nginx实现session的共享

环境准备:(Nginx,tomcat的安装部署本例不赘述.) 192.168.1.13     nginx 192.168.1.225    tomcat7,terracotta 192.168.1.226    tomcat7 部署terracotta+tomcat集群: 一:安装java程序至系统,配置java环境. # vi /etc/profile export JAVA_HOME=/usr/local/java export PATH=/usr/local/java/bin:$PATH

spring boot + redis 实现session共享

这次带来的是spring boot + redis 实现session共享的教程. 在spring boot的文档中,告诉我们添加@EnableRedisHttpSession来开启spring session支持,配置如下: @Configuration @EnableRedisHttpSession public class RedisSessionConfig { } 而@EnableRedisHttpSession这个注解是由spring-session-data-redis提供的,所以

Tomcat集群环境下session共享方案梳理(1)-通过memcached(MSM)方法实现

对于web应用集群的技术实现而言,最大的难点就是:如何能在集群中的多个节点之间保持数据的一致性,会话(Session)信息是这些数据中最重要的一块.要实现这一点, 大体上有两种方式: 一种是把所有Session数据放到一台服务器上或者数据库中,集群中的所有节点通过访问这台Session服务器来获取数据: 另一种就是在集群中的所有节点间进行Session数据的同步拷贝,任何一个节点均保存了所有的Session数据. Tomcat集群session同步方案有以下几种方式: 1)使用tomcat自带的

使用ASP.NET State Server实现多应用程序间共享Session State

原以为ASP.NET State Server原生支持多程序间共享SESSION,以为在同一服务器上 & 同一根域名下部署的多个应用程序间设置了相同了<sessionState/>和<machineKey/>事情就成了! 事实证明是自己TOO YOUNG TOO SIMPLE.根本不WORK! BING了一大轮,再找了一下度娘,看到以下较有参考价值的文章: http://forums.asp.net/t/1759392.aspx?Share+sessions+between

WebLogic 通过数据库的方式实现Session共享的配置

     1. 配置准备 1) 要配置JDBC的方式复制Session,主要为下面三个步骤 (1)在数据库中创建表 (2)创建对数据库具有读/写权限的连接池 (3)在weblogic.xml部署描述符中配置会话持久性 2) 配置会话的持久性的示例如下: <session-descriptor>         <persistent-store-type>jdbc</persistent-store-type>         <persistent-store-

tomcat实现session集群及tomcat+memcached共享session存储(四)

接博客nginx或httpd实现负载均衡tomcat(三) tomcat实现会话管理原理及实现: tomcat管理会话使用的专用的会话管理组件,tomcat的会话管理器有4种: 1.标准会话管理器(StanderdManager) 2.持久会话管理器(PersistentManager可以基于文件存储(FileStore)或JDBC存储(JDBCStore)) 基于JDBC的话就可以实现高可用tomcat的session集群. 1.DeltaManager会话管理器 2.BackupManage