├── .gitignore ├── rocketmq-flume-sink ├── pom.xml └── src │ └── main │ └── java │ └── com │ └── handu │ └── flume │ └── sink │ └── rocketmq │ ├── RocketMQSinkUtil.java │ └── RocketMQSink.java ├── rocketmq-flume-source ├── pom.xml └── src │ └── main │ └── java │ └── com │ └── handu │ └── flume │ └── source │ └── rocketmq │ ├── RocketMQSourceUtil.java │ └── RocketMQSource.java ├── pom.xml └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .* 2 | *.class 3 | *.jar 4 | *.war 5 | *.iml 6 | .settings 7 | target 8 | !.gitignore -------------------------------------------------------------------------------- /rocketmq-flume-sink/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | rocketmq-flume-sink 7 | 8 | 9 | rocketmq-flume 10 | com.handu 11 | 1.0.0 12 | 13 | 14 | -------------------------------------------------------------------------------- /rocketmq-flume-source/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | rocketmq-flume-source 7 | 8 | 9 | rocketmq-flume 10 | com.handu 11 | 1.0.0 12 | 13 | 14 | -------------------------------------------------------------------------------- /rocketmq-flume-sink/src/main/java/com/handu/flume/sink/rocketmq/RocketMQSinkUtil.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2006-2014 handu.com. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.handu.flume.sink.rocketmq; 17 | 18 | import com.alibaba.rocketmq.client.producer.DefaultMQProducer; 19 | import com.alibaba.rocketmq.client.producer.MQProducer; 20 | import com.google.common.base.Preconditions; 21 | import org.apache.flume.Context; 22 | 23 | /** 24 | * Sink工具类 25 | * 26 | * @author Jinkai.Ma 27 | * @since 2015-01-16 28 | */ 29 | public class RocketMQSinkUtil { 30 | 31 | /** 32 | * Topic配置项,如:a1.sinks.s1.topic=TestTopic 33 | */ 34 | public static final String TOPIC_CONFIG = "topic"; 35 | public static final String TOPIC_DEFAULT = "FLUME_ROCKETMQ"; 36 | /** 37 | * Tags配置项,如:a1.sinks.s1.tags=Tag1,Tag2 38 | */ 39 | public static final String TAG_CONFIG = "tag"; 40 | public static final String TAG_DEFAULT = ""; 41 | /** 42 | * Producer分组配置项,如:a1.sinks.s1.producerGroup=please_rename_unique_group_name 43 | */ 44 | public static final String PRODUCER_GROUP_CONFIG = "producerGroup"; 45 | public static final String PRODUCER_GROUP_DEFAULT = "DEFAULT_PRODUCER"; 46 | /** 47 | * Namesrv地址配置项,如:a1.sinks.s1.namesrvAddr=localhost:9876 48 | */ 49 | public static final String NAMESRV_ADDR_CONFIG = "namesrvAddr"; 50 | 51 | public static MQProducer getProducer(Context context) { 52 | final String producerGroup = context.getString(PRODUCER_GROUP_CONFIG, PRODUCER_GROUP_DEFAULT); 53 | final String namesrvAddr = Preconditions.checkNotNull(context.getString(NAMESRV_ADDR_CONFIG), "RocketMQ namesrvAddr must be specified. For example: a1.sinks.s1.namesrvAddr=127.0.0.1:9876"); 54 | 55 | DefaultMQProducer producer = new DefaultMQProducer(producerGroup); 56 | producer.setNamesrvAddr(namesrvAddr); 57 | 58 | return producer; 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | com.handu 7 | rocketmq-flume 8 | pom 9 | 1.0.0 10 | http://www.handu.com 11 | 2014 12 | 13 | 14 | 韩都衣舍 15 | http://www.handu.com 16 | 17 | 18 | 19 | 20 | The Hando Apollo Team 21 | dev@handu.com 22 | http://apollo.handu.com/ 23 | 韩都衣舍 24 | http://www.handu.com/ 25 | 26 | 27 | 28 | 29 | scm:git:https://github.com/rocketmq/rocketmq-flume.git 30 | scm:git:https://github.com/rocketmq/rocketmq-flume.git 31 | 32 | 33 | 34 | UTF-8 35 | 36 | 18.0 37 | 1.5.2 38 | 3.2.6 39 | 4.11 40 | 1.9.0 41 | 42 | 43 | 44 | rocketmq-flume-sink 45 | rocketmq-flume-source 46 | 47 | 48 | 49 | 50 | com.google.guava 51 | guava 52 | ${guava.version} 53 | 54 | 55 | org.apache.flume 56 | flume-ng-core 57 | ${flume.version} 58 | 59 | 60 | com.alibaba.rocketmq 61 | rocketmq-client 62 | ${rocketmq.version} 63 | 64 | 65 | junit 66 | junit 67 | ${junit.version} 68 | test 69 | 70 | 71 | org.mockito 72 | mockito-all 73 | ${mockito.version} 74 | test 75 | 76 | 77 | 78 | 79 | clean install dependency:copy-dependencies 80 | 81 | 82 | org.apache.maven.plugins 83 | maven-compiler-plugin 84 | 3.3 85 | 86 | 1.6 87 | 1.6 88 | 89 | 90 | 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /rocketmq-flume-source/src/main/java/com/handu/flume/source/rocketmq/RocketMQSourceUtil.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2006-2014 handu.com. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.handu.flume.source.rocketmq; 17 | 18 | import com.alibaba.rocketmq.client.consumer.DefaultMQPullConsumer; 19 | import com.alibaba.rocketmq.client.consumer.MQPullConsumer; 20 | import com.alibaba.rocketmq.common.protocol.heartbeat.MessageModel; 21 | import com.google.common.base.Preconditions; 22 | import org.apache.flume.Context; 23 | 24 | /** 25 | * Source工具类 26 | * 27 | * @author Jinkai.Ma 28 | * @since 2015-01-16 29 | */ 30 | public class RocketMQSourceUtil { 31 | 32 | /** 33 | * Topic配置项,如:a1.sources.r1.topic=TestTopic 34 | */ 35 | public static final String TOPIC_CONFIG = "topic"; 36 | /** 37 | * Tags配置项,如:a1.sources.r1.tags=Tag1,Tag2 38 | */ 39 | public static final String TAGS_CONFIG = "tags"; 40 | public static final String TAGS_DEFAULT = "*"; 41 | /** 42 | * Tags header name configuration, eg: a1.sources.r1.tagsHeaderName=name 43 | */ 44 | public static final String TAGS_HEADER_NAME_CONFIG = "tagsHeaderName"; 45 | public static final String TAGS_HEADER_NAME_DEFAULT = "tags"; 46 | /** 47 | * Topic header name configuration, eg: a1.sources.r1.topicHeaderName=name 48 | */ 49 | public static final String TOPIC_HEADER_NAME_CONFIG = "topicHeaderName"; 50 | public static final String TOPIC_HEADER_NAME_DEFAULT = "topic"; 51 | /** 52 | * 一次最多拉取条数配置项,如:a1.sources.r1.maxNums=150 53 | */ 54 | public static final String MAXNUMS_CONFIG = "maxNums"; 55 | public static final int MAXNUMS_DEFAULT = 32; 56 | /** 57 | * Consumer分组配置项,如:a1.sources.r1.consumerGroup=please_rename_unique_group_name 58 | */ 59 | public static final String CONSUMER_GROUP_CONFIG = "consumerGroup"; 60 | public static final String CONSUMER_GROUP_DEFAULT = "DEFAULT_CONSUMER"; 61 | /** 62 | * Namesrv地址配置项,如:a1.sinks.s1.namesrvAddr=localhost:9876 63 | */ 64 | public static final String NAMESRV_ADDR_CONFIG = "namesrvAddr"; 65 | /** 66 | * 订阅方式配置项,如:a1.sources.r1.messageModel=BROADCASTING 67 | */ 68 | public static final String MESSAGEMODEL_CONFIG = "messageModel"; 69 | public static final String MESSAGEMODEL_DEFAULT = "BROADCASTING"; 70 | 71 | public static MQPullConsumer getConsumer(Context context) { 72 | final String consumerGroup = context.getString(CONSUMER_GROUP_CONFIG, CONSUMER_GROUP_DEFAULT); 73 | final String namesrvAddr = Preconditions.checkNotNull(context.getString(NAMESRV_ADDR_CONFIG), "RocketMQ namesrvAddr must be specified. For example: a1.sources.r1.namesrvAddr=127.0.0.1:9876"); 74 | 75 | DefaultMQPullConsumer consumer = new DefaultMQPullConsumer(consumerGroup); 76 | consumer.setNamesrvAddr(namesrvAddr); 77 | consumer.setMessageModel(MessageModel.valueOf(context.getString(MESSAGEMODEL_CONFIG, MESSAGEMODEL_DEFAULT))); 78 | 79 | return consumer; 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /rocketmq-flume-sink/src/main/java/com/handu/flume/sink/rocketmq/RocketMQSink.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2006-2014 handu.com. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.handu.flume.sink.rocketmq; 17 | 18 | import com.alibaba.rocketmq.client.exception.MQClientException; 19 | import com.alibaba.rocketmq.client.producer.MQProducer; 20 | import com.alibaba.rocketmq.client.producer.SendResult; 21 | import com.alibaba.rocketmq.common.message.Message; 22 | import com.google.common.base.Preconditions; 23 | import com.google.common.base.Throwables; 24 | import org.apache.flume.*; 25 | import org.apache.flume.conf.Configurable; 26 | import org.apache.flume.sink.AbstractSink; 27 | import org.slf4j.Logger; 28 | import org.slf4j.LoggerFactory; 29 | 30 | /** 31 | * 发送消息 32 | * 33 | * @author Jinkai.Ma 34 | * @since 2015-01-16 35 | */ 36 | public class RocketMQSink extends AbstractSink implements Configurable { 37 | 38 | private static final Logger LOG = LoggerFactory.getLogger(RocketMQSink.class); 39 | 40 | private String topic; 41 | private String tag; 42 | private MQProducer producer; 43 | 44 | @Override 45 | public void configure(Context context) { 46 | // 获取配置项 47 | topic = context.getString(RocketMQSinkUtil.TOPIC_CONFIG, RocketMQSinkUtil.TOPIC_DEFAULT); 48 | tag = context.getString(RocketMQSinkUtil.TAG_CONFIG, RocketMQSinkUtil.TAG_DEFAULT); 49 | // 初始化Producer 50 | producer = Preconditions.checkNotNull(RocketMQSinkUtil.getProducer(context)); 51 | } 52 | 53 | @Override 54 | public Status process() throws EventDeliveryException { 55 | Channel channel = getChannel(); 56 | Transaction tx = channel.getTransaction(); 57 | try { 58 | tx.begin(); 59 | Event event = channel.take(); 60 | if (event == null || event.getBody() == null || event.getBody().length == 0) { 61 | tx.commit(); 62 | return Status.READY; 63 | } 64 | // 发送消息 65 | SendResult sendResult = producer.send(new Message(topic, tag, event.getBody())); 66 | if (LOG.isDebugEnabled()) { 67 | LOG.debug("SendResult={}, Message={}", sendResult, event.getBody()); 68 | } 69 | tx.commit(); 70 | return Status.READY; 71 | } catch (Exception e) { 72 | LOG.error("RocketMQSink send message exception", e); 73 | try { 74 | tx.rollback(); 75 | return Status.BACKOFF; 76 | } catch (Exception e2) { 77 | LOG.error("Rollback exception", e2); 78 | } 79 | return Status.BACKOFF; 80 | } finally { 81 | tx.close(); 82 | } 83 | } 84 | 85 | @Override 86 | public synchronized void start() { 87 | try { 88 | // 启动Producer 89 | producer.start(); 90 | } catch (MQClientException e) { 91 | LOG.error("RocketMQSink start producer failed", e); 92 | Throwables.propagate(e); 93 | } 94 | super.start(); 95 | } 96 | 97 | @Override 98 | public synchronized void stop() { 99 | // 停止Producer 100 | producer.shutdown(); 101 | super.stop(); 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | rocketmq-flume Source&Sink 2 | ========================== 3 | 4 | 该项目用于[RocketMQ](https://github.com/alibaba/RocketMQ)与[Flume-ng](https://github.com/apache/flume)之间的消息接收和投递。 5 | 6 | 1. 首先请确定您已经对[RocketMQ](https://github.com/alibaba/RocketMQ)和[Flume-ng](https://github.com/apache/flume)有了基本的了解 7 | 2. 确保本地maven库中已经存在[RocketMQ相关的包](https://github.com/alibaba/RocketMQ/releases/download/v3.2.2/alibaba-rocketmq-client-java-3.2.2.tar.gz),或者下载RocketMQ源码自行编译 8 | 3. 在rocketmq-flume项目根目录执行`mvn clean install dependency:copy-dependencies` 9 | 4. 将rocketmq-flume相关依赖jar包拷贝到`$FLUME_HOME/lib`目录中(具体包会在后面描述) 10 | 11 | ## Sink 12 | 13 | ### Sink配置说明 14 | 15 | | 配置项 | 必填 | 默认值 | 说明 | 16 | |---------------|-----|------------------|------| 17 | | namesrvAddr | 必填 | null | Name Server地址,遵循RocketMQ配置方式 | 18 | | producerGroup | 可选 | DEFAULT_PRODUCER | Producer分组 | 19 | | topic | 必填 | null | Topic名称 | 20 | | tags | 可选 | 空字符串 | Tag名称,遵循RocketMQ配置方式 | 21 | 22 | ### Sink综合示例 23 | 24 | - 编写Flume的配置文件 25 | 26 | ``` 27 | agent1.sources=source1 28 | agent1.channels=channel1 29 | agent1.sinks=sink1 30 | 31 | agent1.sources.source1.type=avro 32 | agent1.sources.source1.bind=0.0.0.0 33 | agent1.sources.source1.port=15151 34 | agent1.sources.source1.channels=channel1 35 | 36 | agent1.sinks.sink1.type=com.handu.flume.sink.rocketmq.RocketMQSink 37 | agent1.sinks.sink1.namesrvAddr=rocketmq_namesrv:9876 38 | agent1.sinks.sink1.producerGroup=MyProducerGroup_1 39 | agent1.sinks.sink1.topic=FromFlume 40 | agent1.sinks.sink1.tag=Tag1 41 | agent1.sinks.sink1.channel=channel1 42 | 43 | agent1.channels.channel1.type=memory 44 | agent1.channels.channel1.capacity=100 45 | agent1.channels.channel1.transactionCapacity=100 46 | agent1.channels.channel1.keep-alive=3 47 | ``` 48 | 49 | - 将下面jar包拷贝到`$FLUME_HOME/lib`目录中 50 | 51 | ``` 52 | rocketmq-flume-sink-1.0.0.jar (文件位置: $PROJECT_HOME/rocketmq-flume-sink/target) 53 | fastjson-1.1.41.jar (文件位置: $PROJECT_HOME/rocketmq-flume-sink/target/dependency) 54 | netty-all-4.0.23.Final.jar (文件位置: $PROJECT_HOME/rocketmq-flume-sink/target/dependency) 55 | rocketmq-client-3.2.2.jar (文件位置: $PROJECT_HOME/rocketmq-flume-sink/target/dependency) 56 | rocketmq-common-3.2.2.jar (文件位置: $PROJECT_HOME/rocketmq-flume-sink/target/dependency) 57 | rocketmq-remoting-3.2.2.jar (文件位置: $PROJECT_HOME/rocketmq-flume-sink/target/dependency) 58 | ``` 59 | 60 | - 执行测试命令查看 61 | 62 | ``` 63 | shell1> $FLUME_HOME/bin/flume-ng agent -c conf -f conf/flume.conf -n agent1 -Dflume.root.logger=INFO,console 64 | shell2> $FLUME_HOME/bin/flume-ng avro-client -H localhost -p 15151 -F $FLUME_HOME/README 65 | ``` 66 | 67 | - 查看shell1控制台输出的信息 68 | 69 | ## Source 70 | 71 | ### Source配置说明 72 | 73 | | 配置项 | 必填 | 默认值 | 说明 | 74 | |---------------|-----|------------------|------| 75 | | namesrvAddr | 必填 | null | Name Server地址,遵循RocketMQ配置方式 | 76 | | consumerGroup | 可选 | DEFAULT_CONSUMER | Consumer分组 | 77 | | topic | 必填 | null | Topic名称 | 78 | | tags | 可选 | * | Tag名称,遵循RocketMQ配置方式 | 79 | | messageModel | 可选 | BROADCASTING | BROADCASTING或CLUSTERING | 80 | | maxNums | 可选 | 32 | 一次读取消息数量 | 81 | 82 | ### Source综合示例 83 | 84 | ``` 85 | agent1.sources=source1 86 | agent1.channels=channel1 87 | agent1.sinks=sink1 88 | 89 | agent1.sources.source1.type=com.handu.flume.source.rocketmq.RocketMQSource 90 | agent1.sources.source1.namesrvAddr=rocketmq_namesrv:9876 91 | agent1.sources.source1.consumerGroup=MyConsumerGroup_1 92 | agent1.sources.source1.topic=TopicTest 93 | agent1.sources.source1.tags=* 94 | agent1.sources.source1.messageModel=BROADCASTING 95 | agent1.sources.source1.maxNums=32 96 | agent1.sources.source1.channels=channel1 97 | 98 | agent1.sinks.sink1.type=logger 99 | agent1.sinks.sink1.channel=channel1 100 | 101 | agent1.channels.channel1.type=memory 102 | agent1.channels.channel1.capacity=100 103 | agent1.channels.channel1.transactionCapacity=100 104 | agent1.channels.channel1.keep-alive=3 105 | ``` 106 | 107 | - 将下面jar包拷贝到`$FLUME_HOME/lib`目录中 108 | 109 | ``` 110 | rocketmq-flume-source-1.0.0.jar (文件位置: $PROJECT_HOME/rocketmq-flume-source/target) 111 | fastjson-1.1.41.jar (文件位置: $PROJECT_HOME/rocketmq-flume-sink/target/dependency) 112 | netty-all-4.0.23.Final.jar (文件位置: $PROJECT_HOME/rocketmq-flume-sink/target/dependency) 113 | rocketmq-client-3.2.2.jar (文件位置: $PROJECT_HOME/rocketmq-flume-sink/target/dependency) 114 | rocketmq-common-3.2.2.jar (文件位置: $PROJECT_HOME/rocketmq-flume-sink/target/dependency) 115 | rocketmq-remoting-3.2.2.jar (文件位置: $PROJECT_HOME/rocketmq-flume-sink/target/dependency) 116 | ``` 117 | 118 | - 向RocketMQ中投递一些测试消息 119 | 120 | - 执行测试命令查看控制台输出 121 | 122 | ``` 123 | $FLUME_HOME/bin/flume-ng agent -c conf -f conf/flume.conf -n agent1 -Dflume.root.logger=INFO,console 124 | ``` 125 | -------------------------------------------------------------------------------- /rocketmq-flume-source/src/main/java/com/handu/flume/source/rocketmq/RocketMQSource.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2006-2014 handu.com. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.handu.flume.source.rocketmq; 17 | 18 | import com.alibaba.rocketmq.client.consumer.MQPullConsumer; 19 | import com.alibaba.rocketmq.client.consumer.PullResult; 20 | import com.alibaba.rocketmq.client.consumer.PullStatus; 21 | import com.alibaba.rocketmq.client.exception.MQClientException; 22 | import com.alibaba.rocketmq.common.message.MessageExt; 23 | import com.alibaba.rocketmq.common.message.MessageQueue; 24 | import com.google.common.base.Preconditions; 25 | import com.google.common.base.Throwables; 26 | import com.google.common.collect.Lists; 27 | import com.google.common.collect.Maps; 28 | import org.apache.flume.Context; 29 | import org.apache.flume.Event; 30 | import org.apache.flume.EventDeliveryException; 31 | import org.apache.flume.PollableSource; 32 | import org.apache.flume.conf.Configurable; 33 | import org.apache.flume.event.SimpleEvent; 34 | import org.apache.flume.source.AbstractSource; 35 | import org.slf4j.Logger; 36 | import org.slf4j.LoggerFactory; 37 | 38 | import java.util.HashMap; 39 | import java.util.List; 40 | import java.util.Map; 41 | import java.util.Set; 42 | 43 | /** 44 | * 接收消息 45 | * 46 | * @author Jinkai.Ma 47 | * @since 2015-01-16 48 | */ 49 | public class RocketMQSource extends AbstractSource implements Configurable, PollableSource { 50 | 51 | private static final Logger LOG = LoggerFactory.getLogger(RocketMQSource.class); 52 | 53 | private String topic; 54 | private String tags; 55 | private String topicHeaderName; 56 | private String tagsHeaderName; 57 | private int maxNums; 58 | private MQPullConsumer consumer; 59 | 60 | @Override 61 | public void configure(Context context) { 62 | // 初始化配置项 63 | topic = Preconditions.checkNotNull(context.getString(RocketMQSourceUtil.TOPIC_CONFIG), "RocketMQ topic must be specified. For example: a1.sources.r1.topic=TestTopic"); 64 | tags = context.getString(RocketMQSourceUtil.TAGS_CONFIG, RocketMQSourceUtil.TAGS_DEFAULT); 65 | topicHeaderName = context.getString(RocketMQSourceUtil.TOPIC_HEADER_NAME_CONFIG, RocketMQSourceUtil.TOPIC_HEADER_NAME_DEFAULT); 66 | tagsHeaderName = context.getString(RocketMQSourceUtil.TAGS_HEADER_NAME_CONFIG, RocketMQSourceUtil.TAGS_HEADER_NAME_DEFAULT); 67 | maxNums = context.getInteger(RocketMQSourceUtil.MAXNUMS_CONFIG, RocketMQSourceUtil.MAXNUMS_DEFAULT); 68 | 69 | // 初始化Consumer 70 | consumer = Preconditions.checkNotNull(RocketMQSourceUtil.getConsumer(context)); 71 | consumer.registerMessageQueueListener(topic, null); 72 | } 73 | 74 | @Override 75 | public Status process() throws EventDeliveryException { 76 | List eventList = Lists.newArrayList(); 77 | Map offsetMap = Maps.newHashMap(); 78 | Event event; 79 | Map headers; 80 | 81 | try { 82 | Set mqs = Preconditions.checkNotNull(consumer.fetchSubscribeMessageQueues(topic)); 83 | for (MessageQueue mq : mqs) { 84 | // 获取offset 85 | long offset = this.getMessageQueueOffset(mq); 86 | PullResult pullResult = consumer.pull(mq, tags, offset, maxNums); 87 | // 发现新消息写入Event 88 | if (pullResult.getPullStatus() == PullStatus.FOUND) { 89 | for (MessageExt messageExt : pullResult.getMsgFoundList()) { 90 | event = new SimpleEvent(); 91 | headers = new HashMap(); 92 | headers.put(topicHeaderName, messageExt.getTopic()); 93 | headers.put(tagsHeaderName, messageExt.getTags()); 94 | if (LOG.isDebugEnabled()) { 95 | LOG.debug("MessageQueue={}, Topic={}, Tags={}, Message: {}",new Object[] { 96 | mq, messageExt.getTopic(), messageExt.getTags(), messageExt.getBody()}); 97 | } 98 | event.setBody(messageExt.getBody()); 99 | event.setHeaders(headers); 100 | eventList.add(event); 101 | } 102 | offsetMap.put(mq, pullResult.getNextBeginOffset()); 103 | } 104 | } 105 | // 批量处理事件 106 | getChannelProcessor().processEventBatch(eventList); 107 | for (Map.Entry entry : offsetMap.entrySet()) { 108 | // 更新offset 109 | this.putMessageQueueOffset(entry.getKey(), entry.getValue()); 110 | } 111 | } catch (Exception e) { 112 | LOG.error("RocketMQSource consume message exception", e); 113 | return Status.BACKOFF; 114 | } 115 | return Status.READY; 116 | } 117 | 118 | @Override 119 | public synchronized void start() { 120 | try { 121 | // 启动Consumer 122 | consumer.start(); 123 | } catch (MQClientException e) { 124 | LOG.error("RocketMQSource start consumer failed", e); 125 | Throwables.propagate(e); 126 | } 127 | super.start(); 128 | } 129 | 130 | @Override 131 | public synchronized void stop() { 132 | // 停止Consumer 133 | consumer.shutdown(); 134 | super.stop(); 135 | } 136 | 137 | private void putMessageQueueOffset(MessageQueue mq, long offset) throws MQClientException { 138 | // 存储Offset,客户端每隔5s会定时刷新到Broker或者写入本地缓存文件 139 | consumer.updateConsumeOffset(mq, offset); 140 | } 141 | 142 | private long getMessageQueueOffset(MessageQueue mq) throws MQClientException { 143 | // 从Broker获取Offset 144 | long offset = consumer.fetchConsumeOffset(mq, false); 145 | 146 | if (offset < 0L) { 147 | offset = 0L; 148 | } 149 | return offset; 150 | } 151 | 152 | } 153 | --------------------------------------------------------------------------------