session多服务器共享的⽅案
session的存储了解以前是怎么做的,搞清楚了来龙去脉,才会明⽩进⾏共享背后的思想和出发点。我喜欢按照这样的⽅式来问(或者去搞清楚):为什么要session要进⾏共享,不共享会什么问题呢?
php中session的原理,以前做了⼀下总结,可以参考:
以前业界使⽤session的做法:
默认情况下,php的session⽂件是保存在磁盘⽂件中。在php.ini配置⽂件中的配置项如下:
session.save_handler = files
session.save_path = "N;/path"
第⼀个配置项是指定使⽤files(⽂件形式)存储session数据。
第⼆个参数指定保存的路径。N表⽰⽣成多少级⽬录(不放到⼀个⽬录下,分散到多个磁盘⽬录中去)
我的配置项是:session.save_path = "F:/wamp/tmp"。那么就会去这个⽬录下⾯看到很多session数据的⽂件。
当我们使⽤php的内置函数session_start()的时候,就是去上⾯指定的磁盘⽬录把session数据载⼊,实际上就是拿类似
sess_74dd7807n2mfml49a1i12hkc45的⽂件。
74dd7807n2mfml49a1i12hkc45就是⼤家经常说的什么session的id号。
php.ini中还有⼀个关键配置项,如下:
session.name = PHPSESSID
PHPSESSID就是cookie的名称,其实上⾯⼀串"74dd7807n2mfml49a1i12hkc45"会保存在⼀个名为PHPSESSID的cookie中。
根据http的请求机制,当浏览器请求的时候,头部信息会把浏览器中的cookie⼀起发给服务器。PHPSESSID这个cookie也
是在其中发给了服务器,php引擎通过读取PHPSESSID的值来确定要载⼊哪个session⽂件。
⽐如值为74dd7807n2mfml49a1i12hkc45,载⼊的就是"sess_74dd7807n2mfml49a1i12hkc45"。
注:当你调⽤php的函数session_start(),才表明你需要使⽤session⽂件了。不然平⽩⽆故就去载⼊⽂件,浪费性能。
===========================================
根据如上原理。session的数据默认是保存在磁盘⽂件中。假设这种情况:多台php服务器进⾏负载均衡的时候,⽐如有三台php服务器,为了实现负载均衡,那么三台服务器上⾯的php代码都是⼀样(拷贝⼀份)。
上⾯的图是nginx+fpm部署图。可以看到多台php服务器进⾏负载均衡。
⽣成session数据⽂件都是在本地了(a,b,c各⾃的服务器磁盘上)。负载均衡的⽬的本来就是要为了平均分配请求,所以没有固定第⼀次访问和第⼆次访问是同⼀台服务器,实际上⽆法确定的。第⼀秒访问可能是a服务器,第⼆秒访问的可能是c服务器。
所以同⼀个登录会员,实际上就会出现:第⼀秒访问第⼀台php服务器,第⼆秒访问的是第⼆台服务器。登录的信息⼀般是保存在session中的。这样⼦登录保存的session数据就需要进⾏共享了。不然的话会出现,访问第⼀台服务器⽣成了⼀个session数据。第⼆秒负载请求到第三台服务器,结果获取不到刚才⽣成的session数据。
我的理解是:只有涉及到多台多台后端服务器(php,java等处理服务器)的时候,才涉及到session读取不到的问题。
在php环境中,只有多台php服务器(php服务器⽽⾮web服务器,session⽂件是php引擎⽣成的)的情况下,才会涉及到
session共享的问题。单台php服务器,存储都在⼀台主机上。不涉及到共享问题。因为session直接存储在这台服务器磁盘上是能够被本机读取到的。
如果是:⼀台php服务器,多台mysql服务器。这种也是负载均衡,这种负载均衡不涉及到共享问题。因为怎么session数据怎么操作都是保存在⼀台服务器上。
==================================
ps:实际上,session在php,,java等只要是后端语⾔都会⽤到。session的存储机制,各种语⾔都⼤体差不多。我觉得这跟cookie在各个语⾔中都会⽤到差不多。,java我没去了解过。但是存储原理是差不多的。区别就是,php,java,调⽤的函数,读和取session数据的⽅式不同。默认都是存储在本地⽂件中的(不然怎么会涉及到session共享问题呢,存储在数据库本⾝就可以实现共享的)。
所以,⽆论是还是java都会涉及到session数据共享的问题。
其实我的理解是,session的原理都是⼀样的。讨论session共享⽅案设计,是可以抛开具体的语⾔去讨论session共享⽅案设计。
⽬前业界解决session共享的⼏种思路,我总结如下:
第⼀种办法:把原来存储在服务器磁盘上的session数据存储到客户端的cookie中去。
这样⼦,就不需要涉及到数据共享了。a客户端请求的时候,原来⽣成在服务器的数据⽣成到浏览器的cookie中,根据cookie中的数据识别⽤户。php由原来的”从本地(也就是服务器)磁盘上读取session数据”转变为”浏览器的cookie中读取数据”,
这样⼦,在多台php服务器负载均衡的情况下,即便第⼀秒请求是a服务器,第⼆秒请求是b服务器,都不需要管哪台服务器了。反正都是读取客户端上的cookie数据。
⼀般是把session数据按照⾃⼰定义的加密规则,加密后后存在cookie中。
数据保存在cookie中这种做法有好处,也有坏处。
好处是服务器的压⼒减⼩了,因为session数据不存在服务器磁盘上。根本就不会出现session读取不到的问题。
带来的弊端是:
⽹络请求占⽤很多。每次请求时,客户端都要通过cookie发送session数据给服务器。
另外,浏览器对cookie的⼤⼩存在限制。每个浏览器限制是不同的。
Firefox和Safari允许cookie多达4097个字节,包括名(name)、值(value)和等号。
  Opera允许cookie多达4096个字节,包括:名(name)、值(value)和等号。
  Internet Explorer允许cookie多达4095个字节,包括:名(name)、值(value)和等号。
所以第⼀种⽅案不适合⾼访问量的情况下,因为⾼访问量的情况下,每次请求浏览器都要发送session数据给服务器。⼀般⼀个cookie⼤⼩2k的样⼦。
要占⽤很多带宽了(服务器购买带宽是⼀个很⼤费⽤),成本增⾼。归纳为带宽性能,速度问题。
存储到cookie中去,第⼆⽅⾯是安全问题:把session数据放到客户端,⼀般session中存的都是重要性数据(帐号、昵称、⽤户id等),会存在安全问题。
了解到,淘宝以前⽤过这种⽅式,把session数据存储到cookie中,根据cookie来识别⽤户。
第⼆种思路:⽤⼀种算法(简单理解为规则),什么机制下session是保存在哪台服务器下,那么读取的时候就按照这种规则去读取,就能定位到原来的服务器。叫做分发请求,分发到特定的服务器上去,我理解其原理是存session和读session数据保证都在⼀台服务器操作,就不会需要涉及到共享,具体实现⽅式是通过约定⼀种分发机制来实现。
也叫做sticky模式(粘性会话模式),同⼀个⽤户的访问请求都被派送到同⼀个服务器上。
假设是同⼀个⽤户user1,每次访问都路由到同⼀台服务器上,这样即便是在负载均衡的情况下,也能保证每次访问都能读取到session,不需要做session数据共享了。
关键多台server的原因是为负载均衡⽽做的,那么就得把原来负载均衡的规则假设是—a,现在改为按照session来均衡分发请求的规则—b。
如果这台机⼦挂掉了,那么后续的请求按照session的规则还是会分发到这台服务器上去,但是现在不可⽤了。
本来负载均衡有⼀个⽬的就是:当其中⼀台机⼦不可⽤的时候,会⾃动分发到可⽤的机⼦上去(⾃动判断现在要请求的机⼦是否可⽤)
因为某种规则的session都是保存在⼀台服务器上,⽐如⽤户编号是1-200涉及到的session数据保存到a
服务器上去。所以只要⼀台出问
题,1-200的⽤户就⽆法实现登录了。后⾯就不可⽤了(可能想到1-200⽤户的session服务器⽤多台进⾏复制,这感觉很蹩脚,仍然需要⽤到
复制的话,还不如⽤其他简便的⽅法)
第三种思路:做⼀个中间层,专门来存储所有访问涉及到的session。也就是所有的session都存储在这⾥。
服务器端统⼀从这⾥读取session数据。
具体实现⽅式很多种。我的理解是,这⾥只是⼀种思想层⾯上的。我不知道淘宝的tbsession框架的具体实现。但是⼤致思想差不多,
由这个session框架来维护所有⽹站的session数据。我根据⾃⼰的理解,猜测淘宝的结构画图⼤致如下:
使⽤这种中间层的思想来实现共享,具体的技术⽅案,我归纳为以下⼏种:
1、通过NFS⽂件共享的⽅式,多台php服务器共享保存session⽂件的磁盘。
负载均衡的理解通过nfs的⽅式,各个php服务器操作session数据的时候,是读取本地磁盘⽬录,但实际上是⼀个共享⽹络⽂件。各个php服务器实际上操作的都是同⼀个⽬录的⽂件。
具体的操作细节。到时候还需要详细写⼀下。我根据理解,画了下⾯的图:
 2、保存在数据库中,这种⽅式的扩展性很强,可以随意增加WEB⽽不受影响。放在数据库⾥⾯安全⽅⾯好。
其实我理解本质是:⾃⼰写程序(php,java都可以实现,反正是保存在数据库中)模拟实现session的机制。
具体为,把以前存储在⽂件中的session数据存储到数据库中去,那么这样做,其实就不⽤到php内置的session机制了(像session_start()之类的函数都不需要去⽤了)。
写程序要模拟的是,从数据库拿session数据,约定什么情况下数据过期了然后⾃动清理,这⾥是指删除数据库中的⾏。保存在⽂件中的时候,php有垃圾回收机制会去⾃动清理过期的session⽂件。
====================================弊端
放在数据库⾥⾯,访问量⼩没有问题。⼤流量⽹站这么做,只会拖慢速度。因为得查询数据库,造成数据库压⼒⼤。
⾼并发访问的情况下,会出现很⼤的性能问题。
有些做法跟这种思想是类似的:⽐如ecshop、phpcms是把session数据都存储在数据库中去。服务端就是从数据库中拿session的数据。
放到数据库存储后,就可以实现:多台web服务器统⼀操作数据库,因为数据都在数据库,web服务器都能从数据库进⾏读取,那么session 数据就能实现共享。
存储在数据库的做法,在线⼈数决定了其瓶颈,主要问题是影响性能。在线⼈数,因为登录的session数据存储在数据库中,只要是登录的⽤户就会涉及到频繁操作数据库。
我觉得⼩⽹站,同时1-2万个⼈在线情况下。应该没什么问题。
看⽹上丢出⼀个问题:对于⼤访问量的⽹站,数据库存储session⽅法可⾏性有待商榷。
我搜寻了⼀些资料,理解如下:
访问量⼤的话,⼀个⽤户访问了n多个页⾯,哪怕是刷新页⾯,都需要去数据库取session数据。数据库的承受压⼒,确实很恐怖。pv是多少,就要请求多少次数据库服务器。
访问每个页⾯都会去数据库查询是否登录,或者添加数据进数据库的sessions表
保存在⽂件中的时候,则交给了操作系统去控制。⼀个⽤户怎么刷新页⾯,查看其他页⾯,都只需要读取单个session⽂件
(sess_74dd7807n2mfml49a1i12hkc45)。
我觉得,ecshop,discuz之类的系统之所以把session存储在数据库中去,跟⽹站的应⽤级别有关。他们设计的系统本⾝就是给中⼩站长⽤的,这些中⼩站长⼀般由于规模⼩,经济成本考虑,使⽤的是虚拟主机之类的。不具备对服务器的完全控制权限,⽐如还要安个memcache 之类的,修改 php.ini之类的都需要⾃⼰拥有独⽴服务器才能操控的(vps也算,只是虚拟出来的硬件⽽已)。
其实真正要做到⽹站⼤了,系统承受不住了。也会⾃⼰有独⽴的技术⼈员可以进⾏⼆次开发。
discuz这些做通⽤的软件要考虑思路有个特点:得考虑⼤部分⽤户的服务器环境。⽐如经常看到源代码⾥⾯要做php版本判断的代码,判断是5.0之前的要如何处理,以求尽量适应⼤部分环境。⽽我们公司⾃⼰运营的内部系统,环境我们完全可控。做这些确实是多余的⼯作量。
另外⼀个点是,这些通⽤软件不会为了⾼级⽤户的特殊需求,做⼀些改变,结果另外⼀部分⽤户就⽆法使⽤了。没法两全。所以我的理解是,他们⼀般不会随便去响应站长的需求,⽐如你明明是⼀个很⼤⽤户的站点,你⽤了我的系统,还要说数据量⼤了承受不住,表容易损坏。你都达到某种级别的应⽤了,还不⾃⼰进⾏开发。来这⾥抱怨。我按照你们⽅式定制,愿意给钱就好。
从这⾥我看到,不是说这些软件技术含量就多好,是多么成熟的解决⽅案。他们针对的⽤户不同。
由于http是短连接,每次过程是:建⽴连接(握⼿)》》数据通信》》通信结束后结束连接。如果频繁的这样⼦连接后再断开,性能会⾮常差。session存储在数据库中,有多少pv,就要多少次这样的数据库连接操作(得去数据库拿session才能知道有没有登录,登录是否过时)。
3、可以将session数据保存在memcached,redis之类内存数据库中,memcached是基于内存存储数据的,性能很⾼,⽤户并发量很⼤的时候尤其合适。
主要是利⽤内存的数据读取速度是很快的,与磁盘读取的速度不是⼀个数量级的。
使⽤内存存储:⽅便统计在线⼈数,内存的速度⽐磁盘访问快、内存数据库系统能够控制内存中的过期数据⾃动失效(刚好符合session过期需要)。
存储在redis⽐较理想的选择,存储在数据库中⽅便存储统计在线⼈数,那么存储在redis中也实现了这个要求。
也可以存储在memcache中。但redis⽀持的数据类型多。所以⽤它好点。
关于使⽤技术⼯具复制session数据同步到多台服务器的⽅案权衡:
这种⽅案是,使⽤⼀些⽂件同步⼯具(linux下的rsync),当a服务器中的session数据有更改的时候,就会把这些更改也同步到b,c服务器上去。通过复制的⽅式,最终a,b,c各个服务器上都拷贝了⼀份session数据。
这种⽅式的弊端是,速度慢。复制数据会出现延迟。⽐如第⼀秒访问是a服务器,修改了session数据,负载均衡,可能下⼀秒访问是b服务器,session数据如果没有被复制到b服务器,则是读取不到session数据的,出现时间上的延迟。这种复制数据要消耗很多⽹络带宽的。在实际中业界⽤得⽐较少。机器的数量越多,复制数据的性能损耗越⼤。不具备⾼度扩展性。
复制session的⽅式,⽆论是⽹络带宽成本还是硬件开销上都很⼤的。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。