写点什么

NineData 核心技术揭秘

作者:NineData
  • 2022-12-08
    浙江
  • 本文字数:7616 字

    阅读完需:约 25 分钟

NineData核心技术揭秘

大家好,之前的文章《NineData,领先的多云数据管理平台》介绍了我们的产品,大家在了解我们产品的同时,可能也比较关注我们是怎么做的,用了哪些技术,今天和大家一起来探讨一下 NineData 的技术实现。

01 整体架构


NineData 是一个多云的数据管理平台,所以多云和多源是我们要解决的非常重要的问题,上图的最上层是我们支持的数据库类型,从设计上来说,我们要支持市面上所有主流的数据库,既支持 MySQL、PostgreSQL、SQLServer 这样的关系型数据库,也支持 MongoDB、Redis 这样的 NoSQL,还支持各大云厂商比如 Auroa、PolarDB、高斯 DB 这样的云厂商专属数据库,当然还包括 TiDB、OceanBase 这样的分布式数据库。


最下层是我们支持的基础设施范围,主要包括云厂商和自建机房,也就是说,无论是云上还是云下的数据库,也不论是云上云厂商专属数据库还是自建数据库,NineData 都会提供支持。 当然 NineData 本身也是一个 SaaS 服务,同时部署在各朵云上。


NineData 自身大致可以分为四层,最上层是接入层,包括控制台和 API 两个部分,也就是说,NineData 支持大家在控制台上直接管理数据,也支持通过 API 的形式将 NineData 集成到客户内部的系统中去。


接下来是数据安全层,数据安全是 NineData 从一开始就确立的非常重要的工作。我们会在这一层处理所有涉及到数据安全相关的工作,比如数据加密、鉴权、脱敏以及完整的操作审计。


再往下是核心引擎层,主要用来支撑我们的 SQL 开发、数据复制、备份恢复和数据对比四大核心功能。


最下面是我们的核心能力层,主要包括两个部分,一是公共的核心能力,比如 SQL 解析器和元数据管理,存中间数据的转换框架等等。 第二部分则是 NineData 多云部署框架和调度引擎。


NineData 整体架构有相当的复杂度,我主要想和大家讨论五个方面:

  • 第一是我们高度灵活的多云架构,即我们如何处理多云、多基础设施的问题。

  • 第二是我们怎么做到强一致的实时数据复制。

  • 第三是我们的多策略数据比较。

  • 第四是我们如何高效的利用备份数据。

  • 第五则是我们怎么保证 NineData 的工程质量。


02 多云架构

多云部署


首先来看 NineData 的多云架构,对于对于 NineData 这样的数据管理服务来说,多云的问题主要难点有两个,第一个是部署的问题,因为 NineData 的服务节点最好是越靠近用户的数据库节点越好,举个例子,如果要服务阿里云北京 Region 的用户,那么 NineData 最好也部署在阿里云的北京 Region,一方面可以获得更好的网络连接,另一方面也可以避免出现网络流量方面的开支。以此类推,要服务所有的云厂商,就得在每个云厂端的 Region 里部署 NineData 的服务。但是今天全球主流云厂商的所有 Region 加起来起码有几百个,如果再算上可用区就更多了,如果在每个云的每个 Region 上都预先部署然后才能提供服务的话,这将是一个巨大的工作量并且会造成巨大的成本。 所以我们将 NineData 的架构拆分为了中心控制节点与单元节点,如下图所示:



中心节点作为用户接入层,包含有控制台、账号、角色权限、操作审计、监控报警和计量计费等与用户相关的内容。由于中心节点不做比如数据备份、数据复制这样的具体的工作,所以部署地域不受限制,可以预先拉起。原则上只需要一套中心节点,但考虑到不同国家之间的政策合规和隐私数据保护要求,会存在双中心乃至多中心存在。


单元节点则作为任务执行层,具体负责复制、备份等任务的执行,所以单元节点需要部署在更靠近用户数据库的 Region。但是单元节点不用预先拉起,初始的时候也没有单元节点,当中心节点发现需要在某个云的某个 Region 拉起单元节点时,比如用户创建了涉及到该 Region 的数据复制任务,中心节点会自动购买该 Region 里的资源并拉起单元节点开始服务,且还会通过持续关注任务量来进行自动伸缩。


同时这种架构还提供了另外一种能力,就是可以将单元节点部署在用户环境中作为用户专属集群,方便那些想获得更优质服务的客户。在专属集群的模式下,还可以确保用户的数据只在用户的 VPC 内流动。


多云网络访问


第二个是网络问题,从上图也可以看出,NineData 的单元节点需要访问到用户的数据库,但是出于安全等因素,今天数据库往往被单独放到一个 VPC 里面,而且不会开通公网访问,这对于 NineData 这样的数据管理服务是一个巨大的难题,一般云厂商自己的类似产品往往是通过内部一些特殊的实现才能在不侵入用户的 VPC 或开公网访问的情况下提供服务,而 NineData 则没有这样的特权接口,我们必须要在云厂商限定的范围内解决安全访问用户数据库的问题。但是云厂商的网络产品和网络实现各自不同,甚至有很大的差异,这无疑增加了 NineData 解决这个问题的难度。 

为此我们提供了如下图所示的三个方案:



针对不同的网络处理了大量的技术细节。 第一种是针对网络产品比较齐全、提供私网连接能力的云厂商,用户可以给我们有限的授权来实现私网连接,NineData 把这些流程自动化并且尽可能走成本更优的方案。第二种是针对网络产品没那么齐全的厂商,我们可能需要组合多个云产品来实现私网安全连接。 第三种是完全没有类似产品的云厂商或用户自建 IDC,我们提供了 NineData Gateway 来实现数据库的安全访问。 

解决了部署问题和网络问题后,我们就实现了非常灵活且低成本的云原生架构,这当然也得益于今天云计算给我们带来的便利,如何更好的利用云来助力业务可以说也是每一个企业都会面临的问题,希望通过 NineData 的努力,也能帮助大家更好的用好云。


实时数据复制


接下来看看 NineData 的强一致实时数据复制能力。随着数字化进程的推进,企业的应用越来越复杂,数据越来越多,数据复制或者说数据交换的需求非常普遍, 业界也有很多的工具或产品来解决这些问题,但是都存在比较多的限制。 数据复制大致可以分为两种类型,一种是由 OLTP 到 OLAP,常见的比如每天定时将生产库中的数据同步到数据仓库以作分析使用,这种相对来说比较简单; 另一种则是实时同步,比如数据库实时数仓、只读实例、异地同步以及下游实时消费均属于这种场景, 实时数据复制有相当的难度和复杂度,主要是集中在三个方面: 


第一个当然还是对延时的要求,一方面这是对性能的需求,另一方面则是对正确性、稳定性的要求,在一天同步一次的场景下,失败了可能有比较宽裕的时间来进行修复和重试,但实时同步失败了就会直接影响到下游的业务。 这对稳定和正确性的要求是不可同日而语的。


第二个这条链路长期运行所带来的稳定性问题。实时同步链路往往是 7X24 小时不间断运行,那么这个过程中就不可避免的会出现 DDL、源库、目标库异常或维护等等情况,这些情况处理起来非常复杂。 


第三是数据库版本、异构的处理。这个面临的情况更为复杂,包括结构怎么转换、数据类型怎么映射,DDL 怎么执行等等一系列问题。 NineData 在这几个方面均有深入而细致的处理。


演进的过去几十年里,已经有一些传统的、成熟的数据管理软件和产品。这里列出来了一部分产品,包括 Oracle Goldengate、Informatica、SharePlex 等,我们自己也都比较熟悉,有些也用得很多。我们注意到,这些产于云时代之前的产品,并不能很好适应当下的环境。


NineData 在这几个方面均有深入而细致的处理。 在延时方面,对数据分片、批次提交、并发提交等几个方面作了深入细致的优化:


第一是我们作了自适应的单表并发切片算法,能够根据表的大小预估决定切片粒度,确保全量并发性能,同时根据表的特点,大表、空洞表、无主键表、联合主键表进行切片和分发,确保每个并发线程的的工作任务更加均衡。


第二是我们作了智能分批提交策略,在一些数据集成场景下,只追求数据最终一致,我们会自动进行热点更新的数据合并,同时在提交时启用批量提交以降低目标库的负载。批量提交需要攒一批数据,往往会牺牲一定的延时,因此在 DB 同构复制中,我们会自动检测批量写入或历史数据删除行为来激活批量提交,而在低负载下自动切换到正常提交,以降低低负载情况下的端到端延时。


第三是做了事务级并发。传统的行级同步,虽然能够保障最终一致,但对于在线业务来说,这种同步方式可能会带来业务故障。比如下图中,创建交易订单后,订单状态达到 B3 才能创建物流订单,但行级并发会把交易订单和物流订单同时并发投递到目标,因此目标库在 B1 状态下就可能收到了物流订单,如果目标库提供了业务的读流量,并且根据物流订单来推进订单状态,就会产生业务逻辑错误。因此为了更好地支持在线数据库的一致性同步,我们提供了事务级并发,像数据库的内部复制机制一样,保障数据一致性。具体做法就是根据源端数据库的事务提交顺序,分析其事务依赖关系构建出有向无环图,然后进行并发提交。由于事务在内存中就排好了顺序,在并发提交时可以随机发送到任意发送队列,相比行级并发反而收获了更均衡更稳定的同步性能。



在长期运行的链路稳定性方面,针对 DDL,我们做了 DDL 多版本处理:



核心有三个部分: 

第一、结构语句解析 ND-Parser:业界对 DML 特别是 Query 类的 SQL 引擎已经比较丰富和成熟,比如 Calcite、Druid 等,但对于 DDL,特别是对多种不同数据库引擎的变更语句支持很弱,针对这一问题,NineData 研发了 ND-Parser,通过自动构建的测试语句,已经验证具备非常齐全的 DDL SQL 覆盖度。帮助用户更简单地实现同构或异构复制。


第二、Meta Execute Engine:对于源端的库表结构,以及后续的一系列增量 DDL 变更,ND-Parser 会自动解析提取变更对象,并依次在内存结构中构建对象的 Meta,并基于 Meta 按后续的 DDL 语句顺序进行增量变更,每一次变更都会在 MetaStore 中生成 meta 对象,相当于在内部构造了一个 DDL 语句执行器。


第三、MetaStore:在 ExecuteEngine 生成新 Meta 时,我们会将触发 Meta 的 DDL 语句 pos 位点作为版本记录与 Meta 成对地保存下来。这样我们的 MetaStore 可以支持查询任意一个时刻的 meta 版本,对数据同步中的问题排查和一致性同步提供了强有力的保障。


在其他稳定性方面,我们在产品上也做了很多设计:


第一、 对于链路依赖的外部环境,比如网络、源端或目标端数据库进入维护阶段或者出现异常,NineData 会持续探测并自动恢复链路。 


第二、 可观测性:NineData 非常重视监控趋势,并将并发线程状态白盒化,帮助用户了解当前在执行的语句,比如卡在 DDL 或某些大变更上。


第三、 可干预:运行中支持语句级细粒度的干预,用户可以跳过某些结构、数据同步识别的语句。


在数据库版本、异构的处理上,我们也作了大量的工作:


第一个是中间格式的转换框架。在数据复制中会涉及数据类型和结构的转换,作为一个通用的 SaaS 类产品,必须有很好的扩展性支持各种数据库。因此我们将各数据源的数据类型映射到 NineData 定义的中间格式,再由中间格式转换到目标数据类型,通过这种星型的数据转换框架实现 Any To Any 的数据转换能力,任何新数据源的接入只需要实现到 NineData 中间数据格式转换插件,即可与原有的结构、全量、增量链路打通。在结构迁移的异构转换上,我们依赖 ND-Parser 和 MetaStore 的能力,能够对结构迁移和增量 DDL 实现映射转换。



第二个是深度理解目标数据库并使用目标数据库最合适的数据类型。为了简单起见,市面上很多工具都只支持非常通用的数据类型,或者会把源库的数据类型转成非常通用的数据类型,比如将 JSON 类型转换为字符串,这明显不符合用户的预期。我们在这方面做了非常细致的处理,举个例子,从 MySQL 复制到 ClickHouse, 对于 MySQL 的新的时间日期,空间位置等类型,只有在 ClickHouse 老版本不支持的情况下,我们才会转换为 INT/STRING 等通用类型,一旦探测到版本支持了新的数据类型,我们会立即使用最合适的近似类型。


数据复制是一个看起来简单,但实际上有大量的复杂工作要做的产品,虽然 NineData 的团队在这个方面有深厚的积累,但我们也是如履薄冰,因为一旦出错,可能给用户带来难以估量的业务损失,所以为了保证数据在流动过程中的一致性,NineData 提供了数据库对比功能。


多策略数据库对比


数据流动能让数据发挥价值,但数据在流动过程中也容易发生数据不一致的情况,在生产实践中经常会出现数据不一致的情况,比如生产环境中可能出主备数据不一致、业务和数仓的数据不一致、测试环境和生产环境因为发布的问题造成表结构不一致、上下游数据不一致等等异常情况,这会给业务带来很大的困扰,NineData 通过多策略的数据库对比,可以快速发现异常并及时修复。


得益于在数据复制时构建的高度灵活的架构,数据库对比实现了全网络场景的 Any 2 Any 对比。比如支持 MySQL 到 MySQL 的同构对比,也支持 MySQL 到 Clickhouse 之间的异构对比。并且,NineData 不只是对数据内容作机械的理解和对比,我们提供了大量的选项,比如时间范围、精度,最大值最小值等等,用户可以针对自己的业务逻辑来实现灵活的定制,举个例子,比如数据库 A 日期类型的最大值为 9999-12-31,数据库 B 日期类型最大值为 2038-10-31, 可能在有的情况倾向于判定为一致,有的情况下需要判定为不一致,NineData 都可以支持灵活定制。同时数据库对比还提供了不一致后的订正脚本以方便快速修复。


另外,数据对比非常的高性能和轻量,我们通过智能分片、批量混检和抽样检查等多种技术来提升性能,可以在不影响数据库的情况下达到每秒 100 万条记录对比的速度,同时为了保护数据库,我们会实时观测数据库的压力,在必要的时候进行主动降级。 最后,数据对比提供了非常灵活的比较和触发策略,从按行数到抽样再到全量对比,用户可以根据自己对数据的理解和用途选择比较策略,也可以灵活选择比较时机,既支持周期性对比、也支持在任务完成后自动触发对比。根据比较的结果,同时提供了灵活的处理策略,比如发现不一致后可能做了修复,此时可以运行复检以节省时间,方便用户灵活应用各种异常。 


如果说数据复制和数据对比体现的是我们对数据库与业务场景的深刻理解与专业处理,那么备份数据即时查询就是我们在数据应用创新方面的尝试。


备份数据即时查询


相信大家都会对重要的数据做备份。但数据备份面临非常多的挑战,比如备份时间、存储成本等等,但其中最大的一个问题还是备份出来的数据使用频率较低,因为真正恢复毕竟还是比较少的情况,这就导致了很多人直到需要恢复的那一刻才发现备份的数据无效,从而造成巨大的业务损失,为了防止这种情况,一般我们会通过少量的演练来确保备份数据有效,但这又会引起额外的成本与人力消耗,而且因为抽样的原因仍然无法确保所有的备份数据是有效的。 


NineData 也一直在思考怎么解决这些问题, 从“数据只有用起来才能检验是否有效”的思路出发重新设计了整个备份的架构,一方面是要解决备份本身复杂、成本高等问题,另一方面也是探索怎么将类似备份这样的“冷”数据利用起来以发挥更大的业务价值。


NineData 的备份整体分为三层:



最底层是我们的全量备份数据和增量数据的拉取,这里主要做数据读取和必要的解析工作,然后写入到 NineData 的存储引擎。 对于存储引擎层,总体上我们希望有较高的压缩比以降低数据存储成本,写入方面能够同时支持全量和增量写入。


另外还需要能够支持数据的动态合并、元数据的版本管理以支持未来我们可以高效的查询数据。所以我们在这里借鉴了数据湖的一些思路。首先是把基线数据分片并按列式数据库的方式进行存储,再增量写入日志文件并保存每个版本的元数据。


最上层是我们的查询引擎,由于底层存储引擎的支持,用户可以非常灵活定制查询需求,比如可以单独查询全量备份的数据,适合每天定时将数据同步到数据仓库的场景,数仓的数据抓取程序可以直接抓取备份数据以避免给源库造成压力。 也可以按任意时间点查询数据,适合需要小批量的恢复数据的场景。还可以查询某一条数据的轨迹以观察这条数据的变化历史,在错误排查中非常有用。


总体上来说,将备份数据利用起来可以说是一举数得,不过,备份数据即时查询只是我们在探索数据价值过程中一个比较小的点,未来我们也将持续在数据价值方面进入深入挖掘,让所有的数据都能发挥价值。


NineData 工程质量实践


最后是我们在工程质量上的一些实践。 数据作为今天最重要的生产资料之一,其价值是不言而喻的, NineData 作为管理数据的平台,如果平台本身出现了正确性和稳定性的问题,那么对客户来说将无异于一场灾难,所以工程质量和数据安全是我们从创立之初就定下来的最重要的两件事情。



工程质量须从源头抓起。这个源头就是产品设计,只有合理且有效的产品设计才能保证工程质量。得益于 NineData 团队在数据管理领域的深厚积累,加上对数据管理产品的敬畏与审慎,我们设立了严格的产品评审流程。


在严格遵循编码规范、单元测试、代码审查等软件工程实践之外,还引入了代码与数据的安全扫描,确保每时每刻我们交付出的软件是安全稳定的。 


此外,NineData 碰到的最大的一个问题是我们如何有效的进行集成测试,因为 NineData 要支持这么多云厂商和数据源,所以面临的是一个 N 乘以 N 的测试矩阵,也就是说 NineData 每修改或新增一个功能,就需要在所有支持的云上和涉及到的数据源上进行回归测试。举个例子,比如我们修改了数据复制 MySQL 相关的一个功能,如果我们支持 10 朵云,支持 5 个 MySQL 版本,那么至少需要回归 50 个场景,在生产中实际上还远超过这个数量,因为每朵云的不同 Region 功能上可能也不太相同,我们还需要对每朵云的每个 Region 进行测试,所以这个用例的膨胀和运行成本是非常高的。从这些问题出发,我们实现了一个自动化的测试框架来完成这些工作。


首先它能够以低成本、无需编码的方式来编写测试用例, 将用例抽象为数据库对象+数据+操作流的方式存在,比如编写一个数据复制相关的用例只需要三部分:一是待测试的数据库对象,比如表、视图、存储过程等,二是写入测试数据;测试框架支持写入随机或固定数据;三是复制过程中执行一些操作流,比如 DDL 和 DML。这样无论是开发、测试还是产品同学都可以不断的沉淀用例,我们在短时间内就积累了上万个 case,这可以说是保证工程质量的基础。


其次是能自动化的执行用例,测试框架会自动根据 case 的类型来搭建或者购买环境,并注入我们刚刚写的测试用例,以复制为例,如果这个 case 是 MySQL 相关,那么他就会选择所有的 MySQL 版本作为源,然后再根据源和 NineData 的功能支持情况选择相应的目标,最初目标可能只是 MySQL,但根据 NineData 功能的不断扩展,这个目标会变多,比如其他云数据库、Clickhouse 等等,自动生成一个 N*N 的 case 集合。这样每新增一种数据源,就会自动继承原有的庞大的用例库。


最后是根据用例执行情况与线上故障等要素相结合,制定用例的优先级与补齐漏测场景以达成灵活的用例执行策略。 通过这套机制,NineData 可以做到快速积累测试场景和发现问题,确保我们提供的服务安全稳定。 


03 总结


NineData 致力于为云时代提供更好用的数据管理服务。 首先,NineData 本身是一个 SaaS 服务,支持多云和多数据源,我们期望通过对多云和多数据源的支持,能够帮助客户更好的用好云、用好数据。 其次,希望通过我们的流程和技术,保障客户在数据生产和使用上的安全问题。 第三,是希望不断降低数据管理平台的使用门槛,确保大家在数据管理上足够简单。 最后是,致力于帮助我们的客户不断的挖掘数据价值。


欢迎大家来试用 NineData。现在大家就可以登录 NineData 官网 www.ninedata.cloud 体验完整的产品功能。

用户头像

NineData

关注

NineData公众号(ID:NineData-Cloud) 2022-11-30 加入

还未添加个人简介

评论

发布
暂无评论
NineData核心技术揭秘_数据库_NineData_InfoQ写作社区