精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2009-12-02
当页面执行完毕或调用session_write_close()时把$_SESSION变量写入数据源。 php默认的session.save_handler=files,可以通过文件锁来实现读写同步,保证session数据的一致性,不会产生问题。然而当使用sqlite作为session handler时,由于没有同步机制,会产生bug。如下代码: test1.php session_start(); $_SESSION['data1'] = 'data1'; sleep(10); session_write_close(); test2.php session_start(); $_SESSION['data2'] = 'data2'; session_write_close(); 在同一浏览器进程里(保证使用相同的session_id),先访问test1.php,再访问test2.php,会发现data2根本没有写入sqlite数据库中。session.save_handler=memcache还没有测试,估计也有这个问题。如果采用默认的files handler会发现test2.php的请求会被挂起直至test1.php执行完毕,这就是文件锁同步机制造成的。 我想到了两种解决方案: 1、实现互斥锁,保证同一session_id访问session数据是同步的,这样会产生一个阻塞的问题(php默认的session实现也会有这个问题)。 2、写入session数据时进行数据合并,不过这样仍然不能完全保证数据一致性。 有没有人曾经碰到过这个问题?有什么解决方案吗? 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2009-12-03
最后修改:2009-12-03
互斥锁不行的话就使用乐观锁喽。给每条 session 加个 version,取出来时的 version 如果与写回去的 version 不一致,说明发生了冲突,此时对数据进行 merge。
|
|
返回顶楼 | |
发表时间:2009-12-03
最后修改:2009-12-03
diogin 写道 互斥锁不行的话就使用乐观锁喽。给每条 session 加个 version,取出来时的 version 如果与写回去的 version 不一致,说明发生了冲突,此时对数据进行 merge。
异步读,写入时数据合并的方法我也考虑过,但会产生脏读等问题。 比如: if (...condition...) { $_SESSION['a'] = 'a'; unset($_SESSION['b']); } else { $_SESSION['b'] = 'b'; unset($_SESSION['a']); } 如果是同步读写的话,session数据中b或c只能存在其中一个,如果采用数据合并的有可能会导致b和c同时存在。 |
|
返回顶楼 | |
发表时间:2009-12-03
看到你又发这儿来了。。。
我觉得可以转个弯,把session存入db时使用事务,保证原子操作。 |
|
返回顶楼 | |
发表时间:2009-12-03
hittyo 写道 看到你又发这儿来了。。。
我觉得可以转个弯,把session存入db时使用事务,保证原子操作。 这个开销实在太大了,只能不得已为之 |
|
返回顶楼 | |
发表时间:2009-12-03
最后修改:2009-12-03
折衷吧
或者使用 session_set_save_handler("open", "close", "read", "write", "destroy", "gc"); 自己定义session读写等操作。 假设session记录 select data,time,... from tab where sid=$sid 同时取最后一次写入的时间 $time 写入时判断 update tab set data=合并后的数据 where sid=$sid and time=$time 如果更新不成功则重复上述过程。 |
|
返回顶楼 | |
发表时间:2009-12-03
自定义session handler一样存在这个问题,除非引入锁机制。
据我所知,仅依靠php内置函数只能使用文件读写锁或者IPC信号量,而IPC信号量只能在*nix下使用。很头疼啊。 数据合并依然无法避免脏读等情况,也无法完全实现数据一致性。 |
|
返回顶楼 | |
发表时间:2009-12-04
楼主的情况,应该是每用户的多个变量。 为该用户建个表。 每次session赋值替代了表insert或update。写个类操作起来应该也很方便。
memcache解决这个问题也很不错。 session不会满足楼主的要求。 |
|
返回顶楼 | |
发表时间:2009-12-04
取了个折中的办法:
每次读写session都调用 session_start(),session_write_close(),前后加文件读写锁,降低并发的开销,防止页面阻塞 |
|
返回顶楼 | |
发表时间:2009-12-06
仔细想了下,这确实是个问题,之间我还真没仔细考虑过。
用“session race condition”做关键字 google 了下,找到不少文章,找个时间做个整理。 |
|
返回顶楼 | |