clickhouse 多磁盘存储策略
说明
MergeTree 系列表引擎可以将数据存储在多个块设备上。这对某些可以潜在被划分为“冷”“热”的表来说是很有用的。最新数据被定期的查询但只需要很小的空间。相反,详尽的历史数据很少被用到。如果有多块磁盘可用,那么“热”的数据可以放置在快速的磁盘上(比如 NVMe 固态硬盘或内存),“冷”的数据可以放在相对较慢的磁盘上(比如机械硬盘)。
数据片段是 MergeTree 引擎表的最小可移动单元。属于同一个数据片段的数据被存储在同一块磁盘上。数据片段会在后台自动的在磁盘间移动,也可以通过 ALTER 查询来移动。
配置
<storage_configuration>
<disks>
<disk_name_1> <!-- disk name -->
<path>/mnt/fast_ssd/clickhouse/</path>
</disk_name_1>
<disk_name_2>
<path>/mnt/hdd1/clickhouse/</path>
<keep_free_space_bytes>10485760</keep_free_space_bytes>
</disk_name_2>
<disk_name_3>
<path>/mnt/hdd2/clickhouse/</path>
<keep_free_space_bytes>10485760</keep_free_space_bytes>
</disk_name_3>
...
</disks>
...
</storage_configuration>
<disk_name_N> — 磁盘名,名称必须与其他磁盘不同.
path — 服务器将用来存储数据 (data 和 shadow 目录) 的路径, 应当以 ‘/’ 结尾.
keep_free_space_bytes — 需要保留的剩余磁盘空间.
存储策略(Storage Policies)
存储策略定义了数据在多个存储设备(磁盘、卷)上的分布规则,支持冷热数据分层、多磁盘负载均衡等功能。
磁盘(Disk):表示一个物理存储设备(如本地磁盘、SSD、HDD、S3 等)。
卷(Volume):由多个磁盘组成的逻辑存储单元,可定义数据的冗余和分层策略。
存储策略(Storage Policy):定义数据在卷之间的分布规则(如优先写入热卷,冷卷作为备份)。
卷类型(Volume Types)
卷是存储策略的核心组件,支持多种类型以实现不同存储目标:
基础卷(Simple Volume)
定义:将数据均匀分布在卷内的所有磁盘上。
场景:负载均衡,避免单磁盘 I/O 瓶颈。
配置示例
<storage_configuration>
<disks>
<disk1> <path>/data1/</path> </disk1>
<disk2> <path>/data2/</path> </disk2>
</disks>
<policies>
<default>
<volumes>
<default> <!-- 卷名称 -->
<disk>disk1</disk>
<disk>disk2</disk>
</default>
</volumes>
</default>
</policies>
</storage_configuration>
分层卷(Tiered Volume)
定义:数据按时间或策略在不同卷之间迁移(如热卷 → 冷卷)。
场景:冷热数据分离,优化存储成本。
配置示例
<storage_configuration>
<disks>
<ssd> <path>/mnt/ssd/</path> </ssd>
<hdd> <path>/mnt/hdd/</path> </hdd>
</disks>
<policies>
<hot_cold>
<volumes>
<hot> <!-- 热卷 -->
<disk>ssd</disk>
</hot>
<cold> <!-- 冷卷 -->
<disk>hdd</disk>
</cold>
</volumes>
</hot_cold>
</policies>
</storage_configuration>
冗余卷(Replicated Volume)
定义:数据在卷内的多个磁盘上冗余存储。
场景:提高数据可靠性(类似 RAID 1)。
<storage_configuration>
<disks>
<disk1> <path>/data1/</path> </disk1>
<disk2> <path>/data2/</path> </disk2>
</disks>
<policies>
<replicated>
<volumes>
<replicated_volume>
<disk>disk1</disk>
<disk>disk2</disk>
<max_data_part_size_bytes>1073741824</max_data_part_size_bytes>
</replicated_volume>
</volumes>
</replicated>
</policies>
</storage_configuration>
配置存储策略
定义磁盘和卷
<storage_configuration>
<disks>
<fast_ssd> <path>/mnt/ssd/</path> </fast_ssd>
<slow_hdd> <path>/mnt/hdd/</path> </slow_hdd>
<s3_storage> <!-- S3 磁盘 -->
<type>s3</type>
<endpoint>https://s3.amazonaws.com/your-bucket/</endpoint>
<access_key_id>AKIAXXX</access_key_id>
<secret_access_key>XXXXXX</secret_access_key>
</s3_storage>
</disks>
<policies>
<tiered_policy>
<volumes>
<hot> <!-- 热数据卷 -->
<disk>fast_ssd</disk>
</hot>
<cold> <!-- 冷数据卷 -->
<disk>slow_hdd</disk>
</cold>
<archive> <!-- 归档数据卷 -->
<disk>s3_storage</disk>
</archive>
</volumes>
</tiered_policy>
</policies>
</storage_configuration>
创建表时指定存储策略
CREATE TABLE logs (
timestamp DateTime,
message String
) ENGINE = MergeTree
ORDER BY timestamp
SETTINGS storage_policy = 'tiered_policy'; -- 指定存储策略
数据迁移与冷热分层
手动迁移数据
ALTER TABLE logs MOVE PARTITION '2023-10-01' TO VOLUME 'cold';
自动迁移(TTL 规则)
ALTER TABLE logs MODIFY TTL
timestamp + INTERVAL 7 DAY TO VOLUME 'cold',
timestamp + INTERVAL 30 DAY TO VOLUME 'archive';
存储策略的应用场景
场景 | 存储策略配置 | 优势 |
---|---|---|
冷热数据分离 | 热数据在 SSD,冷数据在 HDD,归档数据在 S3 | 优化性能,降低成本 |
负载均衡 | 数据均匀分布在多个磁盘 | 避免单磁盘 I/O 瓶颈 |
数据冗余 | 数据在多个磁盘上复制 | 提高可靠性 |
云存储集成 | 热数据在本地磁盘,冷数据在 S3 | 弹性扩展存储容量 |
数据迁移策略
<storage_configuration>
...
<policies>
<policy_name_1>
<volumes>
<volume_name_1>
<disk>disk_name_from_disks_configuration</disk>
<max_data_part_size_bytes>1073741824</max_data_part_size_bytes>
<load_balancing>round_robin</load_balancing>
</volume_name_1>
<volume_name_2>
<!-- configuration -->
</volume_name_2>
<!-- more volumes -->
</volumes>
<move_factor>0.2</move_factor>
</policy_name_1>
<policy_name_2>
<!-- configuration -->
</policy_name_2>
<!-- more policies -->
</policies>
...
</storage_configuration>
policy_name_N — 策略名称。策略名称必须是唯一的。
volume_name_N — 卷名称。卷名称必须是唯一的。
disk — 卷内的磁盘。
max_data_part_size_bytes — 可以在卷的任何磁盘上存储的部分的最大大小。如果合并的部分大小估计大于max_data_part_size_bytes,则此部分将写入下一个卷。基本上,此功能允许将新的/较小的部分保存在热的(SSD)卷上,并在它们达到较大大小时将它们移动到冷的(HDD)卷上。如果您的策略只有一个卷,请不要使用此设置。
move_factor — 当可用空间低于此因子时,数据会自动移动到下一个卷(默认为0.1)。ClickHouse按大小从大到小(降序)排序现有部分,并选择总大小足以满足move_factor条件的部分。如果所有部分的总大小不足,所有部分都将被移动。
perform_ttl_move_on_insert — 禁用数据部分插入时的TTL移动。默认情况下(如果启用),如果插入一个已根据TTL移动规则过期的数据部分,它将立即移动到移动规则中声明的卷/磁盘。如果目标卷/磁盘速度较慢(例如S3),这可能会显著减慢插入速度。如果禁用,则已过期的数据部分将写入默认卷,然后立即移动到TTL卷。
load_balancing - 磁盘平衡的策略,round_robin或least_used。
least_used_ttl_ms - 配置更新所有磁盘上可用空间的超时时间(以毫秒为单位)(0表示始终更新,-1表示从不更新,默认为60000)。注意,如果磁盘只能由ClickHouse使用并且不受在线文件系统调整大小/缩小的影响,则可以使用-1,在所有其他情况下不建议这样做,因为这最终会导致空间分布不正确。
prefer_not_to_merge — 不应使用此设置。禁用此卷上的数据部分合并(这有害并导致性能下降)。当启用此设置时(请不要这样做),不允许在此卷上合并数据(这不好)。这允许(但不需要)控制ClickHouse与慢盘的工作方式(不建议使用此设置)。
volume_priority — 定义填充卷的优先级(顺序)。数值越低,优先级越高。参数值应为自然数,从1到N(最低优先级)连续覆盖,不要跳过任何数字。如果所有卷都被标记了,它们将按给定的顺序优先。如果只有部分卷被标记,没有标记的卷具有最低优先级,并且它们按配置中定义的顺序优先。如果没有卷被标记,它们的优先级将按照它们在配置中声明的顺序相应设置。两个卷不能有相同的优先级值。
示例
<storage_configuration>
...
<policies>
<hdd_in_order> <!-- policy name -->
<volumes>
<single> <!-- volume name -->
<disk>disk1</disk>
<disk>disk2</disk>
</single>
</volumes>
</hdd_in_order>
<moving_from_ssd_to_hdd>
<volumes>
<hot>
<disk>fast_ssd</disk>
<max_data_part_size_bytes>1073741824</max_data_part_size_bytes>
</hot>
<cold>
<disk>disk1</disk>
</cold>
</volumes>
<move_factor>0.2</move_factor>
</moving_from_ssd_to_hdd>
<small_jbod_with_external_no_merges>
<volumes>
<main>
<disk>jbod1</disk>
</main>
<external>
<disk>external</disk>
</external>
</volumes>
</small_jbod_with_external_no_merges>
</policies>
...
</storage_configuration>
在给出的例子中, hdd_in_order 策略实现了循环方法。因此这个策略只定义了一个卷(single),数据片段会以循环的顺序全部存储到它的磁盘上。当有多个类似的磁盘挂载到系统上,但没有配置 RAID 时,这种策略非常有用。请注意一个每个独立的磁盘驱动都并不可靠,您可能需要用3份或更多的复制份数来补偿它。
如果在系统中有不同类型的磁盘可用,可以使用 moving_from_ssd_to_hdd。hot 卷由 SSD 磁盘(fast_ssd)组成,这个卷上可以存储的数据片段的最大大小为 1GB。所有大于 1GB 的数据片段都会被直接存储到 cold 卷上,cold 卷包含一个名为 disk1 的 HDD 磁盘。 同样,一旦 fast_ssd 被填充超过 80%,数据会通过后台进程向 disk1 进行转移。
存储策略中卷的枚举顺序是很重要的。因为当一个卷被充满时,数据会向下一个卷转移。磁盘的枚举顺序同样重要,因为数据是依次存储在磁盘上的。
策略应用
CREATE TABLE table_with_non_default_policy (
EventDate Date,
OrderID UInt64,
BannerID UInt64,
SearchPhrase String
) ENGINE = MergeTree
ORDER BY (OrderID, BannerID)
PARTITION BY toYYYYMM(EventDate)
SETTINGS storage_policy = 'moving_from_ssd_to_hdd'
参考文档
https://clickhouse.com/docs/en/engines/table-engines/mergetree-family/mergetree#table_engine-mergetree-multiple-volumes
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?