config.properties 配置文件里面的所有选项,都可以在启动 maxweill ./bin/maxwell
是指定,覆盖配置文件的内容。这里只讲一些常用的。
replication_host
,那么它是真正的binlog来源的mysql server地址,而那么上面的host
用于存放maxwell表结构和binlog位置的地址。schema_host
从哪个host获取表结构。binlog里面没有字段信息,所以maxwell需要从数据库查出schema,存起来。
schema_host一般用不到,但在binlog-proxy场景下就很实用。比如要将已经离线的binlog通过maxwell生成json流,于是自建一个mysql server里面没有结构,只用于发送binlog,此时表机构就可以制动从 schema_host
获取。
gtid_mode
如果 mysql server 启用了GTID,maxwell也可以基于gtid取event。如果mysql server发生failover,maxwell不需要手动指定newfile:postion
正常情况下,replication_host 和 schema_host都不需要指定,只有一个 --host
。
,
号分隔,中间不要包含空格。include_tables=db1,/db\\d+/
,表示 db1, db2, db3…这样的。(下面的filter都支持这种regex)use db1
但 update db2.ttt
,那么maxwell生成的json database
内容是db2。include_column_values
1.12.0新引入的过滤项。只输出满足 column=values 的行,比如 include_column_values=bar=x,foo=y
,如果有bar
字段,那么只输出值为x
的行,如果有foo
字段,那么只输出值为y
的行。
如果没有对应字段,如只有bar=x
没有foo
字段,那么也成立。(即不是 或,也不是 与)
blacklist_dbs
一般不用。blacklist_dbs
字面上难以与exclude_dbs
分开,官网的说明也是模棱两可。
从代码里面看出的意思是,屏蔽指定的这些dbs,tables的结构变更,与行变更过滤,没有关系。它应对的场景是,某个表上频繁的有ddl,比如truncate。
因为往往我们只需要观察部分表的变更,所以要注意这些 include 与 exclude 的关系,记住三点:
举个比较极端的例子:
1 2 3 4 5 |
# database: db1,db2,db3,mydb ① include_dbs=db1,/db\\d+/ ② exclude_dbs=db2 ③ inlcude_tables=t1,t2,t3 ④ exclude_tables=t3 |
配置了 include_dbs,那么mydb不在里面,所以排除;
配置了 exclude_dbs,那么db2排除。剩下db1,db3
同样对 tables,剩下t1,t2
所以db1.t1, db1.t2, db3.t1, db3.t2是筛选后剩下可输出的。如果没有指定include_dbs,那么mydb.t1也可以输出。
如果是长时间运行的maxwell,添加monitor配置,maxwell提供了http api返回监控数据。
FILE:POSITION:HEARTBEAT
。只支持在启动maxwell的命令指定,比如 --init_postion=mysql-bin.0000456:4:0
。Maxwell是将binlog解析成json这种比较通用的格式,那么要去用它可以选择输出到哪里,比如Kafka, rabbitmq, file等,总之送到消息队列里去。每种 Producer 有自己对应的选项。
1 2 |
producer=file output_file=/tmp/mysql_binlog_data.log |
比较简单,直接指定输出到哪个文件output_file
。有什么日志收集系统,可以直接从这里拿。
rabbitmq 是非常流行的一个AMQP协议的消息队列服务,相关介绍请参考 rabbitmq入门
1 2 3 4 5 6 7 8 9 10 11 |
producer=rabbitmq rabbitmq_host=10.81.xx.xxx rabbitmq_user=admin rabbitmq_pass=admin rabbitmq_virtual_host=/some0 rabbitmq_exchange=maxwell.some rabbitmq_exchange_type=topic rabbitmq_exchange_durable=true rabbitmq_exchange_autodelete=false rabbitmq_routing_key_template=%db%.%table% |
上面的参数都很容易理解,1.12.0版本新加入rabbitmq_message_persistent
控制发布消息持久化的参数。rabbitmq_routing_key_template
是按照 db.tbl 的格式指定 routing_key,在创建队列时,可以根据不同的表进入不同的队列,提高并行消费而不乱序的能力。
因为rabbitmq搭建起来非常简单,所以我习惯用这个。
kafka是maxwell支持最完善的一个producer,并且内置了 多个版本的 kafka client(0.8.2.2, 0.9.0.1, 0.10.0.1, 0.10.2.1 or 0.11.0.1),默认 kafka_version=0.11.0.1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
producer=kafka # 指定kafka brokers 地址 kafka.bootstrap.servers=hosta:9092,hostb:9092 # kafka主题可以是固定的,可以是 `maxwell_%{database}_%{table}` 这种按表去自动创建的动态topic kafka_topic=maxwell # ddl单独使用的topic ddl_kafka_topic=maxwell_ddl # kafka和kenesis都支持分区,可以选择根据 database, table, primary_key, 或者column的值去做partition # maxwell默认使用database,在启动的时候会去检查是否topic是否有足够多数量的partitions,所以要提前创建好 # bin/kafka-topics.sh --zookeeper ZK_HOST:2181 --create \ # --topic maxwell --partitions 20 --replication-factor 2 producer_partition_by=database # 如果指定了 producer_partition_by=column, 就需要指定下面两个参数 # 根据user_id,create_date两列的值去分区,partition_key形如 1178532016-10-10 18:29:04 producer_partition_columns=user_id,create_date # 如果不存在user_id或create_date,则按照database分区: producer_partition_by_fallback=database |
maxwell会读取kafka.
开头的参数,设置到连接参数里,比如kafka.acks=1
,kafka.retries=3
等
redis也有简单的发布订阅(pub/sub
)功能
1 2 3 4 5 6 7 |
producer=redis redis_host=10.47.xx.xxx redis_port=6379 # redis_auth=redis_auth redis_database=0 redis_pub_channel=maxwell |
但是试用一番之后,发现如果订阅没有连上去的话,所有pub的消息是会丢失的。所以最好使用push/pop
去实现。
下面的是在使用过程中遇到的一些小问题,做下总结。
maxwell对时间类型(datetime, timestamp, date)都是当做字符串处理的,这也是为了保证数据一致(比如0000-00-00 00:00:00
这样的时间在timestamp里是非法的,但mysql却认,解析成java或者python类型就是null/None)。
如果MySQL表上的字段是 timestamp 类型,是有时区的概念,binlog解析出来的是标准UTC时间,但用户看到的是本地时间。比如 f_create_time timestamp
创建时间是北京时间2018-01-05 21:01:01
,那么mysql实际存储的是2018-01-05 13:01:01
,binlog里面也是这个时间字符串。如果不做消费者不做时区转换,会少8个小时。被这个狠狠坑了一把。
与其每个客户端都要考虑这个问题,我觉得更合理的做法是提供时区参数,然后maxwell自动处理时区问题,否则要么客户端先需要知道哪些列是timestamp类型,或者连接上原库缓存上这些类型。
maxwell可以处理binary类型的列,如blob
、varbinary
,它的做法就是对二进制列使用 base64_encode,当做字符串输出到json。消费者拿到这个列数据后,不能直接拼装,需要 base64_decode。
如果是拿比较老的binlog,放到新的mysql server上去用maxwell拉去,有可能表结构已经发生了变化,比如binlog里面字段比 schema_host 里面的字段多一个。目前这种情况没有发现异常,比如阿里RDS默认会为 无主键无唯一索引的表,增加一个__##alibaba_rds_rowid##__
,在 show create table 和 schema里面都看不到这个隐藏主键,但binlog里面会有,同步到从库。
另外我们有通过git去管理结构版本,如果真有这种场景,也可以应对。