php高并发状态下文件的读写
2015-11-18 10:58
691 查看
php高并发状态下文件的读写
背景1、对于PV不高或者说并发数不是很大的应用,不用考虑这些,一般的文件操作方法完全没有问题
2、如果并发高,在我们对文件进行读写操作时,很有可能多个进程对进一文件进行操作,如果这时不对文件的访问进行相应的独占,就容易造成数据丢失
例如:一个在线聊天室(这里假定把聊天内容写入文件),在同一时刻,用户A和用户B都要操作数据保存文件,首先是A打开了文件,然后更新里面的数据,但这 里B也正好也打开了同一个文件,也准备更新里面的数据。当A把写好的文件保存时,这里其实B已经打开了文件。但当B再把文件保存回去时,这里已经造成了数 据的丢失,因为这里B用户完全不知道它所打开的文件在它对其进行更改时,A用户也更改了这个文件,所以最后B用户保存更改时,用户A的更新就被会丢失。
对于这样的问题,一般的解决方案
1、当一进程对文件进行操作时,首先对其它进行加锁
2、这里只有该进程有权对文件进行读取,其它进程如果现在读,是完全没有问题,但如果这时有进程试图想对其进行更新,会遭到操作拒绝,
3、先前对文件进行加锁的进程这时如果对文件的更新操作完毕,这就释放独占的标识,这时文件又恢复到了可更改的状态
4、接下来同理,如果那个进程在操作文件时,文件没有加锁,这时,它就可以放心大胆的对文件进行锁定,独自享用
所以一般的方案会是
所以使用flock之前,一定要慎重考虑。
那么就没有解决方案了吗?其实也不是这样的。如果flock()我们使用得当,完全可能解决死锁的问题。当然如果不考虑使用flock()函数,也同样会有很好的解决方案来解决我们的问题。
方案一:对文件进行加锁时,设置一个超时时间.
大致实现如下:
方案二:不使用flock函数,借用临时文件来解决读写冲突的问题
大致原理如下:
1、将需要更新的文件copy一份到我们的临时文件目录,将文件最后修改时间保存到一个变量,并为这个临时文件取一个随机的,不容易重复的文件名
2、当对这个临时文件进行更新后,再检测原文件的最后更新时间和先前所保存的时间是否一致
3、如果最后一次修改时间一致,就将所修改的临时文件重命名到原文件,为了确保文件状态同步更新,所以需要清除一下文件状态
4、但是,如果最后一次修改时间和先前所保存的一致,这说明在这期间,原文件已经被修改过,这时,需要把临时文件删除,然后返回false,说明文件这时有其它进程在进行操作
大致实现代码如下:
1.rename() 重命名一个文件或一个目录,该函数其实更像linux里的mv。更新文件或者目录的路径或名字很方便,但当在window测试上面代码时,如果新文件名已经存在,会给出一个notice,说当前文件已经存在,在linux下工作的很好
2.clearstatcache();清除文件的状态.php将缓存所有文件属性信息,以提供更高的性能,但有时,多进程在对文件进行删除或者更新操作 时,php没来得及更新缓存里的文件属性,容易导致访问到最后更新时间不是真实的数据。所以这里需要使用该函数对已保存的缓存进行清除。
方案三:对操作的文件进行随机读写,以降低并发的可能性
在对用户访问日志进行记录时,这种方案似乎被采用的比较多
先前需要定义一个随机空间,空间越大,并发的的可能性就越小,这里假设随机读写空间为[1-500],那么我们的日志文件的分布就为log1~到log500不等。每一次用户访问,都将数据随机写到log1~log500之间的任一文件
在同一时刻,有2个进程进行记录日志,A进程可能是更新的log32文件,而B进程呢?则此时更新的可能就为log399.要知道,如果要让B进程也操作log32,概率基本上为1/500,差不多约等于零
在需要对访问日志进行分析时,这里我们只需要先将这些日志合并,再进行分析即可
使用这种方案来记录日志的一个好处时,进程操作排队的可能性比较小,可以使进程很迅速的完成每一次操作
方案四:将所有要操作的进程放入一个队列中。然后专门放一个服务完成文件操作
队列中的每一个排除的进程相当于第一个具体的操作,所以第一次我们的服务只需要从队列中取得相当于具体操作事项就可以了,如果这里还有大量的文件操作进程,没关系,排到我们的队列后面即可,只要愿意排,队列的多长都没关系。
对于以前几种方案,各有各的好处!大致可能归纳为两类:
1、需要排队(影响慢)比如方案一、二、四
2、不需要排队。(影响快)方案三
在设计缓存系统时,一般我们不会采用方案三。因为方案三的分析程序和写入程序是不同步的,在写的时间,完全不考虑到时候分析的难度,只管写的行了。试想一 下,如我们在更新一个缓存时,如果也采用随机文件读写法,那么在读缓存时似乎会增加很多流程。但采取方案一、二就完全不一样,虽然写的时间需要等待(当获 取锁不成功时,会反复获取),
但读文件是很方便的。添加缓存的目的就是要减少数据读取瓶颈,从而提高系统性能。
原文地址:http://hqlong.com/2009/01/530.html
相关文章推荐
- php调用COM组件
- php 生成唯一id的几种解决方法
- php生成唯一数字id的方法汇总
- Zend Studio 12.0.2源码自动格式化
- yii2 RESTful 接口 api -3 : 账户验证 和 速度控制
- yii2 RESTful 接口 api -2 : 写自己的接口方法search
- yii2 RESTful 接口 api -1 : 接口的基本配置
- php利用stream_socket_server与stream_socket_client
- Statement、PreparedStatement和CallableStatement
- 10.php Html下利用php循环创建组件
- PHP 底层的运行机制与原理
- ContentProvider
- php:订单号和时区
- 基于PHP给大家讲解防刷票的一些技巧
- 浅谈 PHP 与手机 APP 开发(API 接口开发)
- 使用PHP uniqid函数生成唯一ID
- php中文件操作
- 使用PHP实现生成HTML静态页面
- 在editplus中删除多余空行
- 为什么调用 FragmentPagerAdapter.notifyDataSetChanged() 没有更新其 Fragment?