手机版

PHP实现多服务器共享SESSION数据

时间:2021-11-24 来源:互联网 编辑:宝哥软件园 浏览:

1.一个起点稍大的网站,通常有几个服务器,每个服务器运行不同功能的模块,使用不同的二级域名。对于一个完整性强的网站,用户系统是统一的,即在整个网站的每个模块都可以登录使用一套用户名和密码。服务器之间共享用户数据很容易,只需在后端放一个数据库服务器,每个服务器都可以通过统一的接口访问用户数据。但是还有一个问题,就是当用户登录到另一台服务器的其他模块后,登录到这台服务器时,仍然需要重新登录。这是一次登录和所有访问的问题。映射到技术实际上是一个如何在服务器之间共享SESSION数据的问题。二、PHP SESSION的工作原理在解决问题之前,我们先了解一下PHP SESSION的工作原理。当客户端(如浏览器)登录网站时,被访问的PHP页面可以使用SESSION_start()打开会话,这将生成客户端的唯一标识符SESSION ID(该ID可以通过函数session_id()获取/设置)。SESSION ID可以通过两种方式保存在客户端,让PHP程序在请求不同页面时可以知道客户端的SESSION ID;一种是在GET URL或POST表单中自动添加SESSION ID。默认情况下,变量名为PHPSESSID。另一种是通过COOKIE将会话标识保存在COOKIE中。默认情况下,该COOKIE的名称是PHPSESSID。我们这里主要用COOKIE来解释,因为它们被广泛使用。那么SESSION数据存储在哪里呢?当然是在服务器端,但不是在内存中,而是在文件或数据库中。默认情况下,php.ini中设置的SESSION保存模式是file(SESSION . save _ handler=files),也就是说,通过读写文件来保存SESSION数据。保存会话文件的目录由session.save_path指定,文件名以sess_为前缀。后跟SESSION ID,如:sess _ c 72665 af 28 A8 b 14 c 0 Fe 11 AFE 3 b 59 b 51 b。文件中的数据是序列化后的SESSION数据。如果访问量很大,可能会生成更多的SESSION文件。这时可以设置层次目录保存SESSION文件,效率会大大提高。设置方法为:session . save _ path=' N;/save_path ',n是等级数,save_path是起始目录。在写入SESSION数据时,PHP会获取客户端的SESSION_ID,然后根据这个SESSION ID在指定的SESSION文件保存目录中找到对应的SESSION文件,如果不存在就创建,最后将数据序列化写入文件。读取SESSION数据也是类似的操作过程,读取的数据需要反序列化生成相应的SESSION变量。三.多服务器共享SESSION的主要障碍及解决方案通过了解SESSION的工作原理,我们可以发现,默认情况下,每台服务器都会为同一个客户端生成SESSION ID,例如,对于同一个用户浏览器,服务器a生成的SESSION ID为30de 1e 3192 ba 6 ce 2992d 27 a1 b 6a 0 a,而服务器b生成的SESSION ID为c 72665 af 28 A8 b 14 c 0 Fe 11 AFE 3 b 59 b 51 b。另外,PHP的SESSION数据存储在这个服务器的文件系统中。如下图所示:/upload/20090815161113758.gif

一旦发现问题,就可以解决。要想共享SESSION数据,必须达到两个目标:一是每台服务器为同一个客户端生成的SESSION ID必须相同,并且可以通过同一个COOKIE传输,也就是说每台服务器必须能够读取同一个名为PHPSESSID的COOKIE;另一个是SESSION数据的存储模式/位置必须确保所有服务器都可以访问它。简单来说,多台服务器共享客户端的SESSION ID,也必须共享服务器的SESSION数据。第一个目标的实现其实很简单。它只需要专门设置cookies的域。默认情况下,cookies的域是当前服务器的域名/IP地址。如果域不同,各种服务器设置的cookies不能相互访问。例如,www.aaa.com的服务器不能读写www.bbb.com服务器设置的cookies。这里提到的同一个网站的服务器有其特殊性,那就是都属于同一个一级域,比如aaa.infor96.com和www.infor96.com都属于域infor96.com,所以我们可以将COOKIE的域设置为. infor96.com,这样aaa.infor96.com、www.infor96.com等就可以访问这个COOKIE了。PHP代码中的设置如下:(' session.cookie _ domain ', infor 96.com ');这样,所有服务器共享同一个客户端的会话标识。第二个目标可以通过文件共享来实现,比如NFS,但是设置和操作有些复杂。我们可以参考前面提到的统一用户系统的方式,即使用数据库保存SESSION数据,这样每个服务器就可以轻松访问同一个数据源,获得同一个SESSION数据。解决方案如下图所示:/upload/20090815161114361.gif

四、代码实现首先创建数据表,MySQL的结构化查询语言语句如下:CREATE TABLE ` sess `(` sess KEY ` varchar(32)NOT NULL DEFAULT ' ',` expire ` big int(20)NOT NULL DEFAULT ' 0 ',` data` longtext NOT NULL,PRIMARY KEY (`sesskey `),KEY ` expire `(` expire `))ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8 _ unicode _ ci sess KEY为会话标识,到期为会议过期时间,数据用于保存会议数据。默认情况下会议数据是以文件方式保存,想要使用数据库方式保存,就必须重新定义会议各个操作的处理函数PHP。提供了会话集保存句柄()函数,可以用此函数自定义会议的处理过程,当然首先要先将session.save_handler改成用户,可在服务器端编程语言(专业超文本预处理器的缩写)中进行设置:("用户");接下来着重讲一下会话集保存句柄()函数,此函数有六个参数:会话集保存处理程序(字符串打开、字符串关闭、字符串读取、字符串写入、字符串销毁、字符串gc)各个参数为各项操作的函数名,这些操作依次是:打开、关闭、读取、写入、销毁、垃圾回收PHP。手册中有详细的例子,在这里我们使用面向对象的(=面向对象)的方式来实现这些操作,详细代码如下:(' MY_SESS_TIME ',3600);//SESSION生存时长//类定义My _ Sess类{ function init(){ $ domain=。infor 96。com ';//不使用获取/发布变量方式ini_set('session.use_trans_sid ',0);//设置垃圾回收最大生存时间ini _ set('会话。GC _ max生存期',MY _ SESS _ TIME);//使用COOKIE保存会话标识的方式ini_set('session.use_cookies ',1);ini_set('session.cookie_path ','/');//多主机共享保存会话标识的COOKIE ini _ set('会话。COOKIE _ domain ',$ domain);//将session.save_handler设置为用户,而不是默认的文件session _ module _ name(' user ');//定义会议各项操作所对应的方法名:会话集保存处理程序(数组(“My_Sess”,“open”),//对应于静态方法My_Sess:open(),下同数组(“My_Sess”,“close”),数组(“My_Sess”,“read”),数组(“My_Sess”,“write”),数组(“My_Sess”,“销毁”),数组(“My_Sess”,“GC”);}//end function function open($ save _ path,$ session _ name){ 0返回true} //end函数函数close(){ global $ MY _ SESS _ CONN;if ($MY_SESS_CONN) { //关闭数据库连接$ MY _ SESS _ CONN-Close();}返回true}//结束函数函数读取($ SESS key){ global $ MY _ SESS _ CONN;$ SQL='从会话中选择数据,其中会话键=' .$MY_SESS_CONN-qstr($sesskey).和到期='。time();$ RS=$ MY _ SESS _ CONN-Execute($ SQL);if($ RS){ if($ RS-EOF){ return ';} else { //读取到对应于会话标识的会议数据$ v=$ RS-字段[0];$ RS-Close();返回五美元;}//end if }//end if return ';}//end function function write($ SESS key,$ data){ global $ MY _ SESS _ CONN;$ qkey=$ MY _ SESS _ CONN-qstr($ SESS key);$ expire=TIME()My _ SESS _ TIME;//设置过期时间//写入SESSION $ arr=数组(' sess key '=$ qkey,' expiry '=$ expiry,' data '=$ data);$MY_SESS_CONN-Replace('sess ',$arr,' sesskey ',$ autoQuote=true);返回真;}//结束函数函数destroy($ SESS key){ global $ MY _ SESS _ CONN;$ SQL='从会话中删除,其中会话键=' .$ MY _ SESS _ CONN-qstr($ SESS key);$ RS=$ MY _ SESS _ CONN-Execute($ SQL);返回真;}//结束函数函数GC($ max lifetime=null){ global $ MY _ SESS _ CONN;$sql='从会话中删除位置到期时间();$ MY _ SESS _ CONN-Execute($ SQL);//由于经常性的对表税做删除操作,容易产生碎片, //所以在垃圾回收中对该表进行优化操作$ SQL=' OPTIMIZE TABLE SESS $ MY _ SESS _ CONN-Execute($ SQL);返回真;}//结束函数} ///:~ //使用ADOdb作为数据库抽象层。require _ once(' adodb/adodb。Inc . PHP ');//数据库配置项,可放入配置文件中(如:config.inc.php)。$ db _ type=' mysql$ db _ host=' 192。168 .212 .1 ';$ db _ user=' sess _ user $ db _ pass=' sess _ pass $ db _ name=' sess _ db//创建数据库连接,这是一个全局变量。

$ GLOBALS[' MY _ SESS _ CONN ']=adonew connection($ db _ type);$ GLOBALS[' MY _ SESS _ CONN ']-Connect($ db _ host,$db_user,$db_pass,$ db _ name);//初始化SESSION设置,必须在session_start()之前运行!my _ sess :3360 init();五、遗留问题如果网站访问量较大,SESSION的读写会频繁操作数据库,显然会降低效率。考虑到SESSION数据一般不会很大,可以尝试用C/Java编写一个多线程程序,将SESSION数据保存在HASH表中,通过socket通信读写数据,这样SESSION就存储在内存中,读写速度应该会快很多。此外,服务器负载可以通过负载平衡来分担。然而,这些只是我自己的一些想法和假设,没有实践过。

版权声明:PHP实现多服务器共享SESSION数据是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。