如何处理多服务器共享session

Python024

如何处理多服务器共享session,第1张

在默认情况下,各个服务器会各自分别对同一个客户端产生SESSION ID,如对于同一个用户浏览器,A 服务器产生的 SESSION ID 是

30de1e9de3192ba6ce2992d27a1b6a0a,而 B

服务器生成的则是c72665af28a8b14c0fe11afe3b59b51b。另外,PHP 的 SESSION

数据都是分别保存在本服务器的文件系统中。

确定了问题所在之后,就可以着手进行解决了。想要共享 SESSION 数据,那就必须实现两个目标:

一个是各个服务器对同一个客户端产生的 SESSION ID 必须相同,并且可通过同一个 COOKIE 进行传递,也就是说各个服务器必须可以读取同一个名为 PHPSESSID 的 COOKIE

另一个是 SESSION 数据的存储方式/位置必须保证各个服务器都能够访问到。 简单地说就是多服务器共享客户端的 SESSION ID,同时还必须共享服务器端的 SESSION

数据。

第一个目标的实现其实很简单,只需要对 COOKIE 的域(domain)进行特殊地设置即可,默认情况下,COOKIE 的域是当前服务器的域名/IP 地址,而域不同的话,各

个服务器所设置的 COOKIE 是不能相互访问的。

四、代码实现

首先创建数据表,MySQL 的 SQL 语句如下:

CREATE TABLE `sess` (

`sesskey` varchar(32) NOT NULL default '',

`expiry` bigint(20) NOT NULL default '0',

`data` longtext NOT NULL,

PRIMARY KEY (`sesskey`), KEY `expiry` (`expiry`)

) TYPE=MyISAM

sesskey 为 SESSION ID,expiry 为 SESSION 过期时间,data 用于保存 SESSION 数据。

默认情况下 SESSION 数据是以文件方式保存,想要使用数据库方式保存,就必须重新定义 SESSION 各个操作的处理函数。PHP 提供了 session_set_save_handle()

函数,可以用此函数自定义 SESSION 的处理过程,当然首先要先将 session.save_handler 改成 user,可在 PHP 中进行设置: session_module_name('user')

接下来着重讲一下 session_set_save_handle() 函数,

此函数有六个参数:

session_set_save_handler ( string open, string close, string read,

string write, string destroy, string gc ) 各个参数为各项操作的函数名,这些操作依次是:

打开、关闭、读取、写入、销毁、垃圾回收。PHP 手册中有详细的例子,

在这里我们使用 OO 的方式来实现这些操作,详细代码如下:

define('MY_SESS_TIME',3600)//SESSION 生存时长

//类定义

class My_Sess

{

/**

* 数据库连接对象,设置成了静态变量,因为不设置为静态变量,数据库连接对象在其他方法不能被调用,目前还不清楚什么原因

*

* @var obj

*/

static public $db

/**

* 构造函数

*

* @param obj $dbname 数据库连接对象

*/

function __construct($dbname){

self::$db = $dbname

}

/**

* 初始化session,使用数据库mysql来存储session的值,利用session_set_save_handler方法实现

*

*/

function init()

{

$domain = ''

//不使用 GET/POST 变量方式

ini_set('session.use_trans_sid',0)

//设置垃圾回收最大生存时间

ini_set('session.gc_maxlifetime',MY_SESS_TIME)

//使用 COOKIE 保存 SESSION ID 的方式

ini_set('session.use_cookies',1)

ini_set('session.cookie_path','/')

//多主机共享保存 SESSION ID 的 COOKIE,因为我是本地服务器测试所以设置$domain=''

ini_set('session.cookie_domain',$domain)

//将 session.save_handler 设置为 user,而不是默认的 files

session_module_name('user')

//定义 SESSION 各项操作所对应的方法名

session_set_save_handler(

array('My_Sess','open'),//对应于类My_Sess的open()方法,下同。

array('My_Sess','close'),

array('My_Sess','read'),

array('My_Sess','write'),

array('My_Sess','destroy'),

array('My_Sess','gc')

)

//session_start()必须位于session_set_save_handler方法之后

session_start()

}

function open($save_path, $session_name) {

//print_r($sesskey)

return true

} //end function

function close(){

if(self::$db){

self::$db->close()

}

return true

}

function read($sesskey) {

$sql = 'SELECT `data` FROM `sess` WHERE `sesskey`=' . (self::$db->qstr($sesskey)) . ' AND `expiry`>=' . time()

$rs=self::$db->execute($sql)

if($rs){

if($rs->EOF){

return ''

} else {//读取到对应于 SESSION ID 的 SESSION 数据

$v = $rs->fields[0]

$rs->close()

return $v

}

}

return ''

}

function write($sesskey,$data){

$qkey = $sesskey

$expiry = time()+MY_SESS_TIME

$arr = array(

'sesskey' =>$qkey,

'expiry' =>$expiry,

'data' =>$data)

self::$db->replace('sess', $arr, 'sesskey', true)

return true

}

function destroy($sesskey) {

$sql = 'DELETE FROM `sess` WHERE `sesskey`='.self::$db->qstr($sesskey)

$rs =self::$db->execute($sql)

return true

}

function gc($maxlifetime = null) {

$sql = 'DELETE FROM `sess` WHERE `expiry`<'.time()

self::$db->execute($sql)

//由于经常性的对表 sess 做删除操作,容易产生碎片,

//所以在垃圾回收中对该表进行优化操作。

$sql = 'OPTIMIZE TABLE `sess`'

self::$db->Execute($sql)

return true

}

}

//使用 ADOdb 作为数据库抽象层。

require_once('adodb/adodb.inc.php')

//数据库配置项,可放入配置文件中(如:config.inc.php)。

$db_type = 'mysql'

$db_host = '127.0.0.1'

$db_user = 'root'

$db_pass = '111'

$db_name = 'sess_db'

//创建数据库连接。

$cnn=&ADONewConnection($db_type)

$cnn->Connect($db_host,$db_user,$db_pass, $db_name)

//初始化 SESSION 设置,初始化时已经包含了session_start()!

$sess = new My_Sess($cnn)

$sess->init()

$_SESSION['a']='aaa'

$_SESSION['b']='bbb'

$_SESSION['c']='ccc'

print_r($_SESSION)

?>

五、遗留问题 如果网站的访问量很大的话,SESSION 的读写会频繁地对数据库进行操作,这样效率就会明显降低。考虑到 SESSION 数据一般不会很大,可以尝试用

C/Java 写个多线程的程序,用 HASH 表保存 SESSION 数据,并通过 socket 通信进行数据读写,这样 SESSION 就保存在内存中,读写速度应该会快很多。另外还可

以通过负载均衡来分担服务器负载。

%>%是管道符的意思,把左边的输出(不包括 <- 之前的)当成右边的输入。

都可以shift + alt + 上下 :快速复制粘贴

alt + 上下 :移动行

ctrl + alt + 上下 :多重光标

首先选中要注释掉的行,然后按Ctrl+shift+C ,这样就注释掉了。

sessionInfo()

.libPaths()

一篇关于包的博客

library(installr)

updateR()

COS中文论坛 统计之都旗下的论坛网站(d.cosx.org),它和其主站(cosx.org)一 起,是一个致力于推广与应用统计学知识的网站和社区。

1 help("t.test")

2 ?t.test

3 help.search("t.test")

4 apropos("t.test")

5 RGui>Help>Html help

6 查看R包pdf手册

getwd() 显示工作目录

setwd() 设定工作目录

list.files() 列出目录或文件夹下的文件

demo( ) 显示R的基本程序包

example( ) 显示在线帮助的例子

example(barplot)

可以把若干行命令保存在一个文本文件(比如Eg3.R)中,然 后用source函数来运行整个文件: source("E:/R demo/Chapter1-Eg3.R")

sum, mean, var, sd, min, max, range, median, IQR(四分位间距)等为统计量, sort,order,rank与排序有关, 其它还有ave,fivenum,mad,quantile, stem等

-1:1/0 当中/是优先级靠后的操作。相当于c(-1,0,1)/0

names(df) <- c("male", "female", "unknown")

对于矩阵,我们可以使用属性rownames和colnames来访问行名和列名。

我们也可以先定义矩阵x然后再为dimnames(x)赋值:

数值型数据 :1.2345e30

复数常量就用3.5-2.1i

缺失值:NA(Not Available)

是否含有缺失值:

NaN表示不确定的数

NaN属于NA的一种

NA不是NaN

注意下面例子的比较 :

assign("x1", c(1, 2))

sort(x)返回x的元素从小到大排序的结果向量

x=c(2,10,6,8,4,5)sort(x) [1] 2 4 5 6 8 10  order(x)返回使得x从小到大排列的元素下标向量(x[order(x)]等效于sort(x))。

此外numeric(n)可以产生一个长度为n的零向量(numeric(n)是一个 很好用的外部存储器)

paste函数用来把它的自变量连成一个字符串,中间用空格分开

Re( )计算实部,Im( )计算虚部, Mod( ) 计算复数模,Arg( )计算复数幅角。

v为一个向量,取值在-length(x)到-1之间,表示扣除相应 位置的元素。例如:

可以用x[]的写法:

R的对象有两个基本的属性:类型属性(mode)和长度属性(length)。

长度为零的向量 numeric( ) 或者 numeric(0) character( ) 或者 character(0)

数组(array): 带多个下标的类型相同的元素的集合,

函数matrix():用于构造二维数组,即矩阵

函数factor( )用来把一个向量编码成为一个因子。

可以自行指定各离散取值水平(levels),不指定时由x的不同值来求得。

• labels可以用来指定各水平的标签,不指定时用各离散取值的对应字符串。

• exclude参数用来指定要转换为缺失值(NA)的元素值集合。

• ordered取真值时表示因子水平(Levels)是有次序的

因子可以用来作为另外的同长度变量的分类变量,使用tapply() 函数可以完成分类统计

nchar()这个函数简单,统计向量中每个元素的字符个数

tolower()和toupper()可以进行大小写字母的转换

chartr()把字符串里的元素,按要求进行转换

拆分字符串用strsplit()函数,strsplit得到的结果是列表,后面的处理要调用列表

其任何一个语句都可以看成是一个表达式。

表达式之间以分号分隔或用换行分隔。

表达式可以续行,只要前一行不是完整表达式,则下一行为上一行的继续。

线性回归模型:

lm()函数的返回值叫做模型拟合结果对象,本质上是一个列表, 有model 、coefficients、residuals等成员。lm()的结果显示十分 简单,为了获得更多的拟合信息,可以使用对lm类对象有特 殊操作的通用函数,这些函数包括:

add1 coef effects kappa predict residuals alias deviance family labels print summary anova drop1 formula plot proj

加号+或 者减号-,表示在模型中加入一项或去掉一项,第一项前面如果是加号可以 省略

在非交互运行(程序)中应使用print()来输出。

• digits参数指定每个数输出的有效数字位数;

• quote 参数指定字符串输出时是否带两边的撇号;

• print.gap参数指定矩阵或数组输出时列之间的间距

也用来输出,但它可以把多个参数连接起来再输出(具有paste() 的功能)。例如:

读取文件:

strsplit()得到的结果是 列表。

grep() grepl()

sub()和gsub()

但严格地说R语言 没有字符串替换的函数,因为R语言不管什么操作对参数都是传值不传址,区别如下:

用substr()和substring() 可以通过位置进行字符串拆分或提取,两者的参数设置基本相同:

strtrim() 函数可以用于将字符串修剪到特定的显示宽度通过位置进 行字符串拆分或提取:

由于日期内部是用double存储的天数,所以是可以相减的。

weekdays ( )取日期对象所处的周几;

months ( )取日期对象的月份;

quarters ( )取日期对象的季度;

其任何一个语句都可以看成是一个表达式。

表达式之间以分号分隔或用换行分隔。

表达式可以续行,只要前一行不是完整表达式,则下一行为上一行的继续。

quantile(x, probs=seq(0,1,0.25), na.rm=FALSE, names=TRUE, type=7, …)

probs给出相应的百分位数,默认值是0,0.25,0.5,0.75,1;na.rm是处 理缺失数据的,na.rm=TRUE时,NA和NaN将从数据中移走,向量取值中 若有NA或NaN,要添加这一参数,否则会出错;names若为TRUE,返回 值当中有names这个属性"type是取值1-9的整数,选择了九种分位数算法 (具体算法见帮助文件)中的一种。

数据的分布主要考察分布函数(p), 密度函数(d), 分位数函数(q)及产生随机数(r)

以正态分布为例:

hist(x, breaks="Sturges", freq=NULL, probability=!freq,… )

break规定了直方图的组距(必须覆盖数据的范围);freq是逻辑变量,TRUE是频率直方图, FALSE是密度直方图;probability和freq相反,TRUE是密度直方图,FALSE是频率直方图

其形式为 coplot(y ~ x | z),其中x 和y是数值型向量,z是同长度的因子。 对z的每一水平,绘制相应组的x和y的散点图

R缺省的图形边空常常太大,以至于有时图形窗口较小时边空占了整个图形的很大一部分。

R可以在同一页面开若干个按行、列排列的窗格,在每个窗格中可以作一 幅图。每个图有自己的边空,而所有图的外面可以包一个“外边空”。

一页多图用 mfrow 参数或 mfcol 参数规定,如

函数 mtext 用来在外边空加文字标注。其用法为

在多图环境中还可以用 mfg 参数来直接跳到某一个窗格,比如

可以不使用多图环境而直接在页面中的任意位置产生一个窗格来绘图,参数为 fig ,如:

先用as.factor()转化成因子。因为levels()函数里面必须是因子。

dat$Genre没有转化成因子形式,as.factor(dat$Genre)就可以了

该消息表明文件的最后一行不以行尾 (EOL) 字符结尾(换行符 ( \n ) 或回车 + 换行符 ( \r\n ))。此消息的初衷是警告您该文件可能不完整;大多数数据文件都有一个 EOL 字符作为文件中的最后一个字符。

这是因为R读取文件的时候,是一整段character,所以它只会返回1,适当给他分一下段。

[编辑本段]① 国际常用缩略语:“请回复”

R.S.V.P.

=Répondez s'il vous plaît.(法语)

=Reply, if you please.

接到邀请(无论是请柬或邀请信)后,能否出席要尽早答复对方,以便主人安排。一般来说,对注有R.S.V.P.(请答复)字样的,无论出席与否,均应迅速答复。注有“Regrets only”(不能出席请复)字样的,则不能出席时才回复,但也应及时回复。经口头约妥再发来的请柬,上面一般那注有“To remind”(备忘)字样,只起提醒作用,可不必答复。答复对方,可打电话或复以便函。

[编辑本段]② 资源预留协议

资源预留协议(RSVP)最初是IETF为QoS的综合服务模型定义的一个信令协议,用于在流(flow)所经路径上为该流进行资源预留,从而满足该流的QoS要求。资源预留的过程从应用程序流的源节点发送Path消息开始,该消息会沿着流所经路径传到流的目的节点,并沿途建立路径状态;目的节点收到该Path消息后,会向源节点回送Resv消息,沿途建立预留状态,如果源节点成功收到预期的Resv消息,则认为在整条路径上资源预留成功。

rsvp(资源预留协议)是一个在ip上承载的信令协议,它允许路由器网络任何一端上终端系统或主机在彼此之间建立保留带宽路径,为网络上的数据传输预定和保证qos。它对于需要保证带宽和时延的业务,如语音传输,视频会议等具有十分重要的作用。

rsvp协议中涉及到发送者和接收者的概念,这两个概念是在逻辑上进行区分的,发送者指发送路径消息的进程,而接收者是指发送预留消息的进程,同一个进程可以同时发送这两种消息,因此既可以是发送者,也可以是接收者。

rsvp是由接收者提出资源预留申请的,这种申请是单向的,也就是说为从主机a到主机b的数据流预留的资源,对于从主机b到主机a的数据流是不起作用的。因为在当前的internet中,双向的路由是不对称的:从主机a到主机b的路径并不一定是从主机b到主机a的路径的反向;另外一个,两个方向的数据传输特征和对应申请预留的资源也未必相同。

rsvp提供两种类型的预留:

专用预留(distinct reservation):它所要求的预留资源只用于一个发送者。即在同一会话(session)中的不同发送者分别占用不同的预留资源。

共享预留(shared reservation): 它所要求的预留资源用于一个或多个发送者。即在同一会话(session)中的多个发送者共享预留资源。

rsvp提供两种发送者选择方式:

通配符方式(wildcard):默认所有发送者,并通过预留消息中所携带的源端地址列表来限制通配符滤波器

显式指定方式(explicit):滤波器明确指定一个或多个发送者来进行预留。

rsvp用interserv模型的两种服务方式:

cl服务(controlled-load service):给用户数据提供接近于在未超载网络上传输质量的服务。

gs服务(guaranteed service):给用户数据提供能保证带宽与时延的服务。

rsvp适用于为frame-relay,hdlc,ppp等网络提供预留保证。