Activemq knowledge points summary

Definition of Message Middleware (MQ)

In fact, there is no standard definition. It is generally believed that message middleware belongs to a subsystem in a distributed system, focusing on the sending and receiving of data, and uses an efficient and reliable asynchronous message transfer mechanism to integrate the remaining subsystems in the distributed system.

Why use message middleware

Assuming an e-commerce transaction scenario, the user calls the inventory system to reduce inventory after placing an order, and then needs to call the logistics system for delivery. If the transaction, inventory, and logistics belong to the same system, then it is an interface call. However, with the development of the system, each module becomes larger and more complex, and the business logic becomes more and more complex. It is bound to be service-oriented and business split. At this time, you need to consider how these systems interact. The first response is RPC (Remote Procedure Call). The system continues to develop, and a transaction may need to call dozens of interfaces to execute the business, such as the risk control system, short message service, etc. At this time, the message middleware is needed to solve the problem.
Therefore, message middleware mainly solves the transfer of messages between distributed systems, while providing scalability and scalability for other subsystems in the distributed system.

为系统带来了:
	1,低耦合,不管是程序还是模块之间,使用消息中间件进行间接通信。
	2,异步通信能力,使得子系统之间得以充分执行自己的逻辑而无需等待。
	3,缓冲能力,消息中间件像是一个巨大的蓄水池,将高峰期大量的请求存储下来慢慢交给后台进行处理,对于秒杀业务来说尤为重要。

What is the difference with RPC

RPC和消息中间件的场景的差异很大程度上在于就是“依赖性”和“同步性”。
比如短信通知服务并不是事交易环节必须的,并不影响下单流程,不是强依赖,所以交易系统不应该依赖短信服务。比如一些数据分析程序可能需要在拿到一天的总销售量,这个就只需要销售中心提供接口在需要时调用即可。
消息中间件出现以后对于交易场景可能是调用库存中心等强依赖系统执行业务,之后发布一条消息(这条消息存储于消息中间件中)。像是短信通知服务、数据统计服务等等都是依赖于消息中间件去消费这条消息来完成自己的业务逻辑。
RPC方式是典型的同步方式,让远程调用像本地调用。消息中间件方式属于异步方式。消息队列是系统级、模块级的通信。RPC是对象级、函数级通信。
相同点:都是分布式下面的通信方式。

What are the usage scenarios of message middleware

1. Asynchronous processing: increase the corresponding speed and increase the amount of concurrency
2. Application decoupling: both the server and the consumer do not care about each other, similar to the blocking queue
3. Traffic peaking: similar to the spike system, when the traffic suddenly reaches its peak , Can ensure that a large number of requests are queued in the queue, and will not cause pressure on the server
4. Log processing: Log processing refers to the use of message queues in log processing, such as Kafka applications, to solve the problem of a large number of log transmissions.
5. Message communication : Message communication means that message queues generally have built-in efficient communication mechanisms, so they can also be used in pure message communication. For example, to implement point-to-point message queues, or chat rooms, etc.

Comparison of common messaging middleware

支持并发量:ActiveMQ(6000+) < RabbitMQ(万级) < RocketMQ(阿里的,十万级) < KafKa(百万级)
如果一般的业务系统要引入MQ,怎么选型:
	用户访问量在ActiveMQ的可承受范围内,而且确实主要是基于解耦和异步来用的,可以考虑ActiveMQ,也比较贴近Java工程师的使用习惯。 
	RabbitMQ,但是确实erlang语言阻止了我们去深入研究和掌控,对公司而言,几乎处于不可控的状态,但是确实是开源的,有比较稳定的支持,活跃度也高。
	对自己公司技术实力有绝对自信的,可以用RocketMQ 。
	所以中小型公司,技术实力较为一般,技术挑战不是特别高,用ActiveMQ、RabbitMQ是不错的选择;大型公司,基础架构研发实力较强,用RocketMQ是很好的选择
	如果是大数据领域的实时计算、日志采集等场景,用Kafka是业内标准的,绝对没问题,社区活跃度很高,几乎是全世界这个领域的事实性规范。

JMS

1,JMS和ActiveMQ
	JMS(Java Messaging Service)是Java平台上有关面向消息中间件的技术规范,实际上是一套api,它便于消息系统中的Java应用程序进行消息交换,并且通过提供标准的产生、发送、接收消息的接口简化企业应用的开发,ActiveMQ而是这个规范的一个具体实现。

2,JMS对象模型
	1)连接工厂。连接工厂负责创建一个JMS连接。
	2)JMS连接。JMS连接(Connection)表示JMS客户端和服务器端之间的一个活动的连接,是由客户端通过调用连接工厂的方法建立的。
	3)JMS会话。JMS会话(Session)表示JMS客户与JMS服务器之间的会话状态。JMS会话建立在JMS连接上,表示客户与服务器之间的一个会话线程。
	4)JMS目的/ Broker。客户用来指定它生产的消息的目标和它消费的消息的来源的对象,一个消息中间件的实例。
	5)JMS生产者和消费者。生产者(Message Producer)和消费者(Message Consumer)对象由Session对象创建,用于发送和接收消息。
	消息的消费可以采用以下两种方法之一:
	• 同步消费。通过调用 消费者的receive 方法从目的地中显式提取消息。receive 方法可以一直阻塞到消息到达。
	• 异步消费。客户可以为消费者注册一个消息监听器,以定义在消息到达时所采取的动作。

3,JMS规范中的消息
	JMS 消息由以下三部分组成:
		• 消息头。每个消息头字段都有相应的getter 和setter 方法。
		• 消息属性。如果需要除消息头字段以外的值,那么可以使用消息属性。
		• 消息体。JMS 定义的消息类型有TextMessage、MapMessage、BytesMessage、
		StreamMessage 和 ObjectMessage。ActiveMQ也有对应的实现。

4,JMS消息模型
	Point-to-Point(P2P),点对点:
		消息通过称为队列的一个虚拟通道来进行交换。队列是生产者发送消息的目的地和接受者消费消息的消息源。每条消息通仅会传送给一个接受者。可能会有多个接受者在一个队列中侦听,但是每个队列中的消息只能被队列中的一个接受者消费。消息存在先后顺序。一个队列会按照消息服务器将消息放入队列中的顺序,把它们传送给消费者当消息已被消费时,就会从队列头部将它们删除。每个消息只有一个消费者(Consumer)(即一旦被消费,消息就不再在消息队列中)发送者发送了消息之后,不管接收者有没有正在运行,它不会影响到消息被发送到队列
		接收者在成功接收消息之后需向队列应答成功,如果希望发送的每个消息都应该被成功处理的话,使用这个P2P模式。
	
	Topic,主题(发布订阅(Pub/Sub):
		1、消息生产者(发布)将消息发布到topic中,同时有多个消息消费者(订阅)消费该消息。和点对点方式不同,发布到topic的消息会被所有订阅者消费。
		2、如果你希望发送的消息可以不被做任何处理、或者被一个消息者处理、或者可以被多个消费者处理的话,那么可以采用topic模型 

ActiveMQ

Embedded ActiveMQ

You can embed a message queue in your own application.

Persistence of message storage

	ActiveMQ的另一个问题就是只要是软件就有可能挂掉,挂掉不可怕,怕的是挂掉之后把信息给丢了,怎么办,可以进行消息的持久化,ActiveMQ提供了几种持久化方式:
		1.	AMQ消息存储-基于文件的存储方式,它具有写入速度快和容易恢复的特点。消息存储在一个个文件中,文件的默认大小为32M,如果一条消息的大小超过了32M,那么这个值必须设置大一点。当一个存储文件中的消息已经全部被消费,那么这个文件将被标识为可删除,在下一个清除阶段,这个文件被删除。AMQ适用于ActiveMQ5.3之前的版本。
		2.	KahaDB消息存储-提供了容量的提升和恢复能力,是现在的默认存储方式;KahaDB是基于文件的本地数据库储存形式,虽然没有AMQ的速度快,但是它具有强扩展性,恢复的时间比AMQ短,从5.4版本之后KahaDB做为默认的持久化方式。
			KahaDB:
				由于KahaDB是默认的持久化存储方案。所以即使你不配置任何的KahaDB参数信息,ActiveMQ也会启动KahaDB。这种情况下,KahaDB文件所在位置是你的ActiveMQ安装路径下的/data/KahaDB子目录。
		3.	JDBC消息存储-消息基于JDBC存储的;
			在配置文件中配置jdbc数据源,并且对应相应的库,在启动之后会自动生成三张表:
				1,activemq_acks:用于存储订阅关系。如果是持久化Topic,订阅者和服务器的订阅关系在这个表保存
				2,activemq_lock:在集群环境中才有用,只有一个Broker可以获得消息,称为MasterBroker,其他的只能作为备份等待MasterBroker不可用,才可能成为下一个Master Broker。这个表用于记录哪个Broker是当前的Master Broker
				3,activemq_msgs:用于存储消息,Queue和Topic都存储在这个表中

		4.	Memory消息存储-基于内存的消息存储,由于内存不属于持久化范畴。所以内存存储不在讨论范围内。

Persistent subscription

	分别运行订阅模式和P2P模式,可以发现,P2P模式缺省把消息进行持久化,而topic模式是没有的。
	一般topic模式实验:
		1、	启动两个消费者,启动一个生产者,发送消息,两个消费者都可以收到。
		2、	关闭一个消费者,生产者发送消息,活跃的消费者可以收到消息,启动被关闭的消费者,无法收到消息。
		3、	关闭所有消费者,生产者发送消息,在ActiveMQ控制台可以看见消息已被接收,关闭再启动ActiveMQ,启动消费者收不到消息。
		如果topic模式下,需要消费者在离线又上线后,不管ActiveMQ是否重启过,都保证可以接受到消息,就需要进行持久化订阅。
	持久Topic消费者端:
		需要设置客户端id:connection.setClientID("Mark");
		消息的destination变为 Topic 
		消费者类型变为TopicSubscriber
		消费者创建时变为session.createDurableSubscriber(destination,"任意名字,代表订阅名 ");
		运行一次消费者,将消费者在ActiveMQ上进行一次注册。然后在ActiveMQ的管理控制台subscribers页面可以看见我们的消费者。
	效果:
		1、	运行生产者,发布消息,多个消费者可以正常收到。
		2、	关闭一个消费者,运行生产者,发布消息后再启动被关闭的消费者,可以收到离线后的消息;
		3、	关闭所有消费者,运行生产者,发布消息后,关闭ActiveMQ再启动,启动所有消费者,都可以收到消息。
	注意:生产者端无需另外单独配置,即使进行了持久订阅,但是消息本身如果是不持久化的,ActiveMQ关闭再启动,这些非持久化的消息会丢失,进行持久订阅的消费者也是收不到自身离线期间的消息的。

Reliability of the message

After the message was sent successfully, the receiving end received the message. Then process it, but for some reason, whether it is high concurrency or IO blocking, the message failed to be processed on the receiving end anyway. The point-to-point feature is a message that will only be received by one receiver. As long as receiver A receives it successfully, receiver B cannot receive this message. If it is some ordinary message, it is fine, but if it is Some very important news, such as the user's payment order, the user's refund, which are related to money, must be guaranteed to succeed, then how to deal with this time? The reliability of the message must be guaranteed. In addition to the persistence of the message, it also includes two aspects. One is that the message sent by the producer can be received by ActiveMQ, and the other is that the consumer receives the message sent by ActiveMQ.

	生产者:
		send方法
			在生产者端,我们会使用send() 方法向ActiveMQ发送消息,默认情况下,持久化消息以同步方式发送,send()方法会被阻塞,直到broker发送一个确认消息给生产者,这个确认消息表示broker已经成功接收到消息,并且持久化消息已经把消息保存到二级存储中。

		事务消息
			事务中消息(无论是否持久化),会进行异步发送,send()方法不会被阻塞。但是commit方法会被阻塞,直到收到确认消息,表示broker已经成功接收到消息,并且持久化消息已经把消息保存到二级存储中。

		总结
			非持久化又不在事务中的消息,可能会有消息的丢失。为保证消息可以被ActiveMQ收到,我们应该采用事务消息或持久化消息。

	消费者:
		对消息的确认有4种机制
		1、	AUTO_ACKNOWLEDGE = 1    自动确认
			    1,“同步”(receive)方法返回message给消息时会立即确认。
			    2,在"异步"(messageListener)方式中,将会首先调用listener.onMessage(message),如果onMessage方法正常结束,消息将会正常确认。如果onMessage方法异常,将导致消费者要求ActiveMQ重发消息。此外需要注意,消息的重发次数是有限制的,每条消息中都会包含“redeliveryCounter”计数器,用来表示此消息已经被重发的次数,如果重发次数达到阀值,将导致broker端认为此消息无法消费,此消息将会被删除或者迁移到"dead letter"通道中。
 				因此当我们使用messageListener方式消费消息时,可以在onMessage方法中使用try-catch,这样可以在处理消息出错时记录一些信息,而不是让consumer不断去重发消息;如果你没有使用try-catch,就有可能会因为异常而导致消息重复接收的问题,需要注意onMessage方法中逻辑是否能够兼容对重复消息的判断。

		2、	CLIENT_ACKNOWLEDGE = 2    客户端手动确认   
				客户端手动确认,这就意味着AcitveMQ将不会“自作主张”的为你ACK任何消息,开发者需要自己择机确认。可以用方法: message.acknowledge(),或session.acknowledge();效果一样。
				如果忘记调用acknowledge方法,将会导致当consumer重启后,会接受到重复消息,因为对于broker而言,那些尚未真正ACK的消息被视为“未消费”。
				我们可以在当前消息处理成功之后,立即调用message.acknowledge()方法来"逐个"确认消息,这样可以尽可能的减少因网络故障而导致消息重发的个数;当然也可以处理多条消息之后,间歇性的调用acknowledge方法来一次确认多条消息,减少ack的次数来提升consumer的效率,不过需要自行权衡。

		3、	DUPS_OK_ACKNOWLEDGE = 3    自动批量确认
				类似于AUTO_ACK确认机制,为自动批量确认而生,而且具有“延迟”确认的特点,ActiveMQ会根据内部算法,在收到一定数量的消息自动进行确认。在此模式下,可能会出现重复消息,什么时候?当consumer故障重启后,那些尚未ACK的消息会重新发送过来。

		4、	SESSION_TRANSACTED = 0    事务提交并确认
				当session使用事务时,就是使用此模式。当决定事务中的消息可以确认时,必须调用session.commit()方法,commit方法将会导致当前session的事务中所有消息立即被确认。在事务开始之后的任何时机调用rollback(),意味着当前事务的结束,事务中所有的消息都将被重发。当然在commit之前抛出异常,也会导致事务的rollback。

		ACK_MODE描述了Consumer与broker确认消息的方式(时机),比如当消息被Consumer接收之后,Consumer将在何时确认消息。所以ack_mode描述的不是producer于broker之间的关系,而是customer于broker之间的关系。
		对于broker而言,只有接收到ACK指令,才会认为消息被正确的接收或者处理成功了,通过ACK,可以在consumer与Broker之间建立一种简单的“担保”机制.
		session=connection.createSession(false,Session.AUTO_ACKNOWLEDGE);第一个参数:是否支持事务,如果为true,则会忽略第二个参数,自动被jms服务器设置为SESSION_TRANSACTED

Wildcard subscription

	Wildcards 用来支持联合的名字分层体系(federated name hierarchies)。它不是JMS 规范的一部分,而是ActiveMQ 的扩展。ActiveMQ 支持以下三种
	wildcards:
	• "." 用于作为路径上名字间的分隔符。
	• "*" 用于匹配路径上的任何名字。
	• ">" 用于递归地匹配任何以这个名字开始的destination。
	订阅者可以明确地指定destination 的名字来订阅消息,或者它也可以使用wildcards 来定义一个分层的模式来匹配它希望订阅的 destination。

Dead letter queue

	用来保存处理失败或者过期的消息。 
	出现下面情况时,消息会被重发: 
		i.	事务会话被回滚。
		ii.	事务会话在提交之前关闭。
		iii.会话使用CLIENT_ACKNOWLEDGE模式,并且Session.recover()被调用。 
		iv.	自动应答失败
	当一个消息被重发超过最大重发次数(缺省为6次,消费者端可以修改)时,会给broker发送一个"有毒标记“,这个消息被认为是有问题,这时broker将这个消息发送到死信队列,以便后续处理。 
	注意:可以在配置文件(activemq.xml)来调整死信发送策略,自定义策略,可以单独使用死信消费者处理这些死信,死信队列里面的消息必须要定时处理,不然会堆积的很多影响性能。

Mirrored Queue (just understand)

Messages in each queue of ActiveMQ can only be consumed by one consumer. However, sometimes, you want to be able to monitor the message flow between the producer and the consumer.
MirroredQueue: Broker will forward all messages sent to a certain queue to a topic with a similar name, so the monitoring program only needs to subscribe to this topic

Issues to be considered in the consumer cluster

	我们现实中往往有这样的需求:
		1. 消息接收方和发送方都是集群。 
		2. 同一个消息的接收方可能有多个集群进行消息的处理。
		3. 不同集群对于同一条消息的处理不能相互干扰。
	希望可以达到如下的效果:
		1,级联,将Jms的Topic和Queue进行级联使用。缺点,实现方式繁重,需要独立的中转的消息订阅者来完成,多了一次消息的投递和一次消息消费过程,对效率有影响,增加了消息中间件负载压力。
		2,ActiveMQ提供了虚拟主题和组合Destinations都可以达到这个效果。
			虚拟Destination:
				对于消息发布者来说,就是一个正常的Topic,名称以VirtualTopic.开头。例如VirtualTopic.vtgroup
				对于消息接收端来说,是个队列,不同应用里使用不同的前缀作为队列的名称,即可表明自己的身份即可实现消费端应用分组。
				例如Consumer.A.VirtualTopic. vtgroup,说明它是名称为A群组的消费端,同理Consumer.B.VirtualTopic. vtgroup说明是一个名称为B群组的客户端。
				默认虚拟主题的前缀是 :VirtualTopic.
				消费虚拟地址默认格式:Consumer.*.VirtualTopic.

			组合Destination:
				组合队列允许用一个虚拟的destination代表多个destinations。这样就可以通过composite destinations在一个操作中同时向多个destination发送消息。
				多个destination之间采用“,”分割。例如:
				Queue queue = new ActiveMQQueue("FOO.A,FOO.B,FOO.C");
				或
				Destination destination = session.createQueue("my-queue,my-queue2");
				如果希望使用不同类型的destination,那么需要加上前缀如queue:// 或topic://,例如:
				Queue queue = new ActiveMQQueue("cd.queue,topic://cd.mark");

ActiveMQ high availability cluster

	ActiveMQ的集群方式主要由两种:Master-Slave和Broker Cluster
		1,Master-Slave
			Master-Slave方式中,只能是Master提供服务,Slave是实时地备份Master的数据,以保证消息的可靠性。当Master失效时,Slave会自动升级为Master,客户端会自动连接到Slave上工作。Master-Slave模式分为四类:Pure Master Slave、Shared FileSystemMasterSlave和JDBCMasterSlave,以及ReplicatedLevelDBStore方式。Master-Slave方式都不支持负载均衡,但可以解决单点故障的问题,以保证消息服务的可靠性。
			Pure Master Slave方式:
				ActiveMQ5.8以前支持,自从Activemq5.8开始,Activemq的集群实现方式取消了传统的PureMasterSlave方式,并从Activemq5.9增加了基于zookeeper+leveldb的实现方式。使用两个ActiveMQ服务器,一个作为Master,Master不需要做特殊的配置;另一个作为Slave,配置activemq.xml文件,在<broker>节点中添加连接到Master的URI和设置Master失效后不关闭Slave。

			Shared File System Master Slave方式:
				就是利用共享文件系统做ActiveMQ集群,是基于ActiveMQ的默认数据库kahaDB完成的,kahaDB的底层是文件系统。这种方式的集群,Slave的个数没有限制,哪个ActiveMQ实例先获取共享文件的锁,那个实例就是Master,其它的ActiveMQ实例就是Slave,当当前的Master失效,其它的Slave就会去竞争共享文件锁,谁竞争到了谁就是Master。这种模式的好处就是当Master失效时不用手动去配置,只要有足够多的Slave。如果各个ActiveMQ实例需要运行在不同的机器,就需要用到分布式文件系统了。

			Shared  JDBC Master Slave:
			JDBC Master Slave模式和Shared File Sysytem MasterSlave模式的原理是一样的,只是把共享文件系统换成了共享数据库。我们只需在所有的ActiveMQ的主配置文件中activemq.xml添加数据源,所有的数据源都指向同一个数据库。然后修改持久化适配器。这种方式的集群相对SharedFileSystemMasterSlave更加简单,更加容易地进行分布式部署,但是如果数据库失效,那么所有的ActiveMQ实例都将失效。

			
		2,Broker Cluster
			Broker Cluster主要是通过network of Brokers在多个ActiveMQ实例之间进行消息的路由。BrokerCluster模式支持负载均衡,可以提高消息的消费能力,但不能保证消息的可靠性。所以为了支持负载均衡,同时又保证消息的可靠性,我们往往会采用Msater-Slave+Broker Cluster的模式。

Guess you like

Origin blog.csdn.net/qq_28822933/article/details/85238379