面试题答案
一键面试消息发送环节
- 同步发送与确认机制:采用同步发送消息的方式,消息队列接收到消息后返回确认信息,生产者在收到确认后才认为消息发送成功。若未收到确认,进行重试。例如在 RabbitMQ 中,使用
channel.confirmSelect()
开启确认模式,发送消息后通过channel.waitForConfirms()
等待确认。 - 事务机制:生产者开启事务,将消息发送操作包含在事务中。若消息发送失败,回滚事务。不过,事务机制会影响性能,所以要谨慎使用。以 JDBC 事务类比,类似
connection.setAutoCommit(false)
,发送消息后connection.commit()
,失败则connection.rollback()
。 - 日志记录:在发送端记录详细的消息日志,包括消息内容、发送时间、发送状态等,便于后续排查问题。如使用 Log4j 等日志框架记录消息发送相关信息。
消息存储环节
- 持久化策略:消息队列采用持久化存储消息。例如 RabbitMQ 中,将队列和消息都设置为持久化。队列声明时
Queue.Declare("queueName", true, false, false, null)
,消息发送时设置MessageProperties.PERSISTENT_TEXT_PLAIN
属性。这样即使消息队列重启,消息也不会丢失。 - 数据备份与恢复:对消息队列的数据进行定期备份,并且要有完善的恢复机制。如 Kafka 可以通过设置多副本机制,将数据复制到多个 broker 节点上,当某个节点出现故障时,其他副本可以继续提供服务。
- 高可用架构:构建消息队列的高可用集群。如 RabbitMQ 的镜像队列,将队列镜像到多个节点,保证即使部分节点故障,消息依然可正常存储和访问。
消息消费环节
- 手动确认机制:消费者采用手动确认消息的方式,确保消息被成功处理后才向消息队列发送确认。例如在 RabbitMQ 中,设置
channel.basicConsume("queueName", false, "consumerTag", false, false, null, deliverCallback)
,消费处理完成后channel.basicAck(envelope.getDeliveryTag(), false)
。若处理失败不确认,消息会被重新投递给其他消费者或重新入队。 - 幂等性处理:设计消费逻辑时保证幂等性,即多次消费同一条消息的结果与消费一次的结果相同。比如在更新数据库操作中,使用
UPDATE... WHERE id =? AND version =?
,每次更新成功后版本号加 1,防止重复更新。 - 消费重试机制:当消费失败时,设置合理的重试策略。可以采用固定时间间隔重试,如每次间隔 5 秒重试;也可以采用指数退避策略,重试间隔时间逐渐增大,避免频繁重试对系统造成过大压力。同时记录重试次数,达到一定次数仍失败可将消息放入死信队列进一步处理。