canal在分布式系统中的应用

背景

近期在做一个用户行为采集的系统,可选方案基本就是埋点或基于DB监控,考虑到埋点需要各业务系统配合,对原有业务逻辑有一定侵入性,最终选用DB监控为主,埋点为辅(由于部分行为存储在mongo)的方案。canal是阿里开源的数据同步工具,相对比较成熟,而且公司已经有canal的应用,可以说踩过一些坑,当然也提前意识到了一些坑,比如canal强调自己支持HA架构,但只有一个节点处于working状态,而其他节点则处于standby状态,这在分布式应用中显然是不理想的,因为我部署了多个节点,但事实上只有一个节点在working,这样的结果就是一个节点累死累活,而其他节点却悠哉悠哉,对此初步的方案如下

这个方案的主要思想是单独部署client,client通过rpc或mq的方式把数据推送给应用,由于client只是透传,没有处理逻辑,所以系统压力并不大,而作为消费方的应用,由于经过rpc或mq分发的方式可以做到相对均衡的消费,可以说这种方案基本可以适用于大部分的分布式系统消费,当然,考虑到我们这种方案其实是通过rpc或mq方式实现的分布式系统的负载均衡,不可避免的拉长了整个消费的链路,也就使得消费延迟边长,对于新系统希望达到准实时相应来说,这种方案仍有不足,那么还有没有更为合适的方案呢,接下来将结合canal的官方文档(https://github.com/alibaba/canal)和源码,进一步分析。

canal-server架构

一个server可以包含1到n个instance,没个instance又是由eventParser 、eventSink 、eventStore 、metaManager 组成

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

server/client交互协议


参照官方提供的example

```java

protected void process() {
        int batchSize = 5 * 1024;
        while (running) {
            try {
                MDC.put("destination", destination);
                connector.connect();// 1.connect
                connector.subscribe();// 2.subscribe
                while (running) {
                    Message message = connector.getWithoutAck(batchSize); // 3.getWithoutAck
                    long batchId = message.getId();
                    int size = message.getEntries().size();
                    if (batchId == -1 || size == 0) {
                        // try {
                        // Thread.sleep(1000);
                        // } catch (InterruptedException e) {
                        // }
                    } else {
                        printSummary(message, batchId, size);
                        printEntry(message.getEntries());
                    }


                    connector.ack(batchId); // 4.ack
                    // connector.rollback(batchId); // 4.rollback
                }
            } catch (Exception e) {
                logger.error("process error!", e);
            } finally {
                connector.disconnect();// 6.disconnect
                MDC.remove("destination");
            }
        }
    }

```

再看建立连接的过程

```java

CanalConnector connector = CanalConnectors.newClusterConnector("127.0.0.1:2181", destination, "", "");

```

也就是每个connector都是基于destination的,而一个destination事实上对于一个instance,也就是说无论是canal-server还是client,可拆分的最小粒度都是instance,再来看canal的HA机制实现

```

canal的ha分为两部分,canal server和canal client分别有对应的ha实现

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

```

也就是canal作为一个数据同步工具,有着自身的限制,而我认为这种限制也是有必要的,同时也可以看出官方也说明了,canal的HA机制是在instance这个粒度上的,而不是client或server,这就给了我们操作的空间,而分布式系统的核心就是怎么协调资源的分配,那么现在需要考虑的就是如何分配instance。相对于server,client是内嵌的(虽然canal也提供内嵌的server),所以client的可操作空间更大,我们只需要基于client实现instance的分布式算法,就可以使得分布式部署的应用各接口均匀分布这working的instance,最终方案如下


通过一段时间的试运行,方案基本得到了验证,在采集分析3天,每天高峰时间段1W条数据初步分析,DB变动到应用采集平均耗时在100ms左右,达到预期。





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值