米扑项目中有这样的场景

1. 生成文件的时候,由于多个用户同时都有权限进行写入生成,并发请求下会导致生成的结果出现错误,因此需要对生成的过程进行加锁。同一时刻只容许一个用户进行操作,这个时候就需要用到锁了,将这个操作过程锁起来.

2. 在用了cache的时候,cache失效可能导致瞬间的多数并发请求,穿透到数据库此时也可以得需要用锁在同一并发的过程中将这个操作锁定.

 

针对以上的2种情况,现在的解决方法是对处理过程进行锁机制,通过PHP实现如下

用到了Eaccelerator的内存锁 和 文件锁,原理如下:

1. 判断系统中是否安了EAccelerator 如果有则使用内存锁,如果不存在,则进行文件锁

2. 根据带入的key的不同,可以实现多个锁直接的并行处理,类似Innodb的行级锁

 

PHP eAccelerator 安装

eAccelerator 官网: http://eaccelerator.net

eAccelerator Github: https://github.com/eaccelerator/eaccelerator

eAccelerator 下载最新版安装包,解压安装包,进入解压后的文件夹目录

 

场景里使用如下:

$lock = new CacheLock('key_name');
$lock->lock();
// logic code here
$lock->unlock();
//使用过程中需要注意下文件锁所在路径需要有写权限.

 

PHP加锁类如下:

<?php

/**
 * CacheLock进程锁,主要用来当cache失效时的单进程cache获取,防止过多的SQL请求穿透到数据库导致脏数据
 * 用于解决PHP在并发时候的锁控制,通过文件eaccelerator进行进程间锁定
 * 如果没有使用eaccelerator则进行进行文件锁处理,会做对应目录下产生对应粒度的锁
 * 使用了eaccelerator则在内存中处理,性能相对较高
 * 不同的锁之间并行执行,类似mysql innodb的行级锁
 * 本类在phplock的基础上做了少许修改  http://code.google.com/p/phplock 
 * @author mimvp.com
 *
 */
Class CacheLock {
	private $path = null;				// 文件锁存放路径
	private $fp = null;					// 文件句柄
	private $hashnum = 100;				// 锁粒度,设置值越大,粒度越小
	private $name;						// cache key
	private $eAccelerator = false;		// eAccelerator存在标志 true - 存在; false - 不存在
	
	public function __construct($name, $path='./') {
		$this->eAccelerator = function_exists("eAccelerator_lock");		// 缓存路径
		if(!$this->eAccelerator) {
			$this->path = $path.($this->_mycrc32($name) % $this->hashnum) . '.txt';		// 文件路径, 例如: ./97.txt
		}
		$this->name = $name;
	}
	
	private function _mycrc32($string) {
		$crc = abs(crc32($string));
		if($crc & 0x80000000) {
			$crc ^= 0xffffffff;
			$crc += 1;
		}
		return $crc;
	}
	
	// 上锁
	public function lock() {
		if($this->eAccelerator) {
			return eaccelerator_lock($this->name);
		} 
		else {
			$this->fp = fopen($this->path, 'w+');
			if($this->fp === false) {
				return false;
			}
			return flock($this->fp, LOCK_EX);	// 独占锁定
		}
	}
	
	// 解锁
	public function unlock() {
		if($this->eAccelerator) {
			return eaccelerator_unlock($this->name);
		}
		else {
			if($this->fp !== false) {
				flock($this->fp, LOCK_UN);		// 释放锁定
				clearstatcache();				// 清除文件状态缓存
			}
			fclose($this->fp);		// 关闭文件句柄
		}
	}
}


$lock = new CacheLock("key_name");
$lock->lock();

// logic code here
echo 'https://blog.mimvp.com';

$lock->unlock();
?>

 

 

参考推荐

PHP eAccelerator 安装与使用

PHP 多线程的应用实例

PHP 多线程抓取网页

PHP Pthread多线程操作