更多技术交流、求职机会,欢迎关注字节跳动数据平台微信公众号,回复【1】进入官方交流群

随着企业降本增效、智能化数据决策需求的增强,传统的商业数据库已经难以满足和响应快速增长的业务诉求。在此背景下,云原生数据库成为大势所趋。云原生数据库基于云平台构建、部署和分发,具有高可用性、高性能、高可靠等特点,可以帮助企业更好地实现数据智能化决策。

近期,火山引擎ByteHouse技术专家受邀参加DataFunCon2023(深圳站)活动,并以“火山引擎ByteHouse基于云原生架构的实时导入探索与实践”为题进行了技术分享。在分享中,火山引擎ByteHouse技术专家以Kafka和物化MySQL两种实时导入技术为例,介绍了ByteHouse的整体架构演进以及基于不同架构的实时导入技术实现。

架构整体的演进过程

分布式架构概述

ByteHouse是基于社区ClickHouse数据分析管理系统(下文简称社区)来做的产品集成和开发。ClickHouse在开源以后,因为其实时分析方面极致的性能表现在业界被追捧。目前其开源社区的star活跃度非常高,国内很多公司都有针对ClickHouse开源社区做的产品集成和上云服务。

由于ClickHouse是基于OLAP实时分析而生的列存的数据库,其本身是一个分布式数据库,加之其底层设计和实现让它在性能方面非常优秀,具体表现为单机可以达到每秒上亿行的读取速度以及GiB级的数据吞吐。由于社区官方不会做云服务的限制,所以社区开源的只是分布式架构。

社区的开源实现是一个经典的分布式架构。首先它是无中心的多节点集群,有分片(shard)的概念:每个集群有多个shard,每个shard相互独立;集群内每张表的数据划分为不同子集存储在不同shard上。由于分布式架构具有数据分片和本地存储的特性,所以它具有天然的并发性且高吞吐的优势。

当然,分布式架构也有其明显缺陷。首先,当集群达到一定规模后,再小的节点故障率也会导致一定量的故障处理单,而本地存储的运维门槛加剧了故障处理成本,尤其对于单副本集群,节点故障甚至会导致丢数据的风险;其次,分布式架构的读写耦合导致查询和导入存在资源竞争的问题;另外,由于本地存储reshuffle功能的成本问题,分布式架构的扩容成本非常高,而且容易导致线上服务IO热点,进而影响整个集群的稳定性。最后,由于无中心化节点以及事务的缺失,一致性问题是目前社区最为人吐槽的缺陷。

分布式架构下的实时导入

我们再来了解一下社区分布式架构下的实时导入实现,这里以Kafka导入为例。由于分布式架构多shard,每个shard可以独立消费一部分topic partition,可以有天然的并发优势;每个shard内部可以再通过多线程并发执行消费任务,进一步提高消费并发;加上本地写入的优势,使得导入任务可以有很高的吞吐。

社区Kafka消费实现采用high level的消费模式。high level 消费任务完全由broker分配和rebalance,基本无法对数据分配做控制,也就无法满足对数据分配有需求的业务场景;同时也难以保证数据均衡。针对这个问题,ByteHouse在开始引入ClickHouse时就做了优化——实现了low-level消费模式,使得数据分布以及均匀性能够得到保障。

由于架构缺陷,分布式架构下的Kafka导入存在类似痛点。首先由于没有事务保证,无法保证一致性,消费只能做到At-Least-Once 或者 At-Most-Once;其次,查询高峰会导致读写资源的竞争,从而造成消费堆积;当存在扩容需求的时候,数据分布会存在一些冲突。最后,由于中心节点缺失导致需要去每个独立节点排查问题,运维成本随着集群规模线性增长。

从分布式到云原生

基于以上痛点,ByteHouse进行了业界主流的架构升级和演进——从分布式架构到云原生架构的改造。火山引擎ByteHouse云原生架构分为三层:

  • 第一层是服务接入层,负责服务接入以及状态管理,包括整体服务入口、所有元数据信息、事务实现等。
  • 第二层是执行计算层(Virtual WareHouse,以下简称VW),设计为无状态执行层可以轻量级扩缩容;负责执行具体的查询和导入任务,由于查询和导入可以下发到不同Virtual WareHouse 从而实现读写分离。
  • 第三层是数据存储层(VFS),支持远端HDFS存储以及对象存储等多种存储方式,实现了存算分离。

状态管理层有一个元数据管理组件叫做Catalog service,这里存储了包括表的schema以及用户数据的所有元数据信息;另一个重要组件是Server,它的功能是承接整个集群的服务入口,用户的查询需求都会在Server进行预处理;在查询具体计算执行阶段,由于VFS数据存储导致的读数据开销,ByteHouse在计算层实现了DISK cache功能——将频繁查询的数据缓存到计算节点的local disk,以避免频繁远端数据读取的性能损耗。

为了解决社区饱受吐槽的一致性问题,ByteHouse设计和实现了Transaction,几乎所有任务(包括所有用户查询请求、DDL请求、导入请求、后台实时导入任务等)的执行都会封装在一个事务中执行,保证一致性和原子性。

由于架构的升级和演进,实时导入技术也在新架构下做了适配和优化。下面仍旧以Kafka导入为例,看看ByteHouse云原生新架构下的实时导入的实现。

当用户创建一张Kafka表消费时,集群会在Server上为这张表创建一个唯一的任务管理器:管理器负责获取Kafka topic的元信息,并根据用户配置的consumer数据将topic-partition均匀分配给每个consumer任务;然后将每个consumer任务调度到合适的VW节点执行。

在VW节点,每个consumer会从Kafka拉取自身分配到的topic-partition对应的数据,并将这些数据写入到VFS;每次写入数据后,系统会通过事务将写入数据的元信息以及最新Kafka offset提交到Catalog中;然后重复执行下一轮。

这个过程确保了数据从Kafka到ByteHouse引擎的完整导入,包括元信息的获取、后台任务的调度、数据的拉取与写入,以及offset的管理。通过这种方式,系统能够持续不断地从Kafka拉取数据并导入到ByteHouse中,形成一个不断的导入的实时数据流,满足用户的实时写入需求。

下面的表格简单比较了不同架构下实时导入技术的功能支持。除了上述提到的优化和改进,ByteHouse还自研了唯一键引擎,并从bytehouse的分布式架构开始支持,完全适配到云原生架构上,配合Kafka low-level消费模式,可以完美解决用户实时导入唯一键场景需求。同时,ByteHouse云原生架构通过独立的事务实现,在实时导入上消费语义升级支持Exactly-Once,满足了部分用户对数据准确性的要求。这些改进使得团队能够更好地满足用户的需求,提供更加稳定和高效的服务。

基于云原生架构上Kafka和MySQL的设计和实现

下面以Kafka和物化MySQL为例,简单分享一下ByteHouse云原生新架构下的实时导入技术的具体实现细节。

Kafka

如上文所述,在Kafka导入中,每个表在Server端都有一个对应的任务管理器Manager,这是一个后台常驻线程,负责从Kafka broker中获取topic的元信息,并从Catalog中获取上次成功提交的offset;然后,根据任务映射规则,将partition分配给不同的consumer,并将最新的消费offset一同下发到VW节点进行执行。

每个下发的任务都是作为一个常驻线程处理的。一旦任务被调度,如果没有异常,它会不断循环执行:先消费一批数据,然后写入ByteHouse;然后再消费下一批,直到上游停止操作或节点宕机。

此外,为了优化消费,我们引入了一个名为memory buffer的功能。这个功能是为了解决某些业务场景下对延时性要求较高的需求。比如用户需要在1-2秒内查询到数据,但ClickHouse的攒批消费设计实现方式很难做到如此低的数据延时——频繁地小批量写入会导致底层数据文件增长以及查询性能降低。因此,我们引入了memory buffer功能,将消费的数据先写入wal中(持久化存储),然后缓存在内存提供查询,当缓存足够量再一次性刷盘。这样既能提高查询性能,又能解决底层存储问题。

在VW上,每个消费任务的执行流程如下:首先,向Server端发起RPC请求,创建一个事务来进行消费;然后,根据分配的任务,从topic中poll数据;当消费足够量的数据,对数据进行处理和转换,写入VFS;最后将写入VFS的数据元信息和对应的消费offset通过事务提交回Server端,完成一次消费流程。

MySQL:

物化MySQL是社区目前的一个实验性功能,它的作用是把用户的一个MySQL的数据库库同步到ClickHouse里来帮助用户做一些OLAP分析。

物化MySQL的同步原理比较简单,当创建同步任务的时候,初始化阶段会把这个库里需要同步的表的数据全量拉取;当然,这里会有一个加锁和快照的操作,用以记录全量同步的位置,后续增量数据同步会从这个位置开始,通过实时同步MySQL的binlog并进行回放来实现。

对于底层存储,因为MySQL的数据表都有唯一性的需求,所以应用上ByteHouse自研的唯一键引擎就可以完美匹配。BinLog消费跟上文提到Kafka消费原理基本一致。MySQL有一个GTID的功能,可以充当类似于Kafka的offset角色,配合ByteHouse云原生架构的事务功能,每次在回放完以后同步提交数据元信息以及对应的GTID,保证做到不丢不重的消费导入。

目前ByteHouse支持的MySQL数据源包括官方的MySQL版本以及AWS和GCP这两个使用比较多的rds,因为目前ByteHouse物化MySQL更多地服务一些海外的业务,在AWS以及GCP上会更普遍一下。具体支持的功能列表可以参见下图。

云原生架构和导入技术使用现状和未来规划

目前,火山引擎ByteHouse云原生架构已经全面服务内、外部多种业务场景,实时导入已支持超过2500个服务节点,每天实时导入数据规模超过30PB,行数超过10万亿,每天的平均吞吐量是350GB每秒,算到每个消费线程大约18MB每秒。未来,火山引擎ByteHouse团队还将持续探索更通用的实时导入技术解决方案,进一步提升数据导入的性能和通用性,并持续推进开源社区建设。

点击跳转ByteHouse了解更多

火山引擎ByteHouse基于云原生架构的实时导入探索与实践的更多相关文章

  1. 新书《OpenShift云原生架构:原理与实践》第一章第三节:企业级PaaS平台OpenShift

    近十年来,信息技术领域在经历一场技术大变革,这场变革正将我们由传统IT架构及其所支撑的臃肿应用系统时代,迁移至云原生架构及其所支撑的敏捷应用系统时代.在这场变革中,新技术的出现.更新和淘汰之迅速,以及 ...

  2. Docker Data Center系列(一)- 快速搭建云原生架构的实践环境

    本系列文章演示如何快速搭建一个简单的云原生架构的实践环境. 基于这个基础架构,可以持续部署微服务架构的应用栈,演练敏捷开发过程,提升DevOps实践能力. 1 整体规划 1.1 拓扑架构 1.2 基础 ...

  3. .NET 云原生架构师训练营(模块一 架构师与云原生)--学习笔记

    目录 什么是软件架构 软件架构的基本思路 单体向分布式演进.云原生.技术中台 1.1 什么是软件架构 1.1.1 什么是架构? Software architecture = {Elements, F ...

  4. Sentry(v20.12.1) K8S 云原生架构探索,SENTRY FOR JAVASCRIPT SDK 配置详解

    系列 Sentry-Go SDK 中文实践指南 一起来刷 Sentry For Go 官方文档之 Enriching Events Snuba:Sentry 新的搜索基础设施(基于 ClickHous ...

  5. Sentry(v20.12.1) K8S 云原生架构探索, SENTRY FOR JAVASCRIPT 手动捕获事件基本用法

    系列 Sentry-Go SDK 中文实践指南 一起来刷 Sentry For Go 官方文档之 Enriching Events Snuba:Sentry 新的搜索基础设施(基于 ClickHous ...

  6. Sentry(v20.12.1) K8S 云原生架构探索,SENTRY FOR JAVASCRIPT Source Maps 详解

    系列 Sentry-Go SDK 中文实践指南 一起来刷 Sentry For Go 官方文档之 Enriching Events Snuba:Sentry 新的搜索基础设施(基于 ClickHous ...

  7. Sentry(v20.12.1) K8S 云原生架构探索,SENTRY FOR JAVASCRIPT 故障排除

    系列 Sentry-Go SDK 中文实践指南 一起来刷 Sentry For Go 官方文档之 Enriching Events Snuba:Sentry 新的搜索基础设施(基于 ClickHous ...

  8. Sentry(v20.12.1) K8S 云原生架构探索,1分钟上手 JavaScript 性能监控

    系列 Sentry-Go SDK 中文实践指南 一起来刷 Sentry For Go 官方文档之 Enriching Events Snuba:Sentry 新的搜索基础设施(基于 ClickHous ...

  9. Sentry(v20.12.1) K8S 云原生架构探索,JavaScript 性能监控之管理 Transactions

    系列 Sentry-Go SDK 中文实践指南 一起来刷 Sentry For Go 官方文档之 Enriching Events Snuba:Sentry 新的搜索基础设施(基于 ClickHous ...

  10. Sentry(v20.12.1) K8S 云原生架构探索,JavaScript 性能监控之采样 Transactions

    系列 Sentry-Go SDK 中文实践指南 一起来刷 Sentry For Go 官方文档之 Enriching Events Snuba:Sentry 新的搜索基础设施(基于 ClickHous ...

随机推荐

  1. 为何 Linus 一个人就能写出这么强的系统,中国却做不出来?

    前言 知乎上有一个提问:为何 Linus 一个人就能写出这么强的系统,中国却做不出来? ↓↓↓ 今天,我们就这个话题,一起来做个讨论. 不知道大家是怎么看这个问题的?是美国人更聪明吗,所以才能写出这么 ...

  2. Golang日志新选择:slog

    go1.21中,slog这一被Go语言团队精心设计的结构化日志包正式落地,本文将带领读者上手slog,体会其与传统log的差异. WHY 在日志处理上,我们从前使用的log包缺乏结构化的输出,导致信息 ...

  3. Goobye, cnblogs

    转 typecho 了,个人网站的客制化程度当然不是 cnblogs 能比得上的. <cirnovsky.cf>

  4. 【python爬虫】爬虫所需要的爬虫代理ip是什么?

    前言 在进行爬虫程序开发时,经常会遇到访问被限制的网站,这时就需要使用代理 IP 来进行访问.本文将介绍代理 IP 的概念及使用方法,帮助读者更好地应对爬虫程序中的访问限制问题.同时,本文还将提供一些 ...

  5. modbus转profinet网关连接UV系列流量计程序实例

    modbus转profinet网关连接UV系列流量计程序实例 用户现场是西门子1200PLC通过兴达易控Modbus转Profinet网关连接流量计的配置,对流量瞬时值及报警值监控及控制程序案例 硬件 ...

  6. ddddocr1.4.8失效的解决方法

    1. 问题描述 from selenium import webdriver from time import sleep driver = webdriver.Chrome() driver.max ...

  7. Android应用中对于微信分享的实例及问题

    源码地址 如何分享 分享无相应 分享结果如何接收响应 微信 分享回调 (提示几点关键问题:   debug_key 一定要获得对应的签名码 然后和weixin官网的appid对应     ) 几点注意 ...

  8. Go字符串实战操作大全!

    在本篇文章中,我们深入探讨了Go语言中字符串的魅力和深度.从基础定义.操作.字符编码到复杂的类型转换,每个环节都带有实例和代码示例来深化理解.通过这些深入的解析,读者不仅能够掌握字符串在Go中的核心概 ...

  9. 我试图扯掉这条 SQL 的底裤。

    你好呀,我是歪歪. 这次带大家盘一个我觉得有点意思的东西,也是之前写<一个烂分页,踩了三个坑!>这篇文章时,遇到的一个神奇的现象,但是当时忙着做文章搞定这个主线任务,就没有去深究这个支线任 ...

  10. Java多线程编程的优点和缺点

    优点: 加快响应用户的时间:多线程允许并发执行多个任务,可以充分利用多核处理器,从而提高程序的性能和响应速度.比如我们经常用的迅雷下载,都喜欢多开几个线程去下载,谁都不愿意用一个线程去下载,为什么呢? ...