ActiveMQ知识盘点【贰】_设计实现和ActiveMQ集群

上篇文章:ActiveMQ知识盘点【壹】_JMS介绍及两种消息模式


上文介绍了JMS规范的消息模式和组成构件,本文将说一下如何基于ActiveMQ来完成消息队列的使用。


点对点模式


服务端代码:


String user = ActiveMQConnection.DEFAULT_USER;
		String password = ActiveMQConnection.DEFAULT_PASSWORD;
		String url = ActiveMQConnection.DEFAULT_BROKER_URL;
		String subject = "queue.test";
		ConnectionFactory contectionFactory = new ActiveMQConnectionFactory( user, password, url);
		try {
			Connection connection = contectionFactory.createConnection();
			connection.start();
			Session session = connection.createSession(Boolean.TRUE, Session.AUTO_ACKNOWLEDGE);
			Destination destination = session.createQueue(subject);
			MessageProducer producer = session.createProducer(destination);
            producer.setDeliveryMode(DeliveryMode.PERSISTENT);//消息是否持久化,仅queue模式可用
			for (int i = 0; i < 1000; i++) {
				MapMessage message = session.createMapMessage();
				message.setString("msg", "test"+i);
				producer.send(message);
				session.commit();
				System.out.println("发送消息:" + message.getString("msg"));
			}
			producer.close();
			session.close();
			connection.close();
		} catch (Exception e) {
			e.printStackTrace();
		}

消费者代码


String user = ActiveMQConnection.DEFAULT_USER;
		String password = ActiveMQConnection.DEFAULT_PASSWORD;
		String url = ActiveMQConnection.DEFAULT_BROKER_URL;
		String subject = "TOOL.DEFAULT";
		ConnectionFactory connectionFactory = new ActiveMQConnectionFactory( user, password, url);
		Connection connection;
		try {
			connection = connectionFactory.createConnection();
			connection.start();
			final Session session = connection.createSession(Boolean.TRUE, Session.AUTO_ACKNOWLEDGE);
			Destination destination = session.createQueue(subject);
			MessageConsumer message = session.createConsumer(destination);
			message.setMessageListener(new MessageListener() {
				public void onMessage(Message msg) {
					MapMessage message = (MapMessage) msg;
					try {
						System.out.println("收到消息:" + message.getString("msg")));
						session.commit();
						Thread.sleep(1000);
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
				/**
				 * 实现了一个监听器,监听消息的传递,这样只要每有一个消息,都会即时的传递到程序中。
				        但是,这样的处理,在高并发的时候,因为它是被动接收,并没有考虑到程序的处理能力,可能会压跨系统,那要怎么办呢?
				 */
			});
			Thread.sleep(30000);
			session.close();
			connection.close();
		} catch (JMSException e) {
			e.printStackTrace();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}


发布/订阅模式


生产者代码


String user = ActiveMQConnection.DEFAULT_USER;
		String password = ActiveMQConnection.DEFAULT_PASSWORD;
		String url = "tcp://localhost:61616";
		String subject = "TOPIC_TEST2";
		ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(user, password, url);
		Connection connection;
		try {
			connection = factory.createConnection();
			connection.start();
			Session session = connection.createSession(Boolean.TRUE, Session.CLIENT_ACKNOWLEDGE);
			Topic topic = session.createTopic(subject);
			MessageProducer producer = session.createProducer(topic);
			for (int i = 0; i < 20; i++) {
				MapMessage message = session.createMapMessage();
				message.setString("count", "Test"+i);
				producer.send(message);
				System.out.println("--发送消息:" + message.getString("count"));
			}
			session.commit();
			session.close();
			connection.close();
		} catch (JMSException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}

消费者代码


String user = ActiveMQConnection.DEFAULT_USER;
		String password = ActiveMQConnection.DEFAULT_PASSWORD;
		String url = ActiveMQConnection.DEFAULT_BROKER_URL;
		String subject = "TOPIC_TEST2";
		ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(user, password, url);
		Connection connection;
		try {
			connection = factory.createConnection();
			connection.start();
			final Session session = connection.createSession(Boolean.TRUE, Session.CLIENT_ACKNOWLEDGE);
			Topic topic = session.createTopic(subject);
			MessageConsumer consumer = session.createConsumer(topic);
			consumer.setMessageListener(new MessageListener() {
				public void onMessage(Message msg) {
					MapMessage message = (MapMessage) msg;
					try {
						System.out.println("--订阅者[2]收到消息:" + message.getString("count"));
						session.commit();
						Thread.sleep(1000);
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
			});
		} catch (JMSException e) {
			e.printStackTrace();
		}


对于上面使用的api,有几点需要补充说明一下:


在使用Connection创建Session的时候,接口是这样的:createSession(boolean transacted, int acknowledgeMode)。

第一个参数transacted是否支持事务,如果为true,则会忽略第二个参数将被设置为SESSION_TRANSACTED(0)。当第一个参数为false时,acknowledgeMode的值选择如下三个枚举值:

Session.AUTO_ACKNOWLEDGE(1)为自动确认,客户端发送和接收消息不需要做额外的工作。哪怕是接收端发生异常,也会被当作正常发送成功。
Session.CLIENT_ACKNOWLEDGE(2)为客户端确认。客户端接收到消息后,必须调用javax.jms.Message的acknowledge方法。jms服务器才会当作发送成功,并删除消息。
Session.DUPS_OK_ACKNOWLEDGE(3)允许副本的确认模式。一旦接收方应用程序的方法调用从处理消息处返回,会话对象就会确认消息的接收;而且允许重复确认。

需要说明的是,上述配置均只在点对点模式下生效。


Session接口支持创建如下类型的消息:

createTextMessage()    纯字符串的数据
createObjectMessage()    序列化的对象
createStreamMessage()    流,可以用来传递文件等
createBytesMessage()    字节
createMapMessage()    键值对
createMessage()        javax.jms.Message



ActiveMQ集群


ActiveMQ集群自身并没有集成集群部署功能,因此需要借助ZooKeeper来实现集群。

使用ZooKeeper注册所有的ActiveMQ Broker。只有其中的一个Broker可以提供服务,被视为 Master,其他的 Broker 处于待机状态,被视为Slave。Master会将所有的存储操作实时同步给所有Slave。如果Master因故障而不能提供服务,Zookeeper会从Slave中选举出一个Broker充当Master。


ActiveMQ的主从模式特点有:

1)Master 和 Slave各自都单独存储持久化的消息,它们不共享数据;

2)Master收到持久化消息时,需要先同步(sync)给Slave之后,才向Producer发送ACK确认;

3)只有Master负责Client的请求,Slave不接收Client请求。Slave连接到Master,负责备份消息;

4)Master出现故障,Slave有两种处理方式:(1)自己成为Master,(2)关闭;

5)Master 与 Slave之间可能会出现“Split Brain”现象(脑裂问题)。比如:Master本身是正常的,但是Master与Slave之间的网络出现故障,网络故障导致Slave认为Master已经宕机,因为它自己会成为Master(根据配置:shutdownOnMasterFailure)。此时,对Client而言,就会存在两个Master;

6)Slave 只能同步它连接到Master之后的消息。在Slave连接到Master之前Producer向Master发送的消息将不会同步给Slave,这可以通过配置(waitForSlave)参数,只有当Slave也启动之后,Master才开始初始化TransportConnector接受Client的请求(Producer的请求);

7)如果Master或者Slave其中之一宕机,它们之间不同步的消息无法自动进行同步,此时只能手动恢复不同步的消息了。也就是说:“ActiveMQ没有提供任何有效的手段,能够让master与slave在故障恢复期间,自动进行数据同步”;

8)对于非持久化消息,并不会同步给Slave。因此,Master宕机,非持久化消息会丢失。


也就是说,目前ActiveMQ集群并不是高可用的。


ActiveMQ的配置文件


在安装目录conf下,有个Active.xml文件为参考配置文件。常用的配置可参考下面的文章:


http://wosyingjun.iteye.com/blog/2314683




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值