一、Replicated LevelDB: 官网讲解
增加IP 到域名的映射(/etc/hosts 文件)
修改 为相同的borkername
改为 replica levelDB (3个都配,这里列举一个)
<persistenceAdapter>
<replicatedLevelDB
directory="{activemq.data}/leveldb"
replicas="3"
bind="tcp://0.0.0.0:63631"
zkAddress="localhost:2191,localhost:2192,localhost:2193"
zkPassword="123456"
sync="local_disk"
zkPath="/activemq/leveldb-stores"
hostname="wh-mq-server"
/>
</persistenceAdapter>
改端口 02 节点 =》 61617 03 节点 =》 61618
想要启动replica leavel DB 必须先启动所有的zookeper 服务,zookeper 的单机伪节点安装这里不细说了,主要讲zookeper 复制三份后改配置文件,并让之自动生成 myid 文件,并将zk的端口改为之前表格中对应的端口 。这是conf 下的配置文件
其具体配置为:
tickTime=2000
initLimit=10
syncLimit=5
clientPort=2191 // 自行设置
server.1=192.168.17.3:2888:3888
server.2=192.168.17.3:2887:3887
server.3=192.168.17.3:286:3886
dataDir=/zk_server/data/log1 // 自行设置
命令即可让它变为可执行脚本, ./zk_batch.sh start 即可 (即启动了三个zk 的服务)
同理写一个批处理关闭zk 服务的脚本和 批处理开启mq 服务 关闭 mq 服务的脚本。
完成上述之后连接zk 的一个客户端
./zkCli.sh -server 127.0.0.1:2191
连接之后:
表示连接成功
查看我的三个节点: 我的分别是 0…… 3 …… 4 …… 5
查看我的节点状态
get /activemq/leveldb-stores/00000000003
此次验证表明 00000003 的节点状态是master (即为63631 的那个mq 服务) 而其余的(00000004 00000005) activemq 的节点是 slave
如此集群顺利搭建成功 !
此次测试表明只有 8161 的端口可以使用 经测试只有 61 可以使用,也就是61 代表的就是master
测试集群可用性:
首先:
修改java代码
public static final String ACTIVEMQ_URL = "failover:(tcp://192.168.17.3:61616,tcp://192.168.17.3:61617,
tcp://192.168.17.3:61618)?randomize=false";
public static final String QUEUE_NAME = "queue_cluster";
测试:
测试通过连接上集群的 61616
MQ服务收到三条消息:
消息接收
MQ 服务也将消息出队
以上代表集群可以正常使用
此时真正的可用性测试:
杀死 8061 端口的进程 !!!
刷新页面后 8161 端口宕掉,但是 8162 端口又激活了
当 61616 宕机,代码不变发消息 自动连接到 61617 了
这样! 集群的可用性测试成功!
二、面试题:: ?
1> 引入消息队列后 如何保证高可用性
持久化、事务、签收、 以及带复制的 Leavel DB + zookeeper 主从集群搭建
2> 异步投递 Async send(默认异步)
1、对于一个慢消费者,使用同步有可能造成堵塞,消息消费较慢时适合用异步发送消息
2、 activemq 支持同步异步 发送的消息,默认异步。当你设定同步发送的方式和 未使用事务的情况下发持久化消息,这时是同步的。
3、 如果没有使用事务,且发送的是持久化消息,每次发送都会阻塞一个生产者直到 broker 发回一个确认,这样做保证了消息的安全送达,但是会阻塞客户端,造成很大延时 。
4、在高性能要求下,可以使用异步提高producer 的性能。但会消耗较多的client 端内存,也不能完全保证消息发送成功。在 useAsyncSend = true 情况下容忍消息丢失。
// 开启异步投递
activeMQConnectionFactory.setUseAsyncSend(true);
url 后面加参数
开启ActivemqFactury 的Async 为true
将connection 设Async 为true
3 > 如何在投递快还可以保证消息丢失 ?
异步发送消息丢失的情况场景是: UseAsyncSend 为 true 使用 producer(send)持续发送消息,消息不会阻塞,生产者会认为所有的 send 消息均会被发送到 MQ ,如果MQ 突然宕机,此时生产者端尚未同步到 MQ 的消息均会丢失 。 故正确的异步发送方法需要接收回调
同步发送和异步发送的区别就在于 :
同步发送send 不阻塞就代表消息发送成功
异步发送需要接收回执并又客户端在判断一次是否发送
在代码中接收回调的函数 :
activeMQConnectionFactory.setUseAsyncSend(true);
……
for (int i = 1; i < 4 ; i++) {
textMessage = session.createTextMessage("msg--" + i);
textMessage.setJMSMessageID(UUID.randomUUID().toString()+"-- orderr");
String msgid = textMessage.getJMSMessageID();
messageProducer.send(textMessage, new AsyncCallback() {
@Override
public void onSuccess() {
// 发送成功怎么样
System.out.println(msgid+"has been successful send ");
}
@Override
public void onException(JMSException e) {
// 发送失败怎么样
System.out.println(msgid+" has been failure send ");
}
});
}
3> 延迟投递和定时投递
① 在配置文件中设置定时器开关 为 true
② 代码编写
Java 代码中封装的辅助消息类型 ScheduleMessage
可以设置的 常用参数 如下:
long delay = 3 * 1000 ;//延时时间秒
long perid = 4 * 1000 ;//每间隔多久一次延时
int repeat = 7 ;//共循环多少次
for (int i = 1; i < 4 ; i++) {
TextMessage textMessage = session.createTextMessage("delay msg--" + i);
// 消息每过 3 秒投递,每 4 秒重复投递一次 ,一共重复投递 7 次
textMessage.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_DELAY,delay);
textMessage.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_PERIOD,perid);
textMessage.setIntProperty(ScheduledMessage.AMQ_SCHEDULED_REPEAT,repeat);
messageProducer.send(textMessage);
}
4> ActiveMQ 的消息重试机制
最多六次还没发出就会,加入DLQ (死信队列)官网介绍 http://activemq.apache.org/redelivery-policy
5> 死信队列的一些设置
//修改,当嫌6 次太多,设置为 3次 (消费端设置)
// 三次的意思是不计算本来发送的第一次 ,之后再次发送的第三天就被废弃
RedeliveryPolicy redeliveryPolicy = new RedeliveryPolicy();
redeliveryPolicy.setMaximumRedeliveries(3);
activeMQConnectionFactory.setRedeliveryPolicy(redeliveryPolicy);
在spring 中使用 死信机制
6> 如何保证消息不被重复消费,幂等性的问题 ?
幂等性其实就是解决重复提交,解决方案有如下:
1、 给消息分配一个全局id,只要消费过该消息,将<id,message>形式写入redis,那消费前先去redis查询一下就知道有没有重复消费了(textMessage.setJMSMessageID(UUID.randomUUID().toString()) ; )
2、如果是数据库插入操作,可以将这个消息作为唯一主键,重复消费就会冲突