TDSQL-A 倒退历程
TDSQL-A 是一款基于 PostgreSQL 自主研发的分布式在线关系型数据库。是一个面向海量数据实时在线剖析产品,采纳无共享 MPP 构架。面向剖析型场景的极致性能优化,咱们自研了列式存储,同时也反对行列混合存储模式。在数据转发层面上,针对大规模集群面临的连贯风暴问题对集群执行 / 转发框架做了更深刻优化,来保障能够反对超过千台规模的集群能力。同时为减速用户在数据挖掘或剖析场景上的时延,通过多种计算能力优化来达到给用户提供更好成果。
在多年的倒退过程中 TDSQL-A 依靠腾讯外部业务进行充沛打磨,在外部业务及内部企业级用户场景下都有良好体现,并在 2021 年 5 月 18 日上线腾讯云。
TDSQL-A 整体构架
首先整体介绍 TDSQL-A 架构。TDSQL-A 是一个多 CN 入口的 MPP 分布式集群设计,CN 节点作为业务拜访入口,每个节点是对等的,对外提供统一的用户元数据和视图拜访,同时也能够通过多入口分担用户高并发压力场景下的连贯解决。
因为是一个多 CN 入口,须要一个全局事务管理器 GTM 节点,进行全局事务管理以及 Sequence 等全局统一能力的解决节点。晚期 GTM 在高并发状况下获取全局事务快照会有性能瓶颈,TDSQL PG 版以及 TDSQL-A 都针对分布式提交协定做了基于 timestamp 的革新,解决了全局事务快照的单点瓶颈问题。TDSQL-A 整体不论是行存和列存事务提交,整体的提交协定都基于 timestamp(GTS)协定,提供业界当先的高并发能力反对。
数据存储和计算节点咱们称为 Datenode,Datenode 节点通过 TDSQL-A 构架优化,反对超过 1000 个节点以上的集群部署,反对 10PB 级别以上的用户数据量。同时在计算时,会尽可能把所有计算都通过智能的优化器布局推到 DN 节点上做计算。
TDSQL-A 整体构建演进。因为用户数据量继续增大,须要面临最大挑战是在大规模集群下大数据访问量和简单查问场景。例如 TPC-DS 这类简单的用户场景,它的 query 是带有简单的子查问场景及 with 语句的。在这种状况下多表关联会比拟多,在分布式系统下会有多层重散布。
依照之前晚期构架,在执行时碰到 RemoteSubplan 算子的时候才会往下发整体的下一步查问打算,如果查问中重散布的档次比拟多,每一层 DN 都会认为本人是一个发起者,会导致大量多层过程连贯和网络连接耗费。
做一个比较简单的计算,如果 200 个 DN 节点有 100 个并发查问,每个查问是 5 个数据重散布,计算将会有超过 10 万个连接数。这个问题在集群规模达到上千个节点后会更加重大,这也是整个 MPP 在大规模状况下的通用问题。
而 TDSQL-A 针对性地做了比拟大的革新,首先整体执行框架进行了重构,在 TDSQL-A 里查问打算是对立在 CN 下来做布局。当查问打算生成后,会依据 Remote Subplan 或须要做数据重散布这些节点,对查问打算做一个划分。不同档次会对立由 CN 节点到 DN 节点去建设相应 DProcess 过程,相当于有一个对立的 CN 协调者来治理所有过程和连接数,这样就会比拟可控地去建设所需最小过程数和相应连贯。同时不同过程间也能够去进行异步启动,减速简单查问的间接效率。
实际上这里还不够,尽管过程数比拟可控,但同时连接数还是一个问题,例如集群规模十分大,超过 1000 个节点当前,连接数收缩还是很重大。而对于超大规模集群咱们是引入了数据转发节点。数据转发节点会在每台物理机进行部署,如果有混布场景也是一个数据转发节点,会负责这台机器上所有 DN 或 CN 之前的数据交互。这样对于一个大规模计算集群,实际上网络连接数就会比拟可控,因为网络会走到数据转发节点上,而机器上的 DN 节点或者 CN 节点会通过共享内存和数据转发节点进行交互。这里还有一个额定优化,如果在同一台机器有混布的状况下,雷同机器上的 DN 交互能够不走网络,间接走共享内存做一个间接转发。
通过数据转发节点的引入整个集群规模就能够有一个比拟线性和扩大能力,依照 N 个节点和 M 层 Join 来计算,不论你的产品多简单它只有 N*(N-1)个网络连接数,整体由 FN 节点去布局。很好地去解决 MPP 场景下,超大规模集群如何放弃高并发和简单查问场景下网络连接问题。
下面介绍革新之后整个查问打算分片也会比拟明确。包含重散布代价在内,优化器会思考到分布式场景中数据转发的网络开销,基于代价模型去做主动查问优化。在 CN 生成查问打算后会递归遍历整个执行打算树,把整个查问打算分成多个 Fragment。从下面开始向下看,下面是更凑近 CN 节点,就是 Fragmentid 1,这里缩写是 FID 1,这样每次碰到 Remote subplan 节点时相当于须要拆分成一个新的 Fragment。同一个 Fragment 会在每一个参加计算的 DN 对立去建设这样一层过程。两头是通过 FN 节点去进行网络传输。左边是一个比较简单的规范查问打算两个 Hash Join,通过不同 Fragment 去分层的进行异步计算。
咱们的自研列式存储,例如用户有一些星型数据模型或者一些表列数较多而理论参加计算的列比拟少,这种状况很多都须要列裁剪去做执行优化,如果没有列存整体成果会比拟差。通过列存尽可能减少磁盘 IO 扫描和相干的计算层计算裁剪。这样整体在海量数据下计算量耗费升高会比拟显著。其实做优化最高效办法还是通过优化执行打算去做计算裁剪,第二步才是在必要雷同计算量前提上来进行执行优化,不论是你的算子优化,还是机器资源物理层优化。最开始都要从执行打算角度去做,所以列存是十分重要的。
后面有提到咱们的列存表和行存表一样,都应用了基于 timestamp 的分布式提交协定,所以整体行列之间能够放弃混合查问事务一致性。同时用户也能够在同一个库或同一个实例里,去依据业务场景针对不同特色建设行存表和列存表,能够主动在查问打算中抉择更好的 access path。
这是自研列式存储格局的简略介绍,每一张列式存储表,都有一张对应的元数据 registry 表,去记录它存储状态和更新的状态信息。
咱们的物理文件构造最小单元叫 Silo,就是一个谷仓的概念,一个 Silo 是一个数据块列式散布的紧凑排列。这样一个 Silo 外面开展,会有相应的左边这些信息,除了头部信息,最下面还会有一个 checksum 保证数据校验的正确性,前面有标记位去减速数据拜访和 filter 成果以及 null bitmap,最初是具体的数据。
介绍一下列存储提早扫描优化,例如有一个查问,在同一张表上有多个 Predicate 条件,比方 10 列有 3 列带有 Predicate。依照常见的做法,这些尽管是列存储,但须要的这些列还是会提前扫描去做一个整体物化,再做一个 Predicate。这种提早扫描其实能够做更优,因为它可能对两个或三个 Predicate 两头层级选择率比拟显著。能够先扫第一列,第一列扫完后它可能曾经通过 Predicate 过滤掉很多数据,这时再去扫第二列或第三列时,或前面其它数据列,都能够通过 ctid 扫前面须要的一些数据。如果列比拟多或过滤成果比拟好,它会缩小扫描的数据量。这是基于列存储不同列的物理文件隔离去做一个前提,因为这种状况下能力缩小真正扫描量,而不是减少 reaccess 的问题。
下面介绍了每一个 Silo 的格局,咱们会尽量放更多的数据在一个 Silo 里,减少它的数据压缩能力。另外要引入相干压缩能力算法进步整体存储效力,升高用户存储老本。
这里有两层,首先是通用的通明压缩,通明压缩会应用 LZ4 或 Zstd 算法,针对特定数据类型会加轻量级压缩能力。同时对于不同类型咱们也有不同压缩最优举荐,这是具象化到产品里的能力,用户只须要抉择 low、middle,或者是 high,例如你心愿压缩 low,咱们会主动替你抉择相应的压缩算法。
比方整数类型,如果是 low 咱们用 Delta+RLE,middle 和 high 就会加上 Lz4 或 Zstd 相似通明压缩。而针对 Numeric 也有深度优化,这里是列存压缩存储,如果你曾经抉择压缩,实际上它会主动转成 int 类型。这样不仅是存储空间节俭,在你计算同时也能很快的做向量化计算能力。
介绍一下咱们基于列存储和执行框架劣势去深刻开掘执行引擎上的能力。首先是一个多层级并行能力,在这里分为几个层面,一个是分布式多节点和多过程执行能力,这里由 FN 转发能力或优化器主动布局能力去决定,当然也是由 MPP 整体构架来决定的。两头一层,因为当初代码整体是基于 PG10 来做的,但实际上咱们合入了很多更新,例如 PG12、PG13 里的能力或并行能力,包含优化器里针对这些场景,比如说 partitoin-wise Join 的能力都有引入。
在两头这一层算子的并行计算能力状况下也会有比拟好的成果,同时咱们本人针对多种场景,比方 FN 能力在并行过程中遇到的一些问题,做了深刻的解决。整体在基于 MPP 框架,超大规模 MPP 框架下同时对算子级过程做了深度优化。另外一个最底层的在 SIMD 并行指令层面进行深刻的优化。
后面介绍了基于列存咱们做了很多深刻优化,比方后面提到的 LateRead 提早扫描能力,实际上在计算层咱们也有基于列存提早物化能力,能够了解为对立把列存的个性在计算层优化到极致。
提早物化这里介绍下,比方一个 query 外面有 hashjoin,个别的做法是,上面 Scan 层会把所有的列或数据都扫进来,再去做 Join 计算,这是一个通用性场景。实际上如果在 Join 选择率比拟好的状况下,对于不参加 Join condition 的这些列,物理扫描的那些数据列能够通过 Join 之后再去扫描,因为是列存储,能够 Join 之后再把列进行补全,这样 Join 在选择率很好的状况下能够缩小大量的磁盘 IO 和网络耗费。
这里有一个简略计算,一个有 20 亿条数据选择率百分之一的 join 场景,可能会缩小 7.4G 的有效数据传输和有效数据扫描,这个成果非常明显。相似场景下咱们做了提早物化的整体优化,在最开始扫描的时候只须要扫 Join condition 须要的列去做 Join,Join 完结后再把剩下的列数据再补全。
TDSQL-A 执行引擎优化
在这里咱们深入研究,一个是执行引擎框架,另外是基于优化器 CBO 里主动造成提早物化相干的执行打算。如果大家对优化器比拟熟会晓得在这里 PG 的代价模型是很先进的,目前是自底向上的动静布局过程,相比于一些新的优化器应用 cascade model,通用优化成果其实各有优劣。后面提到并行算子在咱们合入了 PG12、PG13 当前,整个优化器里也引入了并行执行 CBO 能力。提早物化也是继续在下面做一个优化,也就是 path 生成的过程中它是能够通过 restriction 去算出最开始扫描时只须要扫的那些列。这样生成 path 时只须要去构架一个辅助信息,去标记一下哪些列是须要提前物化,哪些列是能够进行提早物化的。
这里理论有很多细化问题,例如提早物化常见问题,如果有更多算子导致 reaccess 的场景,成果可能会降落,这在 CBO 里都有思考。例如 Hashjoin 的落盘状况下以及 RemoteSubplan 都可能会有乱序问题,在这里咱们都有相应的思考在外面,所以整体会是一个基于 CBO 比拟智能的提早物化能力。
后面多个点提到了向量化执行引擎整体设计,向量化和 SIMD 是一个更外围方向。在这里咱们自研了整套向量化执行引擎,能够反对 TPC-DS 及更简单的查问场景,让简单查问全都执行在向量化执行引擎下面。
在 Hash Agg 或者表达式计算等场景下,咱们会去做针对列存储和向量化技术做联结优化,比方 numeric 转换成定长类型。同时还去针对向量化内存构造 做了深刻优化,比如说 SIMD 和向量化成果到底能有多少,其实和数据编排有十分大关联性。更好的数据编排以及算子实现能够缩小 CPU Cache miss。在这里咱们花了比拟多的精力在内存编排上。这些都是原生在内核里去实现。同时在算子上也是本人去独自拉出一套向量化执行引擎算子,在 SIMD 场景下针对算子细节和其余典型场景都有 SIMD 指令引入,保障在多个档次上,从数据编排的根底到算子外围,再到 SIMD 整体都进行了深刻优化。
同时做为剖析型产品,可能更多在交易系统后端链路上,须要去接入不同数据源保障能够有更多的适应性场景,如果沿用原有的 Copy 模式性能就会比拟差。
所以咱们针对分布式 MPP 场景去做了高速数据交互工具 TDSQL-TDX,这是借助一个数据服务器,让 TDX 对立去解决 DN 的数据申请,DN 去拜访 TDX 取到切分的数据分片,就能够达到基于 DN 个数并行的进行数据交互。
另外这个工具也反对数据导出,相比传统用的 Copy 模式有数十倍的晋升。另外咱们也将继续对 TDX 工具进行优化,反对更多生态。
将来布局
后面介绍了很多构架降级包含一些细化能力,当然咱们还有更多的点能够持续深刻细化。例如在 SIMD 笼罩场景上加强,深刻对列存储格局编排和向量化执行引擎做深度优化还有更进一步的空间。同时也心愿持续能够和 PG 生态做一个继续交融,比方并行或其它的算子能力,都将继续交融 PG 社区能力,同时也会思考整体把 code base 去进行继续降级。
最初一个点是 Oracle 兼容能力,理论内核能力上 PostgresSQL 整体 Oracle 兼容能力是十分强的,咱们也会继续在相干能力交融和能力进行晋升。对于国产 MPP 或相似 Oracle 代替场景,因为 Oracle 不仅是做为交易型,可能很多厂商都是混合场景,而咱们做为一个 MPP 也能够反对 Oracle 兼容能力,这个能够关上更多的适应性场景。