zoukankan      html  css  js  c++  java
  • MQ消息队列

    一、为什么要用MQ?

    (1)解耦:如果多个模块或者系统中,互相调用很复杂,维护起来比较麻烦,但是这个调用又不是同步调用,就可以运用MQ到这个业务中。

    (2)异步:这个很好理解,比如用户的操作日志的维护,可以不用同步处理,节约响应时间。

    (3)削峰:在高峰期的时候

    二、怎样保证MQ的高可用?

    RabbitMQ是比较有代表性的,因为是基于主从做高可用性的。

    rabbitmq有三种模式:单机模式、普通集群模式、镜像集群模式。
    如何保证不被重复消费?

    不通的消费队列都会有一个消费通知的机制,如:

    RabbitMQ提供了一个ACK确认消息机制,

    rocketMQ返回一个CONSUME_SUCCESS成功标志

    (1)比如,你拿到这个消息做数据库的insert操作。那就容易了,给这个消息做一个唯一主键,那么就算出现重复消费的情况,就会导致主键冲突,避免数据库出现脏数据。
    (2)再比如,你拿到这个消息做redis的set的操作,那就容易了,不用解决,因为你无论set几次结果都是一样的,set操作本来就算幂等操作。
    (3)如果上面两种情况还不行,上大招。准备一个第三方介质,来做消费记录。以redis为例,给消息分配一个全局id,只要消费过该消息,将<id,message>以K-V形式写入redis。那消费者开始消费前,先去redis中查询有没消费记录即可。

    三、如何保证消费的可靠传输性?
    (1) 生产者丢失数据

    以rabbitMQ为例,rabbitMQ提供了transaction和confirm模式来确保生产者不丢失数据,事务机制,发送消息前,开启事务(channel.txSelect()),发送消息后出现异常,事务回滚(channel.txRollback()),发送成功提交事务(channel.txCommit())。

    上面这种方式吞吐量会下降,因此生产上应该使用confirm模式居多。

    一旦channel进入confirm模式,所有在该通道发布上的消息都会被指派一个唯一的ID(从1开始),消息进来如队列后,rabbitMq会立即发送一个ACK给生产者,其中包含了消息的唯一ID,这就使得生产者知道消息已经到达了消息队列里。如果消息队列没能处理该消息,则会发送一个NACK给生产者进行重试操作。

    ) 消息队列丢失数据

    消息队列丢失的情况一般是开启持久化硬盘配置,这个持久化配置可以和confirm机制配合使用,可以在持久化硬盘之后,发送一个ack给生产者,如果生产者收不到ack信息,会重发信息。

    如何持久化硬盘:

    ①将queue的持久化标识durable设置为true,

    ②发送消息的时候将deliveryMode=2

    这样设置就算rabbitMQ挂了,重启后也能恢复数据

    (3) 消费者丢失数据

    消费者丢失数据一般都是以为采用了自动确认消息模式。消费者收到消息后,rabbitMQ会立即从队列里面删除该消息,这是情况如果消费者出现异常而没有及时处理该消息就会丢失数据。

    解决方案:采用手动确认消息。

    四、如何保证消息的时序性?

    先进先出队列,比如linkedBlockingQueue。

    五、如何保证消息的顺序性

    解决方案:

    拆分为多个queue,每个queue由一个consumer消费;

    或者就一个queue但是对应一个consumer,然后这个consumer内部用内存队列做排队,然后分发给底层不同的worker来处理

    人这辈子没法做太多事情,所以每做一件事都要做到精彩绝伦。 因为,这就是我的宿命。人生苦短,你明白吗? 所以这是我为人生做出的选择
  • 相关阅读:
    常见树的总结
    《深入理解Java虚拟机》读书笔记(第三章)
    《Jave并发编程的艺术》学习笔记(1-2章)
    Java多线程与并发之面试常问题
    Morris遍历-如何用空间复杂度O(1)来遍历二叉树
    BFPRT算法
    Manacher
    maven基础
    play framework + sbt入门之环境搭建
    rancher部署kubernets集群
  • 原文地址:https://www.cnblogs.com/junjun1578/p/15100055.html
Copyright © 2011-2022 走看看