使用redis把队列的异步返回改成同步 - 队列使用
程序员文章站
2022-04-27 15:13:25
...
web编程开发中,会遇到资源争用的情况。举例:
有多个商品,商品抢单,每个商品都有数量限制。
但凡遇到此类问题,自古以来,就有两种解决方式:1、使用锁,2、使用队列。
使用任意一个就可以。
使用队列的方式最为简单,不考虑加锁。也无需使用数据库的锁。
把所有的请求都放入队列,然后把队列处理的结果返回给客户端。每次都查询商品的剩余数量是否为0,为0就拒绝请求。
如果商品太多,可以按商品大类分成多个队列。这样处理速度快些。
现在的问题是:队列是异步返回的,怎么办呢?
构思场景,进程A处理web请求(会同时有多个类似A的进程出现),进程B是队列,进程C是监听队列的守护进程。
简单的做法是:A把请求放入队列,然后进程C处理好直接异步通知客户端,但这得有nodejs之类的长连接帮助。因为要推送。
所以使用如下方案解决:
使用redis把队列的异步返回改成同步
1、添加redis守护进程D。
新的场景:进程A处理web请求(会同时有多个类似A的进程出现),进程B是队列,进程C是监听队列的守护进程。进程D是redis。
2、web请求进程A:
创建一个随机数random。
把处理消息发给队列,但是把random加入到消息里。
使用 $result = $redis->blPop(random, 30);// 30秒是等待时间,
$redis->delete(random); // 取出消息后,这个键就没用了。
BLPOP是列表的阻塞式(blocking)弹出原语。
它是LPOP命令的阻塞版本,当给定列表内没有任何元素可供弹出的时候,连接将被BLPOP命令阻塞,直到等待超时或发现可弹出元素为止。
然后只要从$result中获取进程C的返回即可。
3、守护进程C:
把rendom从消息中取出,处理整条消息,得到结果。
然后把结果放到以random为键名称的redis的列表里。即可。
$redis->lPush(random, '处理结果');//这句话执行完后,进程A的blPop方法会立刻返回!
4、缺点:
此方案没什么缺点,只有队列本身的缺点,就是如果并发请求太多,处理不过来,则客户端需要等。
解决方案就是添加多个队列,添加多个守护进程处理队列,守护进程和队列也可以分布在不同的服务器。
5、优点:
超级简单,redis很棒。
有多个商品,商品抢单,每个商品都有数量限制。
但凡遇到此类问题,自古以来,就有两种解决方式:1、使用锁,2、使用队列。
使用任意一个就可以。
使用队列的方式最为简单,不考虑加锁。也无需使用数据库的锁。
把所有的请求都放入队列,然后把队列处理的结果返回给客户端。每次都查询商品的剩余数量是否为0,为0就拒绝请求。
如果商品太多,可以按商品大类分成多个队列。这样处理速度快些。
现在的问题是:队列是异步返回的,怎么办呢?
构思场景,进程A处理web请求(会同时有多个类似A的进程出现),进程B是队列,进程C是监听队列的守护进程。
简单的做法是:A把请求放入队列,然后进程C处理好直接异步通知客户端,但这得有nodejs之类的长连接帮助。因为要推送。
所以使用如下方案解决:
使用redis把队列的异步返回改成同步
1、添加redis守护进程D。
新的场景:进程A处理web请求(会同时有多个类似A的进程出现),进程B是队列,进程C是监听队列的守护进程。进程D是redis。
2、web请求进程A:
创建一个随机数random。
把处理消息发给队列,但是把random加入到消息里。
使用 $result = $redis->blPop(random, 30);// 30秒是等待时间,
$redis->delete(random); // 取出消息后,这个键就没用了。
BLPOP是列表的阻塞式(blocking)弹出原语。
它是LPOP命令的阻塞版本,当给定列表内没有任何元素可供弹出的时候,连接将被BLPOP命令阻塞,直到等待超时或发现可弹出元素为止。
然后只要从$result中获取进程C的返回即可。
3、守护进程C:
把rendom从消息中取出,处理整条消息,得到结果。
然后把结果放到以random为键名称的redis的列表里。即可。
$redis->lPush(random, '处理结果');//这句话执行完后,进程A的blPop方法会立刻返回!
4、缺点:
此方案没什么缺点,只有队列本身的缺点,就是如果并发请求太多,处理不过来,则客户端需要等。
解决方案就是添加多个队列,添加多个守护进程处理队列,守护进程和队列也可以分布在不同的服务器。
5、优点:
超级简单,redis很棒。
下一篇: PHP迭代器模式与环形链表