写点什么

ClickHouse 进阶|如何自研一款企业级高性能网关组件?

  • 2023-05-31
    北京
  • 本文字数:5479 字

    阅读完需:约 18 分钟

ClickHouse进阶|如何自研一款企业级高性能网关组件?

使用原生 ClickHouse 集群进行节点数据查询和写入时,离不开第三方开源网关组件 chproxy 支持。但由于 chproxy 缺少 TCP 协议支持,导致性能、查询能力等受限。这也成为困扰众多 ClickHouse 开发者的一大难题。那么,究竟应该如何突破?本文将揭秘火山引擎 ByteHouse 企业版自研网关组件如何解决以上问题。

一、引言

ClickHouse 是一款广受欢迎且应用广泛的分析型数据库。它通过列式存储和向量化处理等成熟的优化手段,配合高质量的工程化,实现了极高的性能表现。在许多业务场景下,ClickHouse 展现出了非常强悍的性能表现,因此吸引了大量实际生产使用用户。


在使用原生 ClickHouse 集群时,用户往往通过直连节点进行数据查询或写入。然而,由于缺少中间层进行负载均衡,在某些情况下会导致分片节点上的数据写入不均衡。同时,由于客户端配置 ClickHouse 数据源时指定了连接的具体节点信息,查询请求也会集中于部分节点。这样一来,如果某个节点宕机,就会引发单点故障。


为了解决这些问题,ClickHouse 官方文档推荐了一些第三方开源网关组件,如 chproxy 和 KittenHouse 等。其中,chproxy 是应用最广泛的组件之一,具备丰富的功能。它支持灵活的用户和集群映射配置,代理 HTTP 类型的请求。然而,目前开源社区还没有提供在 TCP 协议基础上支持的网关组件。由于 TCP 协议是 ClickHouse 集群间默认的通信协议,也是 ClickHouse 客户端和许多高性能第三方驱动程序所默认选择的查询协议,缺少对 TCP 协议的支持使得使用上存在很大限制。


ByteHouse 企业版是基于开源 ClickHouse 的企业级分析型数据库,支持用户交互式分析 PB 级别的数据,通过多种自研表引擎,灵活支持各类数据分析和应用。为解决原生 ClickHouse 集群存在的一些问题,ByteHouse 企业版试图提供一个高性能的网关组件。同时,这也将进一步释放 ByteHouse 强大的查询引擎能力,为用户提供极致的使用体验。


本文将主要介绍火山引擎 ByteHouse 企业版网关组件的功能和特性、ClickHouse 不同的查询协议对比、ByteHouse 网关与开源 chproxy 的功能对比。

二、ByteHouse 网关组件的功能

2.1 查询路由与负载均衡

ByteHouse 企业版查询网关同时支持 HTTP 协议和 TCP 协议的查询请求,最大程度上兼容了各种社区语言的 Driver,例如 ClickHouse GO、ClickHouse JDBC 等,同时也支持诸如 DataGrip、DBeaver 等数据库管理工具的使用。例:企业版查询网关架构


  • 监听层,同时支持 HTTP 和 TCP 两种 Protocol,接收请求。

  • 流量控制层,记录并限制请求的频率和并发数。

  • 分发层,根据配置中的集群信息和状态,负载均衡算法以及用户等信息,将请求发送至对应 clickhouse 节点

  • 健康检查器,通过发送探针请求的方式,时刻关注每个节点的健康状态以及响应灵敏度,避免将请求转发至不健康节点

2.2 打通 ByteHouse 控制面元数据

企业版网关通过与控制面元数据的连接,使得网关用户可以直接在控制面进行创建和授权。同时,网关读取控制面集群元数据,获取 ByteHouse 集群节点的信息。


ByteHouse 控制面支持多集群下的管控,因此对于企业版网关来说也需要支持多集群模式。与 chproxy 不同的是,企业版网关可以直接读取控制面用户集群授权元数据。对于可自动推断对应集群的用户,网关可以实现自动代理请求到对应的集群,更加灵活和便捷。

2.3 监控告警

火山引擎 ByteHouse 企业版查询网关与控制面的深度集成也体现在监控告警方面。ByteHouse 企业版控制面监控组件可以通过收集网关的查询指标 metrics,支持在控制面配置来自网关指标的告警规则。

例:企业版网关监控告警配置界面

2.4 其他功能

通过连接网关组件,ByteHouse 为用户提供了更多的灵活性,基于代理层能够实现许多原来不便于实现的能力和管控。


因此,基于服务端代理模式的 ByteHouse 企业版查询网关还拓展实现了其他更多功能,诸如下发指定节点和全部节点。其中当用户使用社区 ClickHouse Client 连接 ByteHouse 企业版查询网关可支持直接通过 SQL 语句来切换连接的 ClickHouse 节点


设置网关连接指定节点 示例:

clickhouse client --host <HOST> --user <USER> --password <PASSWORD>
ByteHouse Gateway :) set custom_gw_force_ck_node='<node_ip>'
复制代码


设置网关在全部 ClickHouse 节点执行 SQL 示例:

clickhouse client --host <HOST>.bytehouse-ce.volces.com --user <USER> --password <PASSWORD>
ByteHouse Gateway :) set custom_gw_force_all_nodes=trueByteHouse Gateway :) CREATE TABLE default.test(`id` Int64,`info` String COMMENT '1') ENGINE = MergeTree ORDER BY id SETTINGS index_granularity = 8192
CREATE TABLE default.test( `id` Int64, `info` String COMMENT '1')ENGINE = MergeTreeORDER BY idSETTINGS index_granularity = 8192
复制代码


ByteHouse 企业版查询网关为了避免执行查询时客户端和服务端连接中断导致无法获取查询结果,实现了异步查询来增强 ByteHouse 的查询能力。


对于 HTTP 协议基础的查询,可以通过在 Header 中添加 X-Async-Query 即可使用示例:

curl --location --request POST 'http://<gateway-address>:8123/?user=<user_name>&password=<password>&query_id=<queryID>' \--header 'X-Async-Query: 1' \--data-raw 'show tables FORMAT JSON;'
Query In Progress HTTP Header: X-Async-Query: running
Query Finished HTTP Header: X-Spend-Time: 100 (milliseconds)
复制代码

三、解码 ClickHouse 查询协议

为了更好地了解 ByteHouse 企业版查询网关,首先需要深入探究 ClickHouse 所提供的查询协议和接口。了解 ClickHouse 服务端如何处理客户端请求,有助于我们理解如何构建高性能的查询网关。


在与 ClickHouse 服务端通信时,客户端使用的查询协议主要有两种。一种基于 HTTP 协议的查询协议,另一种基于 TCP(Native)协议的查询协议。HTTP 协议通用性较强,在任何平台或编程语言中使用 HTTP Client 都可以调用 ClickHouse 的 HTTP API 进行查询和数据写入。而 TCP 协议则具有更少的额外开销,通过在 Socket 连接上自定义查询协议和优化的数据类型序列化过程,避免了 HTTP 七层协议带来的不必要的网络 IO 开销,并且原生支持 session。


下面简要介绍这两种协议的不同特点。

3.1 ClickHouse HTTP 协议的特点

ClickHouse 服务端默认使用 8123 端口提供 HTTP API 供客户端进行查询和数据写入操作。在设计和实现上,ClickHouse 为 HTTP 协议查询提供了很大的灵活性。


例如,Query Settings 可以放置在 HTTP Query Parameters 中,查询 SQL 可以放在 GET 请求的 query 参数中或者 POST 请求 body 里,甚至分割开放置在两部分中也是允许的。以下是一些例子:

$ echo 'SELECT 1' | curl 'http://localhost:8123/' --data-binary @-1
$ echo 'SELECT 1' | curl 'http://localhost:8123/?query=' --data-binary @-1
$ echo '1' | curl 'http://localhost:8123/?query=SELECT' --data-binary @-1
复制代码

ClickHouse 本身也提供了一个可交互的前端页面,通过浏览器访问,用户可以直接在 Web 页面上进行 ClickHouse 数据库的查询操作。


HTTP 协议是无状态的,因此在使用 session 时需要在参数中添加 session_id。通过设置 session id,ClickHouse 服务端能够确定请求属于哪个 session。对于带有 session id 参数的请求,同时只能有一条 SQL 语句正在执行,并且不能跨节点设置 session。因此,对于查询网关来说,需要将带有 session id 参数的 HTTP Query 请求转发到同一台 ClickHouse 节点上,以确保 session 生效。

3.2 ClickHouse TCP 协议的特点

ClickHouse TCP 协议是 ClickHouse Client 和 ClickHouse 服务端之间默认的连接协议,也是用于 ClickHouse 节点间通信的协议格式。相较于 HTTP 协议,它具有更少的额外网络 IO 开销,因此效率更高。但是,由于它是基于 TCP 连接底层的二进制数据流编解码,因此实现上相对复杂,需要考虑各种数据类型如何编解码以更高效地进行传输。


例如,当 Client 需要发送查询请求时,它会将查询语句和查询参数转换为 ClickHouse TCP 协议格式的字节流,并将其通过 Socket 连接发送到 ClickHouse 服务端。服务端会解析字节流并执行查询操作,最终将结果以相同的协议格式返回给 Client。在这个过程中,需要考虑如何对各种数据类型进行编解码,以确保传输效率和数据准确性。总之,ClickHouse TCP 协议虽然实现上相对复杂,但由于具有更高的效率和更少的网络 IO 开销,因此在高负载环境下使用它可以提高系统的性能和吞吐量。


例:Client 与 Server 基于 Socket 传输字节流通信


当 Client 端与 ClickHouse Server 端建立 tcp 连接后,Client 会发送一个 Client Hello 数据块给 Server。这个数据块包含了 Client 的版本信息以及用于身份验证的信息等。Server 在收到来自 Client 的 Hello 数据块后,会返回一个 Server Hello 数据块给 Client,其中包含 Server 的版本信息以及一些其他的配置信息。这些信息可以用于确定 Client 和 Server 之间使用哪个协议版本以及哪些功能。


一旦 Client 和 Server 之间成功建立了连接并且进行了协议交换,Client 就可以开始发送查询请求到 Server 了。这些查询请求可以包括 SELECT、INSERT、ALTER 等语句,同时也可以包含一些参数和设置来控制查询的行为。Server 会解析这些请求并且返回结果给 Client。在整个过程中,Client 和 Server 之间通过 tcp 连接来传输数据。


例:TCP 协议 Client Hello 数据块格式



许多语言 ClickHouse Driver 通过支持 TCP Native 协议提高读写性能,例如



由于 ClickHouse TCP 协议天然具有 session 状态,不同于 HTTP 只能在查询结束才能返回查询结果不同,TCP 协议允许 ClickHouse 服务端将查询进度及时返回给 Client。[图片]


例:TCP 协议 ClickHouse 服务端返回给 Client 的几种不同类型的数据块


3.3 探索 ClickHouse 批量写入

由于 ClickHouse 引擎底层依赖 LSM 数据结构进行数据存储,因此它具有独特的引擎特点。为了充分利用这些特点,ClickHouse 推荐以批量的形式进行数据写入,以提高写入的效率并避免产生大量细碎的 part 文件。因此,在实现上,HTTP 和 TCP 协议都支持批量插入,但在底层实现上存在一些区别。


HTTP 协议支持将批量写入的行数据以各种不同的格式放在 HTTP Body 中,并可以通过压缩来提高数据写入的效率。例:

$ echo -ne '10\n11\n12\n' | curl 'http://localhost:8123/?query=INSERT%20INTO%20t%20FORMAT%20TabSeparated' --data-binary @-
复制代码


而 TCP 协议支持发送多个数据块来避免重复提供写入效率,从图中可以看出 Client 发送给 Server 的 data 类型数据块可以很大(受 max_block_size 参数约束,默认值为 65505)

例:TCP 协议发起 batch insert 过程


例:TCP 协议 Data 数据块格式


例:TCP 协议 Column 结构体格式


就 TCP 协议而言,在进行 batch insert 时,插入的数据以整列的形式进行传输。这种方式不仅有利于数据在传输过程中得到更高效的压缩,而且由于自定义了数据类型的序列化机制,所以在读写过程中不需要插入分隔符,直接读取或写入定长的字节数组即可,从而大大提高了 IO 效率。


相比之下,HTTP 协议下的 batch insert 需要通过 FORMAT 来分割行数据进行写入。同时,数据以整行传输不利于压缩,这也是 HTTP 协议相较于 TCP 协议下的 batch insert 效率较低的一个原因。

四、与开源项目 chproxy 的差异

4.1 功能比较

火山引擎 ByteHouse 企业版查询网关与 chproxy 差异对比:

4.2 性能的比较

在查询性能上,由于用户可以通过使用 ClickHouse TCP 协议连接 ByteHouse 网关,因此拥有比 chproxy 更快的性能表现。


特别是在应对批量数据写入 batch insert 的场景下,使用 ByteHouse 网关以 TCP 协议连接有着更高的效率。


参考 ClickHouse Native JDBC 驱动做了对 HTTP、TCP 协议性能测试基础测试https://github.com/housepower/ClickHouse-Native-JDBC/blob/master/docs/dev/benchmark.md


4.3 使用体验的比较

  1. 开箱即用

免二次配置对于用户使用体验来说,ByteHouse 网关由于和 ByteHouse 企业版深度集成,做到了开箱即用。避免了 chproxy 需要手工在机器上维护 yaml 配置文件的繁琐。同时由于有了与控制面集群元数据的打通,因此集群运维操作例如节点替换、水平扩容操作,不需要更新网关配置。

  1. 用户模型对齐

ClickHouse 由于 chproxy 定义了自己的网关用户与实际 ClickHouse 用户不一致,因此无法复用 ClickHouse 的 RBAC 功能。而 ByteHouse 网关用户元数据与控制面一致,在控制面创建和授权的用户可以直接连接 ByteHouse 网关进行连接和查询。

  1. 切换成本低

对比 chproxy,对于原来使用 ClickHouse Go、ClickHouse Native JDBC 等组件连接 ClickHouse 的用户来说,可以直接连接 ByteHouse 网关来无缝切换到 ByteHouse,避免了因为需要切换协议(TCP -> HTTP)而改变客户端 Driver 的问题。

  1. 监控告警集成

集成 ByteHouse 网关与控制面集成了监控指标、告警规则,因此使用 ByteHouse 网关更易于监控,并配置相应告警。

五、总结

本文介绍了 ByteHouse 企业版查询网关组件的功能和特性。并探究了 ClickHouse 查询协议,通过解析 ClickHouse 查询协议和数据类型,我们构建了能够同时代理 ClickHouse 两种不同查询协议的网关 proxy 组件,以进一步提升整个 ByteHouse 的使用体验和可用性。并对比了 ByteHouse 企业版查询网关与社区 chproxy 网关的差别。

六、未来展望

ByteHouse 企业版查询网关将持续迭代,不断完善功能,提升查询体验。在安全性方面,网关将支持数据加密来提高客户端在公网连接时的数据安全性,避免在引擎节点上进行 TLS 卸载,同时提升查询性能。查询网关将配合 ByteHouse 企业版的水平和垂直扩缩容能力,在网关层进一步优化,实现对 Client 无感知的运维动作。当控制面进行运维动作时,网关可以分流请求避免请求落到指定节点上。网关像 sidecar 一样工作,使控制面的运维操作更加智能。


在监控方面,网关将通过接入 ByteHouse Parser 在网关层解析 SQL 语句,实现对集群、库、表,甚至字段的 SQL 执行统计,并深度整合到控制面库表信息和健康度功能上。

发布于: 38 分钟前阅读数: 6
用户头像

小助手微信号:Bytedance-data 2021-12-29 加入

字节跳动数据平台团队,赋能字节跳动各业务线,对内支持字节绝大多数业务线,对外发布了火山引擎品牌下的数据智能产品,服务行业企业客户。关注微信公众号:字节跳动数据平台(ID:byte-dataplatform)了解更多

评论

发布
暂无评论
ClickHouse进阶|如何自研一款企业级高性能网关组件?_数据库_字节跳动数据平台_InfoQ写作社区