时时回头总结,技术才能有飞跃!
1.RocketMQ的几大功能
1.应用解耦
2.削峰限流
3.消息分发
4.分布式一致性保证(分布式事务)
应用解耦:
我使用的一个场景下单完成后 ,支付后的逻辑 库存中心减库存->订单中心加订单->会员中心加积分
对应伪代码:
if 支付成功
do 减库存
do 加订单
do 加积分
这种情况下代码耦合严重如果有新的逻辑加入代码改动较多,如果其中一个异常要全部回滚,对技术来说不友好
这时我们将消息投入到MQ中(怎么投怎么消费待详解),就实现了业务间的解耦
2.RocketMQ消息投递的几种方式
对于发送者有producerGroup,Topic,Queue三个设置
一个Topic下面如果有多个Queue,消息默认会轮流发送到每个Queue,但是你也可以指定发送(MessageQueueSelector)
发送方式:
1.同步发送,发送完成返回结果
send(Message msg,long timeout)
2.异步发送 ,带回调方法,可以实现重试等操作
send(Message msg,SendCallback sendCallback)
3.发送后直接返回,到达broker前就返回了,消息可能会没有持久化造成丢失
sendOneway(final Message msg)
3.RocketMQ消息消费的几种方式
对于消费者也有consumerGroup,Topic,Queue三个设置
1 ) Consumer的GroupName用于把多个Consumer组织到一起,提高并发处理能力,GroupName 需要和消息模式(MessageModel)配合使用。
2)RocketMQ支持两种消息模式: Clustering 和Broadcasting 默认是Clustering。
consumer.setMessageModel(MessageModel.BROADCASTING);
3 ) 在Clustering模式下,同一个ConsumerGroup (GroupName相同)里的每个Consumer只消费所订阅消息的一部分内容, 同一个ConsumerGroup里所有的Consumer消费的内容合起来才是所订阅Topic内容的整体,从而达到负载均衡的目的。
我试过了在数据量少时消息分配极度不均衡
4) 在Broadcasting模式下,同一个ConsumerGroup里的每个Consumer都能消费到所订阅Topic的全部消息,也就是一个消息会被多次分发,被多个Consumer消费。
如果有消费者中间断开了那么它在重新连接前会错过很多消息
5) Topic名称用来标识消息类型,需要提前创建。如果不需要消费某个Topic下的所有消息,可以通过指定消息的Tag进行消息过滤,比如:Consumer.subscribe ( "TopicTest", "tagl II tag2 |I tag3"),表示这个Consumer要消费“TopicTest”下带有tagl或tag2或tag3的消息(Tag是在发送消息时设置的标签)。在填写Tag参数的位置,用null或者“*”表示要消费这个Topic的所有消息。
消费方式:
1. DefaultMQPushConsumer (消费者长轮询读取server消息)
consumer.registerMessageListener((MessageListenerConcurrently) (messages, context) -> {
try{
MessageExt message = messages.get(0);
String body = new String(message.getBody(), StandardCharsets.UTF_8);
log.info("Consumer-获取消息-主题topic为={}, 消费消息为={}", message.getTopic(), body);
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}catch (Exception e){
return ConsumeConcurrentlyStatus.RECONSUME_LATER;
}
});
2. DefaultMQPullConsumer
这种方式需要手动实现 拉取,消费,记录位偏移量,提交回馈等,特别地这种方式当你停止消费者时一定持久化位移偏移量,否则下次从0读取
4.顺序消息
如果要保证消息是流水线工作方式就要保证
1.投递有序,按照业务来说基本也是有序的,但是还是要处理并发的情况
2.消费有序,通常消费者有多个,队列也有多个,这种基本如果不设计业务流转基本搞不定顺序消费,只有设置topic下的队列数量为1才能实现,然后单消费者单线程处理
5.集群实现
6.主从数据同步