Clickhouse 使用简介及MergeTree存储分析

建表,排序,索引及注意事项

https://clickhouse.tech/docs/zh/operations/table_engines/mergetree/

CREATE TABLE [IF NOT EXISTS] [db.]table_name [ON CLUSTER cluster]
(
    name1 [type1] [DEFAULT|MATERIALIZED|ALIAS expr1],
    name2 [type2] [DEFAULT|MATERIALIZED|ALIAS expr2],
    ...
    INDEX index_name1 expr1 TYPE type1(...) GRANULARITY value1,
    INDEX index_name2 expr2 TYPE type2(...) GRANULARITY value2
) ENGINE = MergeTree()
[PARTITION BY expr]
[ORDER BY expr]
[PRIMARY KEY expr]
[SAMPLE BY expr]
[SETTINGS name=value, ...]

我们以 (CounterID, Date) 以主键。排序好的索引的图示会是下面这样:

image.png

如果指定查询如下:

  • CounterID in ('a', 'h'),服务器会读取标记号在 [0, 3)[6, 8) 区间中的数据。
  • CounterID IN ('a', 'h') AND Date = 3,服务器会读取标记号在 [1, 3)[7, 8) 区间中的数据。
  • Date = 3,服务器会读取标记号在 [1, 10] 区间中的数据。

上面例子可以看出使用索引通常会比全表描述要高效。

稀疏索引会引起额外的数据读取。当读取主键单个区间范围的数据时,每个数据块中最多会多读 index_granularity * 2 行额外的数据。大部分情况下,当 index_granularity = 8192 时,ClickHouse的性能并不会降级。

稀疏索引让你能操作有巨量行的表。因为这些索引是常驻内存(RAM)的。

ClickHouse 不要求主键惟一。所以,你可以插入多条具有相同主键的行。

主键的选择

https://clickhouse.tech/docs/zh/operations/table_engines/mergetree/#zhu-jian-de-xuan-ze

主键中列的数量并没有明确的限制。依据数据结构,你应该让主键包含多些或少些列。这样可以:

  • 改善索引的性能。

    如果当前主键是 (a, b) ,然后加入另一个 c 列,满足下面条件时,则可以改善性能: - 有带有 c 列条件的查询。 - 很长的数据范围( index_granularity 的数倍)里 (a, b) 都是相同的值,并且这种的情况很普遍。换言之,就是加入另一列后,可以让你的查询略过很长的数据范围。

  • 改善数据压缩。

    ClickHouse 以主键排序片段数据,所以,数据的一致性越高,压缩越好。

  • CollapsingMergeTree 和 SummingMergeTree 引擎里,数据合并时,会有额外的处理逻辑。

    在这种情况下,指定一个跟主键不同的 排序键 也是有意义的。

长的主键会对插入性能和内存消耗有负面影响,但主键中额外的列并不影响 SELECT 查询的性能。

选择跟排序键不一样主键

指定一个跟排序键(用于排序数据片段中行的表达式) 不一样的主键(用于计算写到索引文件的每个标记值的表达式)是可以的。 这种情况下,主键表达式元组必须是排序键表达式元组的一个前缀。

分区

https://clickhouse.tech/docs/zh/operations/table_engines/custom_partitioning_key/

(
    VisitDate Date, 
    Hour UInt8, 
    ClientID UUID
)
ENGINE = MergeTree()
PARTITION BY toYYYYMM(VisitDate)
ORDER BY Hour;

分区键也可以是表达式元组(类似 [主键]例如:

ENGINE = ReplicatedCollapsingMergeTree('/clickhouse/tables/name', 'replica1', Sign)
PARTITION BY (toMonday(StartDate), EventType)
ORDER BY (CounterID, StartDate, intHash32(UserID));

上例中,我们设置按一周内的事件类型分区。

新数据插入到表中时,这些数据会存储为按主键排序的新片段(块)。插入后 10-15 分钟,同一分区的各个片段会合并为一整个片段。

可以通过 [system.parts]表查看表片段和分区信息。例如,假设我们有一个 visits 表,按月分区。对 system.parts 表执行 SELECT

SELECT 
    partition,
    name, 
    active
FROM system.parts 
WHERE table = 'visits'
──partition─┬─name───────────┬─active─┐
│ 201901    │ 201901_1_3_1   │      0 │
│ 201901    │ 201901_1_9_2   │      1 │
│ 201901    │ 201901_8_8_0   │      0 │
│ 201901    │ 201901_9_9_0   │      0 │
│ 201902    │ 201902_4_6_1   │      1 │
│ 201902    │ 201902_10_10_0 │      1 │
│ 201902    │ 201902_11_11_0 │      1 │
└───────────┴────────────────┴────────┘

partition 列存储分区的名称。此示例中有两个分区:201901201902。在 [ALTER ... PARTITION]语句中你可以使用该列值来指定分区名称。

name 列为分区中数据片段的名称。在 [ALTER ATTACH PART] 语句中你可以使用此列值中来指定片段名称。

这里我们拆解下第一部分的名称:201901_1_3_1

  1. 201901 是分区名称。
  2. 1 是数据块的最小编号。
  3. 3 是数据块的最大编号。
  4. 1 是块级别(即在由块组成的合并树中,该块在树中的深度)。

注意

旧类型表的片段名称为:20190117_20190123_2_2_0(最小日期 - 最大日期 - 最小块编号 - 最大块编号 - 块级别)。

active 列为片段状态。1 激活状态;0 非激活状态。非激活片段是那些在合并到较大片段之后剩余的源数据片段。损坏的数据片段也表示为非活动状态。

正如在示例中所看到的,同一分区中有几个独立的片段(例如,201901_1_3_1201901_1_9_2)。这意味着这些片段尚未合并。ClickHouse 大约在插入后15分钟定期报告合并操作,合并插入的数据片段。此外,你也可以使用 OPTIMIZE 语句直接执行合并。例:

OPTIMIZE TABLE visits PARTITION 201902;
┌─partition─┬─name───────────┬─active─┐
│ 201901    │ 201901_1_3_1   │      0 │
│ 201901    │ 201901_1_9_2   │      1 │
│ 201901    │ 201901_8_8_0   │      0 │
│ 201901    │ 201901_9_9_0   │      0 │
│ 201902    │ 201902_4_6_1   │      0 │
│ 201902    │ 201902_4_11_2  │      1 │
│ 201902    │ 201902_10_10_0 │      0 │
│ 201902    │ 201902_11_11_0 │      0 │
└───────────┴────────────────┴────────┘

非激活片段会在合并后的10分钟左右删除。

查看片段和分区信息的另一种方法是进入表的目录:/var/lib/clickhouse/data//

/。例如:

/var/lib/clickhouse/data/default/visits$ ls -l
total 40
drwxr-xr-x 2 clickhouse clickhouse 4096 Feb  1 16:48 201901_1_3_1
drwxr-xr-x 2 clickhouse clickhouse 4096 Feb  5 16:17 201901_1_9_2
drwxr-xr-x 2 clickhouse clickhouse 4096 Feb  5 15:52 201901_8_8_0
drwxr-xr-x 2 clickhouse clickhouse 4096 Feb  5 15:52 201901_9_9_0
drwxr-xr-x 2 clickhouse clickhouse 4096 Feb  5 16:17 201902_10_10_0
drwxr-xr-x 2 clickhouse clickhouse 4096 Feb  5 16:17 201902_11_11_0
drwxr-xr-x 2 clickhouse clickhouse 4096 Feb  5 16:19 201902_4_11_2
drwxr-xr-x 2 clickhouse clickhouse 4096 Feb  5 12:09 201902_4_6_1
drwxr-xr-x 2 clickhouse clickhouse 4096 Feb  1 16:48 detached
  • 物理存储
[root@izm5eja0h0h0p04ol7ijrpz 20200319_10_10_0]# pwd
/var/lib/clickhouse/data/logs/logs/20200319_10_10_0
[root@izm5eja0h0h0p04ol7ijrpz 20200319_10_10_0]# ll
total 104
-rw-r----- 1 clickhouse clickhouse 831 Mar 19 23:01 checksums.txt
-rw-r----- 1 clickhouse clickhouse 234 Mar 19 23:01 columns.txt
-rw-r----- 1 clickhouse clickhouse  34 Mar 19 23:01 content.bin
-rw-r----- 1 clickhouse clickhouse  48 Mar 19 23:01 content.mrk2
-rw-r----- 1 clickhouse clickhouse   1 Mar 19 23:01 count.txt
-rw-r----- 1 clickhouse clickhouse  30 Mar 19 23:01 create_time.bin
-rw-r----- 1 clickhouse clickhouse  48 Mar 19 23:01 create_time.mrk2
-rw-r----- 1 clickhouse clickhouse  38 Mar 19 23:01 ip.bin
-rw-r----- 1 clickhouse clickhouse  48 Mar 19 23:01 ip.mrk2
-rw-r----- 1 clickhouse clickhouse  32 Mar 19 23:01 level.bin
-rw-r----- 1 clickhouse clickhouse  48 Mar 19 23:01 level.mrk2
-rw-r----- 1 clickhouse clickhouse  34 Mar 19 23:01 log_file_name.bin
-rw-r----- 1 clickhouse clickhouse  48 Mar 19 23:01 log_file_name.mrk2
-rw-r----- 1 clickhouse clickhouse   8 Mar 19 23:01 minmax_partition_date.idx
-rw-r----- 1 clickhouse clickhouse   4 Mar 19 23:01 partition.dat
-rw-r----- 1 clickhouse clickhouse  30 Mar 19 23:01 partition_date.bin
-rw-r----- 1 clickhouse clickhouse  48 Mar 19 23:01 partition_date.mrk2
-rw-r----- 1 clickhouse clickhouse  34 Mar 19 23:01 primary.idx
-rw-r----- 1 clickhouse clickhouse  34 Mar 19 23:01 service_name.bin
-rw-r----- 1 clickhouse clickhouse  48 Mar 19 23:01 service_name.mrk2
-rw-r----- 1 clickhouse clickhouse  33 Mar 19 23:01 thread_name.bin
-rw-r----- 1 clickhouse clickhouse  48 Mar 19 23:01 thread_name.mrk2
-rw-r----- 1 clickhouse clickhouse  30 Mar 19 23:01 timestamp.bin
-rw-r----- 1 clickhouse clickhouse  48 Mar 19 23:01 timestamp.mrk2
-rw-r----- 1 clickhouse clickhouse  27 Mar 19 23:01 trace_id.bin
-rw-r----- 1 clickhouse clickhouse  48 Mar 19 23:01 trace_id.mrk2

文件夹 '201901_1_1_0','201901_1_7_1' 等是片段的目录。每个片段都与一个对应的分区相关,并且只包含这个月的数据(本例中的表按月分区)。

detached 目录存放着使用 DETACH 语句从表中分离的片段。损坏的片段也会移到该目录,而不是删除。服务器不使用detached目录中的片段。可以随时添加,删除或修改此目录中的数据 – 在运行 ATTACH 语句前,服务器不会感知到。

注意
在操作服务器时,你不能手动更改文件系统上的片段集或其数据,因为服务器不会感知到这些修改。对于非复制表,可以在服务器停止时执行这些操作,但不建议这样做。对于复制表,在任何情况下都不要更改片段文件。

注意
那些有相同分区表达式值的数据片段才会合并。这意味着 你不应该用太精细的分区方案(超过一千个分区)。否则,会因为文件系统中的文件数量和需要找开的文件描述符过多,导致 SELECT 查询效率不佳。

弹性支持

  • click house elastic (不支持弹性架构) https://clickhouse.yandex/docs/en/development/architecture

ClickHouse 集群由独立的分片组成,每一个分片由多个副本组成。集群不是弹性的,因此在添加新的分片后,数据不会自动在分片之间重新平衡。相反,集群负载将变得不均衡。该实现为你提供了更多控制,对于相对较小的集群,例如只有数十个节点的集群来说是很好的。但是对于我们在生产中使用的具有数百个节点的集群来说,这种方法成为一个重大缺陷。我们应该实现一个表引擎,使得该引擎能够跨集群扩展数据,同时具有动态复制的区域,这些区域能够在集群之间自动拆分和平衡。

The ClickHouse cluster consists of independent shards, and each shard consists of replicas. The cluster is not elastic, so after adding a new shard, data is not rebalanced between shards automatically. Instead, the cluster load will be uneven. This implementation gives you more control, and it is fine for relatively small clusters such as tens of nodes. But for clusters with hundreds of nodes that we are using in production, this approach becomes a significant drawback. We should implement a table engine that will span its data across the cluster with dynamically replicated regions that could be split and balanced between clusters automatically.

表结构设计参考

CREATE TABLE logs.logs ( 
    ip String, 
    log_file_name String,
    service_name String,
    thread_name String,
    trace_id String,
    timestamp DateTime,
    partition_date UInt32,
    level String, 
    content String,
    create_time DateTime
) ENGINE = MergeTree() PARTITION BY partition_date
ORDER BY (create_time,service_name, trace_id)
SETTINGS index_granularity = 8192

Distributed(cluster_name, db_name, table_name[, sharding_key])

sharding_key=rand()随机写

CREATE TABLE logs.logs_view
( 
    ip String, 
    log_file_name String,
    service_name String,
    thread_name String,
    trace_id String,
    timestamp DateTime,
    partition_date UInt32,
    level String, 
    content String,
    create_time DateTime
)ENGINE =Distributed(log_collector,logs, logs, rand());
  • 新建数据
insert into logs.logs(ip,log_file_name,service_name,thread_name,partition_date,level,content,create_time,timestamp)values('192.168.1.1','log.log','sparrow','thread',20200319,'level','content','2020-03-19 22:59:00','2020-03-19 22:58:00') ;

删除分区 delete parition

https://clickhouse.tech/docs/zh/query_language/alter/#alter_manipulations-with-partitions

  ALTER TABLE testdb.testtable DROP PARTITION '201907'

性能及使用建议

性能测试对比

https://clickhouse.tech/benchmark.html

https://clickhouse.yandex/docs/en/introduction/performance/

数据的写入性能

我们建议每次写入不少于1000行的批量写入,或每秒不超过一个写入请求。当使用tab-separated格式将一份数据写入到MergeTree表中时,写入速度大约为50到200MB/s。如果您写入的数据每行为1Kb,那么写入的速度为50,000到200,000行每秒。如果您的行更小,那么写入速度将更高。为了提高写入性能,您可以使用多个INSERT进行并行写入,这将带来线性的性能提升。

常用命令行

clickhouse-client -h 192.168.1.195 -u root --password=123456

clickhouse-client -m
clickhouse-client --multiline //开启多行模式
create database logs
show databases;

select * from system.clusters; //查询集群状态

安装配置

  • click house config.xml


    
        trace
        /var/log/clickhouse-server/clickhouse-server.log
        /var/log/clickhouse-server/clickhouse-server.err.log
        1000M
        10
    
    8123
    9000
    9009
    my-host-name

    0.0.0.0
    4096
    3000
    1000
    0
    21474836480
    25769803776
    /data/clickhouse/
    /data/clickhouse/tmp/
    /data/clickhouse/user_files/
    users.xml
    default
    default

    
    
    
    3600
    /data/clickhouse/format_schemas/
    /etc/clickhouse-server/metrika.xml


metrika.xml



     
        
            true
            
                192.168.2.254
                9000
                root
                123456
            
        

        
            true
            
                122.168.2.255
                9000
                log_collector
                123456
            
        
    




  
    192.168.209.78
    2181
  
  
    192.168.192.166
    2181
  
  
    192.168.209.79
    2181
  
  
    192.168.192.179
    2181
  
  
    192.168.209.92
    2181
  
  
    192.168.209.94
    2181
  
  
    192.168.192.184
    2181
  



    logs_01




   ::/0





  10000000000
  0.01
  lz4




users.xml



    
        
            25769803776
            0
            random
        

        
            1
            25769803776
            0
            random
        
    

    
        
            
            
                ::/0
            
            default
            default
        

       
            123456
            
                ::/0
            
            default
            default
            
                  logs
            
        
        
        
            
            
                ::1
                127.0.0.1
            
            readonly
            default
        
    

    
        
            
                3600
                0
                0
                0
                0
                0
            
        
    

服务启动

sudo systemctl start 
clickhouse-server.service

你可能感兴趣的:(Clickhouse 使用简介及MergeTree存储分析)