大多数PHP框架的缓存和Session实现都没有考虑并发同步的问题

2013-10-10 10:52:23 +08:00
 tabris17
连Yii这种比较有名的框架也是如此,到底是作者根本没考虑到这些,还是他们觉得PHP也就用在普通web开发上不用很严谨
10855 次点击
所在节点    PHP
60 条回复
tabris17
2013-10-11 09:04:27 +08:00
@Jex 是你没理解才对。我那个链接里把问题说的很清楚了
breeswish
2013-10-11 09:11:43 +08:00
tabris17
2013-10-11 09:14:48 +08:00
@breeswish 嗯,这个贴也是我发的
tabris17
2013-10-11 09:19:01 +08:00
@yangqi 问题在于这些框架都没把这些组件存在的问题说清楚
raincious
2013-10-11 09:41:49 +08:00
@tabris17 框架没必要将PHP自身的问题体现出来吧。如果PHP有这样的问题,造成了框架出现这种情况,那么跟框架没有关系。

PHP SESSION这种东西给我的第一映像就是不适合频繁读写。还是自己实现一个妥当。但,还是不能完全解决这种问题。事实上只有有状态链接的应用程序才能完全解决这个问题。
tabris17
2013-10-11 09:48:11 +08:00
@raincious 不光是session handler实现的问题,还有大多数框架实现的文件型缓存的问题,读写均不是原子操作。比如Yii的CFileCache实现。以写入缓存操作为例:
步骤1、file_put_contents($keyFile, $serilizedValue);
步骤2、touch($keyFile, $lifetime); //设置文件modified time作为缓存过期时间

如果对同一key进行并发写入,实际执行次序可能如下:

file_put_contents($keyFile, $serilizedValue1);
file_put_contents($keyFile, $serilizedValue2);
touch($keyFile, $lifetime2);
touch($keyFile, $lifetime1);

数据1被数据2写入覆盖,但是缓存过期时间确是数据1的
raincious
2013-10-11 09:58:07 +08:00
@tabris17 说真的,我的框架也是这样的。缓存部分不实现原子读写。因为缓存本来的设定就是少写多读。所以“危害性”比Session小很多个数量级,大多数框架都“忽略了”这个问题。

其实也不只PHP的框架,很多其他框架也都是这样的。程序原理的限制,需要花费很多逻辑来修正,关键是这些逻辑是不是值得,显然很多框架选择了不值得,于是。。。。
est
2013-10-11 09:58:21 +08:00
@tabris17 你说说你的使用场景?这种业务压根就不应该往session里放啊。直接做成db操作。user作为外键不是更好么。
breeswish
2013-10-11 11:28:59 +08:00
@tabris17 噢~

在我的项目中,本来想做一个自己的SESSION,使用类似于这样的逻辑:

use_session(function($_SESSION)
{

// session operation here

});

包装一个session,在使用之前读取,在使用之后写入。

后来还是没这么做,主要还是考虑到 首先并发写SESSION情况太少了,这种情况仅仅发生在用户同时开多个页面 然后每个页面都执行了很长时间以至于他们是并发的,并且每个页面都是仅仅在最后才写入SESSION从而导致了冲突;其次就是,SESSION中本来就不应该保存关键数据,保存的数据可以说都是“用户数据缓存”,所以最后还是用了Redis的无锁SESSION。不过为了减少潜在的影响,我还是将session_write_close()这种语句尽可能提前了(比如说,至少提前到了模板引擎渲染页面之前)。
tabris17
2013-10-11 11:33:37 +08:00
@raincious
@breeswish 好吧,看来web应用中数据的完整性和一致性确实不重要,性能和效率才是关键
pubby
2013-10-11 11:34:30 +08:00
@tabris17 "@pubby 用户同时点开两个链接,并发请求这很常见,有些浏览器对于同一IP或站点限制的访问连接数可不止一个"

“同时”总有先后的,哪怕用户先0.000001秒点击第一个链接,但是服务器可能会先处理第二个链接。因为第二个请求头更短,服务器完全有可能先接收完先处理。既然如此,session同步还有啥意思?

session写入应该都是原子的,保证最后一次结果正确不就可以了?
tabris17
2013-10-11 11:36:23 +08:00
pubby
2013-10-11 11:52:22 +08:00
@tabris17 "@pubby http://bbs.phpchina.com/thread-166580-1-1.html"

虽然我没测试过上面的代码,但是我想这不是你所说的问题。

如果浏览器都是第一次访问这个站,那么test.php会生成PHPSESSID ,test2.php也会生成PHPSESSID,这两个必然是不同的。

但问题是test.php 有sleep(10) 所以应该是后于test2.php返回给浏览器,那么在浏览器看来最终的SESSION应该是test.php返回的PHPSESSID对应的数据
raincious
2013-10-11 11:58:12 +08:00
@breeswish 我之前也写过一个Session管理器,但我的Session写入是在程序结束过程时执行的。

但:

我从来不用Session存储什么重要数据,里面只有这几样:Session的Key,用户ID,发给用户的随机Key用来让服务器能够判断Session合法性。然后服务器上存好Session Key和用户ID+用户Key的对应值来做效验。

而且Session会在用户登录的时候写入,然后每次访问读出来用这个做判断以便识别这个用户。同时,唯一频繁更新的也只是用来验证用户提交的Token。

这样一来,所有关键数据都是可以缺失和重建的。

至于Session所产生的数据,我在数据库里有一个内存表(tempDatas,Fields: userID, dataKey, dataVal, updatedTime),使用用户ID+Key来绑定用户站内操作所产生的数据(比如未保存的文章什么的),不过这个基本跟Session没任何关系了。
denghongcai
2013-10-11 13:06:56 +08:00
其他的语言就没有这种问题么?
donnior
2013-10-11 13:46:18 +08:00
@pubby @tabris17

Session的同步,我用过的web框架里面都没有同步功能。

session的并发是存在的,也不仅仅是一个用户同时操作了两次引起的,别忘了所谓的web2.0,还有那么多javascript脚本(诸如定时操作啥的),还有现在基本上每个开发人员都会用的Ajax请求,加上一个用户自己的操作;这样一个用户产生两个并发的请求并不是不可能,很多时候并发产生不一定非得高负载,偶然因素也颇高,所以这时候如果有需要确实要处理session同步问题。

像Java的Servlet Specification中就明确的提到了session的线程安全问题,只不过都是让用户自己去保证。

至于Session中到底应该放什么那就属于设计问题了。
BOYPT
2013-10-11 13:55:07 +08:00
1. 楼主的业务要求的严格顺序不适合使用PHP Session
2. 因为除了file session,memcache/sqlite session都原生保证了原子操作,故不需要锁。即便是file session,也只是保证了单个写入的原子性,不保证请求发生的先后性。
tabris17
2013-10-11 14:42:43 +08:00
@BOYPT PHP默认file handler是加文件锁的,你可以测试下
tabris17
2013-10-11 14:48:14 +08:00
@BOYPT PHP默认file save handler从session_start()执行开始flock加锁,直到session_write_close()才释放文件锁
ksc010
2013-10-11 22:27:31 +08:00
@tabris17 我记得 php好像对同一个会话(session)是有加锁的
原来数据采集的时候,不能同时打开多个请求,每个请求都花费很长时间,并不是同步进行的
不知道跟我用的框架有没有关系(session数据是存在数据库中的,肯定有锁)

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/85066

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX