消息队列MQ

消息队列MQ总结

消息队列技术是分布式应用间交换信息的一种技术。消息队列可驻留在内存或磁盘上,队列存储消息直到它们被应用程序读走。通过消息队列,应用程序可独立地执行–它们不需要知道彼此的位置、或在继续执行前不需要等待接收程序接收此消息。目前使用较多的消息队列有ActiveMQ,RabbitMQ,ZeroMQ,Kafka,MetaMQ,RocketMQ。

一、业务场景说明:

消息队列在大型电子商务类网站,如京东、淘宝、去哪儿等网站有着深入的应用,
队列的主要作用是消除高并发访问高峰,加快网站的响应速度。

在不使用消息队列的情况下,用户的请求数据直接写入数据库,在高并发的情况下,会对数据库造成巨大的压力,同时也使得系统响应延迟加剧。

在使用队列后,用户的请求发给队列后立即返回,
(例如: 当然不能直接给用户提示订单提交成功,京东上提示:您“您提交了订单,请等待系统确认”),
再由消息队列的消费者进程从消息队列中获取数据,异步写入数据库。
由于消息队列的服务处理速度远快于数据库,因此用户的响应延迟可得到有效改善。

二、应用场景

1、应用解耦:
将消息写入消息队列,需要消息的系统自己从消息队列中订阅,从而生产系统不需要做任何修改;

2、异步消息:
将消息写入消息队列,非必要的业务逻辑以异步的方式运行,加快响应速度;

3、流量消峰;
消费系统慢慢的按照数据库能处理的并发量,从消息队列中慢慢拉取消息。在生产中,这个短暂的高峰期积压是允许的。

4、日志处理
日志处理是指将消息队列用在日志处理中,比如Kafka的应用,解决大量日志传输的问题。

5、消息通讯
消息通讯是指,消息队列一般都内置了高效的通信机制,因此也可以用在纯的消息通讯。比如实现点对点消息队列,或者聊天室等。

三、消息队列缺点

1、 系统可用性降低:若消息队列挂了,系统也就用不了了;
2、 系统复杂性增加:要考虑多方面,如一致性问题、如何保证消息不被重复消费,如何保证消息可靠传输等。

四、如何保证消息不被重复消费

因为网络传输等等故障,消费者确认信息没有传送到消息队列,导致消息队列不知道自己已经消费过该消息了,再次将该消息分发给其他的消费者。
如何解决?这个问题针对业务场景来答分以下几点
  (1)比如,你拿到这个消息做数据库的insert操作。那就容易了,给这个消息做一个唯一主键,那么就算出现重复消费的情况,就会导致主键冲突,避免数据库出现脏数据。
  (2)再比如,你拿到这个消息做redis的set的操作,那就容易了,不用解决,因为你无论set几次结果都是一样的,set操作本来就算幂等操作。
  (3)如果上面两种情况还不行,上大招。准备一个第三方介质,来做消费记录。以redis为例,给消息分配一个全局id,只要消费过该消息,将<id,message>以K-V形式写入redis。那消费者开始消费前,先去redis中查询有没消费记录即可。

五、如何保证消费的可靠性传输?

我们在使用消息队列的过程中,应该做到消息不能多消费,也不能少消费。如果无法做到可靠性传输,可能给公司带来千万级别的财产损失。同样的,如果可靠性传输在使用过程中,没有考虑到,这不是给公司挖坑么,你可以拍拍屁股走了,公司损失的钱,谁承担。还是那句话,认真对待每一个项目,不要给公司挖坑。
回答:其实这个可靠性传输,每种MQ都要从三个角度来分析:生产者弄丢数据、消息队列弄丢数据、消费者弄丢数据

六、ActiveMQ

1、Apache ActiveMQ是Apache软件基金会所研发的开放源代码消息中间件;由于ActiveMQ是一个纯Java程序,因此只需要操作系统支持Java虚拟机,ActiveMQ便可执行。AcitveMQ是作为一种消息存储和分发组件,涉及到client与broker端数据交互的方方面面,它不仅要担保消息的存储安全性,还要提供额外的手段来确保消息的分发是可靠的。虽然是java写的消息队列,但是提供Java, C, C++, C#, Ruby, Perl, Python, PHP各种客户端,所以语言上是没什么问题的。配置和使用,基本上是java xml这一套。同时对jms、spring之类的支持很友好。

2、对于消息的传递有两种类型:

点对点模式(queue):
点对点的模式主要建立在一个队列上面,当连接一个列队的时候,发送端不需要知道接收端是否正在接收,可以直接向ActiveMQ发送消息,发送的消息,将会先进入队列中,如果有接收端在监听,则会发向接收端,如果没有接收端接收,则会保存在activemq服务器,直到接收端接收消息,点对点的消息模式可以有多个发送端,多个接收端,但是一条消息,只会被一个接收端给接收到,哪个接收端先连上ActiveMQ,则会先接收到,而后来的接收端则接收不到那条消息。

发布订阅模式(topics )
订阅/发布模式,同样可以有着多个发送端与多个接收端,但是接收端与发送端存在时间上的依赖,就是如果发送端发送消息的时候,接收端并没有监听消息,那么ActiveMQ将不会保存消息,将会认为消息已经发送,换一种说法,就是发送端发送消息的时候,接收端不在线,是接收不到消息的,哪怕以后监听消息,同样也是接收不到的。这个模式还有一个特点,那就是,发送端发送的消息,将会被所有的接收端给接收到,不类似点对点,一条消息只会被一个接收端给接收到。

3、使用方法
生产者:生产消息,发送端。

第一步:创建ConnectionFactory对象,需要指定服务端ip及端口号。
第二步:使用ConnectionFactory对象创建一个Connection对象。
第三步:开启连接,调用Connection对象的start方法。
第四步:使用Connection对象创建一个Session对象。
第五步:使用Session对象创建一个Destination对象(topic、queue),此处创建一个Queue对象。
第六步:使用Session对象创建一个Producer对象。
第七步:创建一个Message对象,创建一个TextMessage对象。
第八步:使用Producer对象发送消息。
第九步:关闭资源。

@Test
public void testQueueProducer() throws Exception {

// 第一步:创建ConnectionFactory对象,需要指定服务端ip及端口号。
//brokerURL服务器的ip及端口号
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://192.168.25.168:61616");

// 第二步:使用ConnectionFactory对象创建一个Connection对象。
Connection connection = connectionFactory.createConnection();

// 第三步:开启连接,调用Connection对象的start方法。
connection.start();

// 第四步:使用Connection对象创建一个Session对象。
//第一个参数:是否开启事务。true:开启事务,第二个参数忽略。
//第二个参数:当第一个参数为false时,才有意义。消息的应答模式。1、自动应答2、手动应答。一般是自动应答。
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);

// 第五步:使用Session对象创建一个Destination对象(topic、queue),此处创建一个Queue对象。
//参数:队列的名称。
Queue queue = session.createQueue("test-queue");

// 第六步:使用Session对象创建一个Producer对象。
MessageProducer producer = session.createProducer(queue);

// 第七步:创建一个Message对象,创建一个TextMessage对象。
/*TextMessage message = new ActiveMQTextMessage();
message.setText("hello activeMq,this is my first test.");*/
TextMessage textMessage = session.createTextMessage("hello activeMq,this is my first test.");

// 第八步:使用Producer对象发送消息。
producer.send(textMessage);

// 第九步:关闭资源。
producer.close();
session.close();
connection.close();
}

消费者:接收消息。

第一步:创建一个ConnectionFactory对象。
第二步:从ConnectionFactory对象中获得一个Connection对象。
第三步:开启连接。调用Connection对象的start方法。
第四步:使用Connection对象创建一个Session对象。
第五步:使用Session对象创建一个Destination对象。和发送端保持一致queue,并且队列的名称一致。
第六步:使用Session对象创建一个Consumer对象。
第七步:接收消息。
第八步:打印消息。
第九步:关闭资源

@Test
public void testQueueConsumer() throws Exception {

	// 第一步:创建一个ConnectionFactory对象。
	ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://192.168.25.168:61616");
	
	// 第二步:从ConnectionFactory对象中获得一个Connection对象。
	Connection connection = connectionFactory.createConnection();
	
	// 第三步:开启连接。调用Connection对象的start方法。
	connection.start();
	
	// 第四步:使用Connection对象创建一个Session对象。
	Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
	
	// 第五步:使用Session对象创建一个Destination对象。和发送端保持一致queue,并且队列的名称一致。
	Queue queue = session.createQueue("test-queue");
	
	// 第六步:使用Session对象创建一个Consumer对象。
	MessageConsumer consumer = session.createConsumer(queue);

	// 第七步:接收消息。
	consumer.setMessageListener(new MessageListener() {

	@Override
	public void onMessage(Message message) {
		try {
		
			TextMessage textMessage = (TextMessage) message;
			String text = null;
		
			//取消息的内容
			text = textMessage.getText();
		
			// 第八步:打印消息。
			System.out.println(text);
		
		} catch (JMSException e) {
			e.printStackTrace();
		}
	
	}

	});

	//等待键盘输入
	System.in.read();
	
	// 第九步:关闭资源
	consumer.close();
	
	session.close();
	
	connection.close();

	}

七、Kafka和activemq对比

相比过去经常使用的activemq,kafka确实非常的不同,做一个对比来深化印象

对比ActivemqKafka
接口协议遵守JMS规范,各语言支持较好没有遵循标准MQ接口协议,使用较为复杂
吞吐量较低,磁盘随机读写较高,磁盘顺序读写
游标位置AMQ来管理,无法读取历史数据客户端自己管理,不乐意甚至重新读一遍也行
HA机制主从复制,竞争锁的方式来选举新的主节点和hadoop系列产品一样,由zk管理所有节点

说到底,主要还是做为kafka的消费方,能感受到最大的不同还是在于几个:

  • 1.吞吐量确实非常高
  • 2.可以重读历史数据

但是也有一些缺点:概念上比较复杂,相对于AMQ只需要知道ip和队列名你就能获得数据,Kafka使用起来非常繁琐
在这里插入图片描述
参考:
一个用消息队列 的人,不知道为啥用 MQ,这就有点尴尬
activeMQ吐血总结
activemq、rabbitmq、kafka原理和比较

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值