苏宁基于ClickHouse的大数据全链路监控实践

2020 年 8 月 28 日

苏宁基于ClickHouse的大数据全链路监控实践

简介


ClickHouse 是一款优秀的 OLAP 分析引擎,尤其是在单表分析 、Colocate Join 方面性能表现尤为突出。ClickHouse 之所以在众多的 OLAP 分析引擎中成为佼佼者,主要是因为它具备以下特点:列式存储、LSM-Tree 存储引擎、向量化执行引擎、异步 Merge 和 Mutation 机制、并发 MPP+ SMP 等。


目前,ClickHouse 在苏宁大数据的指标和标签的应用较多,从技术层面来看,主要解决的场景有:高基数的数据分析、精确去重、交互式分析、多变模式查询、大宽表分析、时序化数据存储、实时聚合的物化视图等。从业务层面来看,主要应用的场景有:新买家、老买家、复购、留存、实时用户画像、人群包圈选等。而基于 ClickHouse 的 RoaringBitmap 方案,保证了以上场景数据分析的实时和高效。


在 ClickHouse 监控方面,目前市面上提供的可适配方案不多,常用的有 Prometheus +Grafana+ClickHouse_Exporter 组合的方式,可通过提供的 Dashboards 来监控集群状况,但需要安装 Prometheus 和 ClickHouse_Exporter,不编译的话还需要安装 GO 环境和 Docker,整个框架过重,成本过高,对个性化的监控也不支持。还有一些其他监控组件如 Graphite + Grafana,在这里就不做介绍。我们将 ClickHouse 融入苏宁全链路监控生态体系,在完善监控体系的同时,也支撑了个性化的监控,进一步拓展了全链路监控平台的深度和广度。


苏宁大数据全链路监控平台


1. 苏宁全链路监控平台介绍



图 2-1 全链路监控架构


苏宁大数据中心数据中台有一整套完善的指标建设体系,包含了指标生命周期管理、指标分析体系以及数据快速可视化平台,数据分析时跨越可视化平台、指标服务平台及 OLAP 分析引擎三大平台,查询链路较长,如果没有一套完整的全链路监控分析平台,对于定位问题会存在较大的困难。全链路监控整体的设计思想是将页面的每次 http 请求生成唯一的流水号(serialId),后续每访问一次指标管理系统,生成唯一的 traceId,每次调用 OLAP 接口生成唯一的 olapId,这样就形成 1 个流水号对应多个 traceId,关联对应后续多个 olapId,形成一个树状请求,得到一个完整的请求链路。


具体设计如下:


(1)报表设计系统后端针对报表前端的每次请求生成唯一 traceId,针对请求的每一步生成层级关系的 spanId,并向指标管理系统透传 traceId 和对应的 spanId。


(2)指标管理系统接受请求后,根据梳理的查询权重计算方式生成“查询权重”priority,在报表设计系统的 spanId 基础上继续生成调用层级关系的 spanId,并向 OLAP 透传 traceId 和对应的 spanId。


(3)Spark RDD 实现将 Druid、PostGreSQL 和 ClickHouse 中的 queryId 与 Spark worker 中的 StageID 以及 JobID 关联起来。


(4)OLAP 接受请求后,在指标管理系统的 spanId 基础上继续生成调用层级关系的 spanId,并向 OLAP 引擎层透传 traceId 和对应的 spanId。


(5)OLAP 分析引擎层,通过打通 traceId 和各自分析引擎执行路径的方式,实现跟踪各执行计划、执行路径的耗时。例如,可通过 bigQueryId 与 Druid 关联,而 PostGreSQL 和 ClickHouse 则可以通过 traceId 映射到引擎内部的方式进行关联。


2. 如何实现将 ClickHouse 纳入到全链路监控平台


ClickHouse 全链路监控覆盖范围较广,包括:查询涉及到的节点、分片、父查询和子查询的关系、在各个节点的查询耗时、请求内存使用、高峰使用内存、CPU 使用数、查询行数、MergeTree 使用状况、查询方式(TCP/HTTP)以及参与查询线程数等。


在调用 ClickHouse 提供服务查询(spark-jdbc)的时候,如何将 traceId 透传给 ClickHouse 的 query_id 呢?


实现全链路监控,主要是通过 traceId 贯穿整个链路。表 system.processes 和表 system.query_log 中的 query_id 是随机生成的,ClickHouse 的 query_id 支持自定义,可将自定义的 query_id 映射到系统自生成的 query_id 上,这样 ClickHouse 内部的监控就能与全链路打通,具体操作如下:


ClickHouse-client --port 1***5 --time --format=Null --query="select count() from aggr_member" --query_id="suning20200706“ echo 'select count() from aggr***member' | curl 'http://localhost:8**3/?query_id=suning2020&query=' --data-binary @-
复制代码


ClickHouse 慢查询监控


1. 实时慢查询监控



图 3-1 实时慢查询监控


父节点查询 ID(initial_query_id)是从上游系统传入的 traceId,此次查询的所有子查询均可根据 traceId 获取,可以实时分析某次查询在集群中各个节点的状态,其中包括查询 query_id 的父子关系及对应的节点信息、各个节点的查询脚本、查询耗时、读取的行数、请求使用的内存、高峰使用的内存、参与查询的线程数、user、ProfileEvents、Settings 等。



图 3-2 单次查询内存/CPU/MergeTree/耗时 TOPN 监控


图 3-2 展示各集群中的慢查询 TOPN、单次查询内存使用 TOPN、单次查询 CPU 使用数 TOPN、MergeTree 耗时 TOPN,支持对超过预期阈值的查询进行告警。


2. 历史慢查询监控



图 3-3 历史慢查询监控


(1)ClickHouse 默认的情况下 query_log 表是未开启的状态,必须将其开启,修改配置文件 users.xml,路径为/etc/clickhouse-server/,新增配置项<log_queries>1</log_queries>,当查询日志服务器参数log_queries=1 时,ClickHouse 才会创建此表。


(2)每个查询在 query_log 表中会创建一条或两条记录,具体取决于查询的状态:


  • 如果查询执行成功,则会分别创建事件类型为1和2的两条记录;

  • 如果在查询处理期间发生错误,则会分别创建事件类型为1和4的两条记录;

  • 如果在查询启动之前发生错误,则会创建事件类型为3的单条记录。


(3) 表 query_log 中的记录,存储的是历史查询在集群中的各个节点的状态,其中包括查询 query_id 的父子关系及对应的节点信息、各个节点的查询脚本、查询开始时间、查询日期、查询时间、查询耗时、查询行数、查询结果的字节大小、请求使用的内存、高峰使用的内存、参与查询的线程数、堆栈跟踪以及查询异常信息等。


3. MergeTree 监控



图 3-4 MergeTree 基础表引擎


MergeTree 表中数据存储在 Part 中,当插入数据的时候,会将数据创建在一个新的 Part 中,Part 的数量代表着提交的频率。后台会进行异步的 Merge 过程,将小的 Part 进行合并,并且会相对均衡的平衡好合并速度和 Part 数量的关系。对于每个 Part 均会生成一个索引文件,索引文件存储的是每个索引块数据主键的 value 值。对于 MergeTree 的监控,主要监控 MergeTree 的异常情况,根据异常信息进行告警。


4. 慢查询归因分析


通过以上的监控,可以快速定位出慢查询。导致慢查询的原因可能有很多,可以从如下几个方面进行分析:


1)判断查询的数据是否存在 page cache 中,从 page cache 获取数据速度远高于磁盘。


2)高基数的聚合或排序对查询效率影响较大,JOIN 操作时应将小表放右边,分区字段不宜过多,导入数据时候最好对数据进行事先排序。


3)影响性能最关键的指标是 CPU 和内存,CPU 超过 70%则可能会出现大范围的查询超时。另外需要关闭虚拟内存,否则物理内存和虚拟内存可能会进行数据交换,从而导致查询变慢。


4)ClickHouse 对高并发支持不太友好,需要对单个查询的资源加以限制,否则会影响当前其它查询的执行效率。


以上是常规的慢查询原因分析,而有些复杂、高基数的查询可通过巧妙的设计方式,达到高效查询的目标。我们在基于 ClickHouse 计算会员新买家、老买家数、复购、留存等场景的时候发现,如果用会员 ID 进行 HASH 分片后再做 RoaringBitmap 计算,最后再将每个分片的计算结果汇总,其执行效率将提高数倍。另外在计算纯新买家和次新买家的时候,通过在子查询中使用 ClickHouse-CTE 的 WITH 方式,同样可以达到实时、高效的查询目标。


ClickHouse 集群状态监控


1. 集群、节点状态监控


可对集群、节点的查询状态进行监控,如成功次数、异常次数和失败次数,并且根据设定的阈值对失败或超时的查询进行预警。同时可对各个节点的连接数、CPU 使用率、内存使用率、FileOpen、根分区使用率以及最大分区使用率进行监控。


2. 集群、节点、分片 QPS 和连接数监控



图 4-1 集群、节点、分片 QPS 监控



图 4-2 集群、节点、分片连接数监控


ClickHouse 的计算和存储是一体式的,并未做资源隔离,为了提高系统的并发能力,可以将数据保存为多个副本,每个副本部署到不同的节点上,再通过 Chproxy 路由到不同的节点进行查询。为了保证集群的持续稳定、可用,需要对单个查询的资源以及集群最大支持的并发进行限制,具体方式如下:


1)集群同时支持的最大并发连接数可通过 Max_Concurrent_queries 来设置,默认为 100。


2)一个查询在单台服务上最大使用的内存可通过 Max_memory_usage 来设置。


3)单个节点上所有查询的最大内存限制是可通过 Max_memory_usage_for_all_queries 来设置。


4)单次查询的最长执行时间可通过 Max_execution_time 来设置。


3. 集群、节点、分片可用性监控


具体可以通过 HTTP API 监视服务器的可用性来实现。通过 HTTP GET 请求后,如果服务器可用,则返回 200 OK,否则返回异常消息。此处需要有个告警配置监控项,一旦监测到节点不可用,可及时通知相关技术人员进行维护,其中告警信息可通过短信、邮件等方式进行推送。


4. 全链路 Replicas Delay 监控



图 4-3 Replicas Delay 监控


(1)Random 分布式随机选取副本有四种算法:


  • Random:选取副本的默认方式,该算法主要是通过计算副本的错误数量,查询发送到出错最少的副本,但这种算法没有考虑到服务节点是否相邻的场景。

  • In order:选取副本的方式是根据配置中指定的顺序。

  • First or random:选择集合中第一个副本,如果第一个副本不可用,则随机进行副本选择。

  • Nearest hostname:每隔5分钟计算副本的错误数量,如果副本的错误数量最少,则将查询发送给它。


(2)副本允许的最长延迟时间,可通过参数 max_replica_delay_for_distributed_queries 来设置;副本的延迟时间,可以使用 HTTP resource /replicas-delay 来查询,不延迟则返回 200 OK,延迟则返回和默认时间的差距。


5. 全链路 Chproxy 监控信息



图 4-4 ClickHouse Manger 工作流程


ClickHouse 的 Http 代理和负载均衡器是 Chproxy,苏宁通过 ClickHouse Manger 来管理 Chproxy 组件的启动、停止、滚动升级以及监控,并通过 ZK 向 Chproxy 同步配置数据。ClickHouse 集群可以部署多个 Chproxy 实例,客户端连接 ClickHouse 集群的代理服务后,通过对查询 SQL 解析,智能的进行负载均衡。同时,Chproxy 也支持水平扩展。


Chproxy 能监控到的重点指标有:集群请求队列大小、远程客户端连接数、查询总请求数、取消请求数、被拒绝请求数、缓存命中情况、集群和节点健康状态等,苏宁全链路监控平台可对上述重点指标进行监控。


全链路监控的优势和展望


全链路监控平台拓展了我们监控系统能力的深度和广度,同时为 ClickHouse 的资源隔离和服务化提供了参考。全链路监控平台目前已经将数据应用层、SparkSQL 解析层、OLAP 路由加速层以及数据加速层全部贯穿,用户发起的请求在各个阶段的耗时一目了然。我们能把各个 OLAP 分析引擎内部执行的耗时,通过统一的 queryId 纳入到苏宁全链路监控平台,形成一条完整的执行耗时监控链路。各阶段预设的超时预警,会在第一时间通知相关责任人,这种方式对问题定位、主动预警都起到了重要的作用,同时给监控运维带来了极大的便利。


在 OLAP 路由层,我们已经对接了 Druid、Elasticsearch、PostGreSQL 以及 ClickHouse 分析引擎,后续我们将对接其它更多的 OLAP 分析引擎,如 Doris、Dremio 和 RocksDB 等,同时我们也将持续细化、分析各引擎内部执行阶段的耗时情况,对全链路监控能力进行更进一步的优化提升。


作者介绍:


范东,苏宁科技集团大数据中心资深架构师,在 OLAP、OLTP 领域有着深厚的技术积累。目前主要负责数据中台和数据工具平台的架构设计及性能调优工作,在数据中台、数据集成开发工具、数据资产、数据质量和数据治理等方面拥有丰富的实战经验。


2020 年 8 月 28 日 12:003187

评论 8 条评论

发布
用户头像
有借鉴意义
2020 年 08 月 31 日 09:01
回复
用户头像
棒棒的
2020 年 08 月 28 日 16:54
回复
用户头像
1
2020 年 08 月 28 日 16:39
回复
用户头像
很棒,支持
2020 年 08 月 28 日 15:34
回复
用户头像
学习,学习
2020 年 08 月 28 日 15:34
回复
用户头像
很好,学习了
2020 年 08 月 28 日 15:23
回复
用户头像
很好的文章
2020 年 08 月 28 日 15:13
回复
用户头像
沙发
2020 年 08 月 28 日 14:38
回复
没有更多评论了
发现更多内容

Gitlab Pipeline+Supervisor 实战Python项目CI/CD

雪雷

gitlab jenkins CI/CD Supervisor

Jenkins部署Python项目实战

雪雷

Python jenkins CI/CD

Docker+Jenkins+Gitlab+Django应用部署实践

雪雷

DevOps jenkins CI/CD

Flink高可用性设置-4

小知识点

scala 大数据 flink 流计算

lower_case_table_names参数详解

Simon

MySQL

微服务注册发现配置中心-consul

雪雷

Consul 服务注册与发现 配置中心

微服务API网关-Kong详解

雪雷

kong api 网关

SonarQube集成gitlab/jenkins

雪雷

jenkins sonar gitlab ci 代码扫描

Elasticsearch安装

北漂码农有话说

API 中签名的使用

flyer0126

接口安全

RabbitMQ实践

雪雷

RabbitMQ 消息队列

业务容器化改造

雪雷

Docker 容器 微服务 服务化改造

Apache常用配置指北

亻尔可真木奉

Apache 代理 跨域

MySQL线程状态详解

Simon

MySQL 线程状态

性能优化-技术专题-并发编程

李浩宇/Alex

Java 多线程

Linux系统检查脚本

雪雷

Shell 系统检测

探测mysqldump详细过程

Simon

MySQL

Docker Web管理工具

雪雷

Docker shipyard dockerui

记一次混合监控的反思

雪雷

监控 zabbix redis监控 监控宝

记一次混合云API发布的反思

雪雷

iptables API api发布

Serverless初探

雪雷

Serverless Lambda 无服务器云函数

JVM-技术专题-GCViewer调优GC

李浩宇/Alex

JVM

JVM-技术专题-管程技术分析

李浩宇/Alex

JVM 管程

Guacamole实战

雪雷

guacamole 远程登录 堡垒机

Ceph集群部署

雪雷

分布式存储 Ceph rdb pvc

API统一管理平台-YApi

雪雷

YAPI API接口管理

Python利用sphinx构建个人博客

雪雷

sphinx Blog

Golang领域模型-开篇

奔奔奔跑

golang 微服务 领域驱动设计 架构设计 后端开发

Jenkins 详解

雪雷

jenkins

Linux自定义快捷工具

雪雷

Linux Shell tools scripts

同态加密

soolaugust

学习 加密 同态加密

苏宁基于ClickHouse的大数据全链路监控实践-InfoQ