mq

mq

active mq

mq,消息中间件,它可以用来存储通信数据

订阅,发送模型

队列详情

功能是解耦合,将服务分开

同步模型

Step1 发送数据 step2 接收数据 step3 接收数据

异步模型

step1 发送数据 step2、step3去mq找数据

概念

  • 消息:两台计算机之间传输的数据单位

  • 消息队列:用来保存消息的容器,如果发送数据时,接收者不可用,那队列会保存消息直到成功传递

  • broker:一个实例,控制台

  • queue:只支持一次消费,消费端关注这个queue

  • topic:可以支持多次消费,只有客户端服务端同时在线才会收到,消息不会保存

  • consumer:消息消费者

    • 同步消费:调用消费者的recive方法阻塞到消息到达
    • 异步消费:注册一个消息监听器,消息到达时触发

消息类型

textmessage

mapmessage

bytesmessage:写的顺序要和读的顺序一致,先写的utf就要先读utf,会有切割字节流的问题,针对文件数据

streammessage

objectmessage:要实现序列化接口,同时在connectionFactory处要添加可信任的类.factory.trustPackages(list),在list里添加某个class的package名称

消费模型

消息默认是异步发送的

在没有开启事务的情况下:

producer发送持久化消息是同步的,调用send会阻塞直到broker把消息保存到磁盘并返回确认。

默认情况下,producer发送非持久化消息是异步发送的,但是在开启事务的情况下,消息都是异步发送

开启事物情况下:

当发送方法在一个事物上下文中时,被阻塞的是 commit 方法而不是 send 方法。commit 方法成功返回意味着所有的持久消息都以被写到二级存储中。

  • pub/sub模型:订阅了的消费者都可以消费
  • p2p模型:只有一个消费者可以消费,其他消费者不可以消费了

流程

创建链接

创建queue或者topic

创建消息创建者\消费者

发送消息/接收消息(接收消息是阻塞的)

应用场景

异步处理,有些服务不需要马上处理消息,等需要的时候再处理数据

解除耦合,两个独立的服务之间通过消息通信.如果没有解除耦合,另一端点出异常则直接返回异常了

顺序保证:mq的消息是顺序排序的,会按照顺序处理.activeMq 里面有 messageGroups 属性,可以指定 JMSXGroupID,消费者会消费指定的 JMSXGroupID。即保证了顺序性,又解决负载均衡的问题

可靠性

一个createSession可以是消费者也可以是生产者,false,auto_ack只对消费者消费数据有兴趣

只有消息被确认并且返回ack后才会清除,客户接收消息,处理消息,返回确认.

在事物会话中,事物被提交时,确认消息自动发生.

非事物会话中,消息何时被确认取决于创建时的应答模式

  • Auto-ack:当消费者调用recv成功返回时,或者调用MessageListener.onmessage方法返回时,会给mq一个ack,代表消息被确认
  • client-ack:消费者通过acknowledge方法确认消息.有个问题是,如果一个消费者在消费10个信息,确认第五个时,后面的5个也会被确认
  • dups-ack:会话迟钝确认,不需要确认

分布式事务,二阶段提交都是靠ack机制,比如消息生产者发送一条消息阻塞住,直到这条消息被消费了才结束阻塞,又或者注册一个listener监听这条消息是否被消费.

while (i<3){
  //确认,会阻塞,与accept相同
            TextMessage message=(TextMessage) consumer.receive();
            //System.out.println(message.getStringProperty("queue"));
            System.out.println(message.getText());
            //session.commit();
            
            if(i==2){
              //确认
                message.acknowledge();
            }
            
            i++;
            
        }        

名词解释:

P:生产者

C:消费者

服务端:P 或者 ActiveMQ服务

客户端:ActiveMQ服务 或者 C

客户端成功接收一条消息的标志是这条消息被签收。成功接收一条消息一般包括如下三个阶段:

1.客户端接收消息;

2.客户端处理消息;

3.消息被签收。

在不带事务的 Session 中,一条消息何时和如何被签收取决于Session的设置。

1.Session.AUTO_ACKNOWLEDGE

当客户端从 receive 或 onMessage成功返回时,Session 自动签收客户端的这条消息的收条。

2.Session.CLIENT_ACKNOWLEDGE

客户端通过调用消息的 acknowledge 方法签收消息。

在带事务的 Session 中,签收自动发生在事务提交时。如果事务回滚,所有已经接收的消息将会被再次传送。

白话总结:

1、对于生产者:服务端端为P,客户端为ActiveMQ服务。 Session设置为AUTO_ACKNOWLEDGE 和CLIENT_ACKNOWLEDGE ,相对来说区别不是很大,根据情况考虑。

2、对于消费者:服务端为ActiveMQ为服务,客户端为C。 Session设置为AUTO_ACKNOWLEDGE ,接收到消息(receive 或 onMessage成功返回时),即为消费成功,然后从队列里移除该数据。不关心该数据有没有正确被处理成我们想要的结果;Session设置为CLIENT_ACKNOWLEDGE 时,必须手动调用acknowledge 方法才为消费成功,然后从队列里移除该条数据。

3、P和C的Session设置成哪种模式,互不影响。

可恢复性

系统的一部分组件失效不会影响整个系统,如果某个处理消息的进程挂掉,只要重启就可以继续消费消息

持久性

jms支持以下两种方式的提交

  • persistent:指示jms provider持久保存,可以让provider不因为自己失败而丢失消息
  • non:不要求持久化消息

kahadb存储:默认的存储,所有的消息都顺序添加到一个日志文件中,同时另外有一个索引文件记录指向这些日志的存储地址,还有一个事物日志用于消息的恢复操作.消息已b tree结构存储,可以快速更新

jdbc:在数据库中存储消息,异步从mq中存到db,消费者先消费mq内存中的数据,再剔除数据库中的数据

优先级

可以扰乱消费的顺序,配置文件需要指定使用优先级的目的(queue),消费端在消费消息时会优先消费优先级高的消息

过期

queue的消息默认永不过期.

当给消息设置了过期时间后,消费端在超时就无法消费了,这类消息会被放入死信队列中,需要从死信队列中取出并重新发送.死信队列不回自动清除,有堆积风险.

生产者可以监视死信队列,将死信队列里的消息取出来,重新投递,投递多少次,同时消费端要做幂等性

activeMq.DLQ

临时目的地

临时创建一个queue或者topic,它们活的时间只是这次链接保持的时间,同时只有临时消费者才能消费这条消息

事物

createSession(是否要事务)

commit();

callback();

与本地事物连在一起,发送消息时要commit不然不发送数据

消息特点

topic

  • 无状态、不保存
  • 不保证发布的每条数据,消费端都能获取到,只有消费者监听后才可以得到消息,否则没法得到消息
  • 一个消费端可以被多个消费端消费
  • 消息有过期时间

queue

  • 消息落地,会保存
  • 保证每条数据都会被消费端接收到
  • 一条消息只能被一个消费端消费
  • 消息被接收后,会通知mq,mq将消息删除

接收消息(死信队列)

接收消息时调用recive方法会阻塞,与accept相同,在IO瓶颈时有性能问题

所以改进方案1,注册一个监听器MessageListener

如果无人接收消息,死信队列数据过多,内存撑爆

producer.setTimetolive(设置消息多少时间失效,进入死信队列,保证了一些有时效性的消息),死信队列也是一个queue,它会将过期的消息从某个queue中取出放到自己的queue,所以也可以使用MessageListener监听,做消息的重新投递.

非持久化消息也可以进入死信队列,都可以配置

独占消费者

只要某个消费者接入了这个queue,那么后续所有消息都由这一个消费者消费,createQueue(“user?excluse=true”)

消息选择器

message = createMessage();

message.setProperty(“week”,1);

设置消息的元数据

createCosumer(“queue”,“week=1”),第二个参数就是分组过滤器,消费者消费元数据中week=1的消息

以分组的形式,可以负载均衡定向分发某一类型的消息.消息筛选

面试问题

如何防止消息重复发送

  • *解决方法*:增加消息状态表。
  • 通俗来说就是一个账本,用来记录消息的处理状态,每次处理消息之前,都去状态表中查询一次,如果已经有相同的消息存在,那么不处理,可以防止重复发送。
  • 2.如何解决mq的重复消费问题
    2.1 重复消费的问题会导致数据库出现脏数据,我们一般通过保证幂等性来解决这个问题
    2.2 幂等性是什么。一次和多次请求某一个资源对于资源本身应该具有同样的结果。如何保证生产者重复消费数据保证幂等性

丢消息怎么办

  • *解决方案*:用持久化消息【*可以使用对数据进行持久化JDBC,AMQ(日志文件),KahaDB和LevelDB*】,或者非持久化消息及时处理不要堆积,或者启动事务,启动事务后,commit()方法会负责任的等待服务器的返回,也就不会关闭连接导致消息丢失了。

持久化消息非常慢

  • 默认的情况下,非持久化的消息是异步发送的,持久化的消息是同步发送的,遇到慢一点的硬盘,发送消息的速度是无法忍受的。但是在开启事务的情况下,消息都是异步发送的,效率会有2个数量级的提升。所以在发送持久化消息时,请务必开启事务模式。其实发送非持久化消息时也建议开启事务,因为根本不会影响性能。

如何防止重复消费

做消息的幂等性处理

如何保证消费顺序

queue,单消费者

消息丢失(出问题才会丢,正常不会丢)

看消息是否持久化,异步发送的消息

负载

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值