0%

PHP使用Redis做队列处理

目前阻塞队列和异步队列两种方式都有使用,具体选择哪种可根据项目具体情况进行选择,我顺便已经做了优缺点了罗列

阻塞队列

  1. 生成uuid
  2. 插入到redis List
  3. 通过当前的uuid和队列第一条对比是否相等,相等则进行业务处理并弹出队列,否则等待
  4. 超过等待时间,弹出队列(走异常处理)

优点:代码实现简单,不影响原代码逻辑,在外部嵌套一层即可,可以迅速实现排队处理数据的需求

缺点:会阻塞请求,超时等待时间不能大于nginx超时时间,否则一个超时,后边的全部超时

$result = $this->loadLogic('product_logic')->getLock(array($this, 'editTeamByParams'), array($params));

异步队列

  1. 生成uuid
  2. 插入到redis List
  3. 保存请求url、入参到db
  4. 用php-cli方式从队列中取第一条数据
  5. 处理后弹出队列

优点:不会阻塞请求,接口响应迅速,适合大量请求处理

缺点:方式不是很简单,需要有一个插入队列的方法,一个处理队列数据的方法,还需要一个队列的消费者,对原代码逻辑有影响

//插入队列
$result = $this->loadLogic('product_logic', array('db' => true))->getTask(config_item('base_url') . 'api/product/editTeamByTask', $params);

//处理队列数据
public function editTeamByTask(){
//...
}

//队列消费者
public function editTeam(){
$this->loadLogic('product_logic');
while (true) {
$this->product_logic->execEditTeam();

var_dump(date('Y-m-d H:i:s'));
sleep(1);
}
}

生成唯一id的方法

使用redis生成唯一id,保证分布式系统中唯一,参考https://github.com/hebaoxia/generate-uuid

/**
* 通过redis生成uuid
*
* @param integer $length
* @return void 2018071900000357
*/
public function getUUID($length = 16){
if (!isset(self::$ci->redis)) {
self::$ci->redis = new Redis();
self::$ci->redis->connect(config_item('ERP_REDIS_HOST'),config_item('ERP_REDIS_PORT'));
if (config_item('ERP_REDIS_PASSWORD')) self::$ci->redis->auth(config_item('ERP_REDIS_PASSWORD')); //密码验证
}
$redis = self::$ci->redis;
$table = 'uuidGenerator';
$today = date('Ymd');
$maxLen = $length - strlen($today);
$counter = $redis->hIncrBy($table, $today, 1);
$counterLen = strlen($counter);
if ($counterLen > $maxLen) {
return false;
}
if ($counter == 1 && $redis->hLen($table) > 7) {
$this->cleanGenerator(7);
}
return $today . str_repeat('0', ($maxLen - $counterLen)) . $counter;
}

请我喝杯咖啡吧 Coffee time !