发布 : 2021-02-14 浏览 :

(一) 前言

  互联网体系架构具有可控性差、 数据量大、 架构复杂等特点,错综复杂的各业务模块需要解耦,各异构数据需要同步,双活/多活的容灾方案需要高实时性 等,在各种场合都需要一套可靠的数据实时推送方案。mysql已成为互联网项目存储的主力,围绕着它的各外围模块急需实时地获取它的数据,binlog监听是解决此实时同步问题的不二之选。duckula就是为了满足此需求而设计与开发出来的中间件。

(二)duckula3简介

  duckula3是一款binlog监听的中间件,但它不仅仅是一款binlog监听的中间件,它可以允许用户自主使用binlog数据。可以有多变的使用方式,可以做为中间件独立布署,也可以嵌入到项目中启动布署,可以嵌入到springboot项目,也可以嵌入到纯java项目,它也有专用于flink的source,可以使flink直连数据库,拿到它的实时数据。由于它良好的插件设计,可以支持任何用户自定义的监听开发。

duckula的由来

   大概在2016年的时候,我在***中间件团队时,当时公司使用了一套叫“精卫”的中间,由于阿里不对它开源,只是使用权,在支撑业务线运行的过程中,发现了较多的问题,如采用回退12秒HA的模式带来的数据重复推送、界面全是手工录入,耗时也易出错,配置非常复杂(特别是分库分表情况往往要1、2个小时才能搞定),HA时启动失败需要重置位点导致的丢数据没有补全方案等方方面面。 由于没有源码,只能干瞪眼。所以那时就下决心解决这个问题。经过一段时间的选型,在github找了几个binlog解释器,就一条:性能不达标,一票否决了,那时也有关注canel,性能是OK,但是它的设计初是解决两地数据复制问题(当时的版本),而与我要找的是精卫的替代方案,它是要满足数据的分类推送(如哪个表推送哪个消息的topic中)。就有了自研的念头。于是就有了zorro中间件。

   离开这家公司后来到了一家央企,无事可干,实在无聊,zorro的设计还是感觉不满意,代码也不能拿出来,但知识是在脑子里的,于是重写binlog中间件,这就是duckula的雏形,纯粹写着玩了。

  等我写完后,离开了央企,到了下一家互联网公司任技术专家,刚好碰到一个“世纪难题”,一张mysql表已3KW了,没有做分库分表,且开发它代码的人都离职了,没人懂里面的细节了,查询条件非常复杂,索引建了无数,但没用,系统越来越慢,而且每天都有5W多的数据新增,而且要保留很长时间的数据(基本上是全部),不能删除,而且实时性要求很高(基本上前一个状态改了马上要能查到,好做下一步操作), 照这样发展,系统肯定得废啊。于是我想到了duckula,但它只有mysql的binlog到kafka这一个模块,并没有监听kafka插入到es模块,而且3KW数据的全量导入ES也是个问题,总不能产生3KW的binlog事件发kafka吧。kafka也得爆(配置不怎么样),于是加紧开发了 这2个模块,加上前面已有的binlog监听模块,这3个模块就完成了从mysql到ES同步的闭环。完美,这就是duckula1初步完成。
  接下来公司要上paas系统了,我们把中间件全部迁上k8s,把spring cloud这一套也全部上k8s,那么duckula1的SSH连接主机(就像cachcloud)管理binlog监听任务的这一套必须得变了,把原来的有“服务器”布署模式变为k8s的“无服务器”布署模式,而且要试着兼容之前的运行模式,这次改造超出了我当初的预期,花费了大量时间,要考虑的东西实在太多了,好在duckula2版本最终出来了,更进一步的是,把它SaaS化,也就是支持让业务线的同学直接跟据需求配置监听任务,这样就没有基础架构组啥事了。且它后面开发了支持”普罗米修斯”的监控。支持binlog的行列过滤等功能也开发了,于是duckula2变得越来越“重”,它表现在布署非常麻烦,配置项就有几百个。

  应该说我们的使用场景太丰富了(toB行业), 接下来又发生了现在的duckula2无法解决的场景—-属地化部署,有一个项目有属地化的需求,给我们的机器资源有限,但是duckula2又对zookeeper、kafka等中间件有依赖,duckula2自身也需要布署一个ops(控制台),不可能有这么多的资源让我布署了,于是跟据需求,我把duckula2又进行了一次重构,形成了一个轻量级的binlog监听工具包叫ducklite,它可以以jar包的形式被项目直接引用,分布式锁从zookeeper改为了mysql锁,表的“列名”,“位点”等元数据存储在mysql里不用zookeeper, 这次真的轻了,只依赖mysql就行了,但它只是临时方案,离完整的binlog解决方案还是有些差距。

  在现实使用ducklite中又发现状况,没有全量方案,最开始上线没多少数据,可以全量修改产生全量的binlog确实没问题,等上了生产后产生了大量数据就玩不转了,还有老客户的旧版本迁移到新系统后,旧系统的数据如何全量推ES?还有,由于ducklite是嵌入到应用系统的,监听任务的开发由业务人员完成的,由于开发人员的素质差异,差的监听执行器往往会影响ducklite的监听任务运行,所以他们经常抱怨“太慢了”,“怎么又死了”,于是下决心在ducklite的基础上开发可以独立布署的新版本:duckula3。

功能概述

  duckula的重头戏是binlog监听,但它又不止于binlog监听,它的作用范围有了进一步的延伸,如:把监听的消息实时入ES,通过配置完成mysql到ES的快速全量导入等,这样就有了一个从mysql到ES的闭环。有了duckula后,业务开发人员就不用理会mysql到es的同步问题,只需跟据业务需求开发ES的查询语句就可以了。

功能模块

  duckula3可以分为三块:

ops: 调度中心,配置中心,不强依赖,只是方便配置和管理执行器。

执行器: binlog监听执行器/kafka consumer执行器/全量导入执行器,这块是duckula的重心。

插件: 支持执行器往各种不同的存储中间件进行导入,现在支持的有ES5、ES6、ES7、kafka、mysql、log(测试用)、http 等

配置项

配置项是为了更好的支持执行器的配置,一切都是为了重用,我们把一个执行器需要的配置项分为6大块

  • 布署环境   执行器将会在哪个环境里运行,现在支持 k8s/docker/contos7,duckula会使用它的配置来布署执行器

  • 实例    binlog监听执行器需要监听哪个数据库,dump(全量导入)需要扫哪个数据库 等配置信息

  • 存储中间件   所有的执行器需要把数据发往哪个地方存储或通知,现在支持ES/mysql等

  • 版本    执行器使用了duckula3的哪个版本

  • 检查点    检查点(checkpoint)是binlog监听执行器用来做HA(高可用),支持 内存/h2db/mysql 三种类型,只有mysql可以做跨机器的HA,h2db只能在本机做HA,内存不能做HA,它需要借助宿主应用做HA,如flink本身就有checkpoint机制,那么duckula3实现的flink source就需要使用内存类型的检查点,duckula3会把元数据借助flink的checkpoint来存储,从而完成HA的。

监控

执行器都有通过jmx暴露普罗米修斯接口。

(三)安装

独立安装

独立jar包启动

duckula3设计的初衷就是简单,布署简单,配置简单,使用简单

  • 执行初始化SQL脚本,创建数据库使用下面的脚本 :duckula-ops\devops\sql\duckula.sql

    https://gitee.com/rjzjh/duckula-ops/blob/master/devops/sql/duckula.sql

  • 下载执行jar包:

    https://cloud.189.cn/t/ZfAn2uRvaQZz

    下载文件主要有三个:

    duckula-3.0.0.tar 执行器

    duckula-data-3.0.0.tar 插件及相关的配置信息

    duckula-ops.jar ops运行程序

    把duckula-3.0.0.tar和duckula-data-3.0.0.tar 复制到启动程序的帐户home目录,如:/home/duckula 这是duckula帐号的用户目录。duckula-ops.jar就是ops可执行程序,它是一个spring boot项目,在下面启动时会用到它。

  • 跟据实距情况修改下面配置,并保存到用户home目录的duckula-ops.properties文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    spring.datasource.dynamic.primary=master
    spring.datasource.dynamic.strict=false
    spring.datasource.dynamic.datasource.master.url=jdbc:mysql://docker.for.win.localhost:3306/duckula?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=true
    spring.datasource.dynamic.datasource.master.username=root
    spring.datasource.dynamic.datasource.master.password=mysql
    spring.datasource.dynamic.datasource.master.driver-class-name=com.mysql.jdbc.Driver
    spring.cloud.refresh.refreshable=none
    mybatis-plus.mapper-locations=classpath:mybatis/primary/sqlmap/*.xml
    logging.level.net.wicp.tams.app.duckula.controller.dao=DEBUG
  • 启动ops。

    简单启动 : java -jar -server duckula-ops.jar

在docker中启动:

前面的文件配置和初始化步骤不变,然后执行:

docker run -d -it –name=duckula-ops -v C:/Users/Administrator:/home/duckula -p 8080:8080 registry.cn-hangzhou.aliyuncs.com/rjzjh/duckula:ops.3.0.0

停止任务:docker stop duckula-ops

删除任务:docker rm duckula-ops

在k8s里启动

要在k8s里启动,首先需要安装helm3,具体安装步骤,k8s的config相关配置, 请自行google。

  1. 找到源码的这个目录: duckula-ops\devops\k8s\duckula3-ops

  2. cmd到这个目录下,跟据实际情况修改文件:values.yaml,再执行命令:

    helm install -name rjzjh .\duckula3-ops\ –namespace default

  3. 查看相关日志:

    日志查看

  1. 本地访问地址

  设置本地转发:kubectl port-forward po/rjzjh-duckula-ops-58f87bf5b9-pl7k2 8080:8080 -n default

  访问地址:http://localhost:8080/

在java编译工具中启动(ide,eclipse等)

  1. 下载源码,安装好jdk和maven,编译成功

  2. 修改配置文件

  如上创建好配置文件duckula-ops.properties,你可以在bootstrap.yml修改配置文件的位置。

  1. 启动springboot的启动类
      启动类为:net.wicp.tams.duckula.ops.App

  2. 打docker镜像

    先通过maven打包或本地安装jar: maven clean install -Dmaven.test.skip=true -Dmaven.javadoc.skip=true

    切换到target目录下执行:docker build -t registry.cn-hangzhou.aliyuncs.com/rjzjh/duckula:duckula-ops.3.0.0 .

    上面的group:registry.cn-hangzhou.aliyuncs.com/rjzjh/duckula跟据自己的情况进行替换。

  3. 推送镜像到image私服

    docker login -u XXXXX

    docker push registry.cn-hangzhou.aliyuncs.com/rjzjh/duckula:duckula-ops.3.0.0 .

嵌入式使用

duckula3可以做为一个jar包的方式存在于一个项目的依赖中,如同使用其它的工具类一样,只要引入相关的jar包,很简单的做些配置就可以在宿主项目中跑起来。duckula3已上传到maven中央库,可以在任何使用maven的项目是直接使用,maven坐标为:

1
2
3
4
5
<dependency>
<groupId>net.wicp.tams</groupId>
<artifactId>common-binlog-alone</artifactId>
<version>最大版本</version>
</dependency>

下面的示例项目在oschina上:https://gitee.com/rjzjh/duckula3-dev-demo

纯java(非spring boot)

项目结构如下:

java结构

主文件入口:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package net.wicp.tams.duckula.demo.cuslistener;

import java.io.IOException;
import java.util.Properties;
import net.wicp.tams.common.Conf;
import net.wicp.tams.common.apiext.IOUtil;
import net.wicp.tams.common.binlog.alone.BusiAssit;

public class Main {
public static void main(String[] args) throws IOException {
Properties props = IOUtil.fileToProperties("/common-binlog-chk-mysql.properties", Main.class);
Conf.overProp(props);
BusiAssit.startListenerForConfig();
System.in.read();
}
}

配置文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#插件可以看common-es-plugin的test
common.binlog.alone.binlog.global.busiPluginDir=null
#默认的监听服务配置,如果有多套,复制此配置并修改global.conf为conf.XXXX(见下面示例)
common.binlog.alone.binlog.global.conf.host= localhost
common.binlog.alone.binlog.global.conf.port = 3307
common.binlog.alone.binlog.global.conf.username = root
common.binlog.alone.binlog.global.conf.password = mysql
common.binlog.alone.binlog.global.conf.listener = net.wicp.tams.duckula.demo.cuslistener.TestListener
common.binlog.alone.binlog.global.conf.rds = false
#设置了groupId表示需要做分布式锁,同一个groupId+ip就是一个集群分布式锁
common.binlog.alone.binlog.global.conf.groupId = 20000
#默认使用CheckPointH2db,还提供了CheckPointMemory的chk实现,CheckPointMysql多进程的HA机制
common.binlog.alone.binlog.global.chk=net.wicp.tams.common.binlog.alone.checkpoint.CheckPointMysql
#如果其它与配置相同就可以不配置
common.binlog.alone.binlog.global.chk.mysql.defaultdb=tams
#cur表示从当前最新位点启动,last表示从记录的最后位点启动,pos表示从上面设置的gtids启动
common.binlog.alone.binlog.global.conf.haType = last
#为了做HA,必须填一个,否则不能区分lastPo
common.binlog.alone.binlog.conf.abc.clientId=20000
#监听规则,这是2组,就是test库的user_info和user_addr表被监听,这两张表有binlog时才会给到上面配置的listener
common.binlog.alone.binlog.conf.abc.rule=test`user_info`{}&test`user_addr`{}

由于使用的是具有HA和分布式锁的最完备的CheckPointMysql,所以配置项会多一些,而且需要在监听项上创建一个tams数据库(binlog监听时需要存储元数据),监听的帐号对这个库具有建表权限(通过表锁来实现分布式锁),上面这些配置都有说明。

实际上可以使用的配置项会非常多,而且会不断的增加,如果不熟悉的使用者肯定搞晕,所以会有duckula-ops帮助配置和布署。

示例项目见:duckula3-dev-demo-cuslistener

spring boot

在spring boot项目中嵌入式使用duckula3,除了上面提及的的maven坐标依赖外,还需引入另一个jar包:

1
2
3
4
5
<dependency>
<groupId>net.wicp.tams</groupId>
<artifactId>common-spring-autoconfig</artifactId>
<version>最后一个版本</version>
</dependency>

在启动类需要中入enable注解:

springboot主入口

springconfpres配置是指像你数据库连接地址的配置,跟据实际情况修改。

接下来就创建一个监听器,使用注解的方式说明:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//chk默认为CheckPointH2db,如果不变无需配置。conf:随意,不能重复  rule:监听配置,监听duckula库sys_user表
@BinlogListener(conf = "abc", chk = "net.wicp.tams.common.binlog.alone.checkpoint.CheckPointMemory", rule = "duckula`sys_user`{}")
public class TestListener extends AbsBinlogListener {
@Override
public void doBusiTrue(Rule rule, DuckulaEvent duckulaEvent, boolean isSplit) {
String username = DuckulaAssit.getValue(duckulaEvent, "username", 0);
System.out.println("username=" + username);
}

// 当修改表时触发,如加字段
@Override
public Result doAlterTableCallBack(Rule rule, ColHis colHis, String sql) {
return Result.getSuc();
}

@Override
public void doInit(Rule rule, int index) {

}
}

示例项目见:duckula3-dev-demo-springboot

duckula3也可以在flink里使用,已完成用于监听binlog的source开发。

用法见博文:https://blog.csdn.net/rjzjh/article/details/100864012

(四)访问

到了见证成果的时候了:
首页

布署页:
布署页

(五)监听任务

  duckula最核心也是最复杂的地方就是binlog监听任务了,在duckula3中,要完成一次binlog任务监听的配置,需要把“配置管理”模块所有的管理配置都配一遍才行,但不用担心,那些配置是可重用的,那些配置也可以避免你的任务配置出现差错导致监听失败,而且 为了配置者(dba与运维人员)与使用者(业务人员)分离,这也是有必要的。 从这点看把“配置管理”模块都配置一遍是值得的,特别是你的数据库实例是分库分表情况下。
  binlog监听任务不但可以快速地配置监听任务,也带有启停任务、查看实时日志、查看配置文件等运维功能,还有一个功能这个版本没有实现的是:HA的主动触发功能。如果是使用zookeeper的类型的checkpoint计划使用watch机制(duckula2已实现),如果是mysql类型的checkpoint会使用job的方式来完成。内存模式虽说也是job来完成,但它不能保证数据的完整性,会丢数据。h2db模式可能会用job的集中式HA,也可能会使用linux守护进程的模式来做HA。

主界面

  入口:运行管理->监听任务

image-20201221213510890

支持“任务名”条件查询。下面是它的编辑界面:

image-20201221214431734

其中所有的配置项都是如上图所示的下拉列表,让用户自行选择配置项,这些配置项都是“配置管理”模块的相关配置信息。

字段说明

  • 监听任务名:用于标识这个发布环境的,需要能一看就懂的监听任务

  • 版本:系统配置->版本管理 的配置项,配置监听任务所用的程序版本

  • 监听实例:系统配置->实例管理 的配置项,配置监听任务会监听哪个mysql实例

  • 布署环境:系统配置->布署管理 的配置项,用于配置监听任务会在哪个环境进行运行。

  • 目的中间件:系统配置->存储中间件管理 配置项,用于配置任务会把数据推送到哪个存储中间件

  • 检查点:系统配置->检查点服务管理 配置项,用于配置任务使用哪种类型的检查点

  • ha类型:

    最后位点:指示使用checkpoint的最后一个记录的位点,真正的HA

    最新位点:指示使用数据库的最新位点,会导致部分数据丢失。

    指定位点:指示使用数据库后面的“启动的gtid”字段填写的gtid位置

  • image-20201221215518429

  • 启动的Gtid:与ha类型配合使用

  • 附加配置:要同步到目的中间件需要的其它配置,由插件来使用这些配置。

  • 编辑规则 :见。。。。

按钮说明:

  • 查询/新增/修改/删除 按钮为默认意义,不细说。
  • 启动: 在指定的部署环境部署和启动监听任务
  • 停止: 停止监听任务运行
  • 查看日志:用于实时显示当前启动的日志,如下所示效果

image-20201221213637225

  • 查看配置:显示现在监听任务的配置信息 和 已部署在相关部署环境中真正的配置 的差异,可以重新部署配置文件,如下图:

image-20201221214120250

  • 权限定义: 未布署的任务不能查看日志,运行中的任务不能修改、删除、启动任务。如下图:

image-20201221214345623

(六)kafka消费任务

  duckula3的kafka消费任务,是延续duckula2的功能,如果binlog监听任务的数据确定只有一个使用者时,可以不配置这个任务,因为,binlog监听任务有足够的能力直达想要去的中间件(见”监听任务”一节),如果想用kafka来做缓存,用于缓冲binlog解析器与存储中间件的接收速度,如果只有一个数据使用者时,这种缓存并不需要,第一,接收中间件速度慢了,数据肯定延迟,加不加缓存不能解决问题。第二,由于只有一个使用者,由于接收中间件接收速度慢并不会影响别人,慢点解析有什么关系呢?使用kafka还有一个作用就是利用kafka的consumer的消费offset来做HA,但是binlog在5.6以后可以支持gtid了,它可以精准定位binlog位置,也就是说mysql本身就具有HA的机制。

  综合来说在数据使用者只有一个时,可以使用直接推送到存储中间件的方案,少一次消息发送和消费的过程,减少失败,如果具有多个使用者同时使用相同的数据时,那必须考虑使用kafka等消息中间件缓存一下,利用消息中间件的广播模式可以很好地做到消息复用。

主界面

  入口:运行管理->kafka消费任务

image-20201222110634795

支持“消费者名”条件查询。上面的小框是它的编辑界面:

字段说明

  • kafka消费任务:用于标识这个消费者的,需要能一看就懂的消费者

  • 版本:执行器对应的程序版本,如果是host/docker发布模式,只能使用发布管理上的版本,所以在此不能进行配置。只有k8s可以配置版本

  • 反查实例: 反查是指通过数据库表的id来查到此记录的全部字段的行为。在以下两种情况下需要反查,当数据由于某种原因丢了部分数据,那么可以采用离线解析的方案把这部分数据补到kafka中,那么这部分数据是旧数据,不应该覆盖目标中间件的现有数据,所以在duckula有一个字段:isError标识为true,对于这部分数据,consumer需要做一次反查db的动作,拿到最新的数据再去覆盖。第二种情况是kafka采用全幂等模式,binlog监听只传一个数据库的id(这样不用考虑顺序性,大大提高发送kafka性能),那么consumer想要添加到存储中间件前必须做一个反查。一般来说这个字段选择的数据库与binlog监听数据库实例相同。

  • 布署环境:消费者执行器将在哪个环境进行布署。

  • kafka实例:将要监听的kafka实例,它会在“存储中间件管理”页面进行配置

  • 目的中间件:将要把监听的kafka消息同步到哪个目标中间件,它会在“存储中间件管理”页面进行配置

  • topic:监听哪个kafka主题,为了减小架构难度,一个kafka消费任务只处理一个topic的数据。

  • 附加配置:要同步到目的中间件需要的其它配置,由插件来使用这些配置。

  • 编辑规则 :见。。。。

    (七)全量任务

  我们有了binlog监听后,实现了增量部分,但数据的初始化运行怎么来做呢?当然,我们可以全表修改update字段,人工产生全量的binlog数据,但是在这之前需要考虑这么几个情况,我们便mysql同步es的方案来说。首先,这次update会不会对 生产环境产生影响,线上系统肯定不会允许大表这么干,其次,如果中间有kafka消息,kafka默认存储7天数据,用它来存大表的全表数据,一不小心就磁盘爆了。还有种情况就是在有kafka的情况下,其中一个用户由于某些原因需要重新消费某段时间的数据,最省事的方案就是在数据库把这段时间的数据做一次update,产生binlog到kafka,那问题来了,其它用户不管愿不愿意,都会再次接收这批补的数据。纯粹浪费资源。再说一种情况,如果es需添加一个字段,这个字段也在数据库存在的,但之前一直没用到就没有放es索引,这时候如何在es里被这个字段呢?而且这种情况经常发生呢?

  上面提及的很多情况都不是binlog能解决的,所以我们需要有一个全量任务支持,那么这个执行器就非常有必要了。它也支持sql过滤,也就是说我们可以同步任何范围的数据,不只是做全量。

  有了增量和全量,这才是一整套完整的数据同步解决方案。

主界面

  入口:运行管理->全量任务

image-20201222130637532

支持“任务名”条件查询。这里与binlog监听任务不同的是。它是一个运行完就退出并释放资源的任务,所以在k8s布署环境里,它是一个job,在执行完后它的状态为:suceeded, 在docker/host里它会在任务执行完后退出虚拟机。因为它是一次性任务。

下面是它的编辑界面:

image-20201222140228010

其中所有的配置项都是如上图所示的下拉列表,让用户自行选择配置项,这些配置项都是“配置管理”模块的相关配置信息。

字段说明

  • 监听任务名:用于标识这个发布环境的,需要能一看就懂的监听任务

  • 版本:系统配置->版本管理 的配置项,用于全量任务的程序版本

  • 监听实例:系统配置->实例管理 的配置项,配置监听任务会监听哪个mysql实例

  • 布署环境:系统配置->布署管理 的配置项,用于配置监听任务会在哪个环境进行运行。

  • 目的中间件:系统配置->存储中间件管理 配置项,用于配置任务会把数据推送到哪个存储中间件

  • 过滤SQL:用于过滤全量数据,当我们只需补某一段时间的数据时可以加上此SQL过滤。

  • 编辑规则 :见。。。。

(八)资源配置

duckula3支持各种配置,这些配置都是在实际项目开发中碰到的痛点总结。

检查点服务管理

  对于binlog监听来说会有一些元数据要存储,如:监听的表的字段信息(binlog不含有字段名),要做到高可用(HA)能正常启动需要存储字段名的历史(会增删字段), 当前监听的位点信息(filename+pos+gtid)等,目的就是为了HA能正常启动。我们称当前的监听位点为checkpoint(借用flink的概念)。

  在duckula2中checkpoint是不可定制的,只有zookeeper一种方案。对于duckula3来说支持3种模式,它们各用应该场景:

  • net.wicp.tams.common.binlog.alone.checkpoint.CheckPointMemory(内存模式):

    它会把所有的元数据存储在内存中,当监听重启或断电后,元数据全部消失,不能做HA,但它有速度快,依赖少(不依赖其它东西来存储)等特点。如果要做HA,那么只能以嵌入式的方式使用duckula3,这时候它就可以使用宿主程序来做HA,比如:flink,它有自己完备的checkpoint机制,那么duckula3提供的flink source则会在flink做checkpoint保存的时候让其代为保存duckula的相关元数据,当启动时,duckula3提供的flink source又会从flink保存的checkpoint中拿到先前保存的元数据,灌到内存中,完成了HA。

  • net.wicp.tams.common.binlog.alone.checkpoint.CheckPointH2db(H2db模式)

    它会在本机启一个h2db数据库,然后把元数据保存到这个h2db数据库中,当重启时,使用相同的h2db数据库文件再次启动这个数据库,这样HA就可以实现了,但它有一个问题,就是跨主机启动的时候,在另一台主机上并不能拿到上次运行的主机上的数据库文件,这样HA会失败,所以只它适合于单机版,duckula3默认就是使用这种模式,对于linux用户建议使用一个守护进程,当监听进程死了的时候在本机重新拉取一个新的进程来做HA。

  • net.wicp.tams.common.binlog.alone.checkpoint.CheckPointMysql(mysql模式)

    这是最完备的HA解决方案,它需要配置一个用于存储元数据的数据库(一般来说一个数据库实例配置一个),且监听帐号对这个数据库具有建表权限。duckula会把所有的元数据存储到这个指定的数据库中,并以groupid为分布式锁,对于同一个groupid只能启动一个监听程序,这样即使监听代码嵌入到应用程序中时,布署了3个应该程序做HA时,也只会启动一个监听程序。

  • net.wicp.tams.common.binlog.alone.checkpoint.CheckPointZookeeper(zookeeper模式)

    暂未测试,就是与duckula2类型,使用zookeeper存储元数据和完成分布式锁功能。

主界面:

  入口:系统配置->检查点服务管理

image-20201221155049712

支持通过主程序版本进行搜索,上面的小框是它的“新增/修改”界面。

字段说明

检查点名:用于标识这个检查点服务的,需要能一看就懂的检查点服务

检查点类型:就是上面介绍的几种

主机/端口/默认数据库/用户名/密码:如果是mysql数据库的话就需要配置,其它类型不需要配置

按钮说明:

  • 查询/新增/修改/删除 按钮为默认意义,不细说。

    布署环境配置

  执行器需要CPU、内存、存储等资源,那么就需要有布署环境,在duckula2中已支持k8s和主机布署,但都是在ops配置后就固定了,也就是说我不能一个执行器布署到k8s另一个执行器又布署到主机上,虽然这种场景有点过度设计的嫌疑,但不能不说存在这种情况,特别对于那种主机布署到k8s布署迁移验证期,k8s布署了测试环境验证,生产环境为了稳妥还没有迁移。大公司有较为复杂的环境主机方式与k8s方式并了,或是属地化部署时,有些客户要求纯主机部署,有些客户要求k8s部署等等。在duckula3中已做过设计,可以满足k8s布署和主机布署共存的情况。

主界面:

  入口:系统配置->布署管理
image-20201221121629016

支持“发布名”条件查询。下面是它的编辑界面:

image-20201221124332658

字段说明

  • 发布名:用于标识这个发布环境的,需要能一看就懂的环境名
  • 发布类型:这是一个枚举,k8s/docker/centos7,duckula3支持这3种模式的发布环境
  • 环境:这个发布环境会运行于公司的哪套环境,由于每个公司的环境名不一样,没法枚举,手填。
  • 备注:用于描述说明这个环境。
  • 镜像组:docker镜像的镜像组。默认是阿里云的镜像中心。可以修改为自己的镜像私库
  • 名称空间:这个布署环境的k8s 的namespace。
  • 版本:duckula3的发布版本
  • 主机/端口:host/docker需要SSH的主机/端口
  • duckula密码:duckula3的执行器禁止使用root帐号启动,在初始化主机时会创建一个名为duckula的帐号,他的密码就是这里填写的密码,后面的执行器的启停等维护动作都使用此帐号.
  • 是否初始化:这是一个只读的状态,host/docker类型时主机初始化后它变为“是”,”k8s”上传了config后它的状态也变为“是”

按钮说明:

  • 查询/新增/修改/删除 按钮为默认意义,不细说。

  • 初始化:当host/docker类型时,刚新增一个布署环境时会出现这个按钮,它需要用户输入root的密码,duckula不会保存此root密码,但需要它来做主机的初始化动作,如:创建duckula用户和组,把duckula加入docker组,从S3上下载duckula的执行器和插件安装到对应目录 下等。

image-20201221140653935

  • 版本升级:当host/docker类型时,duckula有新版本发布时,可以在“版本管理”模块新增好版本,然后通过此按钮来做duckula3的版本升级,它会把现在版本移到历史版本目录中,然后把要升级的版本从S3下载下来。

  • 上传k8s配置:对于k8s类型时,需要上传它的config文件才能使它初始化状态为是。

    image-20201221141925628

实例管理

  一个binlog监听需要配置一个数据库监听实例,为了复用和安全,如dba配置好实例(包括用户名、密码),监听配置人员就可以通过下拉列表进行选择就行了,不需要接触数据库的用户名、密码等敏感资源,基本此设计需要一个实例管理功能。

主界面

入口:系统配置->实例管理
image-20201221142051268

支持通过实例名进行搜索,上面的小框是它的“新增/修改”界面。

字段说明

实例名:实例标识,可以很清楚地辨识不同的实例

是否drds:此实例是否为drds,duckula对于drds会有些特别的处理(后面的任务配置界面)。默认为否。

主机/端口:数据库实例的ip地址或域名、端口

用户名/密码:用于监听binlog的数据库帐号/密码,注意需要开通相关权限。

备注:详细说明此数据库的用途

按钮说明:

  • 查询/新增/修改/删除 按钮为默认意义,不细说。

存储中间件管理

  何谓存储中间件,顾名思议,用于存储的中间件,默认就是一些关系型/非关系型数据库,在duckula3里,不单指数据库,也可以是消息中间件,如kafka,ons,AWS sqs等,也可以是一个http服务接口。在此泛指可以把解析后的binlog数据将要推送的目的地。在duckula3中,要推送到这些存储中间件,需要有自定义的插件来支持,现在duckula3中会内置这么几种存储中间件:

es:用于把mysql的数据同步到es

mysql:用于把监听的mysql数据库实时同步到另一个目的数据库。往往是两个项目的数据库实时复制,避免了接口的编写。

kafka:用于把监听的mysql数据库以消息的方式实时发布。需要的接口入监听相对应的topic就行了。可以一对多广播。

logger:用于监听代码的调试和数据库连通性测试。

http:用于消息驱动模式,监听的mysql数据库有数据变更时会实时调用相应的http服务。

  将来会支持cassandra等更多的数据库同步用的存储中间件和自定义插件方便来实现同步。

主界面

  入口:系统配置->存储中间件管理

image-20201221144428903

支持“中间件名”条件查询。下面是它的编辑界面:

image-20201221151802444

字段说明:

中间件名:用于标识这个中间件的,需要能一看就懂的中间件名

主机:中间件所在的主机,如有多个用逗号隔开(请在多个前面加一层负载)。

中间件类型:上面介绍的几种内置的存储中间件

中间件版本:内存的存储中间件支持的版本。

端口/端口2: 一般来说有一个端口,也就是说端口2为空。但有些特别的中间件如ES等会有两个端口。

用户名/密码:需要认证时可以填,不需要为空

主机hosts:有些中间件服务是注册为主机名的,那么就有必要在docker窗口或host主机中把hosts相关配置填入

其它配置项:一些中间件的特别配置,通过json形式填入,相关发送者插件就可以使用这些特别的配置。

按钮说明:

查询/新增/修改/删除 按钮为默认意义,不细说。

版本管理

  duckula也会有版本的升级,对于k8s类型的布署模式来说只需要要执行器的相关image版本修改一下就完成了,但对于host和docker来说需要下载对应版本的最新的执行器和对应的插件。现在duckula的新版本都会默认存储到AWS 的s3中。

主界面

  入口:系统配置->版本管理

image-20201221153024830

支持通过主程序版本进行搜索,上面的小框是它的“新增/修改”界面。

字段说明

主程序版本:就是各执行器主入口代码版本

数据版本:就是各插件代码版本,一般来说它会与“主程序版本”一样,不排除后期它们不一致,但它一定要与执行器主程序相匹配

存储路径:主程序存储的路径,现只支持s3。

数据路径:插件代码存储的路径,现只支持s3

作者:开发并上传此代码的人

更新时间:此版本发布时间

readme:此版本解决了哪些问题

按钮说明:

  • 查询/新增/修改/删除 按钮为默认意义,不细说。

    (九)规则配置

    duckula实现了自己的一套监听规则,这是duckula的精华所以 由于配置的灵活性导致规则稍显复杂,那么就不太方便通过界面来实现,只能通过手动输入规则的方式来配置监听规则,这就要求配置人员对于规则能熟悉。在“监听管理”、“kafka消费任务”、“全量任务”都会有规则的配置功能,但他们又会跟据各自功能特点和“目的中间件”配置而做出不同的检查与提示。 配置界面如下:

其中,”规则编辑”一栏就是可视化的规则编辑.
eg: demouser{‘key’:’aaa:%s’}
它分三部分,用”`”进行分隔, 一:库名 二:表名 三:相关配置,符合json格式,但注意用单引号.其中key暂支持:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
public enum RuleItem {
topic("消息主题"),

key("redis的keys,es需要主键的colName"), //

relakey("es中关联表的key"), // "table1:key|table2:key",如果只有一张表直接输入key名就OK

appid("cachecloud的使用类型和appid,中间用|分隔,默认为standalone"), // 格式“standalone|10000”或 “sentinel|10000”

redisurl("redis的url"), // ,格式“standalone|127.0.0.1:6279”或
// “sentinel|mastername|127.0.0.1:6279,127.0.0.1:6278,127.0.0.1:6277”
// “null”或者不配置就使用middleware的配置结果

splitkey("分库分表键"),

index("es的index"),

type("es的type"),

esSetting("es的配置"), // 配置es是主表还是从表,如: test:user_info:main|test:user_addr:user_id:true
// 表示user_info是主表,而user_addr是从表,且user_id是关联字段

primarysLogic("逻辑外键"), // 20200610 一般es的从表的外键是主表的主键,特殊情况下,外键是其中一个非主键,在此配置,如
// tax_code与tax_goods,那么tax_good的docId要用它定义的字段不能用主键
//// 逻辑主键,某些情况下会用它来做为es的docId,如果它定义了就不会使用primarys,如:从表的外键并不是主表的主键的情况

copynum("复制份数"), // es自动创建index用

partitions("分区数"), // es自动创建index用

middleware("存储中间件配置"), // es消费时需要指定中间件的配置

dbinstanceid("consumer的jdbc发送者需要"),

dbtb("consumer的jdbc发送者需要,中间用.分隔"),

ks("cassandra用的名称空间"), // 20200122 cassandra等使用的名称空间

table("consumer的jdbc发送者需要,中间用.分隔"), // 20200122 cassandra等数据库使用的表名

colName("附加的列名"), // 在冪等模式下有用

addProp("附加的属性"), // 附加的固定属性

httpRela("httpUrl相对地址"), // http插件

// dump专用
wheresql("查询的语句"),

startId("开始同步的id"),

numDump("要导出的记录数"),

needCols("插件需要的配置"),

other("未知参数");

单库单表

demouser
只关注: demo库的user表

单库多表

demo`user_
会关注: demo库,表名为user_开头后面带任意个数字。
如:user_00,user_01,user_001,user_0002 …等系列表

多库多表

demo_`user_
会关注: 库名为demo_开始后面带任意个数字,表名为user_开始后面带任意个数字。
如:db: demo_00,demo_01,demo02……
tb: user_0000,user_0001,user_0002…..

整个库

demo_*
会关注:库名以demo_开头,任意多数字结尾。表无限制,只要满足库名就好了。
如:db: demo_00

一套库多套表做为一组

demo_(user|order|info)_
会关注:库名以demo_开头,任意多数字结尾,表名以user_或order_或info_开始、任意多数字结尾
如: db: demo_00,demo_01
tb: user_00,user_01,order_00,info_00

多库多表多组

demo_user_{‘topic’:’t1’}&policy_secu_{‘topic’:’t2’}
组以&进行分隔.它会分隔为2组
demo_user_{‘topic’:’t1’} 符合这组规则会发送到t1这个topic
如: db: demo_00……
tb: user_00……
policy_secu_{‘topic’:’t2’} 符合这组规则会发送到t2这个topic
如: db: policy_00……
tb: secu_00…..

过滤器配置

过滤器是用来过滤binlog消息, 使得业务能更精准地得找到想要的数据。它的入器在“修改”->“过滤器”按钮(规则编辑)

image-20211221214345623

现在只支持“行”、“列”过滤,还有就是按“操作类型”进行过滤。

本文作者 : andy.zhou
原文链接 : https://rjzjh.gitee.io/2021/02/14/duckula3/duckula3/
版权声明 : 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明出处!

知识 & 情怀 | 二者兼得

微信扫一扫, 向我投食

微信扫一扫, 向我投食

支付宝扫一扫, 向我投食

支付宝扫一扫, 向我投食

留下足迹