今天无意间看到这个仓库讲php关于 BeanStalkd 的扩展,然后就去了解了一下beanstalkd,才知道它可以用来做队列服务。

话不多说,安装一下试试。

首先 sudo apt search beanstalk 搜索一下发现

Sorting... Done
Full Text Search... Done
awscli/focal-updates,focal-updates 1.18.69-1ubuntu0.20.04.1 all
Universal Command Line Environment for AWS beanstalkd/focal,now 1.11-1 amd64 [installed]
simple, in-memory, workqueue service python-celery-common/focal,focal 4.2.1-5ubuntu1 all
async task/job queue based on message passing (common files) python-celery-doc/focal,focal 4.2.1-5ubuntu1 all
async task/job queue based on message passing (Documentation) python3-celery/focal,focal 4.2.1-5ubuntu1 all
async task/job queue based on message passing (Python3 version) ruby-beaneater/focal,focal 1.0.0-1 all
simple beanstalkd client for Ruby

好了,找到这个beanstalkd了

然后安装

sudo apt-get install beanstalkd

Reading package lists... Done
Building dependency tree
Reading state information... Done
Suggested packages:
doc-base
The following NEW packages will be installed:
beanstalkd
0 upgraded, 1 newly installed, 0 to remove and 90 not upgraded.
Need to get 43.9 kB of archives.
After this operation, 125 kB of additional disk space will be used.
Get:1 http://cn.archive.ubuntu.com/ubuntu focal/universe amd64 beanstalkd amd64 1.11-1 [43.9 kB]
Get:1 http://cn.archive.ubuntu.com/ubuntu focal/universe amd64 beanstalkd amd64 1.11-1 [43.9 kB]
Fetched 31.3 kB in 4s (7,047 B/s)
Selecting previously unselected package beanstalkd.
(Reading database ... 256731 files and directories currently installed.)
Preparing to unpack .../beanstalkd_1.11-1_amd64.deb ...
Unpacking beanstalkd (1.11-1) ...
Setting up beanstalkd (1.11-1) ...
Created symlink /etc/systemd/system/multi-user.target.wants/beanstalkd.service → /lib/systemd/system/beanstalkd.service.
beanstalkd.socket is a disabled or a static unit, not starting it.
Processing triggers for man-db (2.9.1-1) ...
Processing triggers for systemd (245.4-4ubuntu3.11) ...

安装成功,这个东西会监听 11300 端口

然后使用这个工具来看看

监控工具

wget https://github.com/src-d/beanstool/releases/download/v0.2.0/beanstool_v0.2.0_linux_amd64.tar.gz

获取文件后解压

tar -xvzf beanstool_v0.2.0_linux_amd64.tar.gz

然后拷贝到 /usr/local/bin/

sudo cp beanstool_v0.2.0_linux_amd64/beanstool /usr/local/bin/

这样就直接用 beanstool 了

查看当前状态

beanstool stats

结果

+---------+----------+----------+----------+----------+----------+----------+----------+
| Name | Buried | Delayed | Ready | Reserved | Urgent | Waiting | Total |
+---------+----------+----------+----------+----------+----------+----------+----------+
| default | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+---------+----------+----------+----------+----------+----------+----------+----------+

然后使用composer的vendor包

composer require pda/pheanstalk

安装完毕后创建一个input.php文件做生产者

<?php
require __DIR__ . '/vendor/autoload.php'; use Pheanstalk\Pheanstalk; $pheanstalk = Pheanstalk::create('127.0.0.1'); // Queue a Job
$pheanstalk
->useTube('testtube')
->put("job payload goes here\n"); $pheanstalk
->useTube('testtube')
->put(
json_encode(['test' => 'data']), // encode data in payload
Pheanstalk::DEFAULT_PRIORITY, // default priority
30, // delay by 30s
60 // beanstalk will retry job after 60s
);

再创建一个output.php文件做消费者

<?php
require __DIR__ . '/vendor/autoload.php';
use Pheanstalk\Pheanstalk; $pheanstalk = Pheanstalk::create('127.0.0.1'); // we want jobs from 'testtube' only.
$pheanstalk->watch('testtube'); // this hangs until a Job is produced.
$job = $pheanstalk->reserve(); try {
$jobPayload = $job->getData();
// do work. sleep(2);
// If it's going to take a long time, periodically
// tell beanstalk we're alive to stop it rescheduling the job.
$pheanstalk->touch($job);
sleep(2); // eventually we're done, delete job.
$pheanstalk->delete($job);
}
catch(\Exception $e) {
// handle exception.
// and let some other worker retry.
$pheanstalk->release($job);
}

然后执行一下  php input.php

查看 状态

$ beanstool stats
+----------+----------+----------+----------+----------+----------+----------+----------+
| Name | Buried | Delayed | Ready | Reserved | Urgent | Waiting | Total |
+----------+----------+----------+----------+----------+----------+----------+----------+
| default | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| testtube | 0 | 1 | 1 | 0 | 0 | 0 | 2 |
+----------+----------+----------+----------+----------+----------+----------+----------+

我们看到有一个在ready状态,一个在delayed状态,这是由于第二次的put采用了延时30s,然后过一段时间后再看

$ beanstool stats
+----------+----------+----------+----------+----------+----------+----------+----------+
| Name | Buried | Delayed | Ready | Reserved | Urgent | Waiting | Total |
+----------+----------+----------+----------+----------+----------+----------+----------+
| default | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| testtube | 0 | 0 | 2 | 0 | 0 | 0 | 2 |
+----------+----------+----------+----------+----------+----------+----------+----------+

已经有2个在ready状态了。

此时我们用消费者执行一下 php output.php

与此同时迅速看状态

$ beanstool stats
+----------+----------+----------+----------+----------+----------+----------+----------+
| Name | Buried | Delayed | Ready | Reserved | Urgent | Waiting | Total |
+----------+----------+----------+----------+----------+----------+----------+----------+
| default | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| testtube | 0 | 0 | 1 | 1 | 0 | 0 | 2 |
+----------+----------+----------+----------+----------+----------+----------+----------+
再次执行
$ beanstool stats
+----------+----------+----------+----------+----------+----------+----------+----------+
| Name | Buried | Delayed | Ready | Reserved | Urgent | Waiting | Total |
+----------+----------+----------+----------+----------+----------+----------+----------+
| default | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| testtube | 0 | 0 | 1 | 0 | 0 | 0 | 2 |
+----------+----------+----------+----------+----------+----------+----------+----------+

因为我们有sleep(2),所以要尽量快点操作这个状态监控的命令,可以看到有一个拿出来放入了reserved,然后就消失了(实际上这是后面的代码delete导致的,因为已经消费完毕)

再次执行 php output.php

$ beanstool stats
+----------+----------+----------+----------+----------+----------+----------+----------+
| Name | Buried | Delayed | Ready | Reserved | Urgent | Waiting | Total |
+----------+----------+----------+----------+----------+----------+----------+----------+
| default | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| testtube | 0 | 0 | 0 | 1 | 0 | 0 | 2 |
+----------+----------+----------+----------+----------+----------+----------+----------+
$ beanstool stats
+---------+----------+----------+----------+----------+----------+----------+----------+
| Name | Buried | Delayed | Ready | Reserved | Urgent | Waiting | Total |
+---------+----------+----------+----------+----------+----------+----------+----------+
| default | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+---------+----------+----------+----------+----------+----------+----------+----------+

同样也是迅速观测这个状态,发现消费1个,然后删除1个,现在队列空了,这说明确实是符合我们的期望的。

然后回到文章开头提到的扩展,这个扩展就是帮我们实现了composer装的那个pheanstalk包。

这个扩展如何安装呢?

步骤如下:

克隆项目

git clone https://gitee.com/qzfzz/php-beanstalk.git

进行编译

phpize

然后

./configure

之后

make

再 make install

sudo make install

然后修改 php.ini

sudo gedit /etc/php/7.4/cli/php.ini /etc/php/7.4/apache2/php.ini

加上这句

extension=beanstalk

重启apache2

sudo /etc/init.d/apache2 restart

之后就可以使用这个扩展了。

这个扩展它封装为函数了,可以看到他有个例子文件

简单的找了几个例子

<?php

$config = [
'host' => '127.0.0.1',
'port' => 11300
];
$beanstalk_obj = beanstalk_connect($config['host'], $config['port']);
$last_job_id = beanstalk_put($beanstalk_obj, "message detail");
beanstalk_delete($beanstalk_obj, $last_job_id);
$last_job_id = beanstalk_putInTube($beanstalk_obj, 'tubea', "message detail");

可以看到使用 connect 连接, put 塞入新的job消息, putInTube 来塞入指定管道的tubea,delete来删除等等,具体可以看看源代码学习一下,我对比了一下这两种方式实现效率。

第一种采用composer包(我还特意去掉了加载文件所需要的时间)

<?phprequire __DIR__ . '/vendor/autoload.php';

use Pheanstalk\Pheanstalk;

$start = microtime( true );
$pheanstalk = Pheanstalk::create('127.0.0.1'); $pheanstalk
->useTube('testtube')
->put(date("Y-m-d H:i:s") . "job payload goes here\n"); $end = microtime(true); echo ($end - $start) * 1000 . " ms";

执行需要2.59ms

第二种直接用扩展函数

<?php
$start = microtime(true); $config = [
'host' => '127.0.0.1',
'port' => 11300
]; $beanstalk_object = beanstalk_connect($config['host'], $config['port']);
$last_job_id = beanstalk_putInTube($beanstalk_object, 'testtube', date("Y-m-d H:i:s") . "job payload goes here\n"); $end = microtime(true); echo ($end - $start) * 1000 . " ms";

执行需要0.34ms

不得不说,扩展就是扩展,就是快的多啊!

我另外测试了一下投递极限

循环投递10000次消息,大概在500ms左右

$start = microtime( true );
for ($i=0; $i < 10000; $i++) {
$pheanstalk
->useTube('testtube')
->put(date("Y-m-d H:i:s") . "job payload goes here\n");
}
$end = microtime( true );
echo ($end - $start) * 1000 . " ms";

也就意味着1秒钟只能投递20000条消息,这比rabbitmq的投递慢多了(参见这篇文章)

但是它执行1次投递消息的时候却比这个rabbitmq的代码执行的快,原因是我测试了一下这个rabbitmq的连接上就耗费了9ms

$connection = new AMQPStreamConnection('localhost', 5672, 'guest', 'guest');

更别提还有这两步了

$channel = $connection->channel();
$channel->queue_declare('hello', false, false, false, false);

这样来看,想迅速投递一条短消息,或者建立小信息量的job用beanstalk是很不错的,如果有大量消息集中投递,那使用 rabbitmq 是很不错的。

另外这个beanstalk投递可以延时,非常适合有些时候需要在当前时间一段时间后执行某个任务,往后弄个类似于一次性的定时器的功能,这个东西值得尝试。

而且如果使用while死循环将 output.php 脚本一直挂着跑,它就能一直消费消息了,这样就等于有个后端进程一直能帮我们做消费者处理堆积的任务了,特殊场景可以考虑一下这个方案。

BeanStalkd 做队列服务的更多相关文章

  1. 快速入门系列--WCF--06并发限流、可靠会话和队列服务

    这部分将介绍一些相对深入的知识点,包括通过并发限流来保证服务的可用性,通过可靠会话机制保证会话信息的可靠性,通过队列服务来解耦客户端和服务端,提高系统的可服务数量并可以起到削峰的作用,最后还会对之前的 ...

  2. 跟我一起学WCF(11)——WCF中队列服务详解

    一.引言 在前面的WCF服务中,它都要求服务与客户端两端都必须启动并且运行,从而实现彼此间的交互.然而,还有相当多的情况希望一个面向服务的应用中拥有离线交互的能力.WCF通过服务队列的方法来支持客户端 ...

  3. 【阿里云产品公测】消息队列服务MQS java SDK 机器人应用初体验

    [阿里云产品公测]消息队列服务MQS java SDK 机器人应用初体验 作者:阿里云用户啊里新人   初体验 之 测评环境 由于MQS支持外网访问,因此我在本地做了一些简单测试(可能有些业余),之后 ...

  4. 转:基于HTTP协议的轻量级开源简单队列服务:HTTPSQS

    [文章作者:张宴 本文版本:v1.7.1 最后修改:2011.11.04 转载请注明原文链接:http://blog.zyan.cc/httpsqs/] HTTPSQS(HTTP Simple Que ...

  5. WCF中队列服务详解

    WCF中队列服务详解 一.引言 在前面的WCF服务中,它都要求服务与客户端两端都必须启动并且运行,从而实现彼此间的交互.然而,还有相当多的情况希望一个面向服务的应用中拥有离线交互的能力.WCF通过服务 ...

  6. 基于Redis实现延时队列服务

    背景 在业务发展过程中,会出现一些需要延时处理的场景,比如: a.订单下单之后超过30分钟用户未支付,需要取消订单 b.订单一些评论,如果48h用户未对商家评论,系统会自动产生一条默认评论 c.点我达 ...

  7. 基于HTTP协议的轻量级开源简单队列服务:HTTPSQS 笔记

    队列服务就是为了提高相应速度,把耗时或者不需要即时处理的流程放到异步处理过程中,HTTPSQS就是这样一个服务. 更详细的可以参考 http://blog.s135.com/httpsqs/,这里记录 ...

  8. 【转】基于Redis实现延时队列服务

    背景 在业务发展过程中,会出现一些需要延时处理的场景,比如: a.订单下单之后超过30分钟用户未支付,需要取消订单b.订单一些评论,如果48h用户未对商家评论,系统会自动产生一条默认评论c.点我达订单 ...

  9. 基于HTTP协议的轻量级开源简单队列服务:HTTPSQS[转]

    HTTPSQS(HTTP Simple Queue Service)是一款基于 HTTP GET/POST 协议的轻量级开源简单消息队列服务,使用 Tokyo Cabinet 的 B+Tree Key ...

  10. RabbitMQ与Redis做队列比较

    本文仅针对RabbitMQ与Redis做队列应用时的情况进行对比 具体采用什么方式实现,还需要取决于系统的实际需求简要介绍RabbitMQRabbitMQ是实现AMQP(高级消息队列协议)的消息中间件 ...

随机推荐

  1. 安装vsftp服务器的时候遇到的问题

    安装vsftp服务器的时候遇到的问题 环境说明: 系统:阿里云centos7 面板:宝塔面板 问题描述: 在centos7中安装VSFTP的时候,使用命令行,ftp 然后输入用户名和密码,登陆之后,p ...

  2. Seata 1.3.0 ERROR i.s.c.r.n.NettyClientChannelManager -no available service 'null' found, please make sure registry config correct

    根据个人经验,报这个错误是因为nacos里并没有同步seata的config导致的 配置文档:https://www.bookstack.cn/read/seata-1.3.0/4b2f4de4831 ...

  3. MyBatis 从入门到放弃 ( MyBatis基础总结 )

    目录 MyBatis历史 Mybatis特性 MyBatis下载 和其它持久化层技术对比 开发环境 创建maven工程 创建MyBatis的核心配置文件 创建mapper接口 创建MyBatis的映射 ...

  4. C语言浮点数转字符串实现函数

    C语言浮点数转字符串可用库函数sprintf,此处为编写的简单函数. 小数部分最多显示六位. pOut:输出字符串缓冲区 f:浮点数值 isize:输出字符串缓冲区大小 char * Funftoa( ...

  5. 【Azure Policy】使用deployIfNotExists 把 Azure Activity logs 导出保存在Storage Account

    问题描述 使用Azure Policy,对订阅下的全部Activity Log配置Diagnostic Setting,要求: 在Subscription或Management Group级别,针对未 ...

  6. ToCom:一次训练随意使用,华为提出通用的ViT标记压缩器 | ECCV 2024

    标记压缩通过减少冗余标记的数量(例如,修剪不重要的标记或合并相似的标记)来加快视觉变换器(ViTs)的训练和推理.然而,当这些方法应用于下游任务时,如果训练和推理阶段的压缩程度不匹配,会导致显著的性能 ...

  7. 通用能力及AI核心能力表现优异!合合信息智能文档处理系统(IDP)高评级通过中国信通院评估

    数字经济快速发展的背后,全球数据总量呈现出爆发式增长趋势.智能文档处理(IDP)技术能够高效地从多格式文档中捕捉.提取和处理数据,帮助机构和企业大幅提升文档处理效率,节约时间和人力成本.近期,合合信息 ...

  8. DOM – Work with Document.styleSheets and JS/Scss Breakpoint Media Query

    前言 为了方便管理, 我们会定义 CSS Variables, 类似于全局变量. 有时候做特效的时候还需要 JavaScript 配合, 这时就会希望 JavaScript 可以获取到 CSC Var ...

  9. vue前端开发仿钉图系列(5)右侧编辑页面的开发详解

    右侧编辑页面主要有两个入口,一是添加marker或者线面双击结束的时候,新建数据信息:二是点击底部数据的单元行或者查看编辑或者点击地图上的marker以及线面,编辑相关数据.整理总结不易,如需全部代码 ...

  10. 1. C#面试题 - Webservice和WebApi的区别

    1. Webservice : 基于SOAP协议的,数据格式时XML,只支持http协议,不是开源的,只能部署在IIS上 2. Webapi 开源的,.net 平台