素材牛VIP会员
PHP session 独占锁是否有超时设置?
 貪***续  分类:PHP代码  人气:1134  回帖:2  发布于6年前 收藏

最近在开发过程中遇到一个不明白的问题, 查了很久没有思路, 想请教各位大佬.
公司这边使用PHP的session的存储介质是memcached, 架构是php-fpm和nginx.
场景描述:
当用户一个请求执行很慢且使用了session_start()并且没有释放session资源的情况下, 如果此时该用户下一个请求又发送过来, 由于session独占锁的原因, 该用户的第二次请求将会等到第一次请求将session释放后才能执行或者脚本等待导致超时被fpm的master进程kill掉.
那么问题来了, 我发现在上述这种情况下, 用户的第二个请求并不会一直等待上一个请求释放session, 而是经过几秒后, 代码里$_SESSION['name']会返回null.
诡异bug
这种情况就很容易让我想到日常浏览网页会出现一个诡异bug: 假设我的某个操作会执行较久, 而在该请求完成前我又发起多个请求, 如果网站需要通过session验证我的身份, 那么后面的几次请求很可能被判断为我未登陆 (原因 : 前一个请求未完成, session被占用, 后面的请求获取session中信息的时候,session返回为null) 而拒绝请求.这不是很严重的一件事情吗? 但是日常中好像并没有遇到谁家的网站出现过这种问题.
请教大家
我想请教大家, 这个独占锁是否真的会导致后面的请求获取不到session(返回为null值)?
我如何判断是用户真的没登陆还是由于用户上一个请求占用着session资源导致的返回null?
事实上并不像网上说的那样脚本会一直等待之前的请求释放session, 而是经过某段时间就返回null, 那么有哪些参数可以控制这个独占锁超时, 如果超时就返回null?(是否将这个超时时间设置无限大就可以避免刚才提到的日常浏览网页的诡异bug?)

 标签:php

讨论这个帖子(2)垃圾回帖将一律封号处理……

Lv4 码徒
麦***6 站长 6年前#1

很有意思的问题。

我查了下资料,先简单整理一下吧,有时间我再详细分下,结果会在这个答案上更新。

PHP 的 session 核心操作是 Storage,默认是 file,还有大家熟知的 memcached、redis,甚至 mysql或者其他任意的存储结构,只要符合 php 对 Session Storage 的要求即可,具体设置是 session_set_save_handler() 配置即可。

然后题主使用的是默认的,即 file 存储结构。

有了这个前提,我们再看session_start()主要都做了些什么。
1.如果没有 session_id,则在save_path下创建一个 session 文件,并返回给你一个新的 session_id
2.如果有 session_id,则从 session 文件中获取到对应的 session 信息,并填充到 $_SESSION

这样问题就来了,并发问题会导致脏写、读的问题,所以 PHP 对 session 信息加了排它锁,以保证 session 信息的正确性。但这样会阻塞请求,导致性能下降。

在 PHP5 可以使用session_write_close()手动释放锁。
在 PHP7 可以直接在初始化的时候设置自动释放锁 session_start(['read_and_close' => true,]);

因此,可以在会话数据没有变动的时候,避免不必要的文件锁。

关于题主的超时,File Storage 底层是 flock 实现的锁机制。
flock 实现排他锁
php 封装的 flock

现在 redis 和 memcached 都已经支持 session 锁了。

Lv6 码匠
de***oo 页面重构设计 6年前#2

如果你正在使用PHP的memcached扩展,你可以将memcached.sess_locking设置为“off”,来避免session锁。
文件的话参考手册:

<?php
// 如果确定不修改会话中的数据,
// 我们可以在会话文件读取完毕之后立即关闭它
// 来避免由于给会话文件加锁导致其他页面阻塞
session_start([
    'read_and_close'  => true,
]);

memcached扩展的锁实现:

 文明上网,理性发言!   😉 阿里云幸运券,戳我领取