Merge pull request #900 from rewerma/master

kafka server端代码调整
This commit is contained in:
agapple
2018-09-04 10:55:04 +08:00
committed by GitHub
8 changed files with 96 additions and 82 deletions

View File

@@ -1,12 +1,5 @@
package com.alibaba.otter.canal.client.adapter.loader; package com.alibaba.otter.canal.client.adapter.loader;
import com.alibaba.otter.canal.client.adapter.CanalOuterAdapter;
import com.alibaba.otter.canal.client.adapter.support.CanalClientConfig;
import com.alibaba.otter.canal.client.adapter.support.CanalOuterAdapterConfiguration;
import com.alibaba.otter.canal.client.adapter.support.ExtensionLoader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.SocketAddress; import java.net.SocketAddress;
import java.util.ArrayList; import java.util.ArrayList;
@@ -16,6 +9,14 @@ import java.util.Map;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.otter.canal.client.adapter.CanalOuterAdapter;
import com.alibaba.otter.canal.client.adapter.support.CanalClientConfig;
import com.alibaba.otter.canal.client.adapter.support.CanalOuterAdapterConfiguration;
import com.alibaba.otter.canal.client.adapter.support.ExtensionLoader;
/** /**
* 外部适配器的加载器 * 外部适配器的加载器
* *

View File

@@ -1,16 +1,15 @@
package com.alibaba.otter.canal.client.adapter.loader; package com.alibaba.otter.canal.client.adapter.loader;
import com.alibaba.otter.canal.client.CanalConnector;
import com.alibaba.otter.canal.client.CanalConnectors;
import com.alibaba.otter.canal.client.adapter.CanalOuterAdapter;
import com.alibaba.otter.canal.client.adapter.loader.AbstractCanalAdapterWorker;
import com.alibaba.otter.canal.client.impl.ClusterCanalConnector;
import com.alibaba.otter.canal.protocol.Message;
import java.net.SocketAddress; import java.net.SocketAddress;
import java.util.List; import java.util.List;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import com.alibaba.otter.canal.client.CanalConnector;
import com.alibaba.otter.canal.client.CanalConnectors;
import com.alibaba.otter.canal.client.adapter.CanalOuterAdapter;
import com.alibaba.otter.canal.client.impl.ClusterCanalConnector;
import com.alibaba.otter.canal.protocol.Message;
/** /**
* 原生canal-server对应的client适配器工作线程 * 原生canal-server对应的client适配器工作线程
* *

View File

@@ -45,7 +45,7 @@ public class KafkaCanalConnector {
properties.put("auto.offset.reset", "latest"); // 如果没有offset则从最后的offset开始读 properties.put("auto.offset.reset", "latest"); // 如果没有offset则从最后的offset开始读
properties.put("request.timeout.ms", "40000"); // 必须大于session.timeout.ms的设置 properties.put("request.timeout.ms", "40000"); // 必须大于session.timeout.ms的设置
properties.put("session.timeout.ms", "30000"); // 默认为30秒 properties.put("session.timeout.ms", "30000"); // 默认为30秒
properties.put("max.poll.records", "1"); // 所以一次只取一条数据 properties.put("max.poll.records", "1"); // 一次只取一条message数据
properties.put("key.deserializer", StringDeserializer.class.getName()); properties.put("key.deserializer", StringDeserializer.class.getName());
properties.put("value.deserializer", MessageDeserializer.class.getName()); properties.put("value.deserializer", MessageDeserializer.class.getName());

View File

@@ -3,15 +3,15 @@ retries: 0
batchSize: 16384 batchSize: 16384
lingerMs: 1 lingerMs: 1
bufferMemory: 33554432 bufferMemory: 33554432
filterTransactionEntry: true
# Canal的batch size, 默认50K, 由于kafka最大消息体限制请勿超过1M(900K以下)
canalBatchSize: 50
# Canal get数据的超时时间, 单位: 毫秒, 空为不限超时
canalGetTimeout: 100
canalDestinations: canalDestinations:
- canalDestination: example - canalDestination: example
topic: example topic: example
partition: partition:
# 一个destination可以对应多个topic
#topics:
# - topic: example
# partition:

View File

@@ -1,11 +1,12 @@
package com.alibaba.otter.canal.kafka; package com.alibaba.otter.canal.kafka;
import java.io.IOException;
import java.util.Properties; import java.util.Properties;
import java.util.concurrent.Future;
import org.apache.kafka.clients.producer.KafkaProducer; import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.Producer; import org.apache.kafka.clients.producer.Producer;
import org.apache.kafka.clients.producer.ProducerRecord; import org.apache.kafka.clients.producer.ProducerRecord;
import org.apache.kafka.clients.producer.RecordMetadata;
import org.apache.kafka.common.serialization.StringSerializer; import org.apache.kafka.common.serialization.StringSerializer;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@@ -35,6 +36,7 @@ public class CanalKafkaProducer {
properties.put("key.serializer", StringSerializer.class.getName()); properties.put("key.serializer", StringSerializer.class.getName());
properties.put("value.serializer", MessageSerializer.class.getName()); properties.put("value.serializer", MessageSerializer.class.getName());
producer = new KafkaProducer<String, Message>(properties); producer = new KafkaProducer<String, Message>(properties);
// producer.initTransactions();
} }
public void stop() { public void stop() {
@@ -48,42 +50,33 @@ public class CanalKafkaProducer {
} }
} }
public void send(KafkaProperties.Topic topic, Message message) throws IOException { public void send(KafkaProperties.Topic topic, Message message, Callback callback) {
// set canal.instance.filter.transaction.entry = true try {
// producer.beginTransaction();
// boolean valid = false;
// if (message != null) {
// if (message.isRaw() && !message.getRawEntries().isEmpty()) {
// for (ByteString byteString : message.getRawEntries()) {
// CanalEntry.Entry entry = CanalEntry.Entry.parseFrom(byteString);
// if (entry.getEntryType() != CanalEntry.EntryType.TRANSACTIONBEGIN
// && entry.getEntryType() != CanalEntry.EntryType.TRANSACTIONEND) {
// valid = true;
// break;
// }
// }
// } else if (!message.getEntries().isEmpty()){
// for (CanalEntry.Entry entry : message.getEntries()) {
// if (entry.getEntryType() != CanalEntry.EntryType.TRANSACTIONBEGIN
// && entry.getEntryType() != CanalEntry.EntryType.TRANSACTIONEND) {
// valid = true;
// break;
// }
// }
// }
// }
// if (!valid) {
// return;
// }
ProducerRecord<String, Message> record; ProducerRecord<String, Message> record;
if (topic.getPartition() != null) { if (topic.getPartition() != null) {
record = new ProducerRecord<String, Message>(topic.getTopic(), topic.getPartition(), null, message); record = new ProducerRecord<String, Message>(topic.getTopic(), topic.getPartition(), null, message);
} else { } else {
record = new ProducerRecord<String, Message>(topic.getTopic(), message); record = new ProducerRecord<String, Message>(topic.getTopic(), message);
} }
producer.send(record); Future<RecordMetadata> future = producer.send(record);
future.get();
// producer.commitTransaction();
callback.commit();
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug("send message to kafka topic: {} \n {}", topic.getTopic(), message.toString()); logger.debug("send message to kafka topic: {}", topic.getTopic());
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
// producer.abortTransaction();
callback.rollback();
} }
} }
public interface Callback {
void commit();
void rollback();
}
} }

View File

@@ -4,6 +4,7 @@ import java.io.FileInputStream;
import java.util.List; import java.util.List;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
@@ -54,9 +55,9 @@ public class CanalKafkaStarter implements CanalServerStarter {
canalKafkaProducer = new CanalKafkaProducer(); canalKafkaProducer = new CanalKafkaProducer();
canalKafkaProducer.init(kafkaProperties); canalKafkaProducer.init(kafkaProperties);
// set filterTransactionEntry // set filterTransactionEntry
if (kafkaProperties.isFilterTransactionEntry()) { // if (kafkaProperties.isFilterTransactionEntry()) {
System.setProperty("canal.instance.filter.transaction.entry", "true"); // System.setProperty("canal.instance.filter.transaction.entry", "true");
} // }
// 对应每个instance启动一个worker线程 // 对应每个instance启动一个worker线程
List<CanalDestination> destinations = kafkaProperties.getCanalDestinations(); List<CanalDestination> destinations = kafkaProperties.getCanalDestinations();
@@ -101,8 +102,8 @@ public class CanalKafkaStarter implements CanalServerStarter {
while (!running) while (!running)
; ;
logger.info("## start the canal consumer: {}.", destination.getCanalDestination()); logger.info("## start the canal consumer: {}.", destination.getCanalDestination());
CanalServerWithEmbedded server = CanalServerWithEmbedded.instance(); final CanalServerWithEmbedded server = CanalServerWithEmbedded.instance();
ClientIdentity clientIdentity = new ClientIdentity(destination.getCanalDestination(), (short) 1001, ""); final ClientIdentity clientIdentity = new ClientIdentity(destination.getCanalDestination(), (short) 1001, "");
while (running) { while (running) {
try { try {
if (!server.getCanalInstances().containsKey(clientIdentity.getDestination())) { if (!server.getCanalInstances().containsKey(clientIdentity.getDestination())) {
@@ -117,27 +118,38 @@ public class CanalKafkaStarter implements CanalServerStarter {
logger.info("## the canal consumer {} is running now ......", destination.getCanalDestination()); logger.info("## the canal consumer {} is running now ......", destination.getCanalDestination());
while (running) { while (running) {
Message message = server.getWithoutAck(clientIdentity, kafkaProperties.getCanalBatchSize()); // 获取指定数量的数据 Message message;
long batchId = message.getId(); if (kafkaProperties.getCanalGetTimeout() != null) {
message = server.getWithoutAck(clientIdentity,
kafkaProperties.getCanalBatchSize(),
kafkaProperties.getCanalGetTimeout(),
TimeUnit.MILLISECONDS);
} else {
message = server.getWithoutAck(clientIdentity, kafkaProperties.getCanalBatchSize());
}
final long batchId = message.getId();
try { try {
int size = message.isRaw() ? message.getRawEntries().size() : message.getEntries().size(); int size = message.isRaw() ? message.getRawEntries().size() : message.getEntries().size();
if (batchId != -1 && size != 0) { if (batchId != -1 && size != 0) {
if (!StringUtils.isEmpty(destination.getTopic())) {
Topic topic = new Topic(); Topic topic = new Topic();
topic.setTopic(destination.getTopic()); topic.setTopic(destination.getTopic());
topic.setPartition(destination.getPartition()); topic.setPartition(destination.getPartition());
destination.getTopics().add(topic); canalKafkaProducer.send(topic, message, new CanalKafkaProducer.Callback() {
}
for (Topic topic : destination.getTopics()) {
canalKafkaProducer.send(topic, message); // 发送message到所有topic
}
}
if (batchId != -1) { @Override
public void commit() {
server.ack(clientIdentity, batchId); // 提交确认 server.ack(clientIdentity, batchId); // 提交确认
} }
@Override
public void rollback() {
server.rollback(clientIdentity, batchId);
}
}); // 发送message到topic
}
} catch (Exception e) { } catch (Exception e) {
server.rollback(clientIdentity);
logger.error(e.getMessage(), e); logger.error(e.getMessage(), e);
} }
} }

View File

@@ -20,6 +20,7 @@ public class KafkaProperties {
private long bufferMemory = 33554432L; private long bufferMemory = 33554432L;
private boolean filterTransactionEntry = true; private boolean filterTransactionEntry = true;
private int canalBatchSize = 50; private int canalBatchSize = 50;
private Long canalGetTimeout;
private List<CanalDestination> canalDestinations = new ArrayList<CanalDestination>(); private List<CanalDestination> canalDestinations = new ArrayList<CanalDestination>();
@@ -151,6 +152,14 @@ public class KafkaProperties {
this.canalBatchSize = canalBatchSize; this.canalBatchSize = canalBatchSize;
} }
public Long getCanalGetTimeout() {
return canalGetTimeout;
}
public void setCanalGetTimeout(Long canalGetTimeout) {
this.canalGetTimeout = canalGetTimeout;
}
public List<CanalDestination> getCanalDestinations() { public List<CanalDestination> getCanalDestinations() {
return canalDestinations; return canalDestinations;
} }