消息中间件message queue 消息队列
在单体架构中,所有的代码、模块都放在一份代码中,如果其中一个模块需要升级,哪怕只修改了一点点,整个系统也要一起升级,这样耦合度太高,同时代码管理也比较难。


到了分布式系统架构,这里现在有前台系统、订单系统、会员系统,这三个系统分别独立部署,如果需要升级某个系统,其他系统不需要进行调整。
有些请求不是一个系统就能完成的,比如当在一个页面上面同时想看会员积分和下单的信息,通过一次请求,这个请求会涉及多个系统。这种多个系统协作处理一个请求的系统,就被看作是分布式系统,当某个系统压力大时,可以对单个系统进行扩展。
这时就会用到 RPC 技术,调用远程接口的方式实现系统间的互相调用。 但是这种方式的耦合度比较高,为了实现更强的拓展性架构,所以在分布式系统中引入了消息中间件,通过消息中间件解决系统的耦合。

1.什么是消息队列
消息是指数据,数据的格式通常都使用json,消息中间件的作用就是系统解耦、将同步流程异步化,使用场景:抢购秒杀、订单生成预减库存积分优惠券、流量削峰等等
常用的消息中间件有
- rabbitMq(几万-10万之间) erlang语言天然支持高并发与集群,提供了事务机制,保证消息生产和消费的安全性
- avtiveMq (几千-几万) apache下比较老的一款消息中间件产品
- rocketMq (10万以上) 阿里开源到apache一款消息中间件产品
- Kafka (百万级) 大规模写入的效率很高,百万qps,主要用于大数据当中的日志收集
不使用消息队列的问题

消息队列的工作原理:防止出现数据不同步,和系统的阻塞

2.在linux上安装rabbitMq
rabbitMq的安装(centos7)
//这种方式 自动
- 下载erlang:
wget http://www.rabbitmq.com/releases/erlang/erlang-18.3-1.el7.centos.x86_64.rpm
安装erlang:
rpm -ivh erlang-18.3-1.el7.centos.x86_64.rpm
下载socat:
wget http://repo.iotti.biz/CentOS/7/x86_64/socat-1.7.3.2-5.el7.lux.x86_64.rpm
安装socat:
rpm -ivh socat-1.7.3.2-5.el7.lux.x86_64.rpm
下载rabbitmq:
wget http://www.rabbitmq.com/releases/rabbitmq-server/v3.6.5/rabbitmq-server-3.6.5-1.noarch.rpm - 安装rabbitmq:
rpm -ivh rabbitmq-server-3.6.5-1.noarch.rpm - 设置开机启动:
chkconfig rabbitmq-server on - 开启rabbitmq服务:
systemctl start rabbitmq-server
启用web管理插件:
rabbitmq-plugins enable rabbitmq_management
[{rabbit, [{loopback_users, []}]}]. - 设置远程访问登录:
cd /etc/rabbitmq
touch rabbitmq.config
vi rabbitmq.config
写入[{rabbit, [{loopback_users, []}]}]. - 重启rabbitMq
systemctl restart rabbitmq-server - 通过浏览器访问 rabbitMq
ip地址:15672
使用guest guest来登录
添加一个用户 admin 密码是admin tags administrator
设置访问的虚拟路径 /
3.rabbitmq整体简介
https://www.jianshu.com/p/569b8512b14f
优势:RabbitMq的应用场景比较广泛,包括日志管理、应用解耦、流量削峰、异步处理。
其中都是利用了RabbitMq的异步性,响应机制等特性。
rabbitmq采用的amqp协议,该协议有spring的集成。
元素介绍
1、virtual host:为虚拟主机,可以理解为数据库,在定义的库中进行表的创建,进行后续操作,是基础性元素
2、channel:管道,是声明交换机、声明队列、发布消息、消息响应、交换机与队列绑定的载体
3、exchange:交换机,用于传递消息,队列可以绑定到交换机上从而获取转发的消息
4、queue:队列,消息的载体,可以持久化,可以通过不同的响应机制进行状态的标识及补偿消费
5、provider:生产者,消息的提供者,产生消息
6、consumer:消费者,消息的终端,进行消费的最后处理
工作模式
- simple模型(简单模式):简单模式,顾名思义,很简单,一个provider,一个queue,一个消费者 ;1对1

-
work模式
-
轮询模式(round):1个provider,1个队列,多个消费者,消息是一个消费者处理一条,权重相同,你一个我一个

-
公平模式(fair):根据消费者的消费能力,消费完成后,就发下一条消息,多劳多得,但是需要告知mq服务器消费完成,所以要开启消息应答,这里开启自动应答模式

-
-
订阅模式:订阅模式中,出现了exchange交换机,在消息由生产者发送到消费者的过程中,增加了交换机,可以理解为路由器,作用是判断哪个队列满足条件然后发到哪个队列上
- fanout:只要绑定到交换机上的队列都进行发放消息,强调雨露均沾

-
direct:需要有rountingKey进行匹配,exchange会定义一个rountingKey,同样消费者也需要定义一个,只有二者相同,才会消费
-
topic:加入了通配符的rounting绑定,其中*为代替.之间的内容,#代表所有内容
事务机制
生产者发出消息后,需要确认mq服务器是否有收到该消息,两种方式实现
-
AMQP实现事务机制
txSelect:用户将当前channel设置成transation模式
txCommit:用于事务提交
txRollback:用于事务回滚
-
confirm模式,进行消息确认
通过指派唯一的ID进行发送及监听回传
channel.confirmSelect()进行开启
4. rabbitmq的工作示例
<!--导包-->
<dependencies>
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>5.1.2</version>
</dependency>
</dependencies>
//消息生产者
public class BasicProductor {
public static void main(String[] args) throws IOException, TimeoutException {
//创建连接工厂
ConnectionFactory factory = new ConnectionFactory();
//设置连接的服务器地址,不设置表示使用本机地址
factory.setHost("192.168.192.3");
//设置连接的端口号
factory.setPort(5672);
//设置连接的虚拟主机(用来表示权限)
factory.setVirtualHost("/");
//建立连接使用的用户名和密码
factory.setUsername("admin");
factory.setPassword("admin");
//建立连接
Connection connection = factory.newConnection();
//一切关于mq的操作都是通过channel操作的. 建立通道 Work queues默认模式
Channel channel = connection.createChannel();
//队列名称,是否持久化,是否排他(仅对首次声明它的连接可见),是否自动删除,设置队列的一些参数
channel.queueDeclare("hello", true, false, false, null);
String json = "{ordersID:xxx}";
//发布消息,交换机(没有就是空),交换密码(如果没有使用交换机), ,发送的信息内容
channel.basicPublish("", "hello", MessageProperties.PERSISTENT_TEXT_PLAIN, json.getBytes());
channel.close();
connection.close();
}
}
//消息消费者
public class BasicConsumer {
public static void main(String[] args) throws IOException, TimeoutException {
//创建连接工厂
ConnectionFactory factory = new ConnectionFactory();
//设置连接的服务器地址,不设置表示使用本机地址
factory.setHost("192.168.192.3");
//设置连接的端口号
factory.setPort(5672);
//设置连接的虚拟主机(用来表示权限)
factory.setVirtualHost("/");
//建立连接使用的用户名和密码
factory.setUsername("admin");
factory.setPassword("admin");
//建立连接
Connection connection = factory.newConnection();
//创建数据管道
Channel channel=connection.createChannel();
String queueName="hello";
//创建消费者,重写处理函数
Consumer consumer=new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
String message = new String(body);
System.out.println(message);
}
};
//队列名称,消费者
channel.basicConsume(queueName,consumer);
}
}
//使用交换机 路由模式 direct
//消费者
public class ExchangeConsumer {
public static void main(String[] args) throws IOException, TimeoutException {
ConnectionFactory factory=new ConnectionFactory();
factory.setHost("192.168.192.3");
factory.setPort(5672);
factory.setVirtualHost("/");
factory.setUsername("admin");
factory.setPassword("admin");
Connection connection=factory.newConnection();
//建立通道
Channel channel=connection.createChannel();
//自定义队列
channel.queueDeclare("q1", true, false, false, null);
//存储数据的队列,交换机名称,交换密码
channel.queueBind("q1", "test", "zhimakaimen");
Consumer consumer=new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println(new String(body,"utf-8"));
}
};
channel.basicConsume("q1", consumer);
}
}
//生产者
public class ExchangeProductor {
public static void main(String[] args) throws IOException, TimeoutException {
ConnectionFactory factory=new ConnectionFactory();
factory.setHost("192.168.192.3");
factory.setPort(5672);
factory.setVirtualHost("/");
factory.setUsername("admin");
factory.setPassword("admin");
Connection connection=factory.newConnection();
//建立通道
Channel channel=connection.createChannel();
//假如当前mqServer没有交换机,这里需要创建一个交换机
//交换机名称,交换机类型
channel.exchangeDeclare("test","direct");
String json = "hello 2";
//direct模式下不需要创建队列,直接发布,由消费者创建队列接收
//交换机名称,交换密码 ,交换信息
channel.basicPublish("test", "zhimakaimen", MessageProperties.PERSISTENT_TEXT_PLAIN, json.getBytes());
channel.close();
connection.close();
}
}

浙公网安备 33010602011771号