session

2019-10-14补充 :

  1. 关于sessionid是如何生成的?
    答:session在访问tomcat服务器HttpServletRequest的getSession(true)的时候创建,tomcat的ManagerBase类提供创建sessionid的方法:随机数+时间+jvmid;
    Tomcat是Apache 软件基金会(Apache Software Foundation)的Jakarta 项目中的一个核心项目。
    参考:sessionid是如何生成的

  2. 删除cookie方法?

一:直接删除

setcookie("users");//浏览器关闭 是自动失效

二:通过 设置 失效时间

setcookie("users","OKadmin",time()-1);
  1. 改变session生存时间?
    由于session 默认是基于cookie 的,也就是说使用session 会话技术,首先是将session数据保存到服务器端,其次会将sessionID 保存到浏览器端,保存在服务器端的session文件生命周期由php.ini 中的session.gc_maxlifetime、gc_probability 和gc_divisor 来决定,而保存在客户端的sessionID 由客户端cookie 来决定,默认其生存周期直到浏览器关闭,它由php.ini 中的设置session.cookie_lifetime 来控制,二者共同来决定session 的生存时间,二者中的其中任意一个失效了,就有可能造成session失效,要根据自己的需求来决定是要从哪方面来修改其生存时间。
    == PHP中的session有效期默认是1440秒(24分钟),也就是说,客户端超过24分钟没有刷新,当前session就会失效。==
    一: 修改客户端sessionId的有效期:session_set_cookie_params($lifetime)或者
    ini_set(“session.cookie_lifetime”, time()+$limetime)
    通过函数修改 cookie 参数,需要对每个请求都要在调用 session_start() 函数之前调用 session_set_cookie_params() 函数。
    二: 修改服务端session文件的有效期:
    在配置文件php.ini中,你可以找到session.gc_probability=1000,和session.gc_divisor=1这两个配置项,
    "回收机制"在每个session初始化发生是一个概率事件,这个概率是由以下公式得出的:
    gc_probability除以gc_divisor。如果gc_probability值为1,gc_divisor值为100,那么触发“回收机制”的概率为1%。
    就意味着可能有100次php请求,可能才会有一次触发“回收机制”的可能性。所以说如果session已经过期了,但是没有
    触发到“回收机制”,session文件还没有被删除,那session就是还有效的。
    如果需要很精准的触发“回收机制”,让session已过期马上删除,就把以上两个值都设置为1.
    但是这样会极其影响PHP性能。
    所以最有效的方式是修改session.gc_maxlifetime。ini_set(session.gc_maxlifetime,$lifetime)

  2. 关于session.save_path?
    在默认情况下,PHP 中的session信息会以文本文件的形式,被保存在系统的临时文件目录中。这个路径由配置参数session.save_path指定。在Linux下,这一路径通常为\tmp,在 Windows下通常为C:\Windows\Temp。当服务器上有多个PHP应用时,它们会把自己的session文件都保存在同一个目录中(因为它们使用同一个session.save_path参数)。同样地,这些PHP应用也会按一定机率启动GC,扫描所有的session文件。
      问题在于,GC在工作时,并不会区分不同站点的session。举例言之,站点A的gc_maxlifetime设置为2小时,站点B的 gc_maxlifetime设置为默认的24分钟。当站点B的GC启动时,它会扫描公用的临时文件目录,把所有超过24分钟的session文件全部删除掉,而不管它们来自于站点A或B。这样,站点A的gc_maxlifetime设置就形同虚设了。
    找到问题所在,解决起来就很简单了。在页面的开始处调用session_save_path()函数,它能够修改session.save_path参数,把保存session的目录指向一个专用的目录,例如\tmp\myapp\。这样,gc_maxlifetime参数就工作正常了。
    5. php session.save_path = “N;/path”如何使用?
    注:session.save_path = "2;/data/session_tmp"代表将session文件分成两级存放,即/data/session_tmp/4/b /sess_4b1e384ad74619bd212e236e52a5a174If,==取前两位字符,但是php并不生成目录,需要自己手工生成。

以下为正文:

在web开发中,session是个非常重要的概念。Session一般译作会话,Session是一种基于HTTP协议的用以增强web应用能力的机制或者说一种方案,它不是单指某种特定的动态页面技术,而这种能力就是保持状态,也可以称作保持会话。

在许多动态网站的开发者看来,session就是一个变量,而且其表现像个黑洞,他只需要将东西在合适的时机放进这个洞里,等需要的时候再把东西取出来。这是开发者对session最直观的感受,但是黑洞里的景象或者说session内部到底是怎么工作的呢?

web应用是基于HTTP协议的,而HTTP协议是一种无状态协议。也就是说,用户从A页面跳转到B页面会重新发送一次HTTP请求,而服务端在返回响应的时候是无法获知该用户在请求B页面之前做了什么的。解决HTTP协议自身无状态的方式有cookie和session。二者都能记录状态,前者是将状态数据保存在客户端,后者则保存在服务端。

关于Cookie的介绍可以查看这两篇文章:Cookie简介或Cookie与Session的区别。今天主要讲的是Session的实现原理。

session的基本原理是服务端为每一个session维护一份会话信息数据,而客户端和服务端依靠一个全局唯一的标识来访问会话信息数据。用户访问web应用时,服务端程序决定何时创建session,创建session可以概括为三个步骤:

生成全局唯一标识符(sessionid)
开辟数据存储空间。一般会在内存中创建相应的数据结构,但这种情况下,系统一旦掉电,所有的会话数据就会丢失,如果是电子商务网站,这种事故会造成严重的后果。不过也可以写到文件里甚至存储在数据库中,这样虽然会增加I/O开销,但session可以实现某种程度的持久化,而且更有利于session的共享;
将session的全局唯一标示符发送给客户端。
关于服务器如何将session的唯一标识发送个客户端,主要有两种方式:cookie和URL重写。然后浏览器将sessionid其保存到cookie。Cookie与Session的区别中也有写到,这里不再详述。下面就开始说说PHP中的Session。

PHP中session方案包含的信息

session id 用户session唯一标识符,随机生成的一串字符串,具有唯一性,随机性。主要用于区分其它用户的session数据。用户第一次访问web页面的时候,php的session初始化函数调用会分配给当前来访用户一个唯一的ID,也称之为session_id。
session data 我们把需要通过session保存的用户状态信息,称为用户session数据,也称为session数据。一般是在当前session生命周期,相应用的$_SESSION数据。
session file PHP默认将session数据存放在一个文件里。我们把存放session数据的文件称为session文件。它由特殊的php.ini设置session.save_path指定session文件的存放路径。用户session文件的名称,就是以sess_为前缀,以session_id为结尾命名,比如session id为vp8lfqnskjvsiilcp1c4l484d3,那么session文件名就是sess_vp8lfqnskjvsiilcp1c4l484d3
session lifetime 我们把初始化session开始,直到注销session这段期间,称为session生命周期,这样有助于我们理解session管理函数。
由此,我们可见:当每个用户访问web, PHP的session初始化函数都会给当前来访用户分配一个唯一的session ID。并且在session生命周期结束的时候,将用户在此周期产生的session数据持久到session文件中。用户再次访问的时候,session初始化函数,又会从session文件中读取session数据,开始新的session生命周期。

php.ini中与Session相关的设置:

session.save_handler = file 用于读取/回写session数据的方式,默认是files。它会让PHP的session管理函数使用指定的文本文件存储session数据
session.save_path = “/var/lib/php/session” 指定保存session文件的目录,可以指定到别的目录,但是指定目录必须要有httpd守护进程属主(比如apache或www等)写权限,否则无法回存session数据。当指定目录不存在时,php session环境初始化函数是不会帮你创建指定目录的,所以需要你手工建立指定目录 。它还可以写成这样session.save_path = “N;/path” 其中N是整数。这样使得不是所有的session文件都保存在同一个目录中,而是分散在不同目录。这对于服务器处理大量session文件是很有帮助的。(注:目录需要自己手工创建)。设置了多级目录后,php将不会清除这些session文件,必须手动清除。
session.auto_start = 0 如果启用该选项,用户的每次请求都会自动初始化session。我们推荐不启用该设置,最好通过session_start()显示地初始化session。

Session相关PHP函数和事件

session_start() 函数session_start会初始化session,也标识着session生命周期的开始。要使用session,必须初始化一个session环境。有点类似于OOP概念中调用构造函数构创建对象实例一样。session初始化操作,声明一个全局数组$_SESSION,映射寄存在内存的session数据。如果session文件已经存在,并且保存有session数据,session_start()则会读取session数据,填入$_SESSION中,开始一个新的session生命周期。
$_SESSION 它是一个全局变量,类型是Array,映射了session生命周期的session数据,寄存在内存中。在session初始化的时候,从session文件中读取数据,填入该变量中。在session生命周期结束时,将$_SESSION数据写回session文件。
session_register() 在session生命周期内,使用全局变量名称将注全局变量注册到当前session中。所谓注册,就是将变量填入$_SESSION中,值为NULL。它不会对session文件进行任何IO操作,只是影响$_SESSION变量。注意,它的正确写法是session_register(‘varname’),而不是session_register($varname)
session_unregister() 与session_register操作正好相反,即在session生命周期,从当前session注销指定变量。同样只影响$_SESSION,并不进行任何IO操作。
session_unset() 在session生命周期,从当前session中注销全部session数据,让$_SESSION成为一个空数组。它与unset($_SESSION)的区别在于:unset直接删除$_SESSION变量,释放内存资源;另一个区别在于,session_unset()仅在session生命周期能够操作$_SESSION数组,而unset()则在整个页面(page)生命周期都能操作$_SESSION数组。session_unset()同样不进行任何IO操作,只影响$_SESSION数组。
session_destroy() 如果说session_start()初始化一个session的话,而它则注销一个session。意味着session生命周期结束了。在session生命周期结整后,session_register, session_unset, session_register都将不能操作$_SESSION数组,而$_SESSION数组依然可以被unset()等函数操作。这时,session意味着是未定义的,而$_SESSION依然是一个全局变量,他们脱离了关映射关系。
通过session_destroy()注销session,除了结束session生命周期外,它还会删除sesion文件,但不会影响当前$_SESSION变量。即它会产生一个IO操作。

session_regenerate_id() 调用它,会给当前用户重新分配一个新的session id。并且在结束当前页面生命周期的时候,将当前session数据写入session文件。前提是,调用此函数之前,当前session生命周期没有被终止。它会产生一个IO操作,创建一个新的session文件,创建新的session文件的是在session结束之前,而不是调用此函数就立即创建新的session文件。
session_commit() 函数是session_write_close()函数的别名。它会结束当前session的生命周期,并且将session数据立即强制写入session文件。不推荐通过session_commit()来手工写入session数据,因为PHP会在页面生命周期结束的时候,自动结束当前没有终止的session生命周期。它会产生一个IO写操作。
end session 结束session,默认是在页面生命周期结束的之前,PHP会自动结束当前没有终止的session。但是还可以通过session_commit()与session_destroy()二个函数提前结束session。不管是哪种方式,结束session都会产生IO操作,分别不一样。默认情况,产生一个IO写操作,将当前session数据写回session文件。session_commit()则是调用该函数那刻,产生一个IO写操作,将session数据写回session文件。而session_destroy()不一样在于,它不会将数据写回session文件,而是直接删除当前session文件。有趣的是,不管是session_commit(),还是session_destroy()都不会清空$_SESSION数组,更不会删除$SESSION数组,只是所有session*函数不能再操作session数据,因为当前的session生命周期终止了,即不能操作一个未定义对象。

Session ID 是如何传递的?

session终究是因为管理用户状态信息才存在的。session id是用户表明身份的一种标识,就像入场券一样。用户一旦从被分配了session id之后的每次访问(http请求)都会携带这个session id给服务端,用于加载该用户的session数据。

用户端与服务端的web通信协议是http。而PHP通过http取得用户数据惯用的三种方法分别是:POST方法、GET方法还有Cookie。而PHP默认传递方法正是Cookie,也是最佳方法。只有在客户端不支持Cookie的时候(浏览器禁用了Cookie功能)才会通过GET方法来传递session_id,即通过在URL的query_string部分传递session id。
在这里插入图片描述

确定了传递方法,我们还有必要清楚一下session id的传递过程。用户通过浏览器访问网页,将URL输入地址栏回车,浏览器发出请求,在调用sockect send之前浏览器引擎会搜索有效的Cookies记录封装在http请求头的Cookie字段一同发送出去 。服务端器接收到请求后,交给PHP处理。这时session初始化函数如果在$_COOKIE中没有找到以session_name()作为键值存储的生素(值为session id),则会以为用户是第一次访问web。作为第一次访问的用户,session初始化函数总会随机生成一个session_id并且通过setcookie()函数调用将新生成的session_id以”session_name = session_id”的格式填入http响应头Set-Cookie字段,发送给客户端(这样接下来的请求,http请求头Cookie字段都会携带该Cookie记录给web服务器)。如果初始化函数发现用户端Cookies中已定义了存在$_COOKIE[‘sess_name’],则会加载与$_COOKIE[‘sess_name’]相对应的session文件($_COOKIE[‘sess_name’]就是session ID)。如果用户Cookie记录过期,则会被浏览器删除。之后的下一次请求,服务器会以为用户又是第一次访问,如此循环。

php.ini中Session ID 相关设置

session.use_cookies = 1 是否采用Cookie方法传递session id值。默认是1,表示启用。
session.name = PHPSESSID 不管是Cookie传递sessioin_id,还是GET方法传递session_id,都需要使用键值。他们的格式分别是Cookie: sess_name=session_id;和/path.php?sess_name=session_id,其中sess_name就是由这里指定的。
session.use_only_cookies = 0 表示只使用Cookie 的方法传递session id。我们说过,传递cookie的方法,除了cookie,还有GET方法,GET方法是不安全的方法。在用户端禁用了cookie的时候,会采用GET方法传递session_id,可以通过这个设置禁用GET方法传递session_id。
session.cookie_lifetime = 0, session.cookie_path = / 以及session.cookie_domain = 如果使用Cookie方法传递session_id的话,这里分别指定了cookie有效域、目录和时间。分别对应setcookie()函数的形参 e x p i r e 、 expire、 expirepath和$domain。其中cookie_lifetime=0表示直到关闭浏览器才删除Cookie。还可以使用session_set_cookie_params()函数修改这些值。
session_name([string $name]) 获取或更新session_name。如果传了name,则表示不使用默认的名称PHPSESSID(由session.name)指定,否则获取当前session_name。注意:如果设置session_name,则必须在session_start()之前调用才生效。
session_id([string $id]) 与session_name()类似,但它是读取或者设置session_id的方法。同样,设置session_id的话,必须在session_start()之前调用才有效。
session_set_cookie_params()和session_get_cookie_params() 通过session_set_cookie_params()可以重新设定session.cookie_lifetime, session.cookie_path以及session.cookie_domain这三个php.ini设置。而session_get_cookie_params()则是获取这些设定的值。

Session的回收

我们知道session数据存放在服务端指定的session.save_path目录中,同时会在用户端存放一条Cookie用以记录分配给用户的session id。所以,session数据失效分服务端和客户端,要删除(回收)的对象也很清楚:

服务端:删除过期的session文件,启动PHP GC回收。
用户端:使存储了过期session_id的用户端Cookie记录过期。通过将Cookie的Expire设置为负值,要求客户端删除Cookie。

服务端:删除过期的session文件

PHP GC进程被启动以后,则会扫描session.save_path,找出过期的session,并删除该session文件。所谓,过期的session,是指操作系统当前时间与session文件最后访问时间之差大于session.gc_maxlifetime的话,该session认为是过期了。注意:有时候,你会发现,即便是文件过期了,有可能也没有被及时地删除掉。这是因为,每次session初始化的时候,并不会都启动PHP GC进程的,启动GC进程会大大降低php的运行效率。所有一个启动概率,这个概率由php.ini设定session.gc_probability / session.gc_divisor二个设置决定,默认概率是1%(1/1000)。这意味着,每1000次用户请求中,会启动1次PHP GC回收session文件。

客户端:删除过期session id的cookie记录

如果用户发现session已经过期,但是服务端的GC还没有启动,服务端可以手通过手工代码setcookie的方式要求用户端浏览器删除键值为session_name()的Cookie记录。这样,下回访问的时候,浏览器以为用户是第一次访问,并且重新给访问用户分配一个新的session_id。

php.ini中与session相关的设置

session.gc_probability和session.gc_divisor 由这二个函数决定了启用GC的概率,默认是1/1000。也就是说每一千次用户请求中有一次会启动GC回收session。启动GC进程不宜过于频繁。上面的例子我们可以看到它会每次检查session.save_path目录下每个文件的状态。这样会降低php的执行效率。
session.gc_maxlifetime = 1440 设置session存活时间,单位是秒。每次GC启动后, 会通过stat得到session文件最后访问的unix时间,通过现在时间减去文件最后访问时间之间大于session.gc_maxlifetime则会删除该文件。

################################################运维层面####################
strace -p pid php-cgi中高负载的进程

stat("/tmp/sess_6dedc3de5539804adb4e0f17b88f8f46", {st_mode=S_IFREG|0600, st_size=0, …}) = 0
有大量的这样的记录就可确定写seesion导致的i/o问题,解决方法如下:
写内存:


#!/bin/sh
set -x
I="0 1 2 3 4 5 6 7 8 9 a b c d e f"
for acm in $I;
do
for x in $I;
do
mkdir -p /dev/shm/sessions/$acm/$x;
done;
done
chown -R nobody:nobody /dev/shm/sessions
chmod -R 1777 /dev/shm/sessions

因为/dev/shm/sessions是用的内存,服务器重启后,里面的所有文件都会丢失,所以,需要把上面的脚本加入到 /etc/rc.local中,并且要放在启动php之前

第三步,将session存储到不同的目录中
php本身支持session的多级散列
在php.ini中,将 ;session.save_path = /tmp 改为
session.save_path = “2;/dev/shm/sessions”

表示将session存储到 /dev/shm/session这个文件夹中,并且是用2级散列。
保存退出
切记,等第四步结束后迅速重启php,否则会有部分session不同步的现象
删除原有的session
rm -f /tmp/*
第五步,session的回收
session在使用2分法,更改过默认存储路径后,会无法定时删除sessions
所以我们需要手动定时删除,下面这个命令可以删除过期的session
我这里定义的过期时间是3小时内

*/10 * * * * /bin/find /tmp/sessions/ -amin +180 -type f -exec rm -rf {} ;

crontab 10分钟一扫
ok!
转自:php sessions 笔记 以及 大量的seesion导致服务器过载解决方法


session_id() — 获取/设置当前会话 ID
session_save_path() — 读取/设置当前会话的保存路径
session_get_cookie_params() — 获取会话 cookie 参数
session_unset() — 释放所有的会话变量,但不删除 session 文件以及不释放对应的 session id
session_destroy() — 销毁一个会话中的全部数据
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值