MQ的技术选型
1.业内常用的MQ有哪些,哪些活跃的比较高
2.每一种MQ各自的表现如何
3.这个MQ在同等机器条件下,能抗多少QPS(每秒能抗几千QPS,还是几万QPS,QPS:每秒查询率)
4.性能如何(发 一条消息要2ms还是20ms)
5.可靠性能不能得到保障(MQ部署的服务器挂掉怎么办)
RocketMQ:
1.开发语言:java开发
2.性能:吞吐量高,每秒QPS十万级,性能毫秒级,支持集群部署
3.功能: 支持各种高级功能 ,比如:延迟消息,事务消息,消息回溯,死信队列,消息积压等等
4.缺点:官方文档相对简单可能是RocketMq唯一的缺点
5.应用场景 : 适当的丢失数据没有关系,吞吐量要求高,不需要太多的高级功能场景,比如大数据
RockeMQ使用记录
第一步: 引入 : Pom文件
<dependency>
<rocketmq.version>4.2.0</rocketmq.version>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-client</artifactId>
</dependency>
第二步:创建基础的生成者BaseMQProducer(后期业务生产者继承BaseMQProducer,可快速使用生产者)
引入RockeMQ的DefaultMQProducer, 创建start 方法,参入参数
public class BaseMQProducer {
protected DefaultMQProducer producer;
protected static final Logger LOG = LoggerFactory.getLogger(BaseMQProducer.class);
@Autowired
private BasicConfig config;
public BaseMQProducer() {
}
protected void start(String producerGroup, String instanceName) {
LOG.info("serverAddr=" + this.config.getROCKETMQ_ADDR());
if (this.producer == null && this.config.getROCKETMQ_ADDR() != null) {
this.producer = new DefaultMQProducer(this.getEnvValue(producerGroup));
this.producer.setNamesrvAddr(this.config.getROCKETMQ_ADDR());
this.producer.setInstanceName(this.getEnvValue(instanceName));
this.producer.setVipChannelEnabled(false);
this.producer.setRetryTimesWhenSendAsyncFailed(1);
this.producer.setRetryTimesWhenSendFailed(2);
this.producer.setSendMsgTimeout(6000);
try {
this.producer.start();
} catch (MQClientException var4) {
LOG.error(var4.getMessage(), var4);
throw BEException.me("开启MQ生产者失败");
}
}
}
public String getEnvValue(String value) {
return StringUtils.isNotBlank(this.config.getROCKETMQ_ENV()) ? value + this.config.getROCKETMQ_ENV() : value;
}
@PreDestroy
public void shutdown() {
if (null != this.producer) {
this.producer.shutdown();
}
}
protected SendResult sendAsyncMessage(String topic, String tags, String keys, String body) {
Message message = null;
try {
message = new Message(this.getEnvValue(topic), this.getEnvValue(tags), keys, body.getBytes("UTF-8"));
} catch (UnsupportedEncodingException var8) {
throw BEException.me("发送消息失败");
}
try {
SendResult sendResult = this.producer.send(message);
LOG.info("sendResult = {} , key = {} ", sendResult.toString(), keys);
return sendResult;
} catch (Exception var7) {
LOG.error(var7.getMessage(), var7);
throw BEException.me("发送消息失败");
}
}
protected SendResult sendDelayMessage(String topic, String tags, String keys, String body, int level) {
Message message = new Message(this.getEnvValue(topic), this.getEnvValue(tags), keys, body.getBytes());
message.setDelayTimeLevel(level);
try {
SendResult sendResult = this.producer.send(message);
LOG.info("sendResult = {} , key = {} ", sendResult.toString(), keys);
return sendResult;
} catch (Exception var8) {
LOG.error(var8.getMessage(), var8);
throw BEException.me("发送消息失败");
}
}
protected void sendSyncMessage(String topic, String tags, final String keys, String body) {
Message message = new Message(this.getEnvValue(topic), this.getEnvValue(tags), keys, body.getBytes());
try {
this.producer.send(message, new SendCallback() {
public void onSuccess(SendResult sendResult) {
BaseMQProducer.LOG.info("sendResult = {} , key = {} ", sendResult.toString(), keys);
}
public void onException(Throwable e) {
BaseMQProducer.LOG.error(e.getMessage(), e);
}
});
} catch (Exception var7) {
LOG.error(var7.getMessage(), var7);
throw BEException.me("发送消息失败");
}
}
protected void sendOnewayMessage(String topic, String tags, String keys, String body) {
Message message = new Message(this.getEnvValue(topic), this.getEnvValue(tags), keys, body.getBytes());
try {
this.producer.sendOneway(message);
} catch (Exception var7) {
LOG.error(var7.getMessage(), var7);
throw BEException.me("发送消息失败");
}
}
}
第三步:通过枚举类,获取生产者,消费者组名,示例名,标签等
public enum BbcSmsMQTopicConfigEnum {
SMS("BbcSms", "ProducerGroup", "SmsProducer", "SmsConsumerGroup", "BbcSmsConsumer",
"SmsTag");
// 主题
private String topic;
// 生产者组名
private String producerGroupName;
// 生产者实例名
private String producerInstanceName;
// 消费者组名
private String consumerGroupName;
// 消费者实例名
private String consumerInstanceName;
private String tag;
BbcSmsMQTopicConfigEnum(String topic, String producerGroupName, String producerInstanceName,
String consumerGroupName, String consumerInstanceName, String tag) {
this.topic = topic;
this.producerGroupName = producerGroupName;
this.producerInstanceName = producerInstanceName;
this.consumerGroupName = consumerGroupName;
this.consumerInstanceName = consumerInstanceName;
this.tag = tag;
}
public String getTopic() {
return topic;
}
public void setTopic(String topic) {
this.topic = topic;
}
public String getProducerGroupName() {
return producerGroupName;
}
public void setProducerGroupName(String producerGroupName) {
this.producerGroupName = producerGroupName;
}
public String getProducerInstanceName() {
return producerInstanceName;
}
public void setProducerInstanceName(String producerInstanceName) {
this.producerInstanceName = producerInstanceName;
}
public String getConsumerGroupName() {
return consumerGroupName;
}
public void setConsumerGroupName(String consumerGroupName) {
this.consumerGroupName = consumerGroupName;
}
public String getConsumerInstanceName() {
return consumerInstanceName;
}
public void setConsumerInstanceName(String consumerInstanceName) {
this.consumerInstanceName = consumerInstanceName;
}
public String getTag() {
return tag;
}
public void setTag(String tag) {
this.tag = tag;
}
第四步:创建生产者,继承BaseMQProducer
@Component
public class TestMQProducer extends BaseMQProducer {
private static TestMQTopicConfigEnum TOPIC_CONFIG = TestMQTopicConfigEnum.SMS;
public void sendMessage(BbcSmsMQBody body) {
// 发送定时消息
LOG.info("tagName = {}", TOPIC_CONFIG.getTag());
this.sendAsyncMessage(TOPIC_CONFIG.getTopic(), TOPIC_CONFIG.getTag(),
String.valueOf(System.currentTimeMillis()) + "-" + body.getPhone(), body.toJson());
}
@PostConstruct
public void start() {
this.start(TOPIC_CONFIG.getProducerGroupName(), TOPIC_CONFIG.getProducerInstanceName());
LOG.info("TestMQProducer start success .");
}
}
第五步:创建消息实体类
public class TestMQBody implements Serializable {
/**
* 接收号码
*/
private String phone;
/**
* 接受内容
*/
private String content;
/**
* 短信类型
*/
private String type;
public BbcSmsMQBody(){
}
public TestMQBody(String phone, String content) {
super();
this.phone = phone;
this.content = content;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String toJson() {
return JSONObject.toJSONString(this);
}
}
第六步:创建基础消费者
public class BaseMQConsumer {
protected DefaultMQPushConsumer consumer;
protected static final Logger LOG = LoggerFactory.getLogger(BaseMQConsumer.class);
@Autowired
private BasicConfig config;
public BaseMQConsumer() {
}
public void start(String consumerGroup, String instanceName, String topic, String tag, MessageListenerConcurrently messageListenerConcurrently) {
LOG.info("serverAddr=" + this.config.getROCKETMQ_ADDR());
if (this.consumer == null && this.config.getROCKETMQ_ADDR() != null) {
this.consumer = new DefaultMQPushConsumer(this.getEnvValue(consumerGroup));
this.consumer.setNamesrvAddr(this.config.getROCKETMQ_ADDR());
this.consumer.setInstanceName(this.getEnvValue(instanceName));
this.consumer.setVipChannelEnabled(false);
this.consumer.setMaxReconsumeTimes(1);
this.consumer.setConsumeMessageBatchMaxSize(1);
try {
this.consumer.subscribe(this.getEnvValue(topic), this.getEnvValue(tag));
this.consumer.registerMessageListener(messageListenerConcurrently);
this.consumer.start();
} catch (MQClientException var7) {
LOG.error(var7.getMessage(), var7);
throw BEException.me("启动Consumer失败");
}
}
}
public String getEnvValue(String value) {
return StringUtils.isNotBlank(this.config.getROCKETMQ_ENV()) ? value + this.config.getROCKETMQ_ENV() : value;
}
public void shutdown() {
if (null != this.consumer) {
this.consumer.shutdown();
this.consumer = null;
}
}
}
第八步:创建消费者
@Component
public class BbcSmsMQConsumer extends BaseMQConsumer {
private static BbcSmsMQTopicConfigEnum TOPIC_CONFIG = BbcSmsMQTopicConfigEnum.SMS;
@PreDestroy
public void destory() {
super.shutdown();
LOG.info("BbcSmsMQConsumer shutdown success .");
}
private MessageListenerConcurrently getMessageListener() {
MessageListenerConcurrently messageListener = new MessageListenerConcurrently() {
@Override
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) {
for (MessageExt message : msgs) {
LOG.info("Receive New Messages:{} , keys:{}", message.toString(), message.getKeys());
if(message.getReconsumeTimes() > 0){
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; // 消费成功
}
try {
String msgBody = new String(message.getBody(), "UTF-8");
BbcSmsMQBody body = JSONObject.parseObject(msgBody, BbcSmsMQBody.class);
SMSUtil.send(body.getPhone(), body.getContent());
} catch (Exception e) {
LOG.error(e.getMessage(), e);
// return ConsumeConcurrentlyStatus.RECONSUME_LATER; // 消费失败
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; // 消费成功
}
}
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; // 消费成功
}
};
return messageListener;
}
@PostConstruct
public void afterPropertiesSet() throws Exception {
this.start(TOPIC_CONFIG.getConsumerGroupName(), TOPIC_CONFIG.getConsumerInstanceName(), TOPIC_CONFIG.getTopic(),
TOPIC_CONFIG.getTag(), getMessageListener());
LOG.info("BbcSmsMQConsumer start success .");
LOG.info("BbcSmsMQConsumer TagName is {}", TOPIC_CONFIG.getTag());
}
}
第九步 :分别注入消费者和生产者即可使用
配置:
rocketmq: addr: 192.168.1.53:9876 env: devTest