场景

web服务器有多台,每台服务器都会存贮自己的session,session无法在多台服务器共享。所以就需要更换session的存贮空间,存贮在一个共用的空间。通常为了读写速度,我们会选择存贮在内存服务上,如redis、mysql的memory存贮引擎等,本文以reddis存贮贯串上下文。

session共享

nginx ip_hash 或者 url_hash

ip_hash

...
upstream backserver {
ip_hash;
server 192.168.0.14:88;
server 192.168.0.15:80;
}
...

采用ip_hash指令解决这个问题,如果客户已经访问了某个服务器,当用户再次访问时,会将该请求通过哈希算法,自动定位到该服务器。

每个请求按访问ip的hash结果分配,这样每个访客固定访问一个后端服务器,解决session的问题。

url_hash

按访问url的hash结果来分配请求,使每个url定向到同一个(对应的)后端服务器,后端服务器为缓存时比较有效。

...
upstream backserver {
server squid1:3128;
server squid2:3128;
hash $request_uri;
hash_method crc32;
}
...

php.ini修改配置

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

修改完之后,重启 php-fpm。

通过 ini_set() 函数设置

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

session_set_save_handler()函数设置

主流框架都选择用此类方法覆盖session的open、close、read、write、gc机制,容易扩展。我写了个redis的session存贮类,仅供参考:

<?php
//namespace openyii\framework; class CSessionRedis //extends CSession
{
protected $redisInstance; //redis操作实例
public $keyPrefix; //键前缀
public $lifeTime; //生命周期 public function __construct( $keyPrefix,$lifeTime=3600 )
{
$this->lifeTime = $lifeTime;
$this->keyPrefix = $keyPrefix;
session_set_save_handler(
array($this, 'open'),
array($this, 'close'),
array($this, 'read'),
array($this, 'write'),
array($this, 'destroy'),
array($this, 'gc')
);
if ($this->keyPrefix === null) {
$this->keyPrefix = substr(md5(base::$app->id), 0, 5);
}
session_start(); //以全局变量形式保存在一个session中并且会生成一个唯一的session_id,
} function open($savePath, $sessionName)
{
//todo $redis redis的操作实例要自己写下 $this->redisInstance = $redis;
// $this->redisInstance = base::$app->redis;
return true;
} function close()
{
return true;
} function read($id)
{
if( !$this->redisInstance->exists($this->calculateKey($id)) ){
$this->redisInstance->set( $this->calculateKey($id),'' );
}
return $this->redisInstance->get( $this->calculateKey($id) );
} function write($id, $value)
{
return $this->redisInstance->set($this->calculateKey($id), $value, $this->lifeTime)?true:false;
} function destroy($id)
{
$this->redisInstance->delete($this->calculateKey($id));
if( !$this->redisInstance->exists($this->calculateKey($id)) ){
return false;
}
return true;
} function gc($lifetime)
{
//不做实现,redis本身有回收机制 return true;
} /**
* 加密key
* @param $id
* @return string
*/
protected function calculateKey($id)
{
return $this->keyPrefix . md5(json_encode([__CLASS__, $id]));
} }

具体细节可以看我写的php框架代码,如果想自己实现,上面的代码改改就可以实现的。

思考

如果使用mysql如何存贮?

mysql使用memory存贮引擎,设计数据表(sessionid、sessionValue 、过期时间),重写session_set_save_handler方法。

如果redis是哨兵 master-slave模式,session如何共享?

没想清楚,咨询了老大,做法比较坑,php.ini修改配置指定redis master ip,有个守护进程的脚本检测哨兵,发生故障哨兵切换,检测到发邮件通知‘人’去手动修改php.ini master的ip,感觉匪夷所思啊!

我的思路是:哨兵模式会有三个redis服务ip端口,客户端连接获取每个redis服务的info信息,如果info里包含master role,则将此master redis服务操作实例交给上面的代码,实现写操作。

后面自己动手实现了吧,可行的,代码地址贴下,结合代码及说明看看,希望能帮助大家理解:

哨兵主从模式(redis服务ip可直接访问)

哨兵主从模式(redis服务ip不可直接访问,ip映射访问)

session更换存储,实现在多台服务器共享的更多相关文章

  1. 多台服务器共享session问题

    在现在的大型网站中,如何实现多台服务器中的session数据共享呢 当使用多台服务器架设成集群之后,我们通过负载均衡的方式,同一个用户(或者ip)访问时被分配到不同的服务器上,假设在A服务器登录,如果 ...

  2. 多台服务器共享session问题(2)

    多台服务器共享session问题  转载自:https://www.cnblogs.com/lingshao/p/5580287.html 在现在的大型网站中,如何实现多台服务器中的session数据 ...

  3. 多台web如何共享session进行存储(转载)

    session的存储了解以前是怎么做的,搞清楚了来龙去脉,才会明白进行共享背后的思想和出发点.我喜欢按照这样的方式来问(或者去搞清楚):为什么要session要进行共享,不共享会什么问题呢? php中 ...

  4. php多台服务器实现session共享

    使用Redis存储Session(前提是服务期间已实现redis共享,可参照:laravel项目使用twemproxy部署redis集群) 修改php.ini: session.save_handle ...

  5. session多服务器共享的方案

    session的存储了解以前是怎么做的,搞清楚了来龙去脉,才会明白进行共享背后的思想和出发点.我喜欢按照这样的方式来问(或者去搞清楚):为什么要session要进行共享,不共享会什么问题呢? php中 ...

  6. session多服务器共享的方案梳理

    session的存储了解以前是怎么做的,搞清楚了来龙去脉,才会明白进行共享背后的思想和出发点.我喜欢按照这样的方式来问(或者去搞清楚):为什么要session要进行共享,不共享会什么问题呢? php中 ...

  7. 集群环境(session多服务器共享的方案梳理)

    目前业界解决session共享的几种思路,我总结如下: 第一种办法:把原来存储在服务器磁盘上的session数据存储到客户端的cookie中去. 这样子,就不需要涉及到数据共享了.a客户端请求的时候, ...

  8. [转载]session多服务器共享的方案梳理

    转载网址: http://www.cnblogs.com/wangtao_20/archive/2013/10/29/3395518.html session的存储了解以前是怎么做的,搞清楚了来龙去脉 ...

  9. PHP多台服务器跨域SESSION共享

    网站业务规模和访问量的逐步发展,原本由单台服务器.单个域名的迷你网站架构已经无法满足发展需要. 此时我们可能会购买更多服务器,并且启用多个二级子域名以频道化的方式,根据业务功能将网站分布部署在独立的服 ...

随机推荐

  1. SharePoint 2013创建应用程序时IIS端口文件夹下没文件

    最近SharePoint 2007迁移到2013的时候,碰到创建应用程序时IIS端口文件夹下没文件的问题,网上找了大把的原因,终于在这里找到了解决方案: Fix: 1. Open IIS on the ...

  2. 初试spring boot

    最近发现大家都开始使用spring boot了,据说能极大简化spring相关配置,提升开发速度,于是也就决定小小研究一下,在后面的开发中使用一下看看.在这里记录一下学习过程,由于其使用已经相当成熟, ...

  3. [原] Bash Script 显示其自身位置

    SOURCE="${BASH_SOURCE[0]}" BIN_DIR="$( dirname "$SOURCE" )" while [ -h ...

  4. java 生成Excel开门篇

    本随笔的Excel所用的poi jar包(3.17版本)链接: https://pan.baidu.com/s/1gaa3dJueja8IraUDYCSLIQ 提取密码: 9xr7 简单实现:两个类: ...

  5. Java中获取32位UUID

    public class createUUID { public static void main(String[] args) { String uuid = UUID.randomUUID().t ...

  6. importnew:Map大家族的那点事儿

    Map大家族的那点事儿(1) :Map Map大家族的那点事儿(2) :AbstractMap Map大家族的那点事儿(3) :TreeMap Map大家族的那点事儿(4) :HashMap Map ...

  7. K:图的存储结构

      常用的图的存储结构主要有两种,一种是采用数组链表(邻接表)的方式,一种是采用邻接矩阵的方式.当然,图也可以采用十字链表或者边集数组的方式来进行表示,但由于不常用,为此,本博文不对其进行介绍. 邻接 ...

  8. SQL0286N 找不到页大小至少为 "8192"、许可使用授权标识 "db2inst" 的缺省表空间。

    在 SQL 处理期间,它返回: SQL0286N  找不到页大小至少为 "8192".许可使用授权标识 "db2inst" 的缺省表空间. 顾名思义,DB2默认 ...

  9. PHP中的prepare准备语句的意义

    mysqli和PDO扩展都有prepare这个语法,刚开始以为只是单纯的语法,没想到,还是有实际意义的: “每次发送查询语句给MySQL服务时,都必须解析该查询的语法,确保结构正确并能够执行.这是这个 ...

  10. 使用iview-admin2构建的项目,热更新无法启动

    原因:@vue/cli-service版本是3.0.1解决:升级@vue/cli-service到最新版本