深入了解 ByConity的BSP模式:云原生数据仓库的创新实践

263 阅读8分钟

项目背景

大数据时代的挑战与需求

随着企业和组织在大数据时代的蓬勃发展,数据呈现出以下特点

分布广泛:数据通常存储在多个异构数据源中,包括传统关系型数据库(如 MySQL、PostgreSQL)、数据湖(如 AWS S3、HDFS)、以及现代数据仓库(如 Snowflake、BigQuery)。

量级巨大:数据量从 TB 级迅速增长到 PB 级甚至 EB 级。

实时性需求:业务对实时分析和低延迟查询的需求日益增加。

这些趋势使传统的数据仓库架构逐渐显得笨重和不足

数据迁移带来的成本高昂且耗时

传统查询引擎在面对复杂联邦查询时,性能瓶颈显现

数据孤岛的存在导致难以统一查询与分析

在此背景下,联邦查询技术应运而生。它允许用户在不移动数据的情况下,对多个异构数据源执行统一查询。作为一个新兴的开源项目,ByConity 正是为了解决这些问题而设计的。

什么是 ByConity?

ByConity 是一个云原生联邦查询引擎,旨在帮助用户在分布式和异构数据源上实现高效的统一查询与分析。它由 ByteDance(字节跳动) 内部孵化,并最终以 Apache License 2.0 的形式开源,赋能开发者与企业。

ByConity 的设计目标是:

  • 高性能并发查询:通过先进的查询优化器和分布式执行架构,支持 PB 级数据的高吞吐量查询。
  • 异构数据源统一查询:支持主流数据湖、数据库、消息队列等多种数据源,无需数据迁移。
  • 云原生支持:深度适配 Kubernetes 等云环境,具备弹性扩展能力和资源调度优化能力。

以下是 ByConity 的核心优势:

  1. 开源与开放:完全免费,开发者可以灵活地扩展其功能,适配不同的业务场景。
  2. 多数据源支持:兼容传统数据库(如 MySQL、PostgreSQL)、数据湖(如 S3、HDFS),甚至是分布式文件系统。
  3. 弹性可扩展性:适配多云环境,通过容器化技术(如 Kubernetes)实现快速扩容和负载均衡。
  4. 企业级特性:支持分布式查询、高可用性、高效缓存以及安全性配置。

ByConity 的应用场景

ByConity 在多个场景中具有显著的价值:

  1. 跨云和多云数据查询企业通常在多个云服务提供商(如 AWS、Azure、Google Cloud)上存储数据。ByConity 能够对分散在不同云上的数据进行统一查询。
  2. 数据湖查询随着数据湖的广泛应用,ByConity 提供对常见数据湖(如 S3、HDFS)的支持,用户可以对存储在数据湖中的 PB 级数据进行高效查询和分析。
  3. 实时数据分析在物联网、金融、广告等领域,实时性需求高。ByConity 的异步执行和分布式架构能够满足高并发和低延迟的数据分析需求。
  4. ETL(数据提取、转换与加载)任务通过 ByConity,用户可以高效提取数据、进行复杂计算,并将结果写入目标数据库或文件系统。

设计理念与生态整合

ByConity 的设计理念是简化联邦查询的复杂性,通过开源的方式提供一个灵活、高效的解决方案。同时,它与现有的开源大数据生态系统(如 Apache Arrow、Apache Iceberg)紧密集成,增强了其易用性和扩展性

以下是其生态整合的主要方式:

  • Apache Arrow:使用 Arrow 格式作为查询引擎的内存数据结构,提升查询性能。
  • Apache Iceberg:原生支持 Iceberg 数据表格式,为用户提供 ACID 保证和灵活的数据版本管理。
  • 容器化支持:通过 Helm 和 Kubernetes 提供即插即用的部署方案,使用户能快速启动和管理 ByConity 集群。

I. ByConity 的技术架构与特点

ByConity 架构由以下几个核心组件构成:


II. 部署 ByConity(本地部署)

1. 环境准备

  • 操作系统:Linux(建议 Ubuntu 20.04 或以上)
  • 安装工具:Docker、Kubernetes、kubectl、Helm
  • 系统要求:
  • 内存:至少 4 GB
  • CPU:2 核或以上

1.1 安装 Docker

sudo apt update
sudo apt install -y docker.io
sudo systemctl enable docker
sudo systemctl start docker

1.2 安装 Kubernetes 和 Helm

# 安装 Kubernetes CLI
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
chmod +x kubectl
sudo mv kubectl /usr/local/bin/

# 安装 Helm
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash

2. 使用 Docker 部署 ByConity

ByConity 提供了官方 Docker 镜像,可用于快速部署和测试。

2.1 拉取 ByConity Docker 镜像

docker pull byconity/byconity:latest

2.2 启动容器

docker run -d --name byconity -p 9000:9000 byconity/byconity:latest

2.3 验证部署

访问 ByConity 的默认端口:

curl http://localhost:9000/ping

如果返回 Pong,说明服务已成功启动。

3. 使用 Kubernetes 部署 ByConity

在生产环境中,推荐使用 Kubernetes 以实现弹性扩展和高可用性。

3.1 部署 ByConity Helm Chart

helm repo add byconity https://byconity.github.io/charts
helm repo update

helm install byconity byconity/byconity --namespace byconity --create-namespace

3.2 检查部署状态

kubectl get pods -n byconity

3.3 配置访问入口

为 ByConity 配置外部访问的 Service:

apiVersion: v1
kind: Service
metadata:
  name: byconity-service
  namespace: byconity
spec:
  type: LoadBalancer
  ports:
    - port: 9000
      targetPort: 9000
  selector:
    app: byconity

III.SSH连接部署

打开终端,输入ssh -p 23 <提供的用户名>@<ECS服务器IP地址>,并回车确认。

ps:这里输错了两次密码,,,但是问题不大

如果系统提示你输入yes或者no来确认是否连接,输入yes并回车。

然后输入<提供的登录密码>并回车。

为避免使用时超时自动断开连接,请运行tmux new -s $user_id(如 tmux new -s user0001)命令创建一个新的tmux会话,其中$user_id是可以自定义的会话名称。(后续重新登录时,使用 tmux a -t $user_id)。

执行 clickhouse client --port 9010命令进入客户端。如果后续输入 SQL 会被截断,在此处可以执行clickhouse client --port 9010 -mn,此后 SQL 后需要加;作为结束。

然后就可以开始使用了


IV. 使用 ByConity 处理数据

开始进行测试,这里使用的是:

  1. 使用测试用数据库 test_elt:

use test_elt

  1. 由于TPC-DS定义的查询语法为标准 SQL,设置数据库会话的方言类型为 ANSI:

set dialect_type = 'ANSI'

测试多端同时查询对查询速度的影响

分析销售数据,它使用了多个子查询(ws、cs、ss)来分别计算来自不同销售渠道(网络销售、目录销售、商店销售)的销售数据,然后合并这些数据以进行比较和分析

with ws as
        (select d_year AS ws_sold_year, ws_item_sk,
        ws_bill_customer_sk ws_customer_sk,
        sum(ws_quantity) ws_qty,
        sum(ws_wholesale_cost) ws_wc,
        sum(ws_sales_price) ws_sp
        from web_sales
        left join web_returns on wr_order_number=ws_order_number and ws_item_sk=wr_item_sk
        join date_dim on ws_sold_date_sk = d_date_sk
        where wr_order_number is null
        group by d_year, ws_item_sk, ws_bill_customer_sk
        ),
        cs as
        (select d_year AS cs_sold_year, cs_item_sk,
        cs_bill_customer_sk cs_customer_sk,
        sum(cs_quantity) cs_qty,
        sum(cs_wholesale_cost) cs_wc,
        sum(cs_sales_price) cs_sp
        from catalog_sales
        left join catalog_returns on cr_order_number=cs_order_number and cs_item_sk=cr_item_sk
        join date_dim on cs_sold_date_sk = d_date_sk
        where cr_order_number is null
        group by d_year, cs_item_sk, cs_bill_customer_sk
        ),
        ss as
        (select d_year AS ss_sold_year, ss_item_sk,
        ss_customer_sk,
        sum(ss_quantity) ss_qty,
        sum(ss_wholesale_cost) ss_wc,
        sum(ss_sales_price) ss_sp
        from store_sales
        left join store_returns on sr_ticket_number=ss_ticket_number and ss_item_sk=sr_item_sk
        join date_dim on ss_sold_date_sk = d_date_sk
        where sr_ticket_number is null
        group by d_year, ss_item_sk, ss_customer_sk
        )
        select
        ss_sold_year, ss_item_sk, ss_customer_sk,
        round(ss_qty/(coalesce(ws_qty,0)+coalesce(cs_qty,0)),2) ratio,
        ss_qty store_qty, ss_wc store_wholesale_cost, ss_sp store_sales_price,
        coalesce(ws_qty,0)+coalesce(cs_qty,0) other_chan_qty,
        coalesce(ws_wc,0)+coalesce(cs_wc,0) other_chan_wholesale_cost,
        coalesce(ws_sp,0)+coalesce(cs_sp,0) other_chan_sales_price
        from ss
        left join ws on (ws_sold_year=ss_sold_year and ws_item_sk=ss_item_sk and ws_customer_sk=ss_customer_sk)
        left join cs on (cs_sold_year=ss_sold_year and cs_item_sk=ss_item_sk and cs_customer_sk=ss_customer_sk)
        where (coalesce(ws_qty,0)>0 or coalesce(cs_qty, 0)>0) and ss_sold_year=2000
        order by
        ss_sold_year, ss_item_sk, ss_customer_sk,
        ss_qty desc, ss_wc desc, ss_sp desc,
        other_chan_qty,
        other_chan_wholesale_cost,
        other_chan_sales_price,
        ratio
        LIMIT 100
        SETTINGS max_memory_usage=20000000000
        SETTINGS bsp_mode = 1,distributed_max_parallel_size = 12;

都开启bsp的情况下:

双端:

单用户:

只有开启一个bsp的双端情况:

不开bsp的服务端内存不够。


V. 总结

ByConity作为一个云原生联邦查询引擎,在分布式异构数据源查询方面展示了显著的优势:

高性能查询:

  • 实验中,ByConity对复杂多子查询场景的支持良好,通过TPC-DS标准查询能够灵活处理多来源数据,展示了其优秀的并行处理能力。
  • 在开启BSP(ByConity Speculative Processing)模式时,查询速度有显著提升,尤其是处理多端并发任务时的性能表现突出。

弹性与可扩展性:

  • 通过Kubernetes部署,ByConity展示了良好的扩展能力和资源调度优化能力,适合多云和混合云场景。
  • 支持异构数据源查询,无需迁移数据即可统一分析,极大地简化了传统数据仓库的操作流程。

开源生态:

  • ByConity的设计结合了多个开源项目(如Apache Arrow、Iceberg),这不仅提升了查询性能,还增强了其与现代数据湖、数据仓库的兼容性。

多场景适用性:

  • 无论是跨云、多云数据分析,还是实时查询和数据湖操作,ByConity都展示了较强的适配能力。

改进建议

1. BSP 模式与内存管理
  • 问题: 在不开启BSP模式或内存不足的情况下,查询任务可能会因内存超限而失败。
  • 建议:动态资源调度: 引入动态内存分配机制,在内存接近阈值时触发自动调整。查询优化器: 增强查询优化器能力,进一步减少内存占用,例如通过分区查询、按需加载数据等方式。预警机制: 增加实时内存使用监控与告警,帮助用户及时调整配置。
2. 多端查询下的性能优化
  • 问题: 在多端并发查询时,虽然BSP模式有效提升了性能,但在高负载情况下依然可能出现瓶颈。
  • 建议:分布式调度优化: 增强查询任务的负载均衡能力,在多个节点间分配计算资源。并发限流: 设置动态并发查询限制,避免因过多并发请求导致整体性能下降。结果缓存: 对重复查询结果进行缓存,从而减少对数据源的重复访问。
3. 社区与生态发展
  • 功能完善: 借鉴其他联邦查询工具(如Presto、Trino)的一些特性,进一步丰富功能集。
  • 生态拓展: 加强与大数据生态系统的整合,如更紧密地集成Apache Flink、Spark等。
  • 示例项目: 提供丰富的示例项目和最佳实践,帮助用户快速上手。