RabbitMQ、Kafka消息中间件

  • 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自身机制来实现。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值