zoukankan      html  css  js  c++  java
  • Canal学习笔记

    canal的工作原理:

    原理相对比较简单:

    canal模拟mysql slave的交互协议,伪装自己为mysql slave,向mysql master发送dump协议
    mysql master收到dump请求,开始推送binary log给slave(也就是canal)
    canal解析binary log对象(原始为byte流)

    架构

    说明:

    server代表一个canal运行实例,对应于一个jvm
    instance对应于一个数据队列 (1个server对应1..n个instance)
    instance代表了一个实际运行的数据队列,包括了EventPaser,EventSink,EventStore等组件。

    instance模块:

    eventParser (数据源接入,模拟slave协议和master进行交互,协议解析)
    eventSink (Parser和Store链接器,进行数据过滤,加工,分发的工作)
    eventStore (数据存储)
    metaManager (增量订阅&消费信息管理器)

    简单点说:

    mysql的binlog是多文件存储,定位一个LogEvent需要通过binlog filename + binlog position,进行定位
    mysql的binlog数据格式,按照生成的方式,主要分为:statement-based、row-based、mixed。
    mysql> show variables like 'binlog_format';
    +---------------+-------+
    | Variable_name | Value |
    +---------------+-------+
    | binlog_format | ROW |
    +---------------+-------+
    1 row in set (0.00 sec)
    目前canal支持所有模式的增量订阅(但配合同步时,因为statement只有sql,没有数据,无法获取原始的变更日志,所以一般建议为ROW模式)

    EventParser设计
    大致过程:
    整个parser过程大致可分为几步:

    Connection获取上一次解析成功的位置 (如果第一次启动,则获取初始指定的位置或者是当前数据库的binlog位点)
    Connection建立链接,发送BINLOG_DUMP指令
    // 0. write command number
    // 1. write 4 bytes bin-log position to start at
    // 2. write 2 bytes bin-log flags
    // 3. write 4 bytes server id of the slave
    // 4. write bin-log file name
    Mysql开始推送Binaly Log
    接收到的Binaly Log的通过Binlog parser进行协议解析,补充一些特定信息
    // 补充字段名字,字段类型,主键信息,unsigned类型处理
    传递给EventSink模块进行数据存储,是一个阻塞操作,直到存储成功
    存储成功后,定时记录Binaly Log位置

    EventSink设计
    说明:
    数据过滤:支持通配符的过滤模式,表名,字段内容等
    数据路由/分发:解决1:n (1个parser对应多个store的模式)
    数据归并:解决n:1 (多个parser对应1个store)
    数据加工:在进入store之前进行额外的处理,比如join

    EventStore设计
    1. 目前仅实现了Memory内存模式,后续计划增加本地file存储,mixed混合模式
    2. 借鉴了Disruptor的RingBuffer的实现思路

    HA(High Available)机制设计
    canal的ha分为两部分,canal server和canal client分别有对应的ha实现

    canal server: 为了减少对mysql dump的请求,不同server上的instance要求同一时间只能有一个处于running,其他的处于standby状态.
    canal client: 为了保证有序性,一份instance同一时间只能由一个canal client进行get/ack/rollback操作,否则客户端接收无法保证有序。

    整个HA机制的控制主要是依赖了zookeeper的几个特性,watcher和EPHEMERAL节点(和session生命周期绑定)。

    Canal Server:

    大致步骤:
    (1)canal server要启动某个canal instance时都先向zookeeper进行一次尝试启动判断 (实现:创建EPHEMERAL节点,谁创建成功就允许谁启动,类似一个分布式锁)
    (2)创建zookeeper节点成功后,对应的canal server就启动对应的canal instance,没有创建成功的canal instance就会处于standby状态
    (3)一旦zookeeper发现canal server A创建的节点消失后,立即通知其他的canal server再次进行步骤1的操作,重新选出一个canal server启动instance.

    Canal Client:
    canal client每次进行connect时,会首先向zookeeper询问当前是谁启动了canal instance,然后和其建立链接,一旦链接不可用,会重新尝试connect.
    Canal Client的方式和canal server方式类似,也是利用zookeeper的抢占EPHEMERAL节点的方式进行控制.


    ephemeral 短暂的; 瞬息的

    https://github.com/alibaba/canal/wiki/%E7%AE%80%E4%BB%8B#canal%E7%9A%84%E5%B7%A5%E4%BD%9C%E5%8E%9F%E7%90%86

    binlog被删除的问题
    aliyun RDS有自己的binlog日志清理策略,这个策略相比于用户自建mysql会更加激进,默认应该是18小时就会清理binlog并上传到oss上,可以在页面上进行调整,或者业务可以通过oss下载更早的binlog

    canal中配置ak,sk的地方:

    # aliyun ak/sk , support rds/mq
    canal.aliyun.accessKey =
    canal.aliyun.secretKey =

    注意点:
    相比于普通的mysql配置,多了rds oss binlog所需要的aliyun ak/sk/实例id等相关信息(如果不需要在本地binlog超过18小时被清理后自动下载oss上的binlog,可以忽略该值)


    canal.instance.rds.accesskey aliyun账号的ak信息 (如果不需要在本地binlog超过18小时被清理后自动下载oss上的binlog,可以忽略该值)
    canal.instance.rds.secretkey aliyun账号的sk信息(如果不需要在本地binlog超过18小时被清理后自动下载oss上的binlog,可以忽略该值)
    canal.instance.rds.instanceId aliyun rds对应的实例id信息(如果不需要在本地binlog超过18小时被清理后自动下载oss上的binlog,可以忽略该值)

    https://github.com/alibaba/canal/wiki/aliyun-RDS-QuickStart

    otter中配置ak,sk的地方:

    公有云API的认证方式:AK/SK 简介

    1 公有云API的认证方式
    一般有一夏几种认证方式:
        Token认证
        AK/SK认证
        RSA非对称加密方式
        下面主要介绍AK/SK

    1 AK/SK
    1.1 AK/SK 原理

    云主机需要通过使用Access Key Id / Secret Access Key加密的方法来验证某个请求的发送者身份。
    Access Key Id(AK)用于标示用户,Secret Access Key(SK)是用户用于加密认证字符串和云厂商用来验证认证字符串的密钥,其中SK必须保密。 AK/SK原理使用对称加解密
    1.2 AK/SK使用机制

    云主机接收到用户的请求后,系统将使用AK对应的相同的SK和同样的认证机制生成认证字符串,并与用户请求中包含的认证字符串进行比对。如果认证字符串相同,系统认为用户拥有指定的操作权限,并执行相关操作;如果认证字符串不同,系统将忽略该操作并返回错误码。
    1.3 流程
        判断用户请求中是否包含Authorization认证字符串。如果包含认证字符串,则执行下一步操作。
        基于HTTP请求信息,使用相同的算法,生成Signature字符串。
        使用服务器生成的Signature字符串与用户提供的字符串进行比对,如果内容不一致,则认为认证失败,拒绝该请求;如果内容一致,则表示认证成功,系统将按照用户的请求内容进行操作。

    原理:
      客户端:
        1. 构建http请求(包含 access key);
        2. 使用请求内容和 使用secret access key计算的签名(signature);
        3. 发送请求到服务端。
    服务端:
        1. 根据发送的access key 查找数据库得到对应的secret-key;
        2. 使用同样的算法将请求内容和 secret-key一起计算签名(signature),与客户端步骤2相同;
        3. 对比用户发送的签名和服务端计算的签名,两者相同则认证通过,否则失败。
    Token
    Token认证
    使用Token认证方式完成认证鉴权时,用户首先需要获取token,在调用接口时增加“X-XXX-Token”到业务接口请求消息头中。
    流程
        发送请求,获取IAM的Endpoint及消息体中的区域名称。
        获取Token。请求响应成功后在响应消息头中包含的“X-YYY-Token”的值即为Token值。
        调用业务接口,在请求消息头中增加“X-XXX-Token”,取值为2中获取的Token。

    https://blog.csdn.net/makenothing/java/article/details/81158481

    2020-05-29 17:06:25.217 ERROR [bootstrap,,,] 12 --- [37.225.101:2181] - [] org.I0Itec.zkclient.ZkEventThread        : Error handling event ZkEvent[Data of /otter/canal/destinations/zaf-security-admin/1001/running changed sent to com.alibaba.otter.canal.client.impl.running.ClientRunningMonitor$1@731b42f4]
    com.alibaba.otter.canal.protocol.exception.CanalClientException: something goes wrong in initRunning method. 
        at com.alibaba.otter.canal.client.impl.running.ClientRunningMonitor.initRunning(ClientRunningMonitor.java:156) ~[canal.client-1.1.3.jar!/:na]
        at com.alibaba.otter.canal.client.impl.running.ClientRunningMonitor$1.handleDataDeleted(ClientRunningMonitor.java:72) ~[canal.client-1.1.3.jar!/:na]
        at org.I0Itec.zkclient.ZkClient$9.run(ZkClient.java:825) ~[zkclient-0.10.jar!/:na]
        at org.I0Itec.zkclient.ZkEventThread.run(ZkEventThread.java:72) ~[zkclient-0.10.jar!/:na]
    Caused by: com.alibaba.otter.canal.protocol.exception.CanalClientException: java.io.IOException: end of stream when reading header
        at com.alibaba.otter.canal.client.impl.SimpleCanalConnector.doConnect(SimpleCanalConnector.java:189) ~[canal.client-1.1.3.jar!/:na]
        at com.alibaba.otter.canal.client.impl.SimpleCanalConnector.access$000(SimpleCanalConnector.java:50) ~[canal.client-1.1.3.jar!/:na]
        at com.alibaba.otter.canal.client.impl.SimpleCanalConnector$1.processActiveEnter(SimpleCanalConnector.java:422) ~[canal.client-1.1.3.jar!/:na]
        at com.alibaba.otter.canal.client.impl.running.ClientRunningMonitor.processActiveEnter(ClientRunningMonitor.java:221) ~[canal.client-1.1.3.jar!/:na]
        at com.alibaba.otter.canal.client.impl.running.ClientRunningMonitor.initRunning(ClientRunningMonitor.java:123) ~[canal.client-1.1.3.jar!/:na]
        ... 3 common frames omitted
    Caused by: java.io.IOException: end of stream when reading header
        at com.alibaba.otter.canal.client.impl.SimpleCanalConnector.read(SimpleCanalConnector.java:404) ~[canal.client-1.1.3.jar!/:na]
        at com.alibaba.otter.canal.client.impl.SimpleCanalConnector.readNextPacket(SimpleCanalConnector.java:392) ~[canal.client-1.1.3.jar!/:na]
        at com.alibaba.otter.canal.client.impl.SimpleCanalConnector.readNextPacket(SimpleCanalConnector.java:376) ~[canal.client-1.1.3.jar!/:na]
        at com.alibaba.otter.canal.client.impl.SimpleCanalConnector.doConnect(SimpleCanalConnector.java:151) ~[canal.client-1.1.3.jar!/:na]
        ... 7 common frames omitted

    问题一:

    ERROR c.a.otter.canal.parse.inbound.mysql.MysqlEventParser - dump address /192.168.1.50:3306 has an error, retrying. caused by

    com.alibaba.otter.canal.parse.exception.CanalParseException: can't find start position for example

    原因:meta.dat 中保存的位点信息和数据库的位点信息不一致;导致canal抓取不到数据库的动作;

    解决方案:删除meta.dat删除,再重启canal,问题解决;

    集群操作:进入canal对应的zookeeper集群下,删除节点/otter/canal/destinations/xxxxx/1001/cursor ;重启canal即可恢复;

    问题二:

    java.lang.OutOfMemoryError: Java heap space
     

    canal消费端挂了太久,在zk对应conf下节点的

    /otter/canal/destinations/test_db/1001/cursor 位点信息是很早以前,导致重启canal时,从很早以前的位点开始消费,导致canal服务器内存爆掉

    监听数据库变更,只有TransactionBegin/TransactionEnd,没有拿到数据的EventType;

    原因可能是canal.instance.filter.black.regex=.*\..*导致,改canal.instance.filter.black.regex=再重启试试;

    问题三:

    ERROR com.alibaba.otter.canal.common.alarm.LogAlarmHandler - destination:fdyb_db[com.alibaba.otter.canal.parse.exception.CanalParseException: com.alibaba.otter.canal.parse.exception.CanalParseException: parse row data failed.
    Caused by: com.alibaba.otter.canal.parse.exception.CanalParseException: parse row data failed.
    Caused by: com.alibaba.otter.canal.parse.exception.CanalParseException: com.google.common.collect.ComputationException: com.alibaba.otter.canal.parse.exception.CanalParseException: fetch failed by table meta:`mysql`.`pds_4490277`
    Caused by: com.google.common.collect.ComputationException: com.alibaba.otter.canal.parse.exception.CanalParseException: fetch failed by table meta:`mysql`.`pds_4490277`

    Caused by: com.alibaba.otter.canal.parse.exception.CanalParseException: fetch failed by table meta:`mysql`.`pds_4490277`
    Caused by: java.io.IOException: ErrorPacket [errorNumber=1142, fieldCount=-1, message=SELECT command denied to user 'cy_canal'@'11.217.0.224' for table 'pds_4490277', sqlState=42000, sqlStateMarker=#]
    with command: desc `mysql`.`pds_4490277`

    分析:mysql系统表权限较高,canal读该表的binlog失败,位点无法移动

    解决:将配置项中黑名单加上mysql下的所有表:canal.instance.filter.black.regex = mysql\..* ,修改后canal集群不需要重启即可恢复;

    其它注意点:检查下CanalConnector是否调用subscribe(filter)方法;有的话,filter需要和instance.properties的canal.instance.filter.regex一致,否则subscribe的filter会覆盖instance的配置,如果subscribe的filter是.*\..*,那么相当于你消费了所有的更新数据。

    问题四:

    现象:数据库修改后,canal应用感知不到binlog,数据无法正常消费处理;

    定位:1.查看canal服务器,canal应用,zk服务器的日志,确认无异常;2.查看mysql,es服务器,无异常,3.查看canal服务器,canal应用配置项,发现canal服务器的canal.properties有问题;

    原因:canal.properties中配置了canal.ip和canal.zkServers,如果是zk集群模式下的canal配置了canal.ip,则会优先按IP连接canal服务器,从而让zk功能失效,位点文件则会保存到本地;一旦本地位点文件出现问题,各方无错误日志,问题就很难排查;

    解决:将canal.ip配置项置为空,关掉canal服务器,canal应用,删除zk上的节点,重启canal服务器,canal应用,问题解决;
    https://blog.csdn.net/my201110lc/article/details/77885720

  • 相关阅读:
    caffe报错:cudnn.hpp:86] Check failed: status == CUDNN_STATUS_SUCCESS (3 vs. 0) CUDNN_STATUS_BAD_PARAM 原因
    linux C++生成uuid
    linux出现tmp空间满的情况解决
    darknet集成遇到的问题以及解决方法
    机器学习实战-决策树
    机器学习实战-KNN
    Linux学习(二)
    Linux学习(一)
    shell编程(二)
    shell编程(一)
  • 原文地址:https://www.cnblogs.com/softidea/p/12894008.html
Copyright © 2011-2022 走看看