一、前言

名称

版本

ClickHouse

21.9.5.16

Prometheus

2.32.1

Grafana

9.2.4

prom2click

0.2

1、概述

我们都知道,Prometheus的数据存储一般都是存放本地的 TSDB (时序数据库)中,使得Prometheus部署方便快捷,然而原生的 TSDB 对于大数据量的保存及查询支持不太友好,该数据库不能保证可靠性,且无法支持Prometheus集群架构。

对于这方面的完善,Prometheus提供了remote_write和remote_read的特性,支持将数据存储到远端和从远端读取数据的功能。当配置remote_write特性后,Prometheus会将采集到的指标数据通过HTTP的形式发送给适配器(Adaptor),由适配器进行数据的写入。而remote_read特性则会向适配器发起查询请求,适配器根据请求条件从第三方存储服务中获取响应的数据。

clickhouse开启Prometheus clickhouse presto_prometheus

2、Metrics的持久化

其实监控不仅仅是体现在可以实时掌握系统运行情况,及时报警这些。而且监控所采集的数据,在以下几个方面是有价值的

  1. 资源的审计和计费。这个需要保存一年甚至多年的数据的。
  2. 故障责任的追查
  3. 后续的分析和挖掘,甚至是利用AI,可以实现报警规则的设定的智能化,故障的根因分析以及预测某个应用的qps的趋势,提前HPA等,当然这是现在流行的AIOPS范畴了。

3、Prometheus 数据持久化方案

  • AppOptics: write
  • AWS Timestream: read and write
  • Azure Data Explorer: read and write
  • Azure Event Hubs: write
  • Chronix: write
  • Cortex: read and write
  • CrateDB: read and write
  • Elasticsearch: write
  • Gnocchi: write
  • Google BigQuery: read and write
  • Google Cloud Spanner: read and write
  • Grafana Mimir: read and write
  • Graphite: write
  • InfluxDB: read and write
  • Instana: write
  • IRONdb: read and write
  • Kafka: write
  • M3DB: read and write
  • New Relic: write
  • OpenTSDB: write
  • PostgreSQL/TimescaleDB: read and write
  • QuasarDB: read and write
  • SignalFx: write
  • Splunk: read and write
  • Sysdig Monitor: write
  • TiKV: read and write
  • Thanos: read and write
  • VictoriaMetrics: write
  • Wavefront: write
  • clickhouse: read and write

选型方案需要具备以下几点
1、满足数据的安全性,需要支持容错,备份
2、写入性能要好,支持分片
3、技术方案不复杂
4、用于后期分析的时候,查询语法友好
5、grafana读取支持,优先考虑
6、需要同时支持读写

  • 基于以上的几点,clickhouse满足我们使用场景。
    Clickhouse是一个高性能的列式数据库,因为侧重于分析,所以支持丰富的分析函数。

下面是Clickhouse官方推荐的几种使用场景:

  • Web and App analytics
  • Advertising networks and RTB
  • Telecommunications
  • E-commerce and finance
  • Information security
  • Monitoring and telemetry
  • Time series
  • Business intelligence
  • Online games
  • Internet of Things

4、Prometheus设计架构

  • 将prometheus的metric监控及告警数据存入到clickhouse里面,存储的prometheus数据主要是做统计汇总,采用GraphiteMergeTree 引擎。它能减少存储空间,同时能提高Graphite数据的查询效率。

clickhouse开启Prometheus clickhouse presto_clickhouse_02

5、ClickHouse 双分片双副本

  • 在每个节点创建一个数据表,作为一个数据分片,分布表同时负责分片和副本的数据写入工作。分布从2个Shard中随机取一个节点进行访问。其中任何单节点异常时,写入和查询都能保障数据完整性,高可用,业务无感知。

clickhouse开启Prometheus clickhouse presto_数据_03

二、Prometheus Store ClickHouse

1、ClickHouse配置

  • 这里主要是讲ClickHouse配置,以及Prometheus 如何配置,至于搭建请各位小伙伴自行搭建环境

编辑ClickHouse config.xml配置文件,添加配置一个配置一个graphite_rollup (如果不配置的话,创表语句会执行失败的),具体参数含义参考clickhouse官方文档:GraphiteMergeTree

<graphite_rollup>
        <path_column_name>tags</path_column_name>
        <time_column_name>ts</time_column_name>
        <value_column_name>val</value_column_name>
        <version_column_name>updated</version_column_name>
        <default>
                <function>avg</function>
                <retention>
                        <age>0</age>
                        <precision>10</precision>
                </retention>
                <retention>
                        <age>86400</age>
                        <precision>30</precision>
                </retention>
                <retention>
                        <age>172800</age>
                        <precision>300</precision>
                </retention>
        </default>
    </graphite_rollup>

clickhouse开启Prometheus clickhouse presto_sed_04

完整 ClickHouse 配置见:
链接:https://pan.baidu.com/s/1BJYgwEnhTBmF-dD36cSS6Q
提取码:C2hp

2、ClickHouse 创建存储表

需要将prometheus的metric数据存入到clickhouse里面,首先需要做的是创建一张表,将metric数据存入到表内,prometheus的数据格式是key-value格式。

-- 创建 metrics库
CREATE DATABASE IF NOT EXISTS metrics ON CLUSTER default ;
-- 创建 samples存储表(新的SQL建表语法)
CREATE TABLE IF NOT EXISTS  metrics.samples ON CLUSTER default 
(
    `date` Date DEFAULT toDate(0),
    `name` String,
    `tags` Array(String),
    `val` Float64,
    `ts` DateTime,
    `updated` DateTime DEFAULT now()
)
ENGINE = ReplicatedGraphiteMergeTree('/clickhouse/tables/{database}/{table}/{shard}', '{replica}','graphite_rollup')
PARTITION BY  (date)
ORDER BY   (name, tags, ts)
PRIMARY KEY (name, tags, ts)
SETTINGS index_granularity = 8192;
-- 创建 samples存储表(弃用SQL建表语法)
CREATE TABLE  IF NOT EXISTS  metrics.samples  ON CLUSTER default 
(
    `date` Date DEFAULT toDate(0),
    `name` String,
    `tags` Array(String),
    `val` Float64,
    `ts` DateTime,
    `updated` DateTime DEFAULT now()
)
ENGINE = ReplicatedGraphiteMergeTree('/clickhouse/tables/{database}/{table}/{shard}', '{replica}', date, (name, tags, ts), 8192, 'graphite_rollup');
--- 创建samples 分布式表SQL:
CREATE TABLE metrics.samples_all  ON CLUSTER default
AS metrics.samples
ENGINE = Distributed(default, metrics, samples,  sipHash64(name));

以上建表需注意,我这边环境是ClickHouse 集群版,ON CLUSTER 集群名称;

clickhouse开启Prometheus clickhouse presto_数据_05


clickhouse开启Prometheus clickhouse presto_sed_06

三、Prometheus 配置

安装Prometheus并配置远程读写url,这里需要注意ip写prome2click安装机器的ip和端口。

remote_write:
     - url: "http://localhost:9201/write"

remote_read:
     - url: "http://localhost:9201/read"

clickhouse开启Prometheus clickhouse presto_sed_07

四、Prome2click 配置

1、下载源码编译

  • 安装 go 和 glide
wget  https://github.com/iyacontrol/prom2click.git

make get-deps

make build

./bin/prom2click
  • 由于编译中很容易出现各种问题,而且要准备go环境,这边已经编译好,需要的小伙伴自行下载,详见百度网盘

链接:https://pan.baidu.com/s/1BJYgwEnhTBmF-dD36cSS6Q
提取码:C2hp

2、创建ClickHouse 相关账号

-- 创建Prometheus账号
CREATE USER prometheus IDENTIFIED WITH sha256_password BY 'default@2022' HOST ANY ON CLUSTER default;
-- 授权
grant all on metrics.* to prometheus ON CLUSTER default;

clickhouse开启Prometheus clickhouse presto_数据_08

3、启动 Prome2click

1、创建目录,将 prom2click 包拷贝过去

mkdir -p /app/prom2

2、创建system管理脚本,方便管理(ck如果设置的是无分片,也就是1分片,写local本地表),需修改clickhouse 的ip地址和端口

  • List item
cat << EOF >/usr/lib/systemd/system/prom2click-server.service
[Unit]
Description=prom2click-server
After=syslog.target
After=network.target

[Service]
Type=simple
User=prometheus
Group=prometheus
WorkingDirectory=/app/prom2
ExecStart=/app/prom2/prom2click -ch.dsn=tcp://172.17.209.4:9200?database=metrics&username=prometheus&password=default@2022&read_timeout=10&write_timeout=20&alt_hosts=172.17.209.5:9200
Restart=always

[Install]
WantedBy=multi-user.target
EOF

3、reload systemctl

systemctl daemon-reload

4、授权

chmod 754 /usr/lib/systemd/system/prom2click-server.service

5、启动

systemctl start prom2click-server.service

5、查看启动状态

-- 查看状态是否 running
systemctl status prom2click-server.service

-- 查看端口是否监听
netstat -lntp|grep 9201

clickhouse开启Prometheus clickhouse presto_clickhouse_09

五、验证

  • 写入验证

1、查询clickhouse metrics.samples表中数据是否有数据进去

SELECT count(1) FROM metrics.samples;

clickhouse开启Prometheus clickhouse presto_prometheus_10

  • 读取验证

数据呈现一致之后,我们可以试着停止Prometheus服务,同时删除本地data目录的监控数据,模拟Promthues数据丢失的情况后重启服务。重新打开Prometheus后,如果还可以正常查询到本地存储已删除的历史数据记录,则代表配置正常。

六、总结

Prometheus-Clickhuse-Adapter(Prom2click) 是一个将clickhouse作为prometheus 数据远程存储的适配器。

prometheus-clickhuse-adapter,该项目缺乏日志,对于一个实际生产的项目,是不够的,此外一些数据库连接细节实现的也不够完善

在实际使用过程中,要注意并发写入数据的数量,及时调整启动参数

1、 Table is in readonly mode ?

问题现象:由于存在大数据量的数据写入(200MB/s以上的写入速度),时常会在clickhouse-server的日志中看到Table is in readonly mode的告警信息。

问题原因:大体原因和zk的处理性能相关,随着写入数据量的增多,zk的log和snapshot文件会不断膨胀,有时就会出现zk服务不可用的情况,而clickhouse的ReplicatedMergeTree又强依赖于zk,一旦zk不可用,为了保证数据的一致性,系统就会进行“写保护”,出现上述提示。

解决办法

  • 方案1:调整use_minimalistic_part_header_in_zookeeper参数; 网上有些朋友说是调整这个参数可以减少写入zk日志的数据量,但因为我们使用的是21的版本,此版本默认这个参数已经是开启了,因此这个方案对我们实际无效。
  • 方案2:一个CH集群使用多个zk集群来提供服务; 这属于压力转移的策略,我们最后也无奈使用了这种办法,当然能解决问题,但带来的副作用就是zk集群运维管理成本的上升。

2、优化

1、表大小

-- 查看 samples 表占用大小,以及压缩大小
SELECT
	table AS `表名`,
	sum(rows) AS `总行数`,
	formatReadableSize(sum(data_uncompressed_bytes)) AS `原始大小`,
	formatReadableSize(sum(data_compressed_bytes)) AS `压缩大小`,
	round((sum(data_compressed_bytes) / sum(data_uncompressed_bytes)) * 100,
	0) AS `压缩率`
FROM
	system.parts
WHERE
	table IN ('samples')
GROUP BY
table;

clickhouse开启Prometheus clickhouse presto_sed_11

这个只是看的单台分片机器的大小(我们生产环境是 2shard x 2replica),可以看到压缩效率很大,实际占用才800G左右,这还是存储了2021-当前的数据。可以适当的清理一下之前老的数据。

2、清理分区

1、查看分区大小
-- 查看分区详细占用大小
SELECT
	partition AS `分区`,
	sum(rows) AS `总行数`,
	formatReadableSize(sum(data_uncompressed_bytes)) AS `原始大小`,
	formatReadableSize(sum(data_compressed_bytes)) AS `压缩大小`,
	round((sum(data_compressed_bytes) / sum(data_uncompressed_bytes)) * 100,
	0) AS `压缩率`
FROM
	system.parts
WHERE
	(database IN ('metrics'))
	AND (table IN ('samples'))
	AND (partition LIKE '202%')
GROUP BY
	partition
ORDER BY
	partition ASC;

clickhouse开启Prometheus clickhouse presto_clickhouse_12

删除 2021 年整年的分区,只保存 2022年就可以,理论上也不需要用到这么久,可适当清理历史数据(我们在使用时候发现,如果历史监控数据保存时间过长,会给clickhouse带来压力,查询以前的历史数据会很慢,而且ck所在物理服务器CPU、磁盘io压力会非常大,所以有能力可以使用SSD,而且clickhouse最好没有其它业务使用,只单独给 Prometheus 这一套业务使用,不然很容易影响其它业务。)

2、删除历史分区
-- 删除指定分区
ALTER TABLE metrics.samples ON CLUSTER bdmp_ck_cluster DROP PARTITION (202110);
ALTER TABLE metrics.samples ON CLUSTER bdmp_ck_cluster DROP PARTITION (202111);
ALTER TABLE metrics.samples ON CLUSTER bdmp_ck_cluster DROP PARTITION (202112);

clickhouse开启Prometheus clickhouse presto_sed_13

-- 批量删除分区,数据量太大了删除会报错,还是用上面的方法吧...
ALTER TABLE metrics.samples ON CLUSTER bdmp_ck_cluster DELETE WHERE date <= (202201);

clickhouse开启Prometheus clickhouse presto_prometheus_14

3、如果觉得每次都要删除分区太麻烦,可以给表加上 ttl过期时间

-- 保存一年
ALTER TABLE metrics.samples ON CLUSTER bdmp_ck_cluster MODIFY TTL date + INTERVAL 1 YEAR;
-- 保存 90天
ALTER TABLE metrics.samples ON CLUSTER bdmp_ck_cluster MODIFY TTL date + INTERVAL 90 DAY;
-- 保存6个月
ALTER TABLE metrics.samples ON CLUSTER bdmp_ck_cluster MODIFY TTL date + INTERVAL 6 MONTH;
-- 或者是在建表的时候加上 (保存1年)
CREATE TABLE IF NOT EXISTS  metrics.samples ON CLUSTER bdmp_ck_cluster 
(
    `date` Date DEFAULT toDate(0),
    `name` String,
    `tags` Array(String),
    `val` Float64,
    `ts` DateTime,
    `updated` DateTime DEFAULT now()
)
ENGINE = ReplicatedGraphiteMergeTree('/clickhouse/tables/{database}/{table}/{shard}', '{replica}','graphite_rollup')
PARTITION BY  (date)
ORDER BY (name, tags, ts)
TTL date + toIntervalYEAR(1)
PRIMARY KEY (name, tags, ts)
SETTINGS index_granularity = 8192;