PHP7生产环境队列Beanstalkd用法详解


Posted in PHP onMay 19, 2020

应用场景

为什么要用呢,有什么好处?这应该放在最开头说,一件东西你只有了解它是干什么的,适合干什么,才能更好的与自己的项目相结合,用到哪里学到哪里,学了不用等于不会,我们平时就应该多考虑一些这样的问题:自己做个什么项目功能能跟 xx 技术相结合呢?这个 xx 技术放在这种业务场景下行不行呢?而不是 “学了这个 xx 技术能干嘛呢,公司现在也没有用这个的呀,学了也没用啊”,带着这样心情去学习 xx 技术,肯定很痛苦。

队列大家都知道是将一些耗时的操作先不去做,先埋点,再异步去处理,这样对一些发邮件发短信之类的耗时操作,用户是感觉不到的,因为埋点结束,操作也就结束了,消费队列都是在服务器上做的。主要应用在短信或邮件通知,访问第三方接口订阅消息,商城的一些秒杀活动,都可以结合队列来完成。

Beanstalkd 介绍

Beanstalkd 是一个高性能,轻量级的分布式内存队列,C 代码,典型的类 Memcached 设计,协议和使用方式都是同样的风格,所以使用过 memcached 的用户会觉得 Beanstalkd 似曾相识。

beanstalkd 的最初设计意图是在高并发的网络请求下,通过异步执行耗时较多的请求,及时返回结果,减少请求的响应延迟。

Ubuntu 安装

sudo apt-get install beanstalkd

配置文件

vim /etc/default/beanstalkd

查看状态

service beanstalkd status
# 命令回显 #
root@:/www/server/php/72/etc# service beanstalkd status
● beanstalkd.service - Simple, fast work queue
  Loaded: loaded (/lib/systemd/system/beanstalkd.service; enabled; vendor preset: enabled)
  Active: active (running) since Tue 2018-10-16 10:42:28 CST; 6 days ago
   Docs: man:beanstalkd(1)
 Main PID: 7033 (beanstalkd)
  Tasks: 1 (limit: 4634)
  CGroup: /system.slice/beanstalkd.service
      └─7033 /usr/bin/beanstalkd -l 0.0.0.0 -p 11300 -b /var/lib/beanstalkd
Oct 16 10:42:28 ip-10-93-2-137 systemd[1]: Started Simple, fast work queue.

配置连通性 + 持久化

ip 用 0.0.0.0 允许所有连接,靠配置安全组或防火墙去约束连接,放开 -b 参数 (默认没有持久化),内存的队列消息可以落地到硬盘 binlog 实现持久化,断电可重新读取队列消息。

vim /etc/default/beanstalkd
BEANSTALKD_LISTEN_ADDR=0.0.0.0
BEANSTALKD_LISTEN_PORT=11300
BEANSTALKD_EXTRA="-b /var/lib/beanstalkd"

beanstalkd 任务状态

状态 注释
delayed 延迟状态
ready 准备好状态
reserved 消费者把任务读出来,处理时
buried 预留状态
delete 删除状态

管理工具

亲测了很多网上能找到的 beanstalkd 工具,这两款是我最中意的了,一个命令行,一个 web 的。

命令行:https://github.com/src-d/beanstool

web 界面:https://github.com/ptrofimov/beanstalk_console

编程语言客户端

PHP 客户端

https://packagist.org/packages/pda/pheanstalk

composer require pda/pheanstalk

写入 job

<?php
//创建队列消息
require_once('./vendor/autoload.php');
use Pheanstalk\Pheanstalk;
$pheanstalk = new Pheanstalk('127.0.0.1',11300);
$tubeName = 'email_list';
$jobData = [
  'email' => '123456@163.com',
  'message' => 'Hello World !!',
  'dtime' => date('Y-m-d H:i:s'),
];
$pheanstalk->useTube( $tubeName)->put( json_encode( $jobData ) );

消费 job

<?php
ini_set('default_socket_timeout', 86400*7);
ini_set( 'memory_limit', '256M' );
// 消费队列消息
require_once('./vendor/autoload.php');
use Pheanstalk\Pheanstalk;
$pheanstalk = new Pheanstalk('127.0.0.1',11300);
$tubeName = 'email_list';
while ( true )
{
  // 获取队列信息, reserve 阻塞获取
  $job = $pheanstalk->watch( $tubeName )->ignore( 'default' )->reserve();
  if ( $job !== false )
  {
    $data = $job->getData();
    /* TODO 逻辑操作 */
    /* 处理完成,删除 job */
    $pheanstalk->delete( $job );
  }
}

default_socket_timeout 这个参数是一定要加的,php 默认一般是 60s,假如您没有在代码里面设置,采用默认的话(60s),60s 之内如果没有 job 产生,脚本就会报 socket 错误,我写的是 7 天超时,您可以根据业务去调整,记住一定要配置,网上很多搜的 consumer 脚本都没有配置这个,根本不能投入生产环境使用,这是我亲自实践的结果。

关于 while true 是否死循环,很明确告诉你是死循环,但是不会一直耗性能的那样执行下去,它会在 reserve 这里阻塞不动,直到有消息产生才会往下走,所以大可放心使用,我的项目代码里面是使用了方法调用方法自身去实现循环的。

就是这样的代码,供参考:

public function watchJob()
{
  $job = $this->pheanstalk->watch( config( 'tube' ) )->ignore( 'default' )->reserve();
  if ( $job !== false )
  {
    $job_data = $job->getData();
    $this->subscribe( $job_data );
    $this->pheanstalk->delete( $job );
    /* 继续 Watch 下一个 job */
    $this->watchJob();
  }
  else
  {
    $this->log->error( 'reserve false', 'reserve false' );
  }
}

监控 beanstalkd 状态

<?php
//监控服务状态
require_once('./vendor/autoload.php');
use Pheanstalk\Pheanstalk;
$pheanstalk = new Pheanstalk('127.0.0.1',11300);
$isAlive = $pheanstalk->getConnection()->isServiceListening();
var_dump( $isAlive );

可以配合 email 做一个报警邮件,脚本每分钟去执行,判断状态是 false,就给管理员发送邮件报警。

一些相关命令

查看 beanstalkd 服务内存占用

top -u beanstalkd

后台运行 consumer 脚本

nohup php googlehome_subscribe.php &

查看 consumer 脚本运行时间

ps -A -opid,stime,etime,args | grep consumer.php

手工重启 consumer 脚本

ps auxf|grep 'googlehome_subscribe.php'|grep -v grep|awk '{print $2}'|xargs kill -9 
nohup php googlehome_subscribe.php &

一些总结

php 要把错误日志打开,方便收集 consumer 脚本 crash 的 log,脚本跑出一些致命的 error 一定要及时修复,因为一旦有错就会挂掉,这会影响你脚本的可用性,后期稳定之后可以上 supervisor 这种进程管理程序来管控脚本生命周期。

一些网络请求操作,一定要 try catch 到所有错误,一旦没有 catch 到,脚本就崩。我用的是 Guzzle 去做的网络请求,下面是我 catch 的一些错误,代码片段供参考。

try
{
  /* TODO: 逻辑操作 */
}
catch ( ClientException $e )
{
  $results['mid']  = $this->mid;
  $results['code']  = $e->getResponse()->getStatusCode();
  $results['reason'] = $e->getResponse()->getReasonPhrase();
  $this->log->error( 'properties-changed ClientException', $results );
}
catch ( ServerException $e )
{
  $results['mid']  = $this->mid;
  $results['code']  = $e->getResponse()->getStatusCode();
  $results['reason'] = $e->getResponse()->getReasonPhrase();
  $this->log->error( 'properties-changed ServerException', $results );
}
catch ( ConnectException $e )
{
  $results['mid'] = $this->mid;
  $this->log->error( 'properties-changed ConnectException', $results );
}

job 消费之后一定要删除掉,如果长时间不删除,php 客户端会有 false 返回,是因为有 DEADLINE_SOON 这个超时错误产生,所以处理完任务,一定要记得删除,这一点跟 kafka 不一样,beanstalkd 需要开发者自己去删除 job。

以上就是PHP7生产环境队列Beanstalkd用法详解的详细内容,更多关于PHP7中Beanstalkd正确用法的资料请关注三水点靠木其它相关文章!

PHP 相关文章推荐
COM in PHP (winows only)
Oct 09 PHP
php读取EXCEL文件 php excelreader读取excel文件
Dec 06 PHP
深入理解PHP几个算法:PHP冒泡、PHP二分法、PHP求素数、PHP乘法表
Jun 06 PHP
使用cookie实现统计访问者登陆次数
Jun 08 PHP
如何批量清理系统临时文件(语言:C#、 C/C++、 php 、python 、java )
Feb 01 PHP
Yii2搭建后台并实现rbac权限控制完整实例教程
Apr 28 PHP
php 输出json及显示json中的中文汉字详解及实例
Nov 09 PHP
自制PHP框架之路由与控制器
May 07 PHP
PHP 断点续传实例详解
Nov 11 PHP
thinkPHP框架动态配置用法实例分析
Jun 14 PHP
Yii框架函数简单用法分析
Sep 09 PHP
php的instanceof和判断闭包Closure操作示例
Jan 26 PHP
PHP项目多语言配置平台实现过程解析
May 18 #PHP
Yii 框架使用Forms操作详解
May 18 #PHP
thinkphp 框架数据库切换实现方法分析
May 18 #PHP
PHP接口类(interface)的定义、特点和应用示例
May 18 #PHP
php + ajax 实现的写入数据库操作简单示例
May 16 #PHP
PHP date_default_timezone_set()设置时区操作实例分析
May 16 #PHP
Yii框架应用组件用法实例分析
May 15 #PHP
You might like
yii框架源码分析之创建controller代码
2011/06/28 PHP
json的键名为数字时的调用方式(示例代码)
2013/11/15 PHP
PHP图片自动裁切应付不同尺寸的显示
2014/10/16 PHP
详解PHP序列化和反序列化原理
2018/01/15 PHP
PHP基于openssl实现的非对称加密操作示例
2019/01/11 PHP
Aster vs Newbee BO3 第二场2.18
2021/03/10 DOTA
IE 缓存策略的BUG的解决方法
2007/07/21 Javascript
Struts2的s:radio标签使用及用jquery添加change事件
2013/04/08 Javascript
open 动态修改img的onclick事件示例代码
2013/11/13 Javascript
NodeJS制作爬虫全过程
2014/12/22 NodeJs
Javascript中innerHTML用法实例分析
2015/01/12 Javascript
vuex实现简易计数器
2016/10/27 Javascript
javaScript 逻辑运算符使用技巧整理
2017/05/03 Javascript
基于Bootstrap table组件实现多层表头的实例代码
2017/09/07 Javascript
vue 使用html2canvas将DOM转化为图片的方法
2018/09/11 Javascript
微信小程序自定义弹窗wcPop插件
2018/11/19 Javascript
JS实现电商商品展示放大镜特效
2020/01/07 Javascript
vue组件入门知识全梳理
2020/09/21 Javascript
JS画布动态实现黑客帝国背景效果
2020/11/08 Javascript
Python3 正在毁灭 Python的原因分析
2014/11/28 Python
Python线程中对join方法的运用的教程
2015/04/09 Python
python实现员工管理系统
2018/01/11 Python
python机器学习理论与实战(四)逻辑回归
2018/01/19 Python
python使用sqlite3时游标使用方法
2018/03/13 Python
PyQt5实现拖放功能
2018/04/25 Python
Python实现的绘制三维双螺旋线图形功能示例
2018/06/23 Python
推荐WEB开发者最佳HTML5和CSS3代码生成器
2015/11/24 HTML / CSS
Wiggle中国:英国骑行、跑步、游泳 & 铁三运动装备专卖网店
2016/08/02 全球购物
日本钓鱼渔具和户外用品网上商店:naturum
2016/08/07 全球购物
Shell如何接收变量输入
2012/09/24 面试题
珍惜资源的建议书
2014/08/26 职场文书
财务助理岗位职责范本
2014/10/09 职场文书
2015感人爱情寄语
2015/02/26 职场文书
2015年安全工作总结范文
2015/04/02 职场文书
小学教师见习总结
2015/06/23 职场文书
公司保洁员管理制度
2015/08/04 职场文书