1
yangqi 2013-10-10 11:04:32 +08:00
这些本身不属于框架里的,一般框架都是给出最简单的一些功能, 还是需要进行二次开发的
|
2
Dlad 2013-10-10 11:39:42 +08:00
缓存的并发同步应由缓存考虑,Session的并发同步php提供了函数,需要自己做,代码量不大。
可能框架设计者觉得没有必要吧。 |
3
civoic 2013-10-10 11:56:39 +08:00
并发同步的什么问题?是指多用户并发时同时写同一个缓存,出现冲突的问题吗?
|
4
mahone3297 2013-10-10 12:00:34 +08:00
没有明白lz 的意思,说说?你是想说大并发下,数据加锁?
|
5
raincious 2013-10-10 12:02:18 +08:00
Session什么的,可以用PHP自己的session函数组,然后在php.ini里面将session储存方式修改为memcache服务器。冲突什么的交给memcache自己解决。
|
6
tabris17 OP |
7
tabris17 OP @raincious 我测试过PHP内置的memcache session handle,是没有同步的,并发时会产生冲突,只是大多数浏览器对同一站点使用一个HTTP连接同步访问的,所以问题不明显。
|
8
luikore 2013-10-10 12:07:17 +08:00
前面 nginx 再加个 http_limit 限制单 ip 并发数, 消灭并发就没并发问题了...
|
9
yangqi 2013-10-10 12:07:20 +08:00
@tabris17 session应该算基本的组件, cache算不上基本的要求, 一般框架都只是做简单的开发, 肯定需要二次开发. session没考虑并发? 不知道LZ具体指的是什么, 给点代码会比较好
|
10
tabris17 OP @mahone3297 是的
|
12
Ever 2013-10-10 12:11:48 +08:00
https://code.google.com/p/memcached/wiki/NewProgrammingFAQ#Is_memcached_atomic?
Is memcached atomic? Aside from any bugs you may come across, yes all commands are internally atomic. Issuing multiple sets at the same time has no ill effect, aside from the last one in being the one that sticks. |
13
tabris17 OP |
14
tabris17 OP @Ever PHP session同步问题和session handle的存储类型无关,而是和PHP的session实现机制有关
|
15
civoic 2013-10-10 12:24:52 +08:00
@tabris17 filecache什么的,可以打开同一个文件同时写入的么?
另外,你上面发的这个例子,是否要考虑服务器对于单ip的http请求是并发处理还是同步处理的情况。 |
16
yangqi 2013-10-10 12:27:43 +08:00 1
@tabris17 这个和框架有什么关系, 看下面这个. 你那个例子里面应该是那个sleep(10)导致session file一直被lock, 10秒, 第二个session当然无法写入了
http://konrness.com/php5/how-to-prevent-blocking-php-requests/ |
17
tabris17 OP @civoic 打开同一个文件同时写当然是可以的,否则file_put_contents也不用提供LOCK_EX标志做参数了。问题不在于同时写入同一文件,而在于访问缓存必须是原子操作。
|
18
tabris17 OP @yangqi 我已经说过了,默认file类型的session handle是用文件锁实现同步的,而memcache和sqlite作为session handle是没有同步措施的
|
20
raincious 2013-10-10 12:46:24 +08:00
@tabris17 嗯……四不像兄,我觉得这是你的需求太复杂了。一般框架都不会这样封装甚至是这样处理。因为这涉及到业务层的东西。我自己设计框架的时候直接将Session部分忽略了,框架用户必须自己设计适合自己的Session。
另外如果自己封装的话,一切问题就都很好解决了。比如用直接用数据库或者直接调用memcache。 此外个人觉得php的session并不适用各种环境,只是一种简单的解决方案。我宁愿自己写个Session管理器来处理这些东西。 |
21
est 2013-10-10 12:48:13 +08:00
同一个用户的session,前者还没来得及往session里写入 1,后一个请求就马上要求写入2了,是这种并发同步吗?
|
24
est 2013-10-10 12:57:04 +08:00
@tabris17 一般web framework都不会给session加锁。因为很有可能就做成deadlock了。这个时候你要反思下你的设计是不是有问题。可否避免往session里频繁写数据?
不要啥东西都往session里边放。 |
27
iodragon 2013-10-10 13:07:26 +08:00
@tabris17 我记得memcached是有锁的,memcache 3.0.4版本开始也支持加锁了,session这个本来就不是框架应该考虑的问题吧
|
28
Dlad 2013-10-10 13:10:27 +08:00
@tabris17 不理解“session并发同步“是什么意思。
具体到 配置session_set_save_handler 存进redis或者memcached里,会出现什么样的并发问题呢? |
29
raincious 2013-10-10 13:34:10 +08:00
@tabris17 如果是为了防止在本次过程中的Session写入于读取不一致的问题,可以自行封装一个方法,先将Session将要写入memcache的数据存在某个变量里,读取的时候直接读取这个变量。写入方面用register_shutdown方法Late write到服务器上。
比如这样: <script src="https://gist.github.com/raincious/3e5fac8b775697924f6b.js"></script> 用法 <script src="https://gist.github.com/raincious/6662bc0f3cf24ede7fe9.js"></script> |
30
raincious 2013-10-10 13:34:57 +08:00
|
31
raincious 2013-10-10 13:38:03 +08:00
|
32
andyhuax 2013-10-10 17:25:51 +08:00
有些框架的session类里有session_write_close,用来处理这种session并发的问题,将session资源在请求结束前提前释放。
|
33
pubby 2013-10-10 18:03:18 +08:00
用户正常浏览,加上服务器响应正常时,貌似session互斥锁没啥意义啊
要用到同步,说明对写入数据有顺序要求,但是http协议本身就不保证这一点, 只能说这个需求太特殊了,自己实现下吧。 |
34
breeswish 2013-10-10 18:06:01 +08:00
首先。。优秀的代码都是在操作完SESSION之后立即session_write_close()的。。
其次。。PHP自己的SESSION是带文件锁的。。 |
35
Jex 2013-10-10 19:16:52 +08:00 1
这问题怎么提出来的?
session生成的每个ID都是唯一的,怎么可能出现其它用户覆盖你的数据的可能? LZ你这是在? |
36
Jex 2013-10-10 19:19:39 +08:00 1
缓存本来就没有一致性、持久性等保证,怎么可能还需要考虑并发读写同一条缓存?
LZ你没理解,你说的两个场景都是根本不需要考虑并发读写的问题 |
37
yangqi 2013-10-10 23:12:42 +08:00
@tabris17 基本上大部分框架默认肯定是用Php自己的session, 用户要改用sqlite或者别的当然要自己二次开发了,框架不可能把所有需求都开发了,否则也不叫框架了。。。
|
39
tabris17 OP @raincious 不是复杂,而是严谨。虽然并发导致的问题在web应用中发生几率很低,而即便发生了也不太会导致致命错误。所以这个问题从来不被引起重视。至于Cache的一致性问题,由于Cache使用方式的局限性,所以也不会引起致命错误。但实际上错误还是会发生的。
|
40
tabris17 OP @breeswish 不。PHP的Sesssion handler只有内置的file handler是带同步的,而内置的sqlite handler和memcache handler都是不带同步的
|
42
breeswish 2013-10-11 09:11:43 +08:00
|
45
raincious 2013-10-11 09:41:49 +08:00
@tabris17 框架没必要将PHP自身的问题体现出来吧。如果PHP有这样的问题,造成了框架出现这种情况,那么跟框架没有关系。
PHP SESSION这种东西给我的第一映像就是不适合频繁读写。还是自己实现一个妥当。但,还是不能完全解决这种问题。事实上只有有状态链接的应用程序才能完全解决这个问题。 |
46
tabris17 OP @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的 |
47
raincious 2013-10-11 09:58:07 +08:00
@tabris17 说真的,我的框架也是这样的。缓存部分不实现原子读写。因为缓存本来的设定就是少写多读。所以“危害性”比Session小很多个数量级,大多数框架都“忽略了”这个问题。
其实也不只PHP的框架,很多其他框架也都是这样的。程序原理的限制,需要花费很多逻辑来修正,关键是这些逻辑是不是值得,显然很多框架选择了不值得,于是。。。。 |
49
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()这种语句尽可能提前了(比如说,至少提前到了模板引擎渲染页面之前)。 |
50
tabris17 OP |
51
pubby 2013-10-11 11:34:30 +08:00
@tabris17 "@pubby 用户同时点开两个链接,并发请求这很常见,有些浏览器对于同一IP或站点限制的访问连接数可不止一个"
“同时”总有先后的,哪怕用户先0.000001秒点击第一个链接,但是服务器可能会先处理第二个链接。因为第二个请求头更短,服务器完全有可能先接收完先处理。既然如此,session同步还有啥意思? session写入应该都是原子的,保证最后一次结果正确不就可以了? |
52
tabris17 OP |
53
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对应的数据 |
54
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没任何关系了。 |
55
denghongcai 2013-10-11 13:06:56 +08:00
其他的语言就没有这种问题么?
|
56
donnior 2013-10-11 13:46:18 +08:00
@pubby @tabris17
Session的同步,我用过的web框架里面都没有同步功能。 session的并发是存在的,也不仅仅是一个用户同时操作了两次引起的,别忘了所谓的web2.0,还有那么多javascript脚本(诸如定时操作啥的),还有现在基本上每个开发人员都会用的Ajax请求,加上一个用户自己的操作;这样一个用户产生两个并发的请求并不是不可能,很多时候并发产生不一定非得高负载,偶然因素也颇高,所以这时候如果有需要确实要处理session同步问题。 像Java的Servlet Specification中就明确的提到了session的线程安全问题,只不过都是让用户自己去保证。 至于Session中到底应该放什么那就属于设计问题了。 |
57
BOYPT 2013-10-11 13:55:07 +08:00 1
1. 楼主的业务要求的严格顺序不适合使用PHP Session
2. 因为除了file session,memcache/sqlite session都原生保证了原子操作,故不需要锁。即便是file session,也只是保证了单个写入的原子性,不保证请求发生的先后性。 |