研发案例 TiFlash 函数下推必知必会丨十分钟成为 TiFlash Contribut 来源: 发表时间: 2022-07-21 来源:火狐体育最新官网登录入口 作者:火狐体育app

  TiFlash 自开源以来得到了社区的广泛关注,很多小伙伴通过源码阅读的活动学习 TiFlash 背后的设计原理,也有许多小伙伴跃跃欲试,希望能参与到 TiFlash 的贡献中来,十分钟成为 TiFlash Contributor 系列应运而生,我们将从原理到实践,与大家分享关于 TiFlash 的一切!

  本文详细介绍了 TiFlash 下推函数的相关知识,我们也特别筛选了一些相关的 issue:(复制链接至浏览器即可查看),希望你能通过本文的阅读完成这些挑战,更有 TiDB Contributor 专注纪念品等你领取!

  TiFlash 作为 TiDB HTAP 体系的重要一环,会接收并执行 TiDB 下推下来的算子。而有时 Projection, Selection 等等算子里会带有函数,这就意味要下推这些算子就必须支持在 TiFlash 里执行算子包含的函数。

  如上图所示,如果某个算子带有 TiFlash 不支持的函数,就会导致一连串的算子都无法下推到 TiFlash 里执行。为了最大化地发挥 TiFlash MPP 并行计算的能力,我们需要让 TiFlash 支持 TiDB 的所有函数。看似无关紧要的函数支持,却是 TiDB HTAP 的重要一环!

  函数是由 TiDB 下推给 TiFlash 执行的,所以必须保证函数在 TiFlash 执行的逻辑和 TiDB 保持一致,包括:

  以返回值类型为例,sqrt在 TiDB 一定会返回 float64,即便参数是Decimal类型的,也会在函数内部对参数先evalReal;而 floor、ceil 则会根据参数的类型和大小决定返回值是普通的整型,还是Decimal 类型。

  一般情况下,TiFlash 要与 TiDB 保持一致是比较简单的。但是对于一些特别的输入,在实现的时候需要特别关注,如 sqrt 一个负数,是返回 NaN,还是返回 Null,还是抛出异常呢?

  接下来要进行 TiFlash 侧函数主体的开发。如果不能复用 TiFlash 已经开发好的函数,那我们就得继承 IFunction 接口开发一个函数。不过好在 clickhouse 本身已经有很多现成的函数,不过因为不一定与 TiDB/MySQL 兼容,我们不能直接使用,所以留在了 Functions 下面,以待后来者利用。

  如果不巧,没有现成的 clickhouse 函数利用,那就得从 0 开始开发一个向量化函数,不过也不必担忧,虽然向量化函数开发相对困难一点,但是还是可以从别的函数上找到一些脉络,模仿一些开发范式。

  以上两点让 TiFlash 的函数开发有一定的难度,和 TiDB 的函数开发差别会相当大。可以参考下 Function 目录下其他函数的实现,比如 FunctionSubStringIndex。在开发函数的时候大家应该会有很多体会 :)

  在 TiDB 和 TiFlash 侧的开发都完成后,我们需要先在本地验证一下整个下推流程是不是真的 work 了。

  如果函数被下推到了 TiFlash,那 explain 的结果可以看到包含该函数的 Projection 算子在 TiFlash 侧。explain sql 可以反复执行多几次,因为 TiFlash 副本建立需要一些时间,但是不会太长。如果很长一段时间都看不到函数下推了,那么应该就是真的有问题。:)

  FunctionTestUtils 是用于函数测试的公共类,里面提供了各类常用的方法,如 CreateColumn 等等。如果在写 gtest 时发现有其他可以共用方法,也可以补充在这里。

  Decimal 类型在 TiFlash 的内部表示有四种:Decimal32,Decimal64,Decimal128 和 Decimal256,对于所有 Decimal 类型,这四种内部表示都需要测试到。

  函数的每个 arg_i 可能的类型实际上应该以 TiDB 可能下推的类型为准,考虑到获取 TiDB 可能下推的类型比较麻烦,当前测试可以根据 TiFlash 目前支持的类型来写

  有一部分 TiDB 下推的函数中,其下推的函数签名中包含了类型信息,例如对于 a = b ,TiDB 下推的函数签名包括:EQInt,EQReal,EQString,EQDecimal,EQTime,EQDuration,EQJson,虽然 a 和 b 各自都可以是 int/real/string/decimal/time/duration/json 类别,但是 TiDB 下推的时候保证了 a 和 b 的类别是一致的,从工作量角度考虑,当前测试只需要保证相同类别之间的 equal 函数被测试到即可,int = decimal 这种的可以先不测。

  对于输入参数可以无穷多的函数(例如 case when),需要确保其最小循环单元被测试到。

  预期测试过程中会发现很多 bug,对于一些比较容易 fix 的 bug,可以在测试的同时顺便 fix,对于一些比较难或者不确定需不需要 fix 的 bug,可以先开 issue,再将相应的测试注释掉。

  在函数开发中,可能发现某个参数通常为常量,并且如果假设该参数一直为常量的话,开发函数会简单很多,这时候可以考虑强制该参数为常量,不为常量就报错。这时重载 getArgumentsThatAreAlwaysConstant,返回指定的常量参数的下标(从 0 开始)即可。

  任何一个新加入集体的小伙伴都将收到我们充满诚意的礼物,成为 New TiFlash Contributor 即可获赠限量版马克杯,很荣幸能够认识你,也很高兴能和你一起坚定地走得更远。获取流程如下:

  代码提交后 CI 会执行测试,需要保证所有的单元测试是可以通过的。期间可能有其它的提交会与当前 PR 冲突,这时需要修复冲突;

  维护者在 Review 过程中可能会提出一些修改意见。修改完成之后如果 reviewer 认为没问题了,你会收到 LGTM(looks good to me) 的回复。当收到两个及以上的 LGTM 后,该 PR 将会被合并;

  合并 PR 后自动成为 Contributor,就可以填表单领取你的专属马克杯啦,表单地址:

  后台 AI 核查 GitHub ID 及资料信息,确认无误后会快递寄出属于你的限量版马克杯。

上一篇:软件测试 手把手教你安装 MySQL 50版本的教程以及配置 下一篇:LINQ To Object和LINQ To SQL的区别
关注我们
©2022 火狐体育最新登录网址_官网app入口 京公网安备110177777720125 火狐体育最新登录网址|火狐体育app