商务网站建设考试,科技布是什么面料,网站名称格式,企业 网站 客户留言怎么做Logtail 是 CN#xff08;Computation Node#xff09;与 TN#xff08;Transaction Node#xff09;之间的一种日志同步协议#xff0c;是 CN 和 TN 协同工作的基础。本文将介绍 logtail 协议的基本定位#xff0c;协议内容和产生过程#xff0c;也会提及一些遇到的挑战…Logtail 是 CNComputation Node与 TNTransaction Node之间的一种日志同步协议是 CN 和 TN 协同工作的基础。本文将介绍 logtail 协议的基本定位协议内容和产生过程也会提及一些遇到的挑战和问题希望能从宏观层面介绍 logtail以及它在 MatrixOne 架构中的位置和作用。
早前的 TAE 分析文章TAE-MatrixOne云原生事务与分析引擎提到 TN 目前拥有三个职责
处理提交的事务为 CN 提供 Logtail 服务转存最新的事务数据至对象存储中并且推动日志窗口。
其中 1、3 完成时都会产生状态变化比如数据成功写入内存或者成功写入对象存储而 Logtail 是一种日志同步协议面向 CN 以低成本的方式同步 TN 的部分状态。CN 通过获取 Logtail在本地重建出必要的可读的数据。作为 MatrixOne 存算分离架构的关键协议Logtail 有以下特点
串联协同 CN 和 TN本质是一个日志复制状态机让 CN 同步 TN 部分状态。Logtail 支持以 pull 和 push 两种模式获取push 有更强的实时性不断地从 TN 同步增量日志到 CNpull 支持指定任意时间区间同步表的快照也可以按需同步后续产生的增量日志信息。Logtail 支持按照表级别进行订阅、收集在多 CN 支持方面更加灵活更好地实现 CN 负载的均衡。
Part 1 Logtail 协议内容
Logtail 协议的目前主体内容用简单的语言来说分为两个部分内存数据和元数据核心区别在于是否已经转存到对象存储中。
一次事务 commit 产生的更新在转存至对象存储前其日志在 logtail 中会以内存数据的形式呈现。任何数据上的修改都可以归结到插入和删除两种形式对于插入logtail 信息包含该数据行的 row-idcommit-timestamp 以及表定义中的列对于删除logtail 信息则包含 row-idcommit-timestamp 以及主键列。这样的内存数据传递到 CN 后会在内存中以 Btree 的形式组织对上层提供查询。
显然内存数据不能一直保留在内存中增加内存压力通过时间或者容量的限制内存数据会被 flush 到对象存储上形成一个 object。object 包含一个或者多个 block。block 是表数据的最小存储单位一个 block 包含的行数不超过固定上限目前默认是 8192 行。当 flush 完成时logtail 把 block 元数据传递给 CNCN 根据事务时间戳过滤出可见的 block list读取出 block 中的内容再综合内存数据得到某个时刻数据的完整视图。
上面仅仅是最基础的过程随着一些性能优化的引入会呈现更多的细节比如:
1. Checkpoint
当 TN 运行一段时间在某个时刻做 checkpoint这个时刻前的全部数据都已经转存到对象存储因此把这些元数据统一收集并精简得到一个压缩包当一个新启动的 CN 链接到 TN获取第一次 logtail如果订阅时间戳大于 checkpoint 的时间戳就可以把 checkpoint 的元数据(一个字符串)通过 logtail 传递直接在 CN 读取 checkpoint 时刻之前产生的 block 信息避免了在网络上从零传递 block 元数据增加 TN 的 IO 压力。
2. 清理内存
当 TN 产生的 block 元数据给到 CN 时会按照 block-id 去清理之前送达的内存数据。但是在 TN 侧 flush 事务进行过程中可能同时发生了数据的更新比如被 flush 的 block 上新产生了删除。如果此时的策略是回滚重试那么已经写好的数据就完全无效在更新密集的负载下会产生大量的回滚浪费 TN 资源。为了避免这种情况TN 会继续 commit导致这部分 flush 事务开始后产生的内存数据就不能从 CN 中删除于是在 logtail 的 block 元信息中会传递一个时间戳在这个时间戳之前属于这个 block 的内存数据才可以从内存中清理。这些未清除的更新会在下一次 flush 中的异步地刷盘并且推送的到 CN 进行删除。
3. 更快读取
已经转存到对象存储上的 block可能继续产生删除读取这些 block 时需要综合内存里的删除数据。为了更快地明确哪些 block 需要结合内存数据CN 额外维护一个 block 的 Btree 索引在应用 logtail 的时候就需要更小心地修改这个索引处理内存数据时增加索引条目处理 block 元数据时减少索引条目。只能在这个索引中的 block才有去检查内存数据在 block 数量比较多的情况下收益比较大。
4. More
关于 logtail 协议还有更多的改进空间
后续会向 Logtail 中添加更多的控制信息让 CN 中的过期数据得到更及时的清理控制内存使用。尽管经过 TN 后台 merge多个 block 可能在一个 object 中但是目前 CN 中仍然按照 block list 组织数据之后会让元数据在 object 层面传递减少 block list 的规模。
Part 2 Logtail 的产生
如前所述可以通过 pull 和 push 两种方式进行 logtail 获取。这两种模式的特点不同接下来分别介绍。
1. Pull
如前所述pull 实际上是同步表的快照以及后续产生的增量日志信息。
为了达成这个目的TN 维护了一个按照事务 prepare 时间排序的 txn handle 列表logtail table给定任意时刻通过二分查找得到范围内的 txn handle再由 txn handle 得到该事务在哪些 block 上做过更新通过遍历这些 block就能得到完整的日志。为了加快查找速度对 txn handle 做了分页一个页的 bornTs 就是当前页中的 txn handle 的最小 prepare 时间第一层二分的对象就是这些页。
基于 logtail table从接收到 pull 请求主要工作路径如下
根据已有的 checkpoints调整请求的时间范围更早的可以通过 checkpoint 给出。取 logtail table 的一份快照基于访问者模式用 RespBuilder 去迭代这份快照中相关的 txn handle收集已提交的日志信息。将收集到的日志信息按照 logtail 协议格式转换作为响应返回给 CN。 type RespBuilder interface {
OnDatabase(database *DBEntry) error
OnPostDatabase(database *DBEntry) error
OnTable(table *TableEntry) error
OnPostTable(table *TableEntry) error
OnPostSegment(segment *SegmentEntry) error
OnSegment(segment *SegmentEntry) error
OnBlock(block *BlockEntry) error
BuildResp() (api.SyncLogTailResp, error)
Close()
} 这个过程依然有非常多的优化可以做这里举几个例子
如果请求的时间范围不是最新在请求范围右侧范围内发生了数据刷盘那么请求范围内的数据更改应该怎么给呢我们认为再从对象存储中读出这个区间的更改是不必要的直接把 block 元数据给到 CN在 CN 利用时间戳过滤去指定范围的数据是更节省的做法。如果一个时间范围内的内存更改是在太多通过内存发送也是不实际的所以会在收集时检查响应大小如果过大可以强制刷盘重新收集。Logtail table 也需要根据 checkpoint 做定时清理避免内存膨胀。另外也对更早的 txn handle 可以做一些数据上的聚合避免每次都从 txn handle 层面迭代
2. Push
Push 的主要目的是更实时地 TN 同步增量日志到 CN。整体流程分为订阅、收集、推送三个阶段。
订阅一个新 CN 启动后的必要流程就是作为客户端和服务端 TN 建立一个 RPC stream并且订阅 catalog 相关表当 database、table、column 这些基本信息同步完成后CN 才能对外提供服务。当 TN 收到订阅一个表的请求时其实先走一遍 pull 流程会把 截止到上次 push 时间戳前 的所有 logtail 都包含在订阅响应中。目前对一个 CNlogtail 的订阅、取消订阅、数据发送都发生在一条 RPC stream 链接上如果它有任何异常CN 会进入重连流程直到恢复。一旦订阅成功后续的 logtail 就是推送增量日志。
收集在 TN一个事务完成 WAL 写入后触发回调执行在当前事务中收集 logtail。主要流程是遍历 workspace 中的 TxnEntry(一种事务更新的基本容器直接参与到 commit pipeline 中)依据其类型取对应的日志信息转换为 logtail 协议的数据格式。这个收集过程通过 pipeline和 WAL 的 fysnc 并发执行减少阻塞。
推送推送阶段主要做一次过滤如果发现某个 CN 没有订阅该表就跳过该 CN避免推送。
按事务收集有一个比较明显的问题如果一个表长时间没有更新怎么办CN 怎么知道是没有更新还是没有收到呢这里就加入了心跳机制默认是 2 msTN 的 commit 队列中会放入一个 heartbeat 的空事务不做任何实质性工作只消耗时间戳从而触发一次心跳 logtail 发送告知 CN 此前的所有表数据已经发送过更新推动 CN 侧的时间戳水位更新。 Part 3 总结
至此只是从总体上介绍了 logtail篇幅有限挂一漏万并不能展示 logtail 的全部细节。而恰好 logtail 是对细节要求非常高的模块充分考验了协议在两个系统中的适用性。如果对细节的把控不足则会导致数据的漏读、重复读再加上时间戳的这个变量经常引发偶现的错误。今后我们会继续迭代 logtail提升其稳定性规范流程力求更加透明可理解。