一、测试概述
本测试旨在评估三种数据同步工具(Canal、Maxwell、Debezium)在MySQL到Kafka场景下的性能表现。通过模拟企业股东关系数据的生成和同步过程,测试并对比以下核心指标:
- 数据插入性能:MySQL批量插入速度
- 同步延迟:数据从MySQL到Kafka的时间差
- 数据完整性:源端与目标端数据一致性
- 吞吐量:Kafka消费处理能力
- 主从延迟:MySQL主从复制延迟
系统架构图

二、测试环境配置
2.1 数据库层
| 角色 | IP地址 | 版本 | 备注 |
| MySQL Master | xx.xx.xx.xxx | 5.7.44 | 主数据库 |
| MySQL Slave | xx.xx.xx.xxx | 5.7.44 | 从数据库(监控延迟) |
2.2 数据同步层
| 工具 | 版本 | 部署节点 |
| Canal | 1.1.8 | xx.xx.xx.xx |
| Maxwell | 1.41.2 | xx.xx.xx.xx |
2.3 Kafka集群
| 节点 | IP地址 | 版本 |
| Broker1 | xx.xx.xx.xx1 | 4.0.0 |
| Broker2 | xx.xx.xx.xx2 | 4.0.0 |
| Broker3 | xx.xx.xx.xx3 | 4.0.0 |
2.4 测试表结构
CREATE TABLE IF NOT EXISTS mydb.dwd_essential_info_shareholder_info (
id VARCHAR(255) COMMENT '唯一id',
firm_eid VARCHAR(255) COMMENT '企业eid',
firm_id VARCHAR(255) COMMENT '企业id',
firm_name VARCHAR(255) COMMENT '企业名称',
usc_code VARCHAR(255) COMMENT '统一社会信用代码',
reg_no VARCHAR(255) COMMENT '注册号',
org_code VARCHAR(255) COMMENT '组织机构代码',
sha_name VARCHAR(255) COMMENT '股东名称',
sha_type VARCHAR(255) COMMENT '股东类型',
sha_id_type VARCHAR(255) COMMENT '股东证件类型',
sha_id_no VARCHAR(255) COMMENT '股东证件号码',
sha_id VARCHAR(255) COMMENT '股东id',
hold_ratio DECIMAL(18,6) COMMENT '持股比例',
should_cap_items TEXT COMMENT '认缴出资明细(JSON格式)',
cumulative_amt DECIMAL(18,6) COMMENT '累计认缴额',
cumulative_amt_cur VARCHAR(255) COMMENT '累计认缴币种',
real_cap_items TEXT COMMENT '实缴出资明细(JSON格式)',
acc_real_cap DECIMAL(18,6) COMMENT '累计实缴额',
acc_real_cap_cur VARCHAR(255) COMMENT '累计实缴币种',
sha_start_date DATE COMMENT '开始参股时间',
sha_end_date DATE COMMENT '股东退出时间',
country VARCHAR(255) COMMENT '国别',
is_history INT COMMENT '是否历史',
hold_ratio_source INT COMMENT '股比数据来源',
local_row_update_time TIMESTAMP COMMENT '数据更新时间',
is_delete INT COMMENT '是否删除',
partition_date VARCHAR(8) COMMENT 'yyyyMMdd',
test_timestamp BIGINT COMMENT '毫秒级时间戳'
);
三、测试方式
3.1 测试流程
- 数据生成:使用 python_test_mysql.py 生成测试数据
- 全链路测试:运行 run_all.py 进行综合评估
- 工具专项测试:
- Canal测试: test_canal.py
- Maxwell测试: test_maxwell.py
- Kafka性能测试: test_kafka.py
3.2 测试指标
| 指标类别 | 具体指标 |
| MySQL性能 | 插入速度、单条插入耗时、主从延迟 |
| 同步延迟 | 平均延迟、最大/最小延迟 |
| 数据一致性 | MySQL与Kafka记录数比对 |
| Kafka性能 | 生产/消费吞吐量、消息处理延迟 |
四、 测试脚本实现
4.1 数据生成脚本 ( python_test_mysql.py )
核心代码如下:
def generate_test_data(num_records: int = 10):
# 连接MySQL主库
master_conn = pymysql.connect(**MASTER_CONFIG)
# 清空测试表并重建
master_cursor.execute("TRUNCATE TABLE mydb.dwd_essential_info_shareholder_info")
master_cursor.execute(CREATE_TABLE_SQL)
# 生成企业股东关系数据
for i in range(num_records):
# 生成企业信息
company_id = str(uuid.uuid4())
# 生成股东信息(企业/自然人)
is_company = random.choice([True, False])
shareholder_type = "企业" if is_company else "自然人"
# 构造数据记录
row = (...)
batch_values.append(row)
# 每1000条监控主从延迟
if (i + 1) % 1000 == 0:
monitor_replication_lag()
# 批量插入数据
master_cursor.executemany(insert_sql, batch_values)
# 计算性能指标
total_time = time.time() - start_time
print(f"平均插入速度: {inserted_count / total_time:.2f} 条/秒")
4.2 全链路测试脚本 ( run_all.py )
核心代码如下:
def parse_arguments():
parser = argparse.ArgumentParser(description='全链路性能测试')
parser.add_argument('--num_records', type=int, default=10000, help='测试数据量')
parser.add_argument('--batch_size', type=int, default=1000, help='批量插入大小')
parser.add_argument('--kafka_topic', type=str, default='canal_test', help='Kafka主题')
return parser.parse_args()
def main():
args = parse_arguments()
# 1. 生成测试数据
print("开始生成测试数据...")
generate_test_data(args.num_records)
# 2. 启动Canal/Kafka消费者
print("启动Canal/Kafka消费者...")
start_canal_consumer()
# 3. 测量端到端延迟
print("测量端到端延迟...")
measure_end_to_end_latency()
# 4. 验证数据一致性
print("验证数据一致性...")
verify_data_consistency()
4.3 Canal专项测试 ( test_canal.py )
核心代码如下:
def test_canal_data_integrity():
# 获取MySQL记录数
cursor.execute("SELECT COUNT(*) FROM dwd_essential_info_shareholder_info")
mysql_count = cursor.fetchone()[0]
# 消费Kafka消息
consumer = KafkaConsumer('canal_topic4', ...)
for message in consumer:
payload = json.loads(message.value)
if payload.get('type') == 'INSERT':
# 计算延迟
latency = time.time()*1000 - record['test_timestamp']
latencies.append(latency)
msg_count += 1
# 输出结果
print(f"数据一致性: {'通过' if mysql_count == msg_count else '失败'}")
print(f"平均延迟: {sum(latencies)/len(latencies):.2f} ms")
4.4 Kafka性能测试 ( test_kafka.py )
核心代码如下:
def test_kafka_consumer_success(sync_mechanism):
# 创建主题
create_kafka_topic(TOPIC_MAP[sync_mechanism])
# 消费性能测试
consumer = KafkaConsumer(...)
start_time = time.time()
for msg in consumer:
# 实时计算吞吐量
elapsed = time.time() - start_time
throughput = consumed_messages / elapsed
# 输出结果
print(f"消费成功率: {(consumed_messages/total_messages)*100:.2f}%")
print(f"平均吞吐量: {throughput:.2f} 条/秒")
def test_kafka_producer_performance():
# 生产者性能测试
for i in range(1000):
start = time.time()
future = producer.send(...)
metadata = future.get()
latency = (time.time() - start)*1000
# 统计延迟指标
4.4 Flink测试
4.4.1 创建目录
在flink-job文件目录下创建文件
# 进入项目根目录
cd /opt/flink-job
# 创建标准 Maven 目录
mkdir -p src/main/java
mkdir -p src/main/resources
创建完成后如图片所示


4.4.2 编写CanalKafkaConsumer.java文件
在java目录下创建文件CanalKafkaConsumer.java
vi CanalKafkaConsumer.java
文件内容
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.connectors.kafka.FlinkKafkaConsumer;
import org.apache.flink.api.common.serialization.SimpleStringSchema;
import java.util.Properties;
public class CanalKafkaConsumer {
public static void main(String[] args) throws Exception {
final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
// Kafka配置
Properties props = new Properties();
props.setProperty("bootstrap.servers", "xx.xx.xx.xx1:9092,xx.xx.xx.xx2:9092,xx.xx.xx.xx3:9092");
props.setProperty("group.id", "flink-canal-group");
// 消费canal_topic4
FlinkKafkaConsumer<String> consumer = new FlinkKafkaConsumer<>(
"canal_topic4",
new SimpleStringSchema(),
props
);
consumer.setStartFromEarliest(); // 从最早位置消费
// 处理逻辑(这里仅打印,可根据需求修改)
env.addSource(consumer).print();
env.execute("Flink YARN Consumer (canal_topic4)");
}
}
4.4.3 编写文件pom.xml
在flink-job文件目录下编写文件pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>flink-kafka-consumer</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<!-- 确保Flink版本与集群一致 -->
<flink.version>1.14.0</flink.version>
<kafka.version>2.8.1</kafka.version>
<java.version>1.8</java.version>
<scala.binary.version>2.12</scala.binary.version>
<maven.compiler.source>${java.version}</maven.compiler.source>
<maven.compiler.target>${java.version}</maven.compiler.target>
</properties>
<dependencies>
<!-- Flink 核心依赖 -->
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-java</artifactId>
<version>${flink.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-streaming-java_${scala.binary.version}</artifactId>
<version>${flink.version}</version>
<scope>provided</scope>
</dependency>
4.4.4 生成jar包
在flink-job目录下执行
cd /opt/flink-job/
mvn package -Dmaven.test.skip=true
将jar包放到/opt/目录下
cp target/flink-kafka-consumer-1.0-SNAPSHOT-jar-with-dependencies.jar /opt/FlinkKafkaConsumer.jar
4.4.5 编写测试代码
在run_all.py文件中编写核心代码:
def submit_flink_yarn_job():
"""通过带密码的SSH提交Flink任务到YARN集群,消费canal_topic4"""
# 配置信息(需根据实际环境修改)
YARN_PASSWORD = "xxxxxx"
flink_jar_path = "/opt/FlinkKafkaConsumer.jar"
flink_bin_path = "/opt/flink/bin" # 移除末尾多余的斜杠,避免路径拼接问题
# 构造带密码的SSH命令:先加载环境变量,再提交Flink任务到YARN集群
# 关键改进:添加 source /etc/profile 确保HADOOP_CLASSPATH生效
cmd = [
"sshpass", "-p", YARN_PASSWORD,
"ssh", "-o", "StrictHostKeyChecking=no",
"root@xx.xx.xx.xxx",
# 使用双引号包裹远程执行的命令,确保source和flink命令在同一shell会话中执行
f"source /etc/profile && {flink_bin_path}/flink run -m yarn-cluster {flink_jar_path}"
]
logging.info(f"提交Flink任务到YARN:{' '.join(cmd)}")
try:
# 执行命令并实时输出日志
process = subprocess.Popen(
cmd,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
universal_newlines=True
)
for line in iter(process.stdout.readline, ''):
logging.info(f"Flink YARN: {line.strip()}")
process.wait()
if process.returncode == 0:
logging.info("Flink任务提交成功")
return True
else:
logging.error(f"Flink任务提交失败,返回码: {process.returncode}")
return False
except Exception as e:
#在main核心代码中添加
if __name__ == "__main__":
parser = argparse.ArgumentParser(description='全链路性能测试(含关键时间打印)')
parser.add_argument('--num_records', type=int, default=10000)
parser.add_argument('--sync_mechanism', type=str, default='canal',
choices=['canal', 'maxwell', 'debezium'])
args = parser.parse_args()
print("="*70)
print(f"🚀 开始全链路性能测试 | 机制: {args.sync_mechanism} | 数据量: {args.num_records}")
print("="*70)
create_kafka_topic(TOPIC_MAP[args.sync_mechanism])
run_script('python_test_mysql.py', ['--num_records', str(args.num_records)])
# 统一入口:吞吐量和Kafka关键时间
calculate_throughput_and_kafka_time(args.sync_mechanism)
# 根据机制计算延迟
if args.sync_mechanism == 'maxwell':
calculate_maxwell_latency()
else:
calculate_canal_latency(args.sync_mechanism)
run_mysql_performance_test()
run_kafka_performance_test(args.sync_mechanism)
if args.sync_mechanism == 'canal':
print("\n" + "="*50)
print("📡 开始提交Flink on YARN任务消费canal_topic4")
print("="*50)
submit_flink_yarn_job()
print("\n" + "="*70)
print("🏁 全链路性能测试完成!")
print("="*70)
# 五、 测试执行示例
## 5.1 执行全链路测试(10,000条记录):
```bash
python run_all.py --num_records 10000 --sync_mechanism canal
使用canal进行测试时,若之前有测试过,则需要删除之前测试创建的topic,例如如下命令(kafka主节点运行)
./bin/kafka-topics.sh --bootstrap-server xx.xx.xx.xx:9092 --delete --topic canal_topic4
在运行如下命令(kafka主节点运行)
./bin/kafka-console-consumer.sh --bootstrap-server xx.xx.xx.xx:9092 --topic canal_topic4 --from-beginning
同理maxwell的相关测试一致
python run_all.py --num_records 10000 --sync_mechanism maxwell
5.2 测试输出示例:
============================================================
🚀🚀 开始全链路性能测试 | 机制: canal | 数据量: 10000
============================================================
[OK] 数据插入完成! 共插入 10000 条数据
⏱⏱⏱️ 总耗时: 3250.22毫秒
🚀🚀 平均插入速度: 3076.92 条/秒
📊📊 CANAL 吞吐量 & Kafka关键时间
============================================================
有效消息数: 10000
时间跨度: 2800.00 ms
📈📈 平均吞吐量: 3571.43 条/秒
🕒🕒🕒 Kafka第一条消费时间: 2025-07-29 14:05:30 (1722233130000)
🕒🕒🕒 Kafka最后一条消费时间: 2025-07-29 14:05:33 (1722233133000)
📊📊 CANAL 平均延迟: 52.37 ms,有效消息: 10000
🗄🗄️ MYSQL 插入性能结果 & 关键时间
============================================================
📊📊 插入消息数: 10000
⏱⏱⏱️ 总耗时: 3250.22 ms
⏱⏱⏱️ 平均每条耗时: 0.33 ms
🕒🕒🕒 第一条插入MySQL时间: 2025-07-29 14:05:30 (1722233130000)
🕒🕒🕒 最后一条插入MySQL时间: 2025-07-29 14:05:33 (1722233133000)
🚀🚀 KAFKA 消费性能结果
============================================================
📊📊 消费消息数: 10000
⏱⏱⏱️ 总耗时: 2100.50 ms
⏱⏱⏱️ 平均每条耗时: 0.21 ms
============================================================
🏁🏁 全链路性能测试完成!
============================================================
六、测试结果如下
6.1 canal默认配置下的测试结果

6.2 canal优化配置测试结果(一)
修改配置文件的内容如下
# 提升并行处理能力
canal.instance.parser.parallelThreadSize = 16
# 增大内存缓冲区
canal.instance.memory.buffer.size = 65536 # 64K 条目 (4倍提升)
canal.instance.parser.parallelBufferSize = 1024 # 1024 条目 (4倍提升)
# 优化 Kafka 生产者配置
kafka.batch.size = 32768 # 32KB (增大批处理量)
kafka.linger.ms = 20 # 适当等待聚合更多数据
kafka.acks = 1 # Leader确认即可 (降低可靠性提升吞吐)

6.3 canal优化配置测试结果(二)
修改配置文件的内容如下
# 并行解析线程启用
canal.instance.parser.parallelThreadSize = 16
# Kafka 压缩类型修改
kafka.compression.type = lz4

6.4 maxwell默认配置测试结果

6.5 maxwell优化配置测试结果
修改配置文件的内容如下
producer_kafka_acks=all # 需要所有ISR副本确认
producer_kafka_retries=10 # 失败时重试次数
producer_kafka_enable_idempotence=true # 启用幂等性(防止消息重复)
producer_kafka_max_in_flight_requests_per_connection=5

3万+



被折叠的 条评论
为什么被折叠?



