1、认识消息队列php
1.1 消息对列概念mysql
从本质上说消息对列就是一个队列结构的中间件,也就是说消息放入这个中间件以后就能够直接返回,并不须要系统当即处理,而另外会有一个程序读取这些数据,并按顺序进行逐次处理。redis
也就是说当你遇到一个并发特别大而且耗时特别长同时还不须要当即返回处理结果,使用消息队列能够解决这类问题。sql
1.2 核心结构shell
由一个业务系统进行入队,把消息逐次插入到消息队列中,插入成功以后直接返回成功的结果,后续会有一个消息处理系统,这个系统会把消息系统中的记录逐次进行取出并进行处理,完成一个出队的流程。数据库
1.3 应用场景缓存
数据冗余:好比订单系统,后续须要严格的进行数据转换和记录,消息队列能够把这些数据持久化的存储在队列中,而后有订单,后续处理程序进行获取,后续处理完以后在把这条记录进行删除来保证每一条记录都可以处理完成。服务器
系统解耦:使用消息系统以后,入队系统和出队系统是分开的,也就说只要一天崩溃了,不会影响另一台系统正常运转。架构
流量削峰:例如秒杀和抢购,咱们能够配合缓存来使用消息队列,可以有效的顶住瞬间访问量,防止服务器承受不住致使崩溃。并发
异步通讯:消息自己使用入队以后能够直接返回。
扩展性:例如订单队列,不只能够处理订单,还能够给其余业务使用。
排序保证:有些场景须要按照产品的顺序进行处理好比单进单出从而保证数据按照必定的顺序处理,使用消息队列是能够的。
以上都是消息队列常见的使用场景,固然消息队列只是一个中间件,能够配合其余产品进行使用。
1.4 常见队列实现优缺点
队列介质
一、数据库,例如mysql(可靠性高,易实现,速度慢)
二、缓存, 例如redis (速度快,单个消息报包过大时效率低)
三、消息系统,例如rabbitMq (专业性强,可靠,学习成本高)
消息处理触发机制
一、死循环方式读取:易实现,故障时没法及时恢复;(比较适合作秒杀,比较集中,运维集中维护)
二、定时任务:压力均分,有处理上限;目前比较流行的处理触发机制。(惟一的缺点是间隔和数据须要注意,不要等上一个任务没有完成下一个任务又开始了)
三、守护进程:相似于php-fpm 和php-cg,须要shell基础
2、解藕案例:队列处理“订单系统”和“配送系统”
简单说一下程序解耦:程序解耦就是避免出现你老婆和你妈同时掉到水里先去救谁的问题
对于订单流程,咱们能够设计两个系统,一个是“订单系统” 另一个是 “配送系统”, 在网购的时候咱们应该都见过,当我提交了一个订单以后,我在后台能够看到个人货物正在配送中。这个时候就要参与进来一个“配送系统”。
若是咱们在作架构的时候把 “订单系统” 和 “配送系统” 设计在一块儿的话就会出现一些问题,首先对于订单系统来讲,由于系统的压力会比较大,可是 "配送系统" 不必为这些压力作一些即时的反应。
第二个咱们也不但愿在订单系统出现故障以后致使配送系统也出现故障,这个时候就会同时影响到两个系统的正常运转。因此咱们但愿把这两个系统进行解耦。这两系统分开以后咱们能够经过一个中间的 “队列表” 进行这两个系统的沟通。
2.1 架构设计
一、首先订单系统会接收用户的订单,而后进行订单的处理。
二、而后会把这些订单信息写到队列表中,这个队列表是沟通这两个系统的关键。
三、由配送系统定时执行的一个程序来读取队列表进行处理。
四、配送系统处理以后,会把已处理的记录进行标记。
2.2 程序流程
3、流量削峰案例: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 架构设计
一个简单结构秒杀的程序设计。
一、首先记录是哪个用户参与了秒杀同时记录他的时间。
二、将用户的id存到redis列表中,让它排队。若是规定只有前10个用户能够参与成功,若是列表中的个数已经够了就不会让它继续追加数据。这样redis的列表长度就只会是10个
三、最后在慢慢的将redis中的数据写入到数据库中,以减小数据的压力
3.3 代码级设计
一、当用户开始秒杀时,将秒杀程序的请求写入Redis (uid, time_stamp)中。
二、假使规定只有10人能够秒杀成功,检查 Redis 已经存放数据的长度,超出上限直接丢弃说明秒杀完成。
三、最后在死循环处理存入Redis中的10条数据,而后在慢慢的取数据并存入到mysql数据库中。
在秒杀这一块对于数据库的压力特别的大,若是咱们没有这样的设计,会形成mysql的写入瓶颈。咱们经过Redis的一个对列list,而后把秒杀的请求放入到Redis里面, 最后经过入库程序,把数据慢慢的写入到数据库,这样的话就能够实现流量的均衡,对mysql不会形成太大的压力。
4、RabbitMQ
这里讲解一些RabbitMQ的使用,首先咱们以前讲秒杀案例的时候提到了锁的机制,防止其余程序处理同一条记录,若是咱们的系统架构很是的复杂,有多个程序实时的读取一个队列,或者我有多个发送程序,同时来操做一个或多个队列,甚至我还想这些程序分布在不一样的机器上,这种状况下用redis队列就有些力不从心了。这种时候怎么办呢,咱们就须要来引入一些更专业的消息队列系统,这些系统能够更好的来解决问题。
4.1 RabbitMQ的架构和原理
特色:完整的实现了AMQP,集群简化,持久化,跨平台
RabbitMQS使用
一、RabbitMQ安装 (rabbitmq-server, php-amqplib)
二、生产者向消息通道发送消息
三、消费者处理消息
工做队列
思想:
由生产者发送给消息系统,消息系统把任务封装成消息队列以后,而后供多个消费者使用同一个队列。这不只解决了生产者和消费者之间的解耦,还能够实现了消费者和任务的共享,减缓了服务器的压力。