eftec / usagimq
单文件版的Laravel Blade模板引擎
Requires
- php: >=5.4
This package is auto-updated.
Last update: 2024-09-07 07:05:25 UTC
README
UsagiMQ
使用Redis和PHP在单个盒子(一个类)中实现的简约消息队列(少于500行代码)
为什么我应该使用消息队列(MQ)?
让我们来看一个例子,一个系统将信息发送到另一个系统,例如一个Web客户端和一个Web服务。
如果Web服务正在执行一个 慢操作 并且同时接收来自许多客户端的信息,那么,迟早,系统可能会崩溃或出现瓶颈。
例如,如果每个客户端完成操作(接收信息并存储在数据库中)需要0.1秒,而我们有1000名客户,那么每个操作可能需要1.6分钟。
解决方案是在系统中添加一个消息队列。消息队列只是一个存储由发布者接收的消息/操作的服务器,之后订阅者可以执行。
对于同样的例子,发布者(以前的客户端)可以以0.001秒的速度调用MQ。然后订阅者可以执行所有操作,例如每小时或夜间,不必担心所有操作需要几分钟或几小时。
MQ应该尽可能快,能够监听和存储每个发布者的请求(信封)。然而,MQ并不执行最终操作,它类似于电子邮件服务器。稍后,订阅者可以读取这些信息并相应处理。
这种方法的一个缺点是它增加了延迟,处理过程不是同步执行的,而是异步执行的,发布者不知道信息是否被订阅者正确处理。
注意事项
这个库使用Redis。Redis是一个开源(BSD许可)的内存数据结构存储,用作数据库、缓存和消息代理。
为什么选择UsagiMQ?
虽然市场上有很多消息队列(包括开源、免费软件和商业),但它们大多数都是重量级的。UsagiMQ是轻量级的,它是在考虑定制的情况下开发的。你可以优化和定制它以满足你的需求,例如,改变信封的结构。
这是一个基于软件的解决方案,可以根据你的需求进行 重新编程。而大多数MQ都是基于 配置的。
例如,你可以轻松地通过软件创建一个 ORCHESTRATION、CHOREOGRAPHY 或 CLUSTER。
UsagiMQ轻量级
- 一个类,它需要Redis,不需要更多。
- < 500行代码。
- 易于定制。
- 它只需要一个文件(UsagiMQ.php)
它是可扩展的吗?
是的,但它需要一个负载均衡器,你可以编程或使用软件或硬件解决方案。由你决定。
信封结构
- id = 信封的标识(必需)。
- from = 发送信封的人(可选)
- body = 信封的内容(必需)。
- date = 收到信封的日期。(必需,自动生成)
- try = 尝试次数。(必需,用于将来,自动生成)
MQ服务器
谁在监听和存储信封(请求)。它应该尽可能快。
示例
include "UsagiMQ.php";
$usa=new UsagiMQ("127.0.0.1",6379,1);
if ($usa->connected) {
$info=$usa->receive();
if ($info=='NO INFO') {
$usa->webUI(); // if not information is send, then it opens the UI. It is optional
} else {
echo $info; // show the result.
}
} else {
echo "not connected";
}
示例MQ服务器调用工作者(订阅者)。请参阅示例:mqwithworker.php
发布者(谁发送请求/信封)
发布者需要向页面发送POST请求。因此可以是CURL、JavaScript、PHP、Java、C#等。
URL应该是这样的:mq.php?id=ID&op=OP&from=FROM
而信封(内容)应以POST方式发送。
- ID是消息的标识(必需,但不一定是唯一的)
- OP是要执行的操作。它类似于文件夹或分类。
- FROM是发送消息的人。它可以用于身份验证。
<?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "http://localhost/UsagiMQ/mq.php?id=200&op=INSERTCUSTOMER&from=SALESSYSTEM" );
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1 );
curl_setopt($ch, CURLOPT_POST, 1 );
curl_setopt($ch, CURLOPT_POSTFIELDS, "** IT IS WHAT WE WANT TO SEND**" );
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: text/plain'));
$result=curl_exec ($ch);
echo $result; // if returns OKI then the operation was successful. Otherwise, it an error.
订阅者(本地)
这是一个本地订阅者(可以访问Redis)。然而,它可以用于创建远程订阅者。
可能它可以作为一个守护进程/在计划任务中/或根据请求运行。
示例
<?php
// its a local subscriber
include "UsagiMQ.php";
$usa=new UsagiMQ("127.0.0.1",6379,1);
if (!$usa->connected) {
echo "not connected";
die(1);
}
$listEnveloper=$usa->listPending("insert");
foreach($listEnveloper as $id) {
$env=$usa->readItem($id);
var_dump($env);
// todo: code goes here
// $correct indicates if the operation was successful or not. For example, if the operation was to insert and the operation failed.
// We also could decide to delete it for any case. Its up to us.
if ($correct) {
$usa->deleteItem($id); // YAY!
} else {
$usa->failedItem($id,$env); // booh hiss!.
}
}
命令
构造函数
$usa=new UsagiMQ($IPREDIS,$PORT,$DATABASE);
$IPREDIS表示Redis服务器所在的IP。$PORT(可选)表示Redis端口号(默认值6379)$DATABASE(可选),表示Redis的数据库(默认值为0)
receive()
从发布者接收信息。
listPending($op)
列出每个操作待处理封装器的所有键。
示例
$array=$usa->listPending('insert');
$array=$usa->listPending('update');
readItem($key)
读取一个项目。当读取一个项目时,它不会被删除。一旦处理完毕,应该删除它。键可以通过listPending命令获得。
示例
$usa->readItem('UsagiMQ_insert:2');
deleteItem($key)
删除一个项目。
键可以通过listPending命令获得。
示例
$usa->deleteItem('UsagiMQ_insert:2');
failedItem($key,$arr)
我们将项目标记为失败。失败的项目是我们将再次尝试的项目(直到达到限制)。如果我们尝试失败,那么我们将删除该项目。
- 键可以通过listPending命令获得。
- $arr是包含封装器的数组[id,from,body,date,try]
示例
$usa->failedItem('UsagiMQ_insert:2',array('id'=>2,'from'=>'system','body'=>'xxx','date'=>'2000-01-01','try'=>0));
deleteAll()
删除所有项目和重置计数器。
close()
关闭Redis。这不是必需的。
showUI()
可选。它显示具有统计信息的UI。默认用户名和密码是admin,你应该更改它。
版本
- 2017-11-12 1.0 第一个版本
- 2017-11-14 1.1 添加新成员并修复了listPending操作。现在它是排序的。
- 2017-11-19 1.2 添加UI
- 2017-11-21 1.3 为UI添加新功能。代码仍然少于500行。
- 2018-08-06 1.4 一些修复
待办事项
- 错误控制/日志
- 自述文件中缺少命令
- 自述文件中缺少发布者。