基于docker的canal-server部署作业_chenzuancong9642的博客-程序员宅基地

技术标签: 运维  大数据  

基于docker的canal-server部署作业

1. 目标

启动一个canal-server实例监听目标mysql的操作

2. 准备工作

  • Ubuntu下安装Docker,并配置国内镜像
  • 部署一个mysql实例
    $ docker run -p 3306:3306 --name mysql-master -e MYSQL_ROOT_PASSWORD=123456 -d mysql
    
  • 配置mysql (参见canal Quickstart)
    • 启用binlog
    [mysqld]
    log-bin=mysql-bin
    binlog-format=ROW #选择row模式
    server_id=9527 #配置mysql replaction需要定义,不能和canal的slaveId重复
    
    • 添加slave权限
    CREATE USER canal IDENTIFIED BY 'canal';  
    GRANT SELECT, SHOW VIEW, REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'canal'@'%';
    FLUSH PRIVILEGES;
    
    canal Quickstart文档中,并没有要求添加SHOW VIEW权限,但是本作业在执行中会产生如下异常:
    Caused by: java.io.IOException: ErrorPacket [errorNumber=1142, fieldCount=-1, message=SHOW VIEW command denied to user 'canal'@'172.17.0.1' for table 'host_summary', sqlState=42000, sqlStateMarker=#]
    with command: show create table `sys`.`host_summary`; ...
    
    因为canal-server在启动时,会去dump表结构并缓存。
    /*com.alibaba.otter.canal.parse.inbound.mysql.tsdb.DatabaseTableMeta*/
    
    /**
     * 初始化的时候dump一下表结构
     */
    private boolean dumpTableMeta(MysqlConnection connection, final CanalEventFilter filter) {
        try {
            ResultSetPacket packet = connection.query("show databases");
            List<String> schemas = new ArrayList<String>();
            for (String schema : packet.getFieldValues()) {
                schemas.add(schema);
            }
    
            for (String schema : schemas) {
                packet = connection.query("show tables from `" + schema + "`");
                List<String> tables = new ArrayList<String>();
                for (String table : packet.getFieldValues()) {
                    String fullName = schema + "." + table;
                    if (blackFilter == null || !blackFilter.filter(fullName)) {
                        if (filter == null || filter.filter(fullName)) {
                            tables.add(table);
                        }
                    }
                }
    
                if (tables.isEmpty()) {
                    continue;
                }
    
                StringBuilder sql = new StringBuilder();
                for (String table : tables) {
                    sql.append("show create table `" + schema + "`.`" + table + "`;");
                }
    
                List<ResultSetPacket> packets = connection.queryMulti(sql.toString());
                for (ResultSetPacket onePacket : packets) {
                    if (onePacket.getFieldValues().size() > 1) {
                        String oneTableCreateSql = onePacket.getFieldValues().get(1);
                        memoryTableMeta.apply(INIT_POSITION, schema, oneTableCreateSql, null);
                    }
                }
            }
    
            return true;
        } catch (IOException e) {
            throw new CanalParseException(e);
        }
    }
    
    所以首次启动成功后,再将 SHOW VIEW 权限回收并不会影响正常作业(表结果不变的情况下)。这也为我在作业中重现异常带来了一点小麻烦。为了快速跑通QuickStart,遇到问题后我第一时间给canal账号赋予了所有权限:
    GRANT ALL PRIVILEGES ON *.* TO 'canal'@'%' ;
    FLUSH PRIVILEGES;
    
    然后重启canal-server,作业正常。然后回收权限,但异常并不能重现,但canal-server工作正常。
    REVOKE ALL PRIVILEGES ON *.* FROM 'canal'@'%' ;
    GRANT SELECT, REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'canal'@'%';
    FLUSH PRIVILEGES;
    

3. 部署canal-server

官网文档 Canal Docker QuickStart。 文档中使用canal提供的run.sh启动,脚本的工作就是为执行docker run准备参数,在本作业的目标是启动一个canal-server实例,大多参数都使用canal默认配置就可以,所以为了简单,直接使用docker命令进行启动。配置相应的master地址和用户名密码,映射必要的监听端口就足够了。详细配置可参考Canal AdminGuide

docker run --name canal-server \
-e canal.instance.master.address=192.168.83.128:3306 \
-e canal.instance.dbUsername=canal \
-e canal.instance.dbPassword=canal \
-p 11111:11111 \
-d canal/canal-server:v1.1.0

canal-server:v1.1.0有一个小bug,如果canal.properties中没有配置canal.instance.parser.parallelThreadSize(默认情况,该配置项是被注释掉的):

#canal.instance.parser.parallelThreadSize = 16

那么,MysqlMultiStageCoprocessor的parserThreadCount会被设为0,从而在启动线程池的时候会抛IllegalArgumentException异常。

/*com.alibaba.otter.canal.parse.inbound.AbstractEventParser*/
protected Integer parallelThreadSize = Runtime.getRuntime().availableProcessors() * 60 / 100;     //60%的能力跑解析,剩余部分处理网络

public void setParallelThreadSize(Integer parallelThreadSize) {
    if (parallelThreadSize != null) {
        this.parallelThreadSize = parallelThreadSize;
    }
}

protected MultiStageCoprocessor buildMultiStageCoprocessor() {
    MysqlMultiStageCoprocessor mysqlMultiStageCoprocessor = new MysqlMultiStageCoprocessor(parallelBufferSize,
        parallelThreadSize,
        (LogEventConvert) binlogParser,
        transactionBuffer,
        destination);
    mysqlMultiStageCoprocessor.setEventsPublishBlockingTime(eventsPublishBlockingTime);
    return mysqlMultiStageCoprocessor;
}

在canal的master分支上,该bug已经修复,保证线程池至少有一个线程:

Ensure at least 1 thread for thread pool.

/*com.alibaba.otter.canal.parse.inbound.mysql.MysqlMultiStageCoprocessor*/
int tc = parserThreadCount > 0 ? parserThreadCount : 1;
this.parserExecutor = Executors.newFixedThreadPool(tc,
    new NamedThreadFactory("MultiStageCoprocessor-Parser-" + destination));

本作业是在虚拟机上进行,就分配了一个cup,因此虽然canal日志中显示已经启动:

# cat /home/admin/canal-server/logs/canal/canal.log
2018-08-31 19:36:18.970 [main] INFO  com.alibaba.otter.canal.deployer.CanalLauncher - ## the canal server is running now ......

但实际上example实例并不能工作。

# cat /home/admin/canal-server/logs/example/example.log
2018-08-31 19:36:37.345 [destination = example , address = /192.168.83.128:3306 , EventParser] ERROR c.a.o.c.p.inbound.mysql.rds.RdsBinlogEventParserProxy - dump address /192.168.83.128:3306 has an error, retrying. caused by
java.lang.IllegalArgumentException: null
        at java.util.concurrent.ThreadPoolExecutor.<init>(ThreadPoolExecutor.java:1314) ~[na:1.8.0_181]
        at java.util.concurrent.ThreadPoolExecutor.<init>(ThreadPoolExecutor.java:1237) ~[na:1.8.0_181]
        at java.util.concurrent.Executors.newFixedThreadPool(Executors.java:151) ~[na:1.8.0_181]
        at com.alibaba.otter.canal.parse.inbound.mysql.MysqlMultiStageCoprocessor.start(MysqlMultiStageCoprocessor.java:84) ~[canal.parse-1.1.0.jar:na]
        at com.alibaba.otter.canal.parse.inbound.AbstractEventParser$3.run(AbstractEventParser.java:238) ~[canal.parse-1.1.0.jar:na]
        at java.lang.Thread.run(Thread.java:748) [na:1.8.0_181]

解决办法是更改虚拟机配置,设置成2个或以上cpu就能解决问题。通过对问题的分析,对于单cpu的物理机,无法通过修改cpu数量的情况,可以通过配置文件解决。

canal.instance.parser.parallelThreadSize = 1

4. 查看运行效果

对mysql进行update操作,就能看到日下日志:

# cat /home/admin/canal-server/logs/example/meta.log
2018-08-31 20:02:05.289 - clientId:1001 cursor:[mysql-bin.000007,3802,1535716924000,1002,] address[192.168.83.128/192.168.83.128:3306]

也可以运行ClientExample查看效果。

至此,作业完毕。

转载于:https://my.oschina.net/amhuman/blog/1941540

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/chenzuancong9642/article/details/101040754

智能推荐

邵老师的编程题:用户输入一个字符串,将其中的元音字母过滤掉之后,输出剩下的字符。_过滤字符串中的w和l,打印输出过滤后的字符串-程序员宅基地

例如,输入"Hello,World",输出打印显示 “Hll,Wrld"#include&lt;stdio.h&gt;int main(){ char str[128]; printf("请输入字符串:"); gets_s(str); char filter[] = "AEIOUaeiou"; printf("过滤后的字符串:"); for (int i ..._过滤字符串中的w和l,打印输出过滤后的字符串

使用 nodejs 写爬虫(一): 常用模块和 js 语法-程序员宅基地

常用模块常用模块有以下几个:fs-extrasuperagentcheeriolog4jssequelizechalkpuppeteerfs-extra使用 async/await 的前提是必须将接口封装成 promise, 看一个简单的例子:const sleep = (milliseconds) => { return new Promise((reso...

python request下载word_Python网络爬虫笔记(三):下载博客园随笔到Word文档-程序员宅基地

1 importurllib.request as ure2 importre3 importurllib.parse4 from delayed importWaitFor5 importlxml.html6 importos7 importdocx8 #下载网页并返回HTML(动态加载的部分下载不了)9 def download(url,user_agent='FireDrich',num=2...

快速学会 shell 编程-程序员宅基地

在过去几十年中所出现的UNIX和类UNIX操作系统家族已经成为如今最为流行、使用最广泛的操作系统之一,这都算不上什么秘密了。对于使用了多年UNIX的程序员而言,一切都顺理成章:UNIX系统为程序开发提供了既优雅又高效的环境。这正是Dennis Ritchie和Ken Thompson在20世纪60年代晚期在贝尔实验室开发UNIX时的初衷。在本书中,我们使用的术语UNIX泛指基于UNIX的操作系...

Ubuntu18.04安装完anaconda后终端前面多了(base)_ubuntu18.04里怎么出现(base)-程序员宅基地

在安装完anaconda后,系统终端前面多出了了(base),这是anaconda的base环境。打开 ~/.bashrc文件,可以发现是anaconda自动加入了命令到 .bashrc 文件中,在我们打开终端的时候就执行了conda active base命令。解决办法:在终端输入命令:$ conda deactivate但这个是一次性的,要永久的话在.bashrc文件添加conda ..._ubuntu18.04里怎么出现(base)

随便推点

为什么要4k对齐_raid5 实现条带为什么固定为4k-程序员宅基地

机械硬盘物理上分出一个个扇区,每个扇区512字节,因此文件系统也是按照一个扇区512字节来操作硬盘。固态硬盘没有扇区的概念,只有页的概念,一页常见大小是4KB。为了和以前的文件系统兼容(win8以后NTFS支持4K扇区,以前的只支持512扇区),固态硬盘的驱动还是按照一个扇区512字节编写,相当于用4KB的页模拟出512字节的扇区。文件系统的默认分配单元是簇,是文件系统管理的最小单位,一次_raid5 实现条带为什么固定为4k

让Linux修改IP、DNS等可以更简单-程序员宅基地

修改IP:可以用 netconfig,可惜每次都得输入完整的IP、掩码、网关和DNS。 不如直接 vi /etc/sysconfig/network-scripts/ifcfg-eth0 再 /etc/init.d/network restart 来得快。修改DNS:最快的就是 vi /etc/resolv.conf,都不用重启的。重启httpd:/etc/init.d/htt...

sqool导出oracle数据-程序员宅基地

set colsep '|' --设置|为列分隔符 set echo off --在用start命令执行一个sql脚本时,是否显示脚本中正在执行的SQL语句 set feedback off --是否显示当前sql语句查询或修改的行数 set newpage none --会在页和页之间没有任何间隔 set verify off -- ...

获取证书序列号 X509Certificate-程序员宅基地

转载于:https://www.cnblogs.com/webster1/p/5663807.html

利用x264lib编码h264流的源码-程序员宅基地

有问题或者想法,大家交流下哈,没有人评论,都没有继续下去的动力了。。。直接给出代码吧:x264enc.h:#pragma once#include "inttypes.h"extern "C" {#include "x264.h"};class x264enc {public: x264enc(void); virtual ~x264enc(void);publ

vue 2.x 的 v-bind 指令的 .prop 事件修饰符详解-程序员宅基地

vue 官方文档对 .prop 修饰符的解释是:使用例子:那么,具体的原理和用法是什么呢?这要从 html 的 DOM node 说起。在 html 标签里,我们可以定义各种 attribute。在浏览器解析 DOM 树渲染页面后,每个标签都会生成一个对应的 DOM 节点。节点是一个对象,所以会包含一些 properties...