消息队列的概念、原理、实现方式

消息队列概念

在遇到高并发这样的情况时,程序往往无法进行及的处理。这个时候我们需要一个中间的系统来进行分流和减压

  • 队列结构的中间件
  • 消息放入后,不需要立即处理
  • 由订阅者/消费者按顺序处理

    消息队列核心结构

    消息队列应用

  • 冗余:订单系统需要对数据进行严格的转换和记录时,消息队列可以把数据持久化的存在队列中,由订单处理程序进行处理后删除,来保证每一条数据都能处理完成。

  • 解耦:消息队列分离了两套系统,解决了两套系统之间深度耦合的问题。使用消息队列后,入队的系统和出队的系统没有直接关系,其中一套系统崩溃时不会影响到另一套系统。
  • 流量削峰:秒杀、抢购,这种场景会出现非常明显的流量巨峰,大量的请求出现在几秒钟之内;对服务器瞬间压力非常大,配合缓存使用消息队列,可以非常有效撑住瞬间的访问量,防止服务器瞬间崩溃。
  • 异步通信:消息本身可以使入队系统直接返回,实现了程序的异步操作。异步的一些场景都适合使用消息队列来实现。
  • 扩展性:比如订单入队之后会有财务系统进行处理,如果后期需要加一个配货系统,只需要让配货系统订阅这个消息队列就可以了。
  • 排序保证:有些场景下数据的处理顺序是非常重要的,这种情况下也非常适合用队列处理,队列本身就可以做成单线程的单进单出的模式,从而把凭证数据按照顺序进行处理。

    常见消息队列实现的优缺点

    队列介质

  • MySQL(数据库):可靠性高,易实现,速度慢

  • Redis(缓存类):速度快,单条大消息包效率低
  • 消息系统(RabbitMQ):专业性强,可靠,学习成本高

    消息处理的触发机制

  • 死循环的方式读取:易实现,故障时无法及时恢复,适合做秒杀这一类的,使用时间比较集中,运维可以及时维护,一旦有秒杀请求之后,系统可以立即处理。

  • 定时任务:压力均分,有处理量上限
  • 守护进程:类似于PHP-FPM和PHP-CG,需要Shell基础

    队列处理订单系统和配送系统

    架构设计

程序流程

流量削峰案例:Redis的List类型实现秒杀

秒杀的特点就是在瞬间有巨大的访问量,需要通过一些缓解的方法保证业务的正常运行,如果大量的请求直接访问MySQL的话,MySQL会造成瞬间锁死的情况,其他业务模块在这个时间将无法访问MySQL,所以需要使用Redis来做MySQL的一个补充,Redis会周期性的把数据写入硬盘 不需要担心意外断电问题,且Redis提供了五种数据类型,其中的List链表类型更适合用来做秒杀这种需要排队的需求。

Rediss数据类型中的List类型

Redis的List类型是双向数据链表,可以从头部追加元素,也可以从尾部追加元素。

  • LPUSH/LPUSHX:将值插入到(/存在的)列表头部
  • RPUSH/RPUSHX:将值插入到(/存在的)列表尾部
  • LPOP:移除并获取列表的第一个元素
  • RPOP:移除并获取列表的最后一个元素
  • LTRIM:保留指定区域内的元素
  • LLEN:用来获取列表的长度
  • LSET:通过索引设置列表元素的值
  • LINDEX:通过索引获得列表中的元素
  • LRANGE:获取列表指定范围的元素

架构设计

程序流程

  • 秒杀程序把请求加入Redis(UID,time_stamp)
  • 检查Redis已存放的数据长度,超过上限直接丢弃
  • 死循环处理存Redis的数据并入库(因为秒杀的时间短,需要较快的处理)