1. 为什么要使用Session共享?
1、负载均衡:通过前面的负载均衡,可以知道我们做负载,是将用户的请求分发到不同的服务器上。而我们存session默认会存到本地,那我们在其他服务器上是读取不到session的,这样造成的结果就是,你已经在A服务器上登录了,当你再下一步操作时,将你的请求发送给了B服务器,那你仍然处在未登录状态。。
2、单点登录:因为同一台电脑上,每个浏览器请求服务器生成的sessionid不同,这样你在A浏览器登录了,到B的时候还是需要登录,但是这样会很麻烦,换个浏览器就要重新登录。如果要实现两个浏览器同时处在登录状态,那就需要session共享
2. 了解session工作原理
在解决问题之前,先来了解一下 PHP SESSION 的工作原理。在客户端(如浏览器)登录网站时,被访问的 PHP 页面可以使用 session_start() 打开 SESSION,这样就会产生客户端的唯一标识 SESSION ID(此 ID 可通过函数 session_id() 获取/设置)。SESSION ID 可以通过两种方式保留在客户端,使得请求不同的页面时,PHP 程序可以获知客户端的 SESSION ID;一种是将 SESSION ID 自动加入到 GET 的 URL 中 ,或者 POST 的表单中,默认情况下,变量名为 PHPSESSID;另一种是通过 COOKIE,将 SESSION ID 保存在 COOKIE 中,默认情况下,这个 COOKIE 的名字为 PHPSESSID。这里我们主要以 COOKIE 方式进行说明,因为应用比较广泛。
服务端通过客户端传递的session_id区分用户,用来标记用户的登录状态。
用户再次发送请求的时候,把服务端返回的session_id通过cookie[或者URL传参]的形式传递到服务端,这样服务端就可以区分出来具体操作的用户。
3. 如何解决负载均衡之后的session共享问题?
1. 不使用session,换作cookie
把session改成cookie,就能避开session的一些弊端。【安全性较低】
浏览器对session存在大小不同,Safari 4097字节 (苹果浏览器)包括名,值和等号
Firefox 4097
O允许cookies最大长度 4096字节
IE允许cookies最大长度 4095字节
谷歌允许cookies最大长度
2. 数据库记录session信息
使用数据库记录session信息,session的使用频率比较高,如果存在数据库中,频繁的读取会对数据库产生较大的压力,网站性能瓶颈一般都存在数据库,
3. 负载均衡的时候使用ip_hash算法进行分发
使用ip_hash可能会导致某一台服务器负载较大。如果某段时间内服务器进入了很多固定IP代理的请求[翻墙,代理] ,如果代理IP的负载过高就会导致ip_hash对应的服务器负载压力过大,这样ip_hash就失去了负载均衡的作用了。
4. 对session文件进行同步。
使用同步工具对session文件进行同步,保证负载服务器的session文件都是一致的,这种做法虽然可以解决session共享的问题,同样的内容会存在多个服务器上,而且部分服务器存在的session文件可能从开始到结束完全没有使用到,浪费了服务器的资源。 【rsync,inotify-tools等】
5. 使用memcache或者redis保存session信息 [建议]
相比文件取信息,从内存取数据速度要快很多,而且在多个服务器需要共用 session 时会比较方便,将这些服务器都配置成使用同一组 memcached 服务器就可以,减少了额外的工作量。其缺点是 session 数据都保存在 memory 中,一旦宕机,数据将会丢失。但对 session 数据来说并不是严重的问题。
实现:
1. session存cookies(setcookie(1,2,3,4,5,6))
利用cookies跨域,跨域是cookies中比较热门的问题。如果是同一个主域比较简单,可以通过setsession中的domain参数,设置一个主域,一下的子级域名都可以用
2. session入库
原理:我们要实现在一台服务器1存session在另一台服务器2也可以得到session值,因为服务器2没有session存储的文件,所以可以将它入库。服务器1将数据存到数据库,服务器也连接同一个数据库,这样服务器2就可以取到它的值。
步骤:首先要改变session的存储方式,可以在php.ini中将session.save_handler = user,也可以用ini_set('session.save_handler','user')来修改。Session入库需要一个函数session_set_save_handler('open', 'close', 'read', 'write', 'destroy', 'gc');
其中open方法是会用到,read方法读取是用一些其他方法,也和它的名字对应,方法名可以随意。注意在每一个需要session的页面都要加载session_set_save_handler('open', 'close', 'read', 'write', 'destroy', 'gc');这个函数,所以将它写在单独的文件里,直接incude()包含它
3. session存入redis或memcache
session存入redis,同样的需要修改存储机制,也是两种方法第一个该配置文件,第二个则是利用函数
ini_set('session.save_handler','redis');
设置存储方式为redis
ini_set('session.save_path','tcp://192.168.1.19:6379');
存储路径为redis服务器的ip,后面是端口号
取值的时候也是一样的设置
Memcache同理
4、session文件进行同步
使用文件同步rsync