本文首发于微信公众号“Shopee技术团队”。
摘要
Shopee ClickHouse 是一款基于开源数据库 ClickHouse 做二次开发、架构演进的高可用分布式分析型数据库。本文将主要介绍 Shopee ClickHouse 的冷热分离存储架构和支持公司业务的实践。
Shopee ClickHouse 的冷热分离存储架构使用 JuiceFS 客户端 mount 远端对象存储到本地机器路径,通过编写 ClickHouse 的存储策略,如同使用多卷存储一样使用远端对象存储。因为我们用同一个 ClickHouse DB 集群支持多个团队的业务,不同团队甚至相同团队的不同业务之间对数据的冷热划分基准可能都不同,所以在做冷热分离时策略需要做到 ClickHouse 的表级别。
为了做到表级别的冷热分离,我们依照提前编辑好的存储策略,针对存量需要做冷热隔离的业务表,修改表的存储策略。对于新的需要做冷热分离的业务表,建表时指明使用支持数据落在远端存储的存储策略,再通过细化 TTL 表达式判断数据应该落在本地还是远端。
冷热分离存储架构上线后,我们遇到了一些问题和挑战,比如:juicefs object request error
、Redis 内存增长异常、suspicious broken parts
等。本文会针对其中一些问题,结合场景上下文,并通过源码分析来给出解决方案。
总的来说 Shopee ClickHouse 冷热存储架构的整体设计思想是:本地 SSD 存储查询热数据,远端存储查询相对不那么频繁的数据,从而节约存储成本,支持更多的数据存储需求。
1. Shopee ClickHouse 集群总架构
ClickHouse 是一款开源的列存 OLAP(在线分析查询)型数据库,实现了向量化执行引擎,具有优秀的 AP 查询性能。Shopee ClickHouse 则是基于 ClickHouse 持续做二次迭代开发和产品架构演进的分析型数据库。
下图展示了 Shopee ClickHouse DB 集群的架构:
从上到下依次是用户请求介入 SLB、Proxy 层、ClickHouse DB 集群层,最下方是远端对象存储,这里我们用的是 Shopee STO 团队提供的 S3。
其中,SLB 提供用户请求路由;Proxy 层提供了查询路由,请求会根据用户连接串中的集群名,路由到对应的集群中,也提供了部分写入 balance 和查询路由的能力;ClickHouse DB 集群层是由 Shopee ClickHouse 数据库组成的分布式集群,目前有以 SSD 磁盘作为热数据存储介质的计算型分布式集群,和计算型单节点集群,还有以 SATA Disk 作为存储介质的存储型分布式集群;最下方的远端存储则用作冷数据存储介质。
2. 冷热分离存储架构方案
用户希望数据可以存储得更多更久,查询速度更快。但是通常数据存储得越多,在相同查询条件下,返回延时就会越高。
从资源利用率上来说,我们希望存储在 Shopee ClickHouse 上的数据可以被更多地访问和利用,为业务提供更广泛的支持。所以,起初我们要求业务方存储到 Shopee ClickHouse 数据库中的数据是用户的业务热数据。
但是这样也带来了一些问题,比如:用户有时候需要查询时间相对久一点的数据做分析,这样就得把那部分不在 ClickHouse 的数据导入后再做分析,分析结束后还要删除这部分数据。再比如:一些通过日志服务做聚合分析和检索分析的业务,也需要相对久一点的日志服务数据来帮助监管和分析日常业务。
基于此类需求,我们一方面希望资源的最大化利用,一方面希望支持更多的数据存储量,同时不影响用户热数据的查询速度,所以使用冷热数据分离的存储架构就是一个很好的选择。
通常,冷热分离方案的设计需要考虑以下几个问题:
- 如何存储冷数据?
- 如何高效稳定简单地使用冷存介质?
- 热数据如何下沉到冷存介质?
- 架构的演进如何不影响现有的用户业务?
而冷数据存储介质的选择一般通过以下几个要点做对比分析:
- 成本
- 稳定性
- 功能齐全(数据在下沉过程中依然可以被正确查询,数据库的数据也可以被正确写入)
- 性能
- 扩展性
2.1 冷存介质的选择和 JuiceFS
可以用作冷存储的介质一般有 S3、Ozone、HDFS、SATA Disk。其中,SATA Disk 受限于机器硬件,不易扩展,可以先淘汰。而 HDFS、Ozone 和 S3 都是比较好的冷存介质。
同时,为了高效简单地使用冷存介质,我们把目光锁定在了 JuiceFS 上。JuiceFS 是一种基于 Redis 和云对象存储构建的开源 POSIX 文件系统,可以使我们更加便捷和高效地访问远端对象存储。
JuiceFS 使用公有云中已有的对象存储,如 S3、GCS、OSS 等。用 JuiceFS 做存储,数据实际上存储在远端,而 JuiceFS 重点关注这些存储在远端的数据文件的元数据管理。JuiceFS 选择 Redis 作为存储元数据的引擎,这是因为 Redis 存储都在内存中,可以满足元数据读写的低延时和高 IOPS,支持乐观事务,满足文件系统对元数据操作的原子性。
JuiceFS 提供了一种高效便捷的远端存储访问方式,只需要通过 JuiceFS 的客户端,使用 format
和 mount
命令,就可以将远端存储 mount 到本地路径。我们 ClickHouse 数据库访问远端存储就可以如同访问本地路径一样访问。
选择了 JuiceFS 后,我们再把目光转回冷数据存储介质的筛选。由于 JuiceFS 主要支持的后台存储层为对象存储类别,余下的选项变成了 S3 和 Ozone。我们设计了一个如下的 benchmark , 使用 ClickHouse TPCH Star Schema Benchmark 1000s(benchmark 详细信息可以参照 ClickHouse 社区文档)作为测试数据,分别测试 S3 和 Ozone 的 Insert 性能,并使用 Star Schema Benchmark 的 select 语句做查询性能对比。
查询的数据处于以下三种存储状态:
- 一部分在 Ozone/S3,一部分在本机 SSD 磁盘;
- 全部在 Ozone/S3;
- 全部在 SSD 上。
以下是我们的测试抽样结果:
(1)Insert 性能抽样结果
Insert Lineorder 表数据到 Ozone:
Insert Lineorder 表数据到 S3:
可以看出,S3 的 Insert 性能稍微强势一点。
(2)查询性能抽样结果
根据 ClickHouse Star Schema Benchmark,在导入完毕 Customer、Lineorder、Part、Supplier 表后,需要根据四张表的数据创建一个打平的宽表。
CREATE TABLE lineorder_flat
ENGINE = MergeTree
PARTITION BY toYear(LO_ORDERDATE)
ORDER BY (LO_ORDERDATE, LO_ORDERKEY)
AS
SELECT
l.LO_ORDERKEY AS LO_ORDERKEY,
l.LO_LINENUMBER AS LO_LINENUMBER,
l.LO_CUSTKEY AS LO_CUSTKEY,
l.LO_PARTKEY AS LO_PARTKEY,
l.LO_SUPPKEY AS LO_SUPPKEY,
l.LO_ORDERDATE AS LO