MySQL Binlog 同步工具go-mysql-transfer Lua模块使用说明

一、go-mysql-transfer

go-mysql-transfer是一款MySQL实时、增量数据同步工具。能够实时解析MySQL二进制日志binlog,并生成指定格式的消息,同步到接收端。

go-mysql-transfer具有如下特点:

1、不依赖其它组件,一键部署

2、集成多种接收端,如:Redis、MongoDB、Elasticsearch、RabbitMQ、Kafka、RocketMQ,不需要再编写客户端,开箱即用

3、内置丰富的数据解析、消息生成规则;支持Lua脚本,以处理更复杂的数据逻辑

4、支持监控告警,集成Prometheus客户端

5、高可用集群部署

6、数据同步失败重试

7、全量数据初始化

详情及安装说明 请参见: MySQL Binlog 增量同步工具go-mysql-transfer实现详解

项目开源地址:

gitee (速度更快) :go-mysql-transfer
github:go-mysql-transfer

如果此工具对你有帮助,请Star支持下

二、Lua脚本引擎

go-mysql-transfer中使用gopher-lua作为Lua虚拟机,支持Lua5.1规范。Lua作为专业的内置脚本语言,其设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。开发者只需要花费少量时间就能大致掌握其用法。

基于Lua的高扩展性,可以实现更为复杂的数据解析、消息生成、数据处理逻辑。

三、json模块

提供json数据格式的序列化和反序列化功能,提供encode和decode两个方法。
使用示例如下:

local json = require("json")   -- 加载json模块
local ops = require("mqOps") --加载mq操作模块

local row = ops.rawRow()  --当前数据库的一行数据,table类型,key为列名称
local action = ops.rawAction()  --当前数据库事件,包括:insert、updare、delete

local id = row["ID"] --获取ID列的值
local userName = row["USER_NAME"] --获取USER_NAME列的值
local password = row["PASSWORD"] --获取USER_NAME列的值
local createTime = row["CREATE_TIME"] --获取CREATE_TIME列的值

local result = {}  -- 定义一个table,作为结果
result["id"] = id
result["action"] = action

if action == "delete" -- 删除事件
then
    local val = json.encode(result) -- 将result转为json
    ops.SEND("transfer_test_topic",val) -- 发送消息,第一个参数为topic(string类型),第二个参数为消息内容
else 
    result["userName"] = userName
    result["password"] = password
    result["createTime"] = createTime
    result["source"] = "binlog" -- 数据来源
    local val = json.encode(result) -- 将result转为json
    ops.SEND("transfer_test_topic",val) -- 发送消息,第一个参数为topic(string类型),第二个参数为消息内容
    -- local obj = json.decode(val ) -- json反序列化
    -- print(obj ["createTime"])

四、db(数据库操作)模块

比如我们有角色表(t_role):

ID CODE NAME REMARK
1 r1 管理员 具有所有操作权限
2 r2 测试员 具有测试功能的操作权限

用户表(t_user):

ID USER_NAME PASSWORD ROLE_CODE CREATE_TIME
1 admin 123456 r1 2020-10-20 22:00:10

我们需要监听t_user表,并向接收端发送如下格式的消息:

{
       
    "id": "1",
    "userName": "admin"
    "password": "123456",
    "createTime": 100001,
    "roleName": "系统管理员",
    "roleRemark": "管理后台相关信息",
    "source": "binlog",
    
}

基于Binlog的数据同步工具,只能监听到一行数据的变更,进行响应。无法像基于SQL的ETL工具那样具有多表连接的能力。如果要得到向上面那样的聚合数据,需要使用dbOps模块,用法如下:

local json = require("json")   -- 加载json模块
local ops = require("mqOps") --加载mq操作模块
local db = require("dbOps") --加载数据库(db)操作模块

local row = ops.rawRow()  --当前数据库的一行数据,table类型,key为列名称
-- print(json.encode(row))
local action = ops.rawAction()  --当前数据库事件,包括:insert、updare、delete

local id = row["ID"] --获取ID列的值
local userName = row["USER_NAME"] --获取USER_NAME列的值
local password = row["PASSWORD"] --获取USER_NAME列的值
local roleCode = row["ROLE_CODE"] --角色编码
local createTime = row["CREATE_TIME"] --获取CREATE_TIME列的值

local result = {}  -- 定义一个table,作为结果
result["id"] = id
result["action"] = action

if action == "delete" -- 删除事件
then
    local val = json.encode(result) -- 将result转为json
    ops.SEND("user_topic",val) -- 发送消息,第一个参数为topic(string类型),第二个参数为消息内容
else 
    
    local sql = string.format("SELECT * FROM ESEAP.T_ROLE WHERE CODE = '%s'",roleCode) -- SQL语句,不能直接使用表名,要使用(数据库名称.表名称),如:ESEAP.T_ROLE
    local roleRS = db.selectOne(sql) -- 执行SQL查询,返回一条查询结果,table类型,结构如:{"CODE":"a1","ID":"1","NAME":"系统管理员","REMARK":"管理后台相关信息"}
    -- print(json.encode(roleRS))
    local roleName = roleRS["NAME"] --角色名称
    local roleRemark = roleRS["REMARK"] --角色描述
    
    -- local roleListRS = db.select(sql) -- 执行SQL查询,返回多条条查询结果,数组类型,元素为table,结构如:[{"CODE":"a1","ID":"1","NAME":"系统管理员","REMARK":"管理后台相关信息"}]
    -- print(json.encode(roleListRS))
    
    result["userName"] = userName
    result["password"] = password
    result["createTime"] = createTime
    result["source"] = "binlog" -- 数据来源
    result["roleName"] = roleName
    result["roleRemark"] = roleRemark
    local val = json.encode(result) -- 将result转为json
    ops.SEND("user_topic",val) -- 发送消息,第一个参数为topic(string类型),第二个参数为消息内容
end 

dbOps模块的方法说明:
1、selectOne(sql) 查询一条数据,返回table类型的结果;如果查询不到数据,返回空table;如果查询到多个结果,会出错
2、select(sql) 查询多条数据,返回数组类型的结果,数组元素为tablem(格式如:[table1,table2]);查询不到结果,返回空table;

四、http客户端模块

让go-mysql-transfer具体发送任意http请求的能力,httpOps提供的方法说明:

1、get(url,headers) 发送get请求;url为请求地址;headers为请求头参数,table类型
2、delete(url,headers) 发送delete请求;url为请求地址;headers为请求头参数,table类型
3、post(url,headers,formItems) 发送post请求;url为请求地址;headers为请求头参数,table类型;formItems为表单数据,table类型
4、put(url,headers,formItems) 发送put请求;url为请求地址;headers为请求头参数,table类型;formItems为表单数据,table类型

上面4个方法的返回值为一个table类型的结果,元素"status_code"为http响应状态,Number类型(如:200、401、403、500等);元素body为http响应内容,string类型

httpOps模块具体用法如下:

local json = require("json")   -- 加载json模块
local ops = require("redisOps") --加载redis操作模块
local httpcli = require("httpOps") --加载http操作模块

local row = ops.rawRow()  --数据库当前变更的一行数据,table类型,key为列名称
local action = ops.rawAction()  --当前数据库事件,包括:insert、updare、delete

local _id = row["ID"] --获取ID列的值
local _userName = row["USER_NAME"] --获取USER_NAME列的值
local _password = row["PASSWORD"] --获取USER_NAME列的值
local _createTime = row["CREATE_TIME"] --获取CREATE_TIME列的值
local key = "user_".._id -- 定义key

if action == "insert" -- 插入事件
then
    -- get
     local url = string.format("http://localhost:9999/http_tests?user_name=%s", userName) 
     local res = httpcli.get(url,{
        Authorization="Basic OSdjJGRpbjpvcGVuIANlc2SdDE=="
     }) -- http get请求,第一个参数为URL,类型为string;第二个参数为header参数,类型为table
     local status = res.status_code
    --print(res.status_code)  -- http响应代码,如:200、401、403、500等
    --print(res.body)-- http响应内容,string类型
    --local resObj = json.decode(res.body) -- json反序列化响应内容
    --print(resObj["msg"])
    
    
    -- delete
    --local url = string.format("http://localhost:9999/http_tests?user_name=%s", userName) 
    --local res = httpcli.delete(url,{
    --  Authorization="Basic OSdjJGRpbjpvcGVuIANlc2SdDE=="
    --}) -- http delete请求,第一个参数为URL,类型为string;第二个参数为header参数,类型为table
    
    -- post
    --local url = "http://localhost:9999/http_tests"
    --local res = httpcli.post(url,{
    --  Authorization="Basic OSdjJGRpbjpvcGVuIANlc2SdDE=="
    --},{
    --  id=_id,
    --  userName=_userName,
    --  password=_password,
    --  createTime=_createTime
    --}) -- http post请求,第一个参数为URL,类型为string;第二个参数为header参数,类型为table;第三个参数为post内容,类型为table
    
    --put
    --local url = "http://localhost:9999/http_tests"
    --local res = httpcli.put(url,{
    --  Authorization="Basic OSdjJGRpbjpvcGVuIANlc2SdDE=="
    --},{
    --  id=_id,
    --  userName=_userName,
    --  password=_password,
    --  createTime=_createTime
    --}) -- http put请求,第一个参数为URL,类型为string;第二个参数为header参数,类型为table;第三个参数为post内容,类型为table
    
    if status == 200
    then 
        ops.SADD("user_set",userName.."|succeed") -- 对应Redis的SADD命令,第一个参数为key(支持string类型),第二个参数为value
    else
        ops.SADD("user_set",userName.."|failed") -- 对应Redis的SADD命令,第一个参数为key(支持string类型),第二个参数为value
    end
    
    
end 
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270