消息中间件基本上是互联网公司必用的一个中间件,为什么要使用MQ,当然是因为能给我们的系统带来很多好处。
消息队列简单来说是一种先进先出的数据结构,先简单认识下。
一、应用场景
消息中间件主要应用场景主要三个方面是:异步、解耦、削峰
异步
异步比较好理解,很多公司其实本身系统的并发量还是访问量不一定会很大,但是业务会很复杂,一个动作会牵扯到很多业务,当用户触发某个事件后,后面可能有N个步骤,这些步骤如果都需要一个一个串行去走完,那么用户等待的时间就会非常长,这样,即使系统的使用人数不多,也是不能接受的。
这个时候我们使用消息中间件去做异步处理就很好理解了,当有一个长链条操作时,我们将这个长链条进行拆分,使用异步去处理,举个最常见的例子吧。
用户下单,我们简单可想的后续操作就有很多,如扣除优惠券,增加积分,消息提醒等等,这些操作在客户下单的时候,他不需要马上得到这些结果,我们完全可以进行异步操作。
当然,有人说,这个不是可以用多线程去操作么?其实这个就引出了下一个应用场景
解耦
在程序设计过程中,有一条原则是大家耳熟能详的,高内聚、低耦合,如刚刚说的,虽然用多线程,可以进行异步,但是毕竟是一个流程中去调用,这样系统必定耦合度会比较高,耦合度太高,容错性就低,如上,其中一个系统出错,就会导致整个系统出错,而且如果又要增加业务,那整个系统需要重新发布,而且也需要再进行测试。
消息中间件怎么进行解耦呢?主系统下单完成后,写入消息,其他的系统只要按照需要进行消费即可,这样其他系统出错了也不会影响主业务,也很方便的去增加或减少业务,只要增加消费或去掉消费即可。
削峰
削峰用最常见的秒杀来就很好理解,秒杀会使短时间内使系统面临巨大流量,而平时系统的服务器硬件不需要配置这么高,那我们其他的服务,特别是数据库这些,很容易就被打挂了,这个时候我们使用消息,将访问请求都放到队列中,让业务分散到长时间去处理请求,这样虽然暂时会使得系统变得慢一些,但不会使整个系统直接崩溃。
二、带来的问题
当然,很多事情都有两面性,只有好处没有坏处的事情是很少的,那我们来想想消息会带来哪些问题。
系统可用性降低
这个很好理解,既然引用了MQ,那就存在MQ宕机的情况,这必然就会造成业务影响,这里就要考虑MQ的高可用。
系统复杂度
添加一个组件,必然会带来系统的复杂度,当我们引用一个组件,就要想到它可能带来的问题。加上MQ后,既然是异步调用,那就要考虑消息有没有被重复消费,消息有可能丢失,还有消息的传递顺序。
一致性问题
分布式服务本身都会存在这个问题,A系统处理完业务,通过MQ分发送消息,那每个系统处理,都会有自己的状态,A成功了,B失败了,这样必然就有数据一致性问题。
三、各MQ的比较
目前在市面上比较主流的消息队列中间件主要有,Kafka、ActiveMQ、RabbitMQ、RocketMQ 等这几种。我们可以做个比较。
ActiveMQ 使用比较少了,RabbitMQ语言不是java,这点很要命, Kafka很好用,一般大数据领域使用的非常多,一般规模的话使用RocketMQ,毕竟阿里出品的,生态方面都比较稳。
四、快速入门
理论太多,容易劝退,先跑起来再说。
下载源码
下载二进制文件即可,需要看源码再下载源码:https://rocketmq.apache.org/dowloading/releases/
上传到服务器,工作之后还是建议买一台自己的服务器,个人服务器还是很便宜的。
unzip rocketmq-all-4.8.0-bin-release.zip
如果没有安装解压工具,则安装:
yum install -y unzip zip
可以修改下解压包名称
mv rocketmq-all-4.8.0-bin-release rocketmq
启动RocketMq
4.1 启动NameServer,以下命令都在bin目录下
# 启动命令,并且常驻内存,nohup 属于后台启动,当前目录下生成 nohup.out 日志文件,也可以指定日志输出位置。 $ nohup sh mqnamesrv & # 可以直接启动项目 $ sh mqnamesrv : # 查看启动日志,能看到 "The Name Server boot success" 字样则成功 $ tail -f ~/logs/rocketmqlogs/namesrv.log
如果显示没有日志文件目录,那说明没有启动成功,是因为默认的初始化内存8G,内存不足导致的
vi runserver.sh
vi runbroker.sh
找到设置内存的位置,改成256m即可
4.2 启动 Broker 中间件
# 启动命令,并且常驻内存,nohup 属于后台启动,当前目录下生成 nohup.out 日志文件,也可以指定日志输出位置。 nohup sh mqbroker -n localhost:9876 & # 直接启动 sh mqbroker -n localhost:9876 : # 查看启动日志 tail -f ~/logs/rocketmqlogs/broker.log
4.3 测试发送消息
打开两个tab进行命令执行,可以更加直观的查看
测试生产消息
export NAMESRV_ADDR=localhost:9876 sh tools.sh org.apache.rocketmq.example.quickstart.Producer
结果如下:
测试消费者
export NAMESRV_ADDR=localhost:9876 sh tools.sh org.apache.rocketmq.example.quickstart.Consumer
结果:
4.4 关闭mq
与启动顺序相反进行关闭,先关闭 broker、在关闭 nameserv
sh mqshutdown broker
sh mqshutdown namesrv
以上就是启动mq的流程,其实还是挺简单的,下面再介绍下几个概念,后面再进行下深入学习。
五、角色介绍
几个基础概念
名字服务(Name Server):名称服务充当路由消息的提供者。生产者或消费者能够通过名字服务查找各主题相应的Broker IP列表。多个Namesrv实例组成集群,但相互独立,没有信息交换。
代理服务器(Broker Server):消息中转角色,负责存储消息、转发消息。代理服务器在RocketMQ系统中负责接收从生产者发送来的消息并存储、同时为消费者的拉取请求作准备。代理服务器也存储消息相关的元数据,包括消费者组、消费进度偏移和主题和队列消息等。
消息生产者(Producer):负责生产消息,一般由业务系统负责生产消息。一个消息生产者会把业务应用系统里产生的消息发送到broker服务器。RocketMQ提供多种发送方式,同步发送、异步发送、顺序发送、单向发送。同步和异步方式均需要Broker返回确认信息,单向发送不需要。
消息消费者(Consumer):负责消费消息,一般是后台系统负责异步消费。一个消息消费者会从Broker服务器拉取消息、并将其提供给应用程序。从用户应用的角度而言提供了两种消费形式:拉取式消费、推动式消费。
主题(Topic):表示一类消息的集合,每个主题包含若干条消息,每条消息只能属于一个主题,是RocketMQ进行消息订阅的基本单位。