怎么做?
⽬前对消息队列并不了解其原理,记录下来为后续学习打下基础。
众所周知在对⽹站设计的时候,会遇到给⽤户“发短信”,“订单系统有⼤量的⽇志”,“秒杀设计”等,服务器没法处理这种瞬间迸发的压⼒,这种情况要保证系统正常有效的使⽤,就需要“消息队列”的帮助。本篇主要通过消息队列的思路进⾏学习。
主要了解如下知识:
1、队列是个什么东西,他能⼲什么?
2、对列的应⽤场景有哪些?
3、如何使⽤队列对业务进⾏解偶?
4、如何使⽤Redis队列来消除⾼压⼒?
5、专业的对列系统如何使⽤?
归纳如下主要内容
@消息队列的概念,原理和场景
@解耦案例:队列处理订单系统和配送系统
@流量削峰案例:Redis的List类型实现秒杀
@RabbitMQ:更专业的消息系统实现⽅案
⼀、认识消息队列
2022年高三复读1.1 消息对列概念
从本质上说消息对列就是⼀个队列结构的中间件,也就是说消息放⼊这个中间件之后就可以直接返回,并不需要系统⽴即处理,⽽另外会有⼀个程序读取这些数据,并按顺序进⾏逐次处理。
也就是说当你遇到⼀个并发特别⼤并且耗时特别长同时还不需要⽴即返回处理结果,使⽤消息队列可以解决这类问题。
1.2 核⼼结构
由⼀个业务系统进⾏⼊队,把消息逐次插⼊到消息队列中,插⼊成功之后直接返回成功的结果,后续会有⼀个消息处理系统,这个系统会把消息系统中的记录逐次进⾏取出并进⾏处理,完成⼀个出队的流程。
1.3 应⽤场景
数据冗余:⽐如订单系统,后续需要严格的进⾏数据转换和记录,消息队列可以把这些数据持久化的存储在队列中,然后有订单,后续处理程序进⾏获取,后续处理完之后在把这条记录进⾏删除来保证每⼀条记录都能够处理完成。
系统解耦:使⽤消息系统之后,⼊队系统和出队系统是分开的,也就说只要⼀天崩溃了,不会影响另外⼀台系统正常运转。
流量削峰:例如秒杀和抢购,我们可以配合缓存来使⽤消息队列,能够有效的顶住瞬间访问量,防⽌服务器承受不住导致崩溃。
异步通信:消息本⾝使⽤⼊队之后可以直接返回。
扩展性:例如订单队列,不仅可以处理订单,还可以给其他业务使⽤。
排序保证:有些场景需要按照产品的顺序进⾏处理⽐如单进单出从⽽保证数据按照⼀定的顺序处理,使⽤消息队列是可以的。
以上都是消息队列常见的使⽤场景,当然消息队列只是⼀个中间件,可以配合其他产品进⾏使⽤。
1.4 常见队列实现优缺点
队列介质
1、数据库,例如mysql(可靠性⾼,易实现,速度慢)
2、缓存, 例如redis (速度快,单个消息报包过⼤时效率低)
3、消息系统,例如rabbitMq (专业性强,可靠,学习成本⾼)
消息处理触发机制
1、死循环⽅式读取:易实现,故障时⽆法及时恢复;(⽐较适合做秒杀,⽐较集中,运维集中维护)
2、定时任务:压⼒均分,有处理上限;⽬前⽐较流⾏的处理触发机制。(唯⼀的缺点是间隔和数据需要注意,不要等上⼀个任务没有完成下⼀个任务⼜开始了)
3、守护进程:类似于php-fpm 和php-cg,需要shell基础
黄河大合唱歌曲⼆、解藕案例:队列处理“订单系统”和“配送系统”
简单说⼀下程序解耦:程序解耦就是避免出现你⽼婆和你妈同时掉到⽔⾥先去救谁的问题(偷笑ing)
对于订单流程,我们可以设计两个系统,⼀个是“订单系统” 另外⼀个是 “配送系统”, 在⽹购的时候我们应该都见过,当我提交了⼀个订单之后,我在后台可以看到我的货物正在配送中。这个时候就要参与进来⼀个“配送系统”。
如果我们在做架构的时候把 “订单系统” 和 “配送系统” 设计在⼀起的话就会出现⼀些问题,⾸先对于订单系统来说,因为系统的压⼒会⽐较⼤,但是 "配送系统" 没必要为这些压⼒做⼀些即时的反应。
第⼆个我们也不希望在订单系统出现故障之后导致配送系统也出现故障,这个时候就会同时影响到两个系统的正常运转。所以我们希望把这两个系统进⾏解耦。这两系统分开之后我们可以通过⼀个中间的 “队列表” 进⾏这两个系统的沟通。
2.1 架构设计
1、⾸先订单系统会接收⽤户的订单,然后进⾏订单的处理。
2、然后会把这些订单信息写到队列表中,这个队列表是沟通这两个系统的关键。
3、由配送系统定时执⾏的⼀个程序来读取队列表进⾏处理。
4、配送系统处理之后,会把已处理的记录进⾏标记。
2.2 程序流程
三、流量削峰案例:Redis 的 list 类型实现秒杀
redis 基于内存,它的速度会⾮常快,redis 对数据库有⼀个⾮常好的补充作⽤因为它是可持久化的,redis会周期性的把数据写到硬盘⾥,所以它不⽤担⼼断电的问题,从这⽅⾯说它⽐另⼀款缓存 memcache 更有优势些,另外 redis 提供五种数据类型(字符串,双向链表,哈希,集合,有序集合)
⼀般情况下,做秒杀案例,抢购,瞬间⾼⽐你⾼发,需要排队 的案例中 redis是⼀个很好的选择。
国庆寄语大全3.1 redis数据类型中的 list 类型
redis 的list 是⼀个双向链表,可以从头部或者尾部追加数据。
* LPUSH/LPUSHX :将值插⼊到(/存在的)列表头部连翘花
* RPUSH/RPUSHX: 将值插⼊到(/存在的)列表尾部
* LPOP : 移除并获取列表的第⼀个元素
* RPOP: 移除并获取列表的最后⼀个元素
* LTRIM: 保留指定区间内的元素
* LLEN: 获取列表长度
* LSET: 通过索引设置列表元素的值
* LINDEX: 通过索引获取列表中的元素
* LRANGE: 获取列表指定范围内的元素
3.2 架构设计
⼀个简单结构秒杀的程序设计。
1、⾸先记录是哪⼀个⽤户参与了秒杀同时记录他的时间。
2、将⽤户的id存到redis列表中,让它排队。如果规定只有前10个⽤户可以参与成功,如果列表中的个数已经够了就不会让它继续追加数据。这样redis的列表长度就只会是10个
3、最后在慢慢的将redis中的数据写⼊到数据库中,以减少数据的压⼒
3.3 代码级设计
1、当⽤户开始秒杀时,将秒杀程序的请求写⼊Redis (uid, time_stamp)中。
2、假使规定只有10⼈可以秒杀成功,检查 Redis 已经存放数据的长度,超出上限直接丢弃说明秒杀完成。
3、最后在死循环处理存⼊Redis中的10条数据,然后在慢慢的取数据并存⼊到mysql数据库中。
在秒杀这⼀块对于数据库的压⼒特别的⼤,如果我们没有这样的设计,会造成mysql的写⼊瓶颈。我们通过Redis的⼀个对列list,然后把秒杀的请求放⼊到Redis⾥⾯, 最后通过⼊库程序,把数据慢慢的写⼊到数据库,这样的话就可以实现流量的均衡,对mysql不会造成太⼤的压⼒。
四、RabbitMQ
这⾥讲解⼀些RabbitMQ的使⽤,⾸先我们之前讲秒杀案例的时候提到了锁的机制,防⽌其他程序处理同⼀条记录,如果我们的系统架构⾮常的复杂,有多个程序实时的读取⼀个队列,或者我有多个发送程序,同时来操作⼀个或多个队列,甚⾄我还想这些程序分布在不同的机器上,这种情况下⽤redis队列就有些⼒不从⼼了。这种时候怎么办呢,我们就需要来引⼊⼀些更专业的消息队列系统,这些系统可以更好的来解决问题。
4.1 RabbitMQ的架构和原理
特点:完整的实现了AMQP,集简化,持久化,跨平台
RabbitMQS使⽤
1、RabbitMQ安装 (rabbitmq-server, php-amqplib)
2、⽣产者向消息通道发送消息
3、消费者处理消息
⼯作队列
思想:由⽣产者发送给消息系统,消息系统把任务封装成消息队列之后,然后供多个消费者使⽤同⼀个队列
这不仅解决了⽣产者和消费者之间的解耦,还可以实现了消费者和任务的共享,减缓了服务器的压⼒。
五、总结卡布叻
以上主要学习消息队列的概念,原理,场景。解耦案例以及削峰案例,以及了解RabbitMQ的简单使⽤⽅法。
六、问题
redis 和消息服务器 选择的最⼤区别是什么。
正月初九是黄道吉日吗2023 我的理解是Redis 是⼀个⼀个处理请求,redis属于单线程,它和消息服务器 IO 的实现⽅式不同,⼀个是同步⼀个是异步,⽽redis使⽤的是同步阻塞,⽽消息服务器使⽤的是异步⾮阻塞。
发布评论