- RabbitMQ
官网地址:https://www.rabbitmq.com/
Docker安装参考官方文档:
docker run -it --rm --name rabbitmq -p 5672:5672 -p 15672:15672 rabbitmq:4.0-management
- SpringBoot集成RabbitMQ
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
- 连接配置
配置ConnectionFactory,可以是CachingConnectionFactory或者其他实现
根据RabbitMQ服务器的配置,设置相应的参数,例如主机名、端口、用户名、密码等
@Bean
public CachingConnectionFactory connectionFactory() {
CachingConnectionFactory factory = new CachingConnectionFactory();
factory.setHost(host);
factory.setPort(port);
factory.setUsername(username);
factory.setPassword(password);
//缓存模式,这里使用默认的工厂配置的模式
factory.setCacheMode(CachingConnectionFactory.CacheMode.CHANNEL);
return factory;
}
将连接工厂放入监听里
@Bean
public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory(CachingConnectionFactory connectionFactory) {
SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
factory.setConnectionFactory(connectionFactory);
return factory;
}
使用配置好的ConnectionFactory创建RabbitAdmin实例
@Bean
public RabbitAdmin rabbitAdmin(ConnectionFactory connectionFactory) {
RabbitAdmin rabbitAdmin = new RabbitAdmin(connectionFactory);
rabbitAdmin.setAutoStartup(true);
return rabbitAdmin;
}
使用配置好的ConnectionFactory创建RabbitTemplate实例
@Bean
public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
return new RabbitTemplate(connectionFactory);
}
- 创建队列、交换机
-- 创建交换机
@Bean
public DirectExchange customExchange() {
return new DirectExchange(exchangeName);
}
-- 创建队列
@Bean
public Queue customQueue() {
return new Queue(queueName, true, true, true);
}
-- 绑定交换机和队列
@Bean
public Binding bindQueueExchange(DirectExchange customExchange, Queue customQueue) {
return BindingBuilder.bind(customQueue).to(customExchange).with(routeName);
}
发送消息
@Resource
private RabbitTemplate rabbitTemplate;
rabbitTemplate.convertAndSend(exchangeName, routeName, message);
监听订阅消息,发送消息是什么类型这里就用什么类型接收
@RabbitListener(queues = QueueName)
public void consumer(Object message){...}
- 延迟队列
启动延迟交换机插件
rabbitmq-plugins enable rabbitmq_delayed_message_exchange
未安装插件的情况下可在官网下载安装:https://www.rabbitmq.com/community-plugins
https://github.com/rabbitmq/rabbitmq-delayed-message-exchange/releases
rabbitmq_delayed_message_exchange-4.0.2.ez
将插件copy到容器,如果你是docker启动的mq
sudo docker cp /mnt/d/rabbitmq/rabbitmq_delayed_message_exchange-4.0.2.ez rabbitmq:/plugins/
进入容器启动插件
rabbitmq-plugins enable rabbitmq_delayed_message_exchange
退出容器在RabbitMQ的管理界面,交换机新建队列查看选择队列类型是否出现:x-delayed-message
在代码层面需要修改的地方
-- 创建延迟队列交换机
private CustomExchange delayExchange(String name) {
Map<String, Object> arguments = Maps.newHashMap();
arguments.put("x-delayed-type", ExchangeTypes.DIRECT);
return new CustomExchange(name, "x-delayed-message", true, false, arguments);
}
-- 绑定延迟队列交换机和队列
@Bean
public Binding exchangeQueueBind(CustomExchange delayExchange, Queue queue) {
return BindingBuilder.bind(queue).to(delayExchange).with(route).noargs();
}
-- 延迟消息发送
public void send(Object message, long delay) {
rabbitTemplate.convertAndSend(exchangeName, routeName, message, processor -> {
processor.getMessageProperties().setHeader("x-delay", 毫秒值);
return processor;
});
}
- 消费者手动确认消息
设置确认模式为手动
SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
factory.setAcknowledgeMode(AcknowledgeMode.MANUAL)
监听时的操作
@RabbitListener
public void comsumer(Channel channel,Message message,Object data) {
-- data是接收的数据,可根据发送的数据类型接收
long tag = message.getMessageProperties().getDeliveryTag();
-- 确认消息被正常处理
channel.basicAck(tag,false);
-- 处置失败想重新放进队列的
channel.basicNack(tag,true,true);
}
- RabbitMQ基础知识
支持的消息协议:AMQP、STOMP、MQTT
生产消费模式:生产者通过信道channel发送消息到交换机Exchange,交换机根据配置的路由规则将消息转发到队列Queue,队列作为一种存储消息的数据结构保存消息,等待消费者从队列获取数据。
生产者和交换机、消费者和队列之间都是通过channel信道通信。
交换机类型:
直连交换机 - direct:点对点模式,一个路由对应一个队列,交换机将消息转发的匹配的一个队列
扇形交换机 - fanout:发布订阅模式,交换机将消息复制分发给所有绑定的队列
主题交换机 - topic:
头信息交换机 - headers:
延迟交换机 - X-delayed-message:需要插件支持,
点对点模式或发布订阅模式都是针对交换机转发消息到队列的过程,多个消费者监听同一个队列接收消息要依据队列消息的分发行为,默认是轮询模式(消费者排个序一个一个的接收),公平调度模式(更加均匀分发,在未处理完消息时不会接收到新消息)
RabbitMQ的Boker是指服务本身是消息队列核心组件,处理接收生产者消息和分发消息到消费者。由交换机、队列、信道、交换机队列绑定等组成。
- Kafka
可视化工具:https://gitee.com/dushixiang/kafka-map
安装:https://kafka.apache.org/quickstart
注意这里需要挂在配置文件server.properties,其位置在 /etc/kafka/docker/server.properties
-- broker监听的网络接口
listeners=PLAINTEXT://0.0.0.0:9092,CONTROLLER://0.0.0.0:9093
-- 对外宣传的监听地址,对应客户端连接到当前Broker
advertised.listeners=PLAINTEXT://127.0.0.1:9092
- SpringBoot集成kafka
<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka</artifactId>
</dependency>
生产者配置
@Bean
public KafkaTemplate<String, Object> kvKafkaTemplate() {
return new KafkaTemplate<>(producerFactory());
}
private ProducerFactory<String, Object> producerFactory() {
Map<String, Object> configs = Maps.newHashMap();
configs.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "127.0.0.1:9092");
//消息发送失败后的重试次数
configs.put(ProducerConfig.RETRIES_CONFIG, 1);
//设置消息发送成功的确认级别:("0"不等待任何确认)、("1"等待来自leader broker的确认)、("all"或"-1"等待所有的确认 in-sync replicas)
configs.put(ProducerConfig.ACKS_CONFIG, "1");
//key和value的序列化与返回类型对应的各类型一致
configs.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
configs.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, JsonDeserializer.class);
return new DefaultKafkaProducerFactory<>(configs);
}
消费者配置
@Bean
public ConcurrentKafkaListenerContainerFactory<String, Object> kafkaListenerContainerFactory() {
ConcurrentKafkaListenerContainerFactory<String, Object> factory = new ConcurrentKafkaListenerContainerFactory<>();
factory.setConsumerFactory(consumerFactory());
//设置Ack为手动模式,确认正常消费:Acknowledgment.acknowledge(),失败消费让消息重新进队列等待下次消费:抛异常或Acknowledgment.nack()
factory.getContainerProperties().setAckMode(ContainerProperties.AckMode.MANUAL);
return factory;
}
private ConsumerFactory<String, Object> consumerFactory() {
Map<String, Object> configs = Maps.newHashMap();
configs.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, "127.0.0.1:9092");
configs.put(ConsumerConfig.GROUP_ID_CONFIG, "consume-group");
//指定消费者开始消费偏移量:earliest(起始位置)、latest(最新位置)、none(不设置需要手动提供偏移量否则抛出异常)
configs.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "earliest");
//设置每次从borker中获取数据的最大条数
configs.put(ConsumerConfig.MAX_POLL_RECORDS_CONFIG, Number.TEN);
//禁用自动提交偏移量,配合Acknowledgment手动确认,监听工厂设置Ack模式为手动
configs.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, false);
//反序列化配置
configs.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringSerializer.class);
configs.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, JsonDeserializer.class);
return new DefaultKafkaConsumerFactory<>(configs);
}
登录密码的配置(这里只提供最简单验证模式)
private void security(Map<String, Object> configs, String username, String password) {
configs.put(CommonClientConfigs.SECURITY_PROTOCOL_CONFIG, SecurityProtocol.SASL_PLAINTEXT.name);
configs.put(SaslConfigs.SASL_MECHANISM, "PLAIN");
String jaas = "org.apache.kafka.common.security.scram.ScramLoginModule required username = '%s' password='%s';";
configs.put(SaslConfigs.SASL_JAAS_CONFIG, String.format(jaas, username, password));
}
- kafka基础知识
kafka是一个分布式的基于订阅发布模式的消息系统,具有高吞吐量、低延迟和持久化的特性。
生产者生产消息并将消息发送给Topic(主题:消息发布容器)上对应的分区(分区的选择是根据消息的key或配置的分区策略),Topic由多个分区组成,分区可以在不同的机器上也就是不同的Broker(Broker是kafka集群中的一个节点相当于一个服务),提供并发处理、容错能力,每个分区为一个有序的消息队列,从而保证消息的顺序,分区也是数据的实际存储单元。为了提高可用性和容错性每个分区创建多个副本(Replica)每个分区有一个Leader和多个follower(Leader和Follower是副本的角色),消息发送确认的级别有数据发送到Leader成功的确认和同步到其它副本成功的确认,Leader同步到其它副本的过程就是ISR(In-Sync Replica).
消费者从Broker获取当前偏移量,然后从分区中获取消息并消费,确认消费后提交偏移量。
消费模式通过消费组来实现
发布/订阅模式:将消费者设置为不同的消费组
点对点模式:将消费者设置为同一个消费组。多个消费者放在同一个消费组订阅同一个Topic,消费者加入消费组是会被分配到一个分区,且每个分区只会分配给一个消费者,通过负载均衡的方式实现公平消费。
ZooKeeper在Kafka中的作用
分区副本Leader的选举,比如Leader发生故障时选一个Follower来成为新的Leader,Borker在注册的时候告知集群以提供服务,消费者组管理包括成员列表、偏移量提交等。
在新版本的kafka中这些通过kafka自身机制来实现。