消息队列大杂烩,kafka,rocketmq,rabbitmq专题
Kafka安装以及kafka的特性。
Java安装
步骤1 - 验证Java安装
验证Java是否已安装:
$ java -version
如果Java未安装,继续下一步。
步骤1.1 - 下载JDK
访问Oracle官网下载最新版本的JDK:
Download the Latest Java LTS Free
例如,最新版本为JDK 8u60,文件名为jdk-8u60-linux-x64.tar.gz
。
步骤1.2 - 提取文件
进入下载路径并解压文件:
$ cd /path/to/download
$ tar -zxf jdk-8u60-linux-x64.tar.gz
步骤1.3 - 移动到选择目录
将Java移动到/opt/jdk
目录:
$ su
password: (输入root用户密码)
$ mkdir /opt/jdk
$ mv jdk-1.8.0_60 /opt/jdk/
步骤1.4 - 设置路径
将以下内容添加到~/.bashrc
文件中:
export JAVA_HOME=/opt/jdk/jdk-1.8.0_60
export PATH=$PATH:$JAVA_HOME/bin
应用更改:
$ source ~/.bashrc
步骤1.5 - Java替代
设置Java替代:
update-alternatives --install /usr/bin/java java /opt/jdk/jdk1.8.0_60/bin/java 100
步骤1.6 - 验证Java安装
验证Java版本:
$ java -version
ZooKeeper安装
步骤2.1 - 下载ZooKeeper
访问Apache ZooKeeper官网下载最新版本:
Apache ZooKeeper Releases
例如,最新版本为ZooKeeper 3.4.6,文件名为zookeeper-3.4.6.tar.gz
。
步骤2.2 - 提取tar文件
解压ZooKeeper文件:
$ cd /opt/
$ tar -zxf zookeeper-3.4.6.tar.gz
$ cd zookeeper-3.4.6
$ mkdir data
步骤2.3 - 创建配置文件
编辑conf/zoo.cfg
文件:
$ vi conf/zoo.cfg
配置内容如下:
tickTime=2000
dataDir=/opt/zookeeper/data
clientPort=2181
initLimit=5
syncLimit=2
步骤2.4 - 启动ZooKeeper服务器
启动ZooKeeper:
$ bin/zkServer.sh start
启动成功后,输出如下:
JMX enabled by default
Using config: /path/to/zookeeper-3.4.6/bin/../conf/zoo.cfg
Starting zookeeper ... STARTED
步骤2.5 - 启动CLI
连接到ZooKeeper服务器:
$ bin/zkCli.sh
连接成功后,输出如下:
Connecting to localhost:2181
................
Welcome to ZooKeeper!
................
WATCHER::
WatchedEvent state:SyncConnected type: None path:null
[zk: localhost:2181(CONNECTED) 0]
步骤2.6 - 停止ZooKeeper服务器
停止ZooKeeper:
$ bin/zkServer.sh stop
Apache Kafka安装
步骤3.1 - 下载Kafka
访问Apache Kafka下载页面:
Apache Download Mirrors
下载最新版本kafka_2.11-0.9.0.0.tgz
。
步骤3.2 - 解压tar文件
解压Kafka文件:
$ cd /opt/
$ tar -zxf kafka_2.11-0.9.0.0.tgz
$ cd kafka_2.11-0.9.0.0
步骤3.3 - 启动Kafka服务器
启动Kafka服务器:
$ bin/kafka-server-start.sh config/server.properties
启动成功后,输出如下:
[2016-01-02 15:37:30,410] INFO KafkaConfig values:
request.timeout.ms = 30000
log.roll.hours = 168
inter.broker.protocol.version = 0.9.0.X
log.preallocate = false
security.inter.broker.protocol = PLAINTEXT
步骤4 - 停止Kafka服务器
停止Kafka服务器:
$ bin/kafka-server-stop.sh config/server.properties
关于kafka的消息模型:
RocketMQ和RabbitMQ学习提示
- RocketMQ学习:可以参考Apache RocketMQ官网文档,了解其架构、特性及使用方法。官网地址:Apache RocketMQ
- RabbitMQ学习:可以参考RabbitMQ官网文档,学习其安装、配置及消息队列的使用。官网地址:RabbitMQ
Rocketmq的安装以及Rockemq的特性:
以下是整理后的整齐格式内容:
消息生产者代码
/***************************消息生产者***************************/
@Autowired
private MQTransactionListener mqTransactionListener; // 事务消息监听器
// 消息生产者配置信息
@Value("${rocketmq.producer.namesrvAddr:127.0.0.1:9876}")
private String pNamesrvAddr; // 生产者 NameServer 地址
@Value("${rocketmq.producer.maxMessageSize:4096}")
private Integer maxMessageSize; // 消息最大大小,默认 4M
@Value("${rocketmq.producer.sendMsgTimeout:30000}")
private Integer sendMsgTimeout; // 消息发送超时时间,默认 30 秒
@Value("${rocketmq.producer.retryTimesWhenSendFailed:2}")
private Integer retryTimesWhenSendFailed; // 消息发送失败重试次数,默认 2 次
private static ExecutorService executor = ThreadUtil.newExecutor(32); // 执行任务的线程池
// 普通消息生产者
@Bean("default")
public DefaultMQProducer getDefaultMQProducer() {
DefaultMQProducer producer = new DefaultMQProducer(this.groupName);
producer.setNamesrvAddr(this.pNamesrvAddr);
producer.setMaxMessageSize(this.maxMessageSize);
producer.setSendMsgTimeout(this.sendMsgTimeout);
producer.setRetryTimesWhenSendFailed(this.retryTimesWhenSendFailed);
try {
producer.start();
} catch (MQClientException e) {
System.out.println(e.getErrorMessage());
}
return producer;
}
// 事务消息生产者(RocketMQ 支持柔性事务)
@Bean("transaction")
public TransactionMQProducer getTransactionMQProducer() {
// 初始化事务消息基本与普通消息生产者一致
TransactionMQProducer producer = new TransactionMQProducer("transaction_" + this.groupName);
producer.setNamesrvAddr(this.pNamesrvAddr);
producer.setMaxMessageSize(this.maxMessageSize);
producer.setSendMsgTimeout(this.sendMsgTimeout);
producer.setRetryTimesWhenSendFailed(this.retryTimesWhenSendFailed);
// 添加事务消息处理线程池
producer.setExecutorService(executor);
// 添加事务消息监听
producer.setTransactionListener(mqTransactionListener);
try {
producer.start();
} catch (MQClientException e) {
System.out.println(e.getErrorMessage());
}
return producer;
}
消息类型
根据消息功能分类
- 普通消息:最基本的发送类型。
- 事务消息:用于保证多服务模块间的事务一致性。
- 事务消息发送后会先生成一个半消息,进入事务消息监听器。
- 确保事务提交成功后才会向 Broker 发送消息,消费者才能获取并消费。
- 顺序消息:保证消息的顺序性。
- 延时消息:可设置消息的延时发送时间。
根据发送方式分类
- 同步消息:需要等待 Broker 响应,告知消息发送状态,常用于重要消息。
- 异步消息:需要快速返回,通过回调代码块异步监听 Broker 响应。
- 单向消息:对发送结果不敏感,无需监听 Broker 响应,常用于日志发送等。
消息优化建议
- 尽量减小消息体积,选择轻量级协议。
- 对于超过一定体积的消息,进行压缩处理。
- 消息协议优先级:二进制协议 < 文本协议,文本协议中 JSON < XML。
生产者相关参数
参数名 | 参数说明 |
---|---|
producerGroup | 消息生产者组名,一个应用的消息生产者应归为同一个组 |
namesrvAddr | 生产者 NameServer 地址 |
sendMsgTimeout | 消息发送超时时间(单位:毫秒) |
maxMessageSize | 消息最大大小,默认为 4M |
retryTimesWhenSendFailed | 消息发送失败重试次数,默认为 2 次 |
executorService | 事务消息处理线程池 |
transactionListener | 事务消息监听器 |
消费者相关参数
参数名 | 参数说明 |
---|---|
consumerGroup | 消费者组名,一个应用的消息消费者应归为同一个组 |
namesrvAddr | 消费者 NameServer 地址 |
consumeThreadMin | 消费者线程最小线程数 |
consumeThreadMax | 消费者线程最大线程数 |
subscribe | 消费者订阅主题信息,* 表示订阅所有 Tag,指定 Tag 则使用具体值 |
consumeMessageBatchMaxSize | 并发消费条数,默认为 1 |
消费模式
- 集群消费模式(CLUSTERING):同组内多个实例均摊消费消息,一个实例消费后其他实例不再消费。适用于大部分消息业务。
- 广播消费模式(BROADCASTING):同一消息会被同组内每个实例各自消费一次,ConsumerGroup 概念意义不大。适用于分发消息场景。
示例代码
-
生产者发送消息示例
Message message = new Message(MQ_CONFIG_TOPIC, MQ_CONFIG_TAG_PUSH, "KEY" + i, content.getBytes(RemotingHelper.DEFAULT_CHARSET));
-
消费者订阅示例
consumer.subscribe(MQ_CONFIG_TOPIC, MQ_CONFIG_TAG_PUSH);
RocketMQ 消费者默认配置
public DefaultMQPushConsumer(String consumerGroup, RPCHook rpcHook, AllocateMessageQueueStrategy allocateMessageQueueStrategy) {
this.messageModel = MessageModel.CLUSTERING; // 默认为集群消费方式
this.consumeFromWhere = ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET;
this.consumeTimestamp = UtilAll.timeMillisToHumanString3(System.currentTimeMillis() - 1800000L);
this.subscription = new HashMap<>();
this.consumeThreadMin = 20; // 默认最小线程数
this.consumeThreadMax = 64; // 默认最大线程数
this.adjustThreadPoolNumsThreshold = 100000L;
this.consumeConcurrentlyMaxSpan = 2000;
this.pullThresholdForQueue = 1000;
this.pullThresholdSizeForQueue = 100;
this.pullThresholdForTopic = -1;
this.pullThresholdSizeForTopic = -1;
this.pullInterval = 0L;
this.consumeMessageBatchMaxSize = 1; // 默认一次消费一条消息
this.pullBatchSize = 32; // 默认批量拉取 32 条消息
this.postSubscriptionWhenPull = false;
this.unitMode = false;
this.maxReconsumeTimes = -1;
this.suspendCurrentQueueTimeMillis = 1000L;
this.consumeTimeout = 15L;
this.consumerGroup = consumerGroup;
this.allocateMessageQueueStrategy = allocateMessageQueueStrategy;
this.defaultMQPushConsumerImpl = new DefaultMQPushConsumerImpl(this, rpcHook);
}
关于RocketMQ的架构图
参考资料
- Why choose RocketMQ | RocketMQ
- 什么是消息队列 RocketMQ 版
RocketMQ 官网:http://rocketmq.apache.org/docs/motivation/
阿里云消息队列 MQ:https://help.aliyun.com/document_detail/29532.html
阿里巴巴中间件团队:http://jm.taobao.org/2016/11/29/apache-rocketmq-incubation/
RocketMq运行在云服务器上,本质上也是运行在jvm上。
RocketMQ跑在云服务器上时,如下图runserver.sh是配置跑nameserver的文件
RocketMQ的消费模式
生产者发的消息:
关于消费者的代码
偏移量的概念
各个消息模式
用countdownlatch控制异步发送和同步发送策略:
异步发送之前的代码
连续启动两个消费者
在每个消费者接收到的消息顺序都保持顺序
消息的重试:
就是这个消息没有被提交之后被重新提交到这个队列了.....
重新提交给这个队列去进行消费了
例如发送了0到9的消息
第一个消费者接收到了0,1,2,4。
第二个消费者接收到了其他的。
这就是顺序消费。
全局消息队列:
用一个broker,一个消息队列完成
rabbitmq中接收到延迟消息要通过死信队列实现。
通过一个特殊的类实现批量发送消息
批量消息的大小受到两个东西限制:
一个是broker的大小,一个本身官方的定义的消息大小
RocketMQ的死信队列的具体意义和思考角度