PHP 消息队列 详解

前言:之前做过的一些项目中有时候会接触到消息队列,但是对消息队列并没有一个很清楚的认知,本篇文章将会详细分析和归纳一些笔记,以供后续学习。

 

一、消息对列概念

从本质上说消息对列就是一个队列结构的中间件,也就是说消息放入这个中间件之后就可以直接返回,并不需要系统立即处理,而另外会有一个程序读取这些数据,并按顺序进行逐次处理。

 

二、结构

由一个业务系统进行入队,把消息逐次插入到消息队列中,插入成功之后直接返回成功的结果,后续会有一个消息处理系统,这个系统会把消息系统中的记录逐次进行取出并进行处理,完成一个出队的流程。

 

 

三、应用场景

1、数据冗余:比如订单系统,后续需要严格的进行数据转换和记录,消息队列可以把这些数据持久化的存储在队列中,然后有订单,后续处理程序进行获取,后续处理完之后在把这条记录进行删除来保证每一条记录都能够处理完成。

2、系统解耦:使用消息系统之后,入队系统和出队系统是分开的,也就说其中一个崩溃之后不会影响另外一个的正常运行。

3、异步通信:消息本身使用入队之后可以直接返回。

4、扩展性:例如订单队列,不仅可以处理订单,还可以给其他业务使用。

5、排序保证:有些场景需要按照产品的顺序进行处理比如单进单出从而保证数据按照一定的顺序处理,使用消息队列是可以的。

6、流量削峰:就是秒杀和抢购的时候,会出现明显的流量剧增,对服务器的压力非常大。 

7、
消息通讯:消息队列一般都内置了高效的通信机制,因此也可以用在纯的消息通讯。比如实现点对点消息队列,或者聊天室等。

 

四、队列介质

1、数据库,例如mysql(可靠性高,易实现,速度慢)
2、缓存, 例如redis(速度快,单个消息报包过大时效率低)
3、消息系统,专业性强,可靠,学习成本高(例如rabbitMq是实现了高级消息队列协议(AMQP)的开源消息代理软件(亦称面向消息的中间件)。
4、Beanstalkd (一个高性能、轻量级的分布式内存队列系统)

 

五、消息处理触发机制

1、死循环方式读取:易实现,故障时无法及时恢复;(比较适合做秒杀,比较集中,运维集中维护)

2、定时任务:压力均分,有处理上限;目前比较流行的处理触发机制。(唯一的缺点是间隔和数据需要注意,不要等上一个任务没有完成下一个任务又开始了)

3、守护进程:类似于php-fpm 和php-cg,需要shell基础

4、采用发布订阅的方式

 

六、案例一:应用解耦

  应用解耦:在订单系统出现故障时,不会影响到物流系统

一、说明:电商系统中订单系统、物流系统、财务系统以及操作日志记录系统之间的关系。

二、注意点:需要考虑中间数据的容灾能力,当故障发生并恢复时,保证业务流程可以恢复。保证每条数据都可以正确地完成处理。

三、传统模式:订单系统调用库存系统的接口。
缺点:1)假如
物流系统无法访问,则订单无法调用物流接口,从而导致订单失败;
       2) 订单系统与库存系统耦合

四、架构设计(以订单系统、物流系统为例,mysql为队列介质)
1、首先订单系统会接收用户的订单,然后进行订单的处理。
2、然后会把这些订单信息写到队列表中,这个队列表是沟通这两个系统的关键。
3、由配送系统定时执行的一个程序来读取队列表进行处理。
4、配送系统处理之后,会把已处理的记录进行标记。

  架构图

  

  程序流程图

  

  发布订阅方式

  

 

 

七、案例二:流量削峰

说明:一般情况下,做秒杀案例,抢购,瞬间高并发,需要排队 的案例中 redis是一个很好的选择。

解释:小明制作蛋糕的时间比较长,订单来到后先登记成一个清单,然后逐次按顺序制作,订单量过大时,会暂时挂出『已售完』的牌子。

注意点:对于消峰需求,可以高峰期挂出『暂时无法购买,请稍等』等提示,防止流量对后续业务的冲击。对于秒杀等抢完即停的需求,需要考虑超发问题,可以添加一个名额计数器,或者在秒杀名额已满员时,发放一个秒杀完成标记,后续处理程序检测到完成标记后,再进行后续处理。

redis数据类型中的 list 类型常用命令:
    * redis 的list 是一个双向链表,可以从头部或者尾部追加数据。

    1、LPUSH/LPUSHX :将值插入到(/存在的)列表头部
    2、RPUSH/RPUSHX: 将值插入到(/存在的)列表尾部
    3、LPOP : 移除并获取列表的第一个元素
    4、RPOP: 移除并获取列表的最后一个元素
    5、LTRIM: 保留指定区间内的元素
    6、LLEN: 获取列表长度
    7、LSET: 通过索引设置列表元素的值
    8、LINDEX: 通过索引获取列表中的元素
    9、LRANGE: 获取列表指定范围内的元素

  架构图

  

 

 

八、案例三:送达保证

场景说明:内容需要逐条严格执行,并保证执行成功,执行不成功或者中断时,可以恢复

解释:小明制作的蛋糕需要客户验货签收后,才可以继续制作下一个蛋糕。

实现:入队系统将业务需求写入消息队列后,即进行下一次业务处理。后续处理程序对队列内容进行逐条处理,处理完成后发放『完成许可』。消息队列中的内容,只有取得『完成许可』后,才可以从消息队列中删除。

注意点:重点考虑容灾相关问题,如业务恢复问题、重复处理问题。

  架构图

   

 

九、案例四:排序保证

说明:消息队列中的内容有严格的顺序。

案例:抢号排队等系统

解释:小明制作蛋糕的顺序需要严格按下单顺序来制作。

实现:入队系统将内容逐条写入消息队列,并按单线排列,按先进先出的顺序来提出数据并进行后续处理。

注意点:需要使用单线程,保证只有一条生产线。

  架构图

 

 

十、案例五:扩展性

场景:采用发布-订阅模式时,添加新的订阅者

案例:注册用户后,发送成功短信的模型中,追加一个发送email的功能

实现: 由多个消费者订阅一个消息的中间层,然后发布者将信息发布到中间层中。 订阅了这个中间层的消费者均可以收到这个消息,并进行后续处理。在这个结构中。如果想添加一个消息的后续处理组件 ,只需要将这个组件订阅到中间层即可

注意点:保证业务之间没有深度耦合,防止扩展时造成干扰。

  架构图

   

 

十一、案例六:异步处理

场景说明:用户注册后,需要发注册邮件和注册短信。传统的做法有两种

(1)串行方式:将注册信息写入数据库成功后,发送注册邮件,再发送注册短信。以上三个任务全部完成后,返回给客户端。

(2)并行方式:将注册信息写入数据库成功后,发送注册邮件的同时,发送注册短信。以上三个任务完成后,返回给客户端。与串行的差别是,并行的方式可以提高处理的时间。

  串行示意图

  并行示意图

  

我们可以发现:假设三个业务节点每个使用50毫秒钟,不考虑网络等其他开销,则串行方式的时间是150毫秒,并行的时间可能是100毫秒问题:如以上案例描述,传统的方式系统的性能(并发量,吞吐量,响应时间)会有瓶颈。如何解决这个问题呢?

解决:引入消息队列,将不是必须的业务逻辑,异步处理。改造后的架构如下:

  引入消息队列示意图

解释说明:按照以上约定,用户的响应时间相当于是注册信息写入数据库的时间,也就是50毫秒。注册邮件,发送短信写入消息队列后,直接返回,因此写入消息队列的速度很快,基本可以忽略,
   因此用户的响应时间可能是50毫秒。因此架构改变后,系统的吞吐量提高到每秒20 QPS。比串行提高了3倍,比并行提高了两倍。

 

 十二、案例七:消息通讯

场景说明:消息通讯是指,消息队列一般都内置了高效的通信机制,因此也可以用在纯的消息通讯。比如实现点对点消息队列,或者聊天室等。

  点对点通讯:客户端A和客户端B使用同一队列,进行消息通讯。

  聊天室通讯:客户端A,客户端B,客户端N订阅同一主题,进行消息发布和接收。实现类似聊天室效果。

以上实际是消息队列的两种消息模式,点对点或发布订阅模式。

  点对点示意图

  

  聊天室示意图

  

 

以上就是我关于消息队列整理的一些信息,整篇文章主要是对消息队列的认识和能用来干什么的描述,看完后也能对消息队列有个清晰的认知。

 

参考链接:https://cloud.tencent.com/developer/article/1031602

     http://www.cnblogs.com/dump/p/8243868.html

posted @ 2019-04-19 15:33  陈浩宇人呢  阅读(8735)  评论(0编辑  收藏  举报