在对比了RabbitMQ,apacheMQ之后,发现还是 rocketMQ 好用。
为什么好用,百度查查就都知道了。
不说废话直接说说 Linux安装:
下载地址
[release 下载地址](https://github.com/apache/incubator-rocketmq/releases)
https://github.com/apache/incubator-rocketmq/releases
rocketmq-all-4.0.0-incubating-bin-release.zip
就不多说了
进入安装文件夹的bin 下面
使用命令:nohup sh mqnamesrv &
查看 nohup日志
发现报错信息Caused by: java.net.UnknownHostException: smkzfbweb02: 未知的名称或服务
这个时候查看文件/etc/hosts 和 /etc/hostname
发现问题所在了,我的生产服务器的hostname 被管理员改了,但是没有加入到 hosts 对应列表中,所以报错。java.net.UnknownHostException
再次启动
The Name Server boot success. serializeType=JSON
使用命令 nohup sh mqbroker -n “1273.0.0.1:9876” &
查看日志
这里说的是# Native memory allocation (malloc) failed to allocate 8589934592 bytes for committing reserved memory. 内存不足够了。
查看配置文件
runbroker.sh文件是 broker 的启动文件
runserver.sh 文件是 namesev 启动文件
这里发现他们的默认需要的内存 都很大,所以根据自己的服务器配置 减少一些配置
配置好了之后再启动就OK了。
package com.cat.common.rocketmq;
import java.util.Properties;
import org.apache.log4j.Logger;
import com.alibaba.rocketmq.client.consumer.DefaultMQPushConsumer;
import com.alibaba.rocketmq.client.exception.MQClientException;
import com.alibaba.rocketmq.client.producer.DefaultMQProducer;
import com.alibaba.rocketmq.client.producer.SendResult;
import com.alibaba.rocketmq.common.message.Message;
import com.alibaba.rocketmq.common.protocol.heartbeat.MessageModel;
import com.cat.common.lang.RDate;
import com.cat.common.lang.RString;
import com.cat.common.lang.RUuid;
import com.cat.common.properties.PropertiesUtil;
/**
* RocketMQ不保证消息不重复,如果你的业务需要保证严格的不重复消息,需要你自己在业务端去重。
* 线上应该关闭autoCreateTopicEnable,即在配置文件中将其设置为false。。后果就是:以后所有该TOPIC的消息,都将发送到这台broker上,达不到负载均衡的目的。
* API 3.6.2.Final JAR包是有问题,不推荐使用,目前使用,3.5.9JAR 可以
* 使用3.6.2jar问题是,生产者发送的消息,消费者消费后,不能把消息状态同步给 broken,导致消费者 重启后,还是会再次受到 消息,重复消费。
* 集群消费者= 多个消费者都是 集群消费者,订阅了同一个消息后,broken会把消息平均分配到 所有集群消费者
* 不同的集群消费者(指定了不通的组名),订阅同一个TOPIC ,都会收到这个topic消息
* 广播消费者= 多个广播消费者 订阅了同一个消息后,每个广播消费者都会 接收到消息
* 同一个JVM里面只能存在唯一的 组名+实例名 的 生产者,或者是消费者,所以以下的生产者和消费者的实例名称都用uuid 指定
* @author luoyang
*
*/
public class RocketMqUtils{
private static Logger _logger = Logger.getLogger(RocketMqUtils.class);
private static final Logger _socketLog = Logger.getLogger("SocketMQSendMessage");
private static DefaultMQProducer producer;
private static DefaultMQPushConsumer consumer;
private static DefaultMQPushConsumer broadConsumer;
private static Object obj = null;
private static Properties properties = null;
private static void initProperties(){
if(null == properties){
properties = new Properties();
// String path = RSystemConfig.Home_Path + "socketmq.properties";
String path = "d://socketmq.properties";
properties = PropertiesUtil.getInstance().getProperties(path);
_logger.info(" init socketmq.properties success.");
}
}
public static void sendMessage(String topic,
String messageContent){
try{
if(RString.isBlank(topic)){
return;
}
if(null == producer){
getProducer();
}
_logger.info("sendMessage topic=" + topic + " messageContent=" + messageContent);
_socketLog.info(RString.format("{0}, sendMessage topic={1}, messageContent={2}", RDate.getCurrentTimeStr() + "|", topic, messageContent));
// topic, body
Message msg = new Message(topic, messageContent.getBytes());
SendResult sendResult = producer.send(msg);
_logger.info("sendMessage sendResult= " + sendResult.toString());
}catch(Exception e){
_socketLog.error(RDate.getCurrentTimeStr() + "| sendMessage topic=" + topic + " messageContent=" + messageContent, e);
}
}
/**
* 发送消息,工具类
*
* @param topic
* @param messageContent 消息内容
* @param repeatTime 如果发送失败,允许重复发送的次数,每次失败间隔200ms之后继续发送
*/
public static void sendMessage(String topic,
String messageContent,
int repeatTime){
_logger.info("sendMessage topic=" + topic + " messageContent=" + messageContent);
_socketLog.info(RString.format("{0}, sendMessage topic={1}, messageContent={2}", RDate.getCurrentTimeStr() + "|", topic, messageContent));
if(RString.isBlank(topic)){
return;
}
if(null == producer){
getProducer();
}
boolean result = false;
for(int i = 1; i <= repeatTime; i++){
try{
Message msg = new Message(topic, messageContent.getBytes());
SendResult sendResult = producer.send(msg);
_logger.info("sendMessage sendResult= " + sendResult.toString());
result = true;
}catch(Exception e){
e.printStackTrace();
_logger.error("send message have exception" + e + "topic=" + topic + " messageContent=" + messageContent);
}
_logger.info("sendMessage topic=" + topic + " messageContent=" + messageContent);
if(!result){
try{
Thread.sleep(200);
}catch(InterruptedException e){
e.printStackTrace();
_logger.error("send message have exception" + e + "topic=" + topic + " messageContent=" + messageContent + "repeat time=" + i);
}
continue;
}else{
break;
}
}
}
private static synchronized DefaultMQProducer getProducer(){
if(null != producer){
return producer;
}
initProperties();
//一个jvm内,具有相同producerGroup名字的生产者实例只有一个。
producer = new DefaultMQProducer(RTopicConstants.Product_Group);
producer.setNamesrvAddr(properties.getProperty("namesrv_addr"));
producer.setInstanceName(RUuid.makeUuid());
try{
// 生产者开启
producer.start();
// 关闭容器时,关闭生产者
Runtime.getRuntime().addShutdownHook(new Thread(new Runnable(){
public void run(){
_logger.info("getProducer" + ".............producer.shutdown.....");
producer.shutdown();
}
}));
_logger.info("getProducer init product success..data[namesrvAddr={0}]" + properties.getProperty("namesrv_addr"));
}catch(MQClientException e){
e.printStackTrace();
_logger.error("getProducer have exception" + e);
}
return producer;
}
public static DefaultMQPushConsumer getConsumer(){
if(null != obj){
return consumer;
}
initConsumer();
return consumer;
}
public static DefaultMQPushConsumer getBroadConsumer(){
if(null != obj){
return broadConsumer;
}
initConsumer();
return broadConsumer;
}
private static synchronized void initConsumer(){
try{
if(null == obj){
initProperties();
consumer = new DefaultMQPushConsumer(RTopicConstants.Consumer_Group);
consumer.setNamesrvAddr(properties.getProperty("namesrv_addr"));
consumer.setInstanceName(RUuid.makeUuid());
broadConsumer = new DefaultMQPushConsumer(RTopicConstants.Broad_Consumer_Group);
broadConsumer.setNamesrvAddr(properties.getProperty("namesrv_addr"));
broadConsumer.setMessageModel(MessageModel.BROADCASTING);
broadConsumer.setInstanceName(RUuid.makeUuid());
obj = new Object();
_logger.info("intConsumer init consumer success..data[namesrvAddr={0}]" + properties.getProperty("namesrv_addr"));
}
}catch(Exception e){
e.printStackTrace();
_logger.error("initConsumer have exception" + e);
}
}
}
package com.cat.common.rocketmq;
public class RTopicConstants{
/**
* 默认集群消费者
*/
public static final String Consumer_Group="ConsumerGroup";
/**
* 广播消费者
*/
public static final String Broad_Consumer_Group="BroadConsumerGroup";
/**
* 生产者群
*/
public static final String Product_Group="ProductGroup";
/**
* 默认生产者
*/
public static final String Instancename_Producer = "Producer";
/**-------UIC消息TOPIC-------**/
public static final String luoyang="luoyang";
}
生产者
package com.cat.common.rocketmq;
import java.util.HashMap;
import java.util.Map;
import com.cat.common.json.RJson;
import com.cat.common.lang.RDate;
public class DemoProduct{
public static void main(String[] args){
try{
for(int i = 0; i < 5; i++){
Map m = new HashMap();
m.put("name", i+"1");
m.put("age", 10);
m.put("address", i+"杭州市晋江市带卡");
String msg = RJson.getJson(m);
RocketMqUtils.sendMessage(RTopicConstants.luoyang, msg);
Thread.sleep(1000);
System.out.println(RDate.getCurrentTimeStr()+ ",生产发送消息"+i);
}
}catch(Exception e){
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
消费者
package com.cat.common.rocketmq;
import java.util.List;
import com.alibaba.rocketmq.client.consumer.DefaultMQPushConsumer;
import com.alibaba.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext;
import com.alibaba.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
import com.alibaba.rocketmq.client.consumer.listener.MessageListenerConcurrently;
import com.alibaba.rocketmq.client.exception.MQClientException;
import com.alibaba.rocketmq.common.message.MessageExt;
public class DemoCustom{
public static void initConsumer(){
try{
System.out.println("开启集群消费者1:");
DefaultMQPushConsumer consumer = RocketMqUtils.getConsumer();
consumer.subscribe(RTopicConstants.luoyang, "*");
consumer.registerMessageListener(new MessageListenerConcurrently(){
public ConsumeConcurrentlyStatus consumeMessage(List msgs,
ConsumeConcurrentlyContext context){
try{
MessageExt msg = msgs.get(0);
String data = new String(msg.getBody());
if(msg.getTopic().equals(RTopicConstants.luoyang)){
System.out.println("集群消费者接收到消息:" + data);
}
}catch(Exception e){
e.printStackTrace();
//一会之后重新发送,可自行判断 时候要重试
return ConsumeConcurrentlyStatus.RECONSUME_LATER;
}
//根据业务逻辑成功处理 返回成功
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
});
// 开启消费
consumer.start();
}catch(Exception e){
e.printStackTrace();
}
}
/**
* 注册广播模式消息
* @throws MQClientException
*/
public static void initBroadConsumer()
throws MQClientException{
System.out.println("开启广播消费者");
DefaultMQPushConsumer broadConsumer = RocketMqUtils.getBroadConsumer();
broadConsumer.subscribe(RTopicConstants.luoyang, "*");
broadConsumer.registerMessageListener(new MessageListenerConcurrently(){
public ConsumeConcurrentlyStatus consumeMessage(List msgs,
ConsumeConcurrentlyContext context){
try{
MessageExt msg = msgs.get(0);
String data = new String(msg.getBody());
// 数据解析
// 同步配置中心数据
if(msg.getTopic().equals(RTopicConstants.luoyang)){
System.out.println("广播消费者接收到消息:" + data);
}
}catch(Exception e){
e.printStackTrace();
return ConsumeConcurrentlyStatus.RECONSUME_LATER;
}
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
});
broadConsumer.start();
}
public static void main(String[] args){
try{
initConsumer();
initBroadConsumer();
}catch(Exception e){
e.printStackTrace();
}
}
}
对于生产者
//一个jvm内,具有相同producerGroup名字的生产者实例只有一个。
producer = new DefaultMQProducer(RTopicConstants.Product_Group);
producer.setNamesrvAddr(properties.getProperty("namesrv_addr"));
producer.setInstanceName(RUuid.makeUuid());
同一个JVM 内 组名+InstanceName 必须唯一。
否则会报错。所以我这里设置的instanceName 是uuid
对于消费者
有两种,一种是广播,一种是集群
广播模式的消费者 消息不会保存在broken里面,直接下发到消费者中,所有的广播消费者都会消费消息。
集群模式,如果一组消费者的groupname 一致,就定义为是同一个消费集群。必须保证一台JVM 里面 消费者的instanceName 是唯一的。
同一组的集群消费者 平均消费 消息
并且,如果是集群消费,那么集群消费的所有消费者必须订阅相同的topic,否则会报错