diff --git a/deployer/src/main/java/com/alibaba/otter/canal/deployer/CanalConstants.java b/deployer/src/main/java/com/alibaba/otter/canal/deployer/CanalConstants.java
index d68d5871..b328feb7 100644
--- a/deployer/src/main/java/com/alibaba/otter/canal/deployer/CanalConstants.java
+++ b/deployer/src/main/java/com/alibaba/otter/canal/deployer/CanalConstants.java
@@ -16,6 +16,7 @@ public class CanalConstants {
public static final String CANAL_IP = ROOT + "." + "ip";
public static final String CANAL_PORT = ROOT + "." + "port";
public static final String CANAL_ZKSERVERS = ROOT + "." + "zkServers";
+ public static final String CANAL_WITHOUT_NETTY = ROOT + "." + "withoutNetty";
public static final String CANAL_DESTINATIONS = ROOT + "." + "destinations";
public static final String CANAL_AUTO_SCAN = ROOT + "." + "auto.scan";
diff --git a/deployer/src/main/java/com/alibaba/otter/canal/deployer/CanalController.java b/deployer/src/main/java/com/alibaba/otter/canal/deployer/CanalController.java
index 08c0744d..7bd78c5f 100644
--- a/deployer/src/main/java/com/alibaba/otter/canal/deployer/CanalController.java
+++ b/deployer/src/main/java/com/alibaba/otter/canal/deployer/CanalController.java
@@ -43,7 +43,7 @@ import com.google.common.collect.MigrateMap;
/**
* canal调度控制器
- *
+ *
* @author jianghang 2012-11-8 下午12:03:11
* @version 1.0.0
*/
@@ -97,9 +97,12 @@ public class CanalController {
port = Integer.valueOf(getProperty(properties, CanalConstants.CANAL_PORT));
embededCanalServer = CanalServerWithEmbedded.instance();
embededCanalServer.setCanalInstanceGenerator(instanceGenerator);// 设置自定义的instanceGenerator
- canalServer = CanalServerWithNetty.instance();
- canalServer.setIp(ip);
- canalServer.setPort(port);
+ String canalWithoutNetty = getProperty(properties, CanalConstants.CANAL_WITHOUT_NETTY);
+ if (canalWithoutNetty == null || "true".equals(canalWithoutNetty)) {
+ canalServer = CanalServerWithNetty.instance();
+ canalServer.setIp(ip);
+ canalServer.setPort(port);
+ }
// 处理下ip为空,默认使用hostIp暴露到zk中
if (StringUtils.isEmpty(ip)) {
@@ -431,11 +434,15 @@ public class CanalController {
}
// 启动网络接口
- canalServer.start();
+ if(canalServer!=null) {
+ canalServer.start();
+ }
}
public void stop() throws Throwable {
- canalServer.stop();
+ if(canalServer!=null) {
+ canalServer.stop();
+ }
if (autoScan) {
for (InstanceConfigMonitor monitor : instanceConfigMonitors.values()) {
@@ -454,7 +461,7 @@ public class CanalController {
// 释放canal的工作节点
releaseCid(ZookeeperPathUtils.getCanalClusterNode(ip + ":" + port));
logger.info("## stop the canal server[{}:{}]", ip, port);
-
+
if (zkclientx != null) {
zkclientx.close();
}
diff --git a/deployer/src/main/resources/canal.properties b/deployer/src/main/resources/canal.properties
index f765e71b..c2f57375 100644
--- a/deployer/src/main/resources/canal.properties
+++ b/deployer/src/main/resources/canal.properties
@@ -7,6 +7,7 @@ canal.port= 11111
canal.zkServers=
# flush data to zk
canal.zookeeper.flush.period = 1000
+canal.withoutNetty = false
# flush meta cursor/parse position to file
canal.file.data.dir = ${canal.conf.dir}
canal.file.flush.period = 1000
diff --git a/kafka/pom.xml b/kafka/pom.xml
new file mode 100644
index 00000000..67397a19
--- /dev/null
+++ b/kafka/pom.xml
@@ -0,0 +1,131 @@
+
+
+
+ canal
+ com.alibaba.otter
+ 1.0.26-SNAPSHOT
+
+ 4.0.0
+
+ canal.kafka
+
+
+
+ com.alibaba.otter
+ canal.deployer
+ ${project.version}
+
+
+
+
+ org.apache.kafka
+ kafka-clients
+ 0.10.0.1
+
+
+ org.apache.kafka
+ kafka_2.11
+ 0.10.0.1
+
+
+
+
+
+
+
+ maven-jar-plugin
+
+
+ true
+
+
+ **/logback.xml
+ **/canal.properties
+ **/spring/**
+ **/example/**
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-assembly-plugin
+
+ 2.2.1
+
+
+ assemble
+
+ single
+
+ package
+
+
+
+ false
+ false
+
+
+
+
+
+
+
+ dev
+
+ true
+
+ env
+ !release
+
+
+
+
+
+
+ maven-assembly-plugin
+
+
+
+ ${basedir}/src/main/assembly/dev.xml
+
+ canal
+ ${project.build.directory}
+
+
+
+
+
+
+
+
+ release
+
+
+ env
+ release
+
+
+
+
+
+
+ maven-assembly-plugin
+
+
+
+ ${basedir}/src/main/assembly/release.xml
+
+
+ ${project.artifactId}-${project.version}
+
+ ${project.parent.build.directory}
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/kafka/src/main/assembly/dev.xml b/kafka/src/main/assembly/dev.xml
new file mode 100644
index 00000000..df9eca81
--- /dev/null
+++ b/kafka/src/main/assembly/dev.xml
@@ -0,0 +1,61 @@
+
+ dist
+
+ dir
+
+ false
+
+
+ .
+ /
+
+ README*
+
+
+
+ ./src/main/bin
+ bin
+
+ **/*
+
+ 0755
+
+
+ ../deployer/src/main/conf
+ /conf
+
+ **/*
+
+
+
+ ../deployer/src/main/resources
+ /conf
+
+ **/*
+
+
+
+ ./src/main/resources
+ /conf
+
+ **/*
+
+
+
+ target
+ logs
+
+ **/*
+
+
+
+
+
+ lib
+
+ junit:junit
+
+
+
+
diff --git a/kafka/src/main/assembly/release.xml b/kafka/src/main/assembly/release.xml
new file mode 100644
index 00000000..d79ecf3c
--- /dev/null
+++ b/kafka/src/main/assembly/release.xml
@@ -0,0 +1,61 @@
+
+ dist
+
+ tar.gz
+
+ false
+
+
+ .
+ /
+
+ README*
+
+
+
+ ./src/main/bin
+ bin
+
+ **/*
+
+ 0755
+
+
+ ../deployer/src/main/conf
+ /conf
+
+ **/*
+
+
+
+ ../deployer/src/main/resources
+ /conf
+
+ **/*
+
+
+
+ ./src/main/resources
+ /conf
+
+ **/*
+
+
+
+ target
+ logs
+
+ **/*
+
+
+
+
+
+ lib
+
+ junit:junit
+
+
+
+
diff --git a/kafka/src/main/bin/startup.bat b/kafka/src/main/bin/startup.bat
new file mode 100755
index 00000000..429cc653
--- /dev/null
+++ b/kafka/src/main/bin/startup.bat
@@ -0,0 +1,25 @@
+@echo off
+@if not "%ECHO%" == "" echo %ECHO%
+@if "%OS%" == "Windows_NT" setlocal
+
+set ENV_PATH=.\
+if "%OS%" == "Windows_NT" set ENV_PATH=%~dp0%
+
+set conf_dir=%ENV_PATH%\..\conf
+set canal_conf=%conf_dir%\canal.properties
+set logback_configurationFile=%conf_dir%\logback.xml
+
+set CLASSPATH=%conf_dir%
+set CLASSPATH=%conf_dir%\..\lib\*;%CLASSPATH%
+
+set JAVA_MEM_OPTS= -Xms128m -Xmx512m -XX:PermSize=128m
+set JAVA_OPTS_EXT= -Djava.awt.headless=true -Djava.net.preferIPv4Stack=true -Dapplication.codeset=UTF-8 -Dfile.encoding=UTF-8
+set JAVA_DEBUG_OPT= -server -Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,address=9099,server=y,suspend=n
+set CANAL_OPTS= -DappName=otter-canal -Dlogback.configurationFile="%logback_configurationFile%" -Dcanal.conf="%canal_conf%"
+
+set JAVA_OPTS= %JAVA_MEM_OPTS% %JAVA_OPTS_EXT% %JAVA_DEBUG_OPT% %CANAL_OPTS%
+
+set CMD_STR= java %JAVA_OPTS% -classpath "%CLASSPATH%" java %JAVA_OPTS% -classpath "%CLASSPATH%" com.alibaba.otter.canal.kafka.CanalLauncher
+echo start cmd : %CMD_STR%
+
+java %JAVA_OPTS% -classpath "%CLASSPATH%" com.alibaba.otter.canal.kafka.CanalLauncher
\ No newline at end of file
diff --git a/kafka/src/main/bin/startup.sh b/kafka/src/main/bin/startup.sh
new file mode 100644
index 00000000..184c4b3f
--- /dev/null
+++ b/kafka/src/main/bin/startup.sh
@@ -0,0 +1,104 @@
+#!/bin/bash
+
+current_path=`pwd`
+case "`uname`" in
+ Linux)
+ bin_abs_path=$(readlink -f $(dirname $0))
+ ;;
+ *)
+ bin_abs_path=`cd $(dirname $0); pwd`
+ ;;
+esac
+base=${bin_abs_path}/..
+canal_conf=$base/conf/canal.properties
+logback_configurationFile=$base/conf/logback.xml
+export LANG=en_US.UTF-8
+export BASE=$base
+
+if [ -f $base/bin/canal.pid ] ; then
+ echo "found canal.pid , Please run stop.sh first ,then startup.sh" 2>&2
+ exit 1
+fi
+
+if [ ! -d $base/logs/canal ] ; then
+ mkdir -p $base/logs/canal
+fi
+
+## set java path
+if [ -z "$JAVA" ] ; then
+ JAVA=$(which java)
+fi
+
+ALIBABA_JAVA="/usr/alibaba/java/bin/java"
+TAOBAO_JAVA="/opt/taobao/java/bin/java"
+if [ -z "$JAVA" ]; then
+ if [ -f $ALIBABA_JAVA ] ; then
+ JAVA=$ALIBABA_JAVA
+ elif [ -f $TAOBAO_JAVA ] ; then
+ JAVA=$TAOBAO_JAVA
+ else
+ echo "Cannot find a Java JDK. Please set either set JAVA or put java (>=1.5) in your PATH." 2>&2
+ exit 1
+ fi
+fi
+
+case "$#"
+in
+0 )
+ ;;
+1 )
+ var=$*
+ if [ -f $var ] ; then
+ canal_conf=$var
+ else
+ echo "THE PARAMETER IS NOT CORRECT.PLEASE CHECK AGAIN."
+ exit
+ fi;;
+2 )
+ var=$1
+ if [ -f $var ] ; then
+ canal_conf=$var
+ else
+ if [ "$1" = "debug" ]; then
+ DEBUG_PORT=$2
+ DEBUG_SUSPEND="n"
+ JAVA_DEBUG_OPT="-Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,address=$DEBUG_PORT,server=y,suspend=$DEBUG_SUSPEND"
+ fi
+ fi;;
+* )
+ echo "THE PARAMETERS MUST BE TWO OR LESS.PLEASE CHECK AGAIN."
+ exit;;
+esac
+
+str=`file -L $JAVA | grep 64-bit`
+if [ -n "$str" ]; then
+ JAVA_OPTS="-server -Xms2048m -Xmx3072m -Xmn1024m -XX:SurvivorRatio=2 -XX:PermSize=96m -XX:MaxPermSize=256m -Xss256k -XX:-UseAdaptiveSizePolicy -XX:MaxTenuringThreshold=15 -XX:+DisableExplicitGC -XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled -XX:+UseCMSCompactAtFullCollection -XX:+UseFastAccessorMethods -XX:+UseCMSInitiatingOccupancyOnly -XX:+HeapDumpOnOutOfMemoryError"
+else
+ JAVA_OPTS="-server -Xms1024m -Xmx1024m -XX:NewSize=256m -XX:MaxNewSize=256m -XX:MaxPermSize=128m "
+fi
+
+JAVA_OPTS=" $JAVA_OPTS -Djava.awt.headless=true -Djava.net.preferIPv4Stack=true -Dfile.encoding=UTF-8"
+CANAL_OPTS="-DappName=otter-canal -Dlogback.configurationFile=$logback_configurationFile -Dcanal.conf=$canal_conf"
+
+if [ -e $canal_conf -a -e $logback_configurationFile ]
+then
+
+ for i in $base/lib/*;
+ do CLASSPATH=$i:"$CLASSPATH";
+ done
+ CLASSPATH="$base/conf:$CLASSPATH";
+
+ echo "cd to $bin_abs_path for workaround relative path"
+ cd $bin_abs_path
+
+ echo LOG CONFIGURATION : $logback_configurationFile
+ echo canal conf : $canal_conf
+ echo CLASSPATH :$CLASSPATH
+ $JAVA $JAVA_OPTS $JAVA_DEBUG_OPT $CANAL_OPTS -classpath .:$CLASSPATH com.alibaba.otter.canal.kafka.CanalLauncher 1>>$base/logs/canal/canal.log 2>&1 &
+ echo $! > $base/bin/canal.pid
+
+ echo "cd to $current_path for continue"
+ cd $current_path
+else
+ echo "canal conf("$canal_conf") OR log configration file($logback_configurationFile) is not exist,please create then first!"
+fi
diff --git a/kafka/src/main/bin/stop.sh b/kafka/src/main/bin/stop.sh
new file mode 100644
index 00000000..f398749c
--- /dev/null
+++ b/kafka/src/main/bin/stop.sh
@@ -0,0 +1,65 @@
+#!/bin/bash
+
+cygwin=false;
+linux=false;
+case "`uname`" in
+ CYGWIN*)
+ cygwin=true
+ ;;
+ Linux*)
+ linux=true
+ ;;
+esac
+
+get_pid() {
+ STR=$1
+ PID=$2
+ if $cygwin; then
+ JAVA_CMD="$JAVA_HOME\bin\java"
+ JAVA_CMD=`cygpath --path --unix $JAVA_CMD`
+ JAVA_PID=`ps |grep $JAVA_CMD |awk '{print $1}'`
+ else
+ if $linux; then
+ if [ ! -z "$PID" ]; then
+ JAVA_PID=`ps -C java -f --width 1000|grep "$STR"|grep "$PID"|grep -v grep|awk '{print $2}'`
+ else
+ JAVA_PID=`ps -C java -f --width 1000|grep "$STR"|grep -v grep|awk '{print $2}'`
+ fi
+ else
+ if [ ! -z "$PID" ]; then
+ JAVA_PID=`ps aux |grep "$STR"|grep "$PID"|grep -v grep|awk '{print $2}'`
+ else
+ JAVA_PID=`ps aux |grep "$STR"|grep -v grep|awk '{print $2}'`
+ fi
+ fi
+ fi
+ echo $JAVA_PID;
+}
+
+base=`dirname $0`/..
+pidfile=$base/bin/canal.pid
+if [ ! -f "$pidfile" ];then
+ echo "canal is not running. exists"
+ exit
+fi
+
+pid=`cat $pidfile`
+if [ "$pid" == "" ] ; then
+ pid=`get_pid "appName=otter-canal"`
+fi
+
+echo -e "`hostname`: stopping canal $pid ... "
+kill $pid
+
+LOOPS=0
+while (true);
+do
+ gpid=`get_pid "appName=otter-canal" "$pid"`
+ if [ "$gpid" == "" ] ; then
+ echo "Oook! cost:$LOOPS"
+ `rm $pidfile`
+ break;
+ fi
+ let LOOPS=LOOPS+1
+ sleep 1
+done
\ No newline at end of file
diff --git a/kafka/src/main/java/com/alibaba/otter/canal/kafka/CanalLauncher.java b/kafka/src/main/java/com/alibaba/otter/canal/kafka/CanalLauncher.java
new file mode 100644
index 00000000..0797004e
--- /dev/null
+++ b/kafka/src/main/java/com/alibaba/otter/canal/kafka/CanalLauncher.java
@@ -0,0 +1,70 @@
+package com.alibaba.otter.canal.kafka;
+
+
+import com.alibaba.otter.canal.deployer.CanalController;
+import org.apache.commons.lang.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.FileInputStream;
+import java.util.Properties;
+
+/**
+ * canal-kafka独立版本启动的入口类
+ *
+ * @author machengyuan 2018-6-11 下午05:30:49
+ * @version 1.0.0
+ */
+public class CanalLauncher {
+
+ private static final String CLASSPATH_URL_PREFIX = "classpath:";
+ private static final Logger logger = LoggerFactory.getLogger(CanalLauncher.class);
+
+ public static void main(String[] args) throws Throwable {
+ try {
+ logger.info("## set default uncaught exception handler");
+ setGlobalUncaughtExceptionHandler();
+
+ logger.info("## load canal configurations");
+ String conf = System.getProperty("canal.conf", "classpath:canal.properties");
+ Properties properties = new Properties();
+ if (conf.startsWith(CLASSPATH_URL_PREFIX)) {
+ conf = StringUtils.substringAfter(conf, CLASSPATH_URL_PREFIX);
+ properties.load(com.alibaba.otter.canal.deployer.CanalLauncher.class.getClassLoader().getResourceAsStream(conf));
+ } else {
+ properties.load(new FileInputStream(conf));
+ }
+
+ logger.info("## start the canal server.");
+ final CanalController controller = new CanalController(properties);
+ controller.start();
+ logger.info("## the canal server is running now ......");
+ Runtime.getRuntime().addShutdownHook(new Thread() {
+
+ public void run() {
+ try {
+ logger.info("## stop the canal server");
+ controller.stop();
+ } catch (Throwable e) {
+ logger.warn("##something goes wrong when stopping canal Server:", e);
+ } finally {
+ logger.info("## canal server is down.");
+ }
+ }
+
+ });
+ } catch (Throwable e) {
+ logger.error("## Something goes wrong when starting up the canal Server:", e);
+ System.exit(0);
+ }
+ }
+
+ private static void setGlobalUncaughtExceptionHandler() {
+ Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
+ @Override
+ public void uncaughtException(Thread t, Throwable e) {
+ logger.error("UnCaughtException", e);
+ }
+ });
+ }
+}
\ No newline at end of file
diff --git a/kafka/src/main/java/com/alibaba/otter/canal/kafka/producer/CanalKafkaProducer.java b/kafka/src/main/java/com/alibaba/otter/canal/kafka/producer/CanalKafkaProducer.java
new file mode 100644
index 00000000..9a64b1a5
--- /dev/null
+++ b/kafka/src/main/java/com/alibaba/otter/canal/kafka/producer/CanalKafkaProducer.java
@@ -0,0 +1,62 @@
+package com.alibaba.otter.canal.kafka.producer;
+
+import com.alibaba.otter.canal.kafka.producer.KafkaProperties.Topic;
+import com.alibaba.otter.canal.protocol.Message;
+import org.apache.kafka.clients.producer.KafkaProducer;
+import org.apache.kafka.clients.producer.Producer;
+import org.apache.kafka.clients.producer.ProducerRecord;
+import org.apache.kafka.common.serialization.StringSerializer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Properties;
+
+/**
+ * kafka producer 主操作类
+ *
+ * @author machengyuan 2018-6-11 下午05:30:49
+ * @version 1.0.0
+ */
+public class CanalKafkaProducer {
+ private static final Logger logger = LoggerFactory.getLogger(CanalKafkaProducer.class);
+
+ private static Producer producer;
+
+ public static void init(KafkaProperties kafkaProperties) {
+ Properties properties = new Properties();
+ properties.put("bootstrap.servers", kafkaProperties.getServers());
+ properties.put("acks", "all");
+ properties.put("retries", kafkaProperties.getRetries());
+ properties.put("batch.size", kafkaProperties.getBatchSize());
+ properties.put("linger.ms", kafkaProperties.getLingerMs());
+ properties.put("buffer.memory", kafkaProperties.getBufferMemory());
+ properties.put("key.serializer", StringSerializer.class.getName());
+ properties.put("value.serializer", MessageSerializer.class.getName());
+ producer = new KafkaProducer(properties);
+
+ Runtime.getRuntime().addShutdownHook(new Thread() {
+
+ public void run() {
+ try {
+ logger.info("## stop the kafka producer");
+ producer.close();
+ } catch (Throwable e) {
+ logger.warn("##something goes wrong when stopping kafka producer:", e);
+ } finally {
+ logger.info("## kafka producer is down.");
+ }
+ }
+
+ });
+ }
+
+ public static void send(Topic topic, Message message) {
+ ProducerRecord record;
+ if (topic.getPartition() != null) {
+ record = new ProducerRecord(topic.getTopic(), topic.getPartition(), null, message);
+ } else {
+ record = new ProducerRecord(topic.getTopic(), message);
+ }
+ producer.send(record);
+ }
+}
diff --git a/kafka/src/main/java/com/alibaba/otter/canal/kafka/producer/CanalKafkaStarter.java b/kafka/src/main/java/com/alibaba/otter/canal/kafka/producer/CanalKafkaStarter.java
new file mode 100644
index 00000000..bc048956
--- /dev/null
+++ b/kafka/src/main/java/com/alibaba/otter/canal/kafka/producer/CanalKafkaStarter.java
@@ -0,0 +1,88 @@
+package com.alibaba.otter.canal.kafka.producer;
+
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import com.alibaba.otter.canal.kafka.producer.KafkaProperties.Topic;
+import com.alibaba.otter.canal.protocol.ClientIdentity;
+import com.alibaba.otter.canal.protocol.Message;
+import com.alibaba.otter.canal.server.embedded.CanalServerWithEmbedded;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class CanalKafkaStarter {
+ private static final Logger logger = LoggerFactory.getLogger(CanalKafkaStarter.class);
+
+ private volatile static boolean running = false;
+ private static short CLIENT_ID = 1001;
+
+ public static void init(KafkaProperties kafkaProperties) {
+ //初始化 kafka producer
+ CanalKafkaProducer.init(kafkaProperties);
+
+ //对应每个instance启动一个worker线程
+ List topics = kafkaProperties.getTopics();
+
+ ExecutorService executorService = Executors.newFixedThreadPool(topics.size());
+
+ for (final Topic topic : topics) {
+ executorService.execute(new Runnable() {
+ @Override
+ public void run() {
+ worker(topic);
+ }
+ });
+ }
+ running = true;
+ }
+
+ private static void sleep(long time) {
+ try {
+ Thread.sleep(time);
+ } catch (InterruptedException e) {
+ //ignore
+ }
+ }
+
+ public static void worker(Topic topic) {
+ while (!running) ;
+ //TODO 等待canal server启动完毕
+ logger.info("## start the canal consumer: {}.", topic.getDestination());
+ CanalServerWithEmbedded server = CanalServerWithEmbedded.instance();
+ ClientIdentity clientIdentity = new ClientIdentity(topic.getDestination(), CLIENT_ID, "");
+ while (running) {
+ try {
+ if (!server.getCanalInstances().containsKey(clientIdentity.getDestination())) {
+ sleep(3000);
+ continue;
+ }
+ server.subscribe(clientIdentity);
+ logger.info("## the canal consumer {} is running now ......", topic.getDestination());
+
+ while (running) {
+ Message message = server.getWithoutAck(clientIdentity, 5 * 1024); // 获取指定数量的数据
+ long batchId = message.getId();
+ try {
+ int size = message.getEntries().size();
+ if (batchId == -1 || size == 0) {
+ sleep(1000);
+ } else {
+ CanalKafkaProducer.send(topic, message);
+ }
+
+ if (batchId != -1) {
+ server.ack(clientIdentity, batchId); // 提交确认
+ }
+ } catch (Exception e) {
+ server.rollback(clientIdentity);
+ logger.error(e.getMessage(), e);
+ sleep(1000);
+ }
+ }
+ } catch (Exception e) {
+ logger.error("process error!", e);
+ }
+ }
+ }
+}
diff --git a/kafka/src/main/java/com/alibaba/otter/canal/kafka/producer/KafkaProperties.java b/kafka/src/main/java/com/alibaba/otter/canal/kafka/producer/KafkaProperties.java
new file mode 100644
index 00000000..4b81238e
--- /dev/null
+++ b/kafka/src/main/java/com/alibaba/otter/canal/kafka/producer/KafkaProperties.java
@@ -0,0 +1,111 @@
+package com.alibaba.otter.canal.kafka.producer;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * kafka 配置项
+ *
+ * @author machengyuan 2018-6-11 下午05:30:49
+ * @version 1.0.0
+ */
+public class KafkaProperties {
+ private String servers = "localhost:6667";
+ private int retries = 0;
+ private int batchSize = 16384;
+ private int lingerMs = 1;
+ private long bufferMemory = 33554432L;
+
+ private List topics = new ArrayList();
+ private Map topicMap = new HashMap();
+
+ public static class Topic {
+ private String topic;
+ private Integer partition;
+ private String destination;
+
+ public String getTopic() {
+ return topic;
+ }
+
+ public void setTopic(String topic) {
+ this.topic = topic;
+ }
+
+ public Integer getPartition() {
+ return partition;
+ }
+
+ public void setPartition(Integer partition) {
+ this.partition = partition;
+ }
+
+ public String getDestination() {
+ return destination;
+ }
+
+ public void setDestination(String destination) {
+ this.destination = destination;
+ }
+ }
+
+ public String getServers() {
+ return servers;
+ }
+
+ public void setServers(String servers) {
+ this.servers = servers;
+ }
+
+ public int getRetries() {
+ return retries;
+ }
+
+ public void setRetries(int retries) {
+ this.retries = retries;
+ }
+
+ public int getBatchSize() {
+ return batchSize;
+ }
+
+ public void setBatchSize(int batchSize) {
+ this.batchSize = batchSize;
+ }
+
+ public int getLingerMs() {
+ return lingerMs;
+ }
+
+ public void setLingerMs(int lingerMs) {
+ this.lingerMs = lingerMs;
+ }
+
+ public long getBufferMemory() {
+ return bufferMemory;
+ }
+
+ public void setBufferMemory(long bufferMemory) {
+ this.bufferMemory = bufferMemory;
+ }
+
+ public List getTopics() {
+ return topics;
+ }
+
+ public void setTopics(List topics) {
+ this.topics = topics;
+
+ if (topics != null) {
+ for (Topic topic : topics) {
+ this.topicMap.put(topic.destination, topic);
+ }
+ }
+ }
+
+ public Topic getTopicByDestination(String destination) {
+ return this.topicMap.get(destination);
+ }
+}
diff --git a/kafka/src/main/java/com/alibaba/otter/canal/kafka/producer/MessageSerializer.java b/kafka/src/main/java/com/alibaba/otter/canal/kafka/producer/MessageSerializer.java
new file mode 100644
index 00000000..d1a9577a
--- /dev/null
+++ b/kafka/src/main/java/com/alibaba/otter/canal/kafka/producer/MessageSerializer.java
@@ -0,0 +1,49 @@
+package com.alibaba.otter.canal.kafka.producer;
+
+import com.alibaba.otter.canal.protocol.CanalEntry;
+import com.alibaba.otter.canal.protocol.CanalPacket;
+import com.alibaba.otter.canal.protocol.Message;
+import org.apache.kafka.common.errors.SerializationException;
+import org.apache.kafka.common.serialization.Serializer;
+import org.springframework.util.CollectionUtils;
+
+import java.util.Map;
+
+/**
+ * Message类的序列化Kafka实现
+ *
+ * @author machengyuan 2018-6-11 下午05:30:49
+ * @version 1.0.0
+ */
+public class MessageSerializer implements Serializer {
+ @Override
+ public void configure(Map configs, boolean isKey) {
+ }
+
+ @Override
+ public byte[] serialize(String topic, Message data) {
+ try {
+ if (data == null)
+ return null;
+ else {
+ CanalPacket.Messages.Builder messageBuilder = CanalPacket.Messages.newBuilder();
+ if (data.getId() != -1 && !CollectionUtils.isEmpty(data.getEntries())) {
+ for (CanalEntry.Entry entry : data.getEntries()) {
+ messageBuilder.addMessages(entry.toByteString());
+ }
+ }
+ CanalPacket.Packet.Builder packetBuilder = CanalPacket.Packet.newBuilder();
+ packetBuilder.setType(CanalPacket.PacketType.MESSAGES);
+ packetBuilder.setBody(messageBuilder.build().toByteString());
+ return packetBuilder.build().toByteArray();
+ }
+ } catch (Exception e) {
+ throw new SerializationException("Error when serializing message to byte[] ");
+ }
+ }
+
+ @Override
+ public void close() {
+ // nothing to do
+ }
+}
diff --git a/kafka/src/main/resources/kafka.yml b/kafka/src/main/resources/kafka.yml
new file mode 100644
index 00000000..2d07cf14
--- /dev/null
+++ b/kafka/src/main/resources/kafka.yml
@@ -0,0 +1,12 @@
+servers: localhost:6667
+retries: 0
+batchSize: 16384
+lingerMs: 1
+bufferMemory: 33554432
+
+topics:
+ - topic: exampe
+ partition:
+ destination: example
+
+
diff --git a/pom.xml b/pom.xml
index 1c4ff11b..bbe33de0 100644
--- a/pom.xml
+++ b/pom.xml
@@ -127,6 +127,7 @@
client
deployer
example
+ kafka
@@ -254,7 +255,7 @@
com.alibaba.fastsql
fastsql
- 2.0.0_preview_371
+ 2.0.0_preview_186
com.alibaba