作为线上定位问题和排查故障的重要手段,日志在可观测领域有着不可替代的作用。因此,日志系统需要追求稳定性、性能、成本、易用性、可扩展性等关键点。
目前我司的日志系统是基于ELK的,支持云主机、容器日志采集和特殊分类日志的综合采集等功能。但是随着公司的业务发展,日志应用场景逐渐遇到了一些瓶颈:
2. 数据质量和可靠性要求提高:日志数据对于公司业务和运维至关重要,因此数据质量和可靠性要求越来越高。原有的日志系统存在日志丢失、日志收集慢等问题,需要进行改进。
现状:目前总共运行 8个 ES 集群,机器数量100+, Logstash 机器 50+,需要的硬件和维护成本很高,通过扩容的方法去满足业务场景,ES集群会太大会变动不稳定,创建独立集群,也需要更高成本,两者都会使得成本和维护工作量剧增。
鉴于这些问题,去年下半年开始探索新的日志系统架构,以彻底解决上面的问题。
1. 功能
高效支持聚合查询
支持多区域和跨租户查询
2. 效率和维护
降低成本,并能处理 10 倍规模的问题
提高可靠性,简化操作
3. 从 ELK 平台透明迁移
兼容性:能够无缝迁移现有的ELK平台的数据,无需进行大量修改
最好用户可以继续使用类Kibana 来交互分析日志
4. 增强日志系统的完整性
高性能采集器:采用高性能的采集器,提高日志收集的速度,降低数据采集延迟。
并行处理:采用并行处理的方式,同时处理多个日志数据流,提高数据处理速度和效率。
# 来源(sources)
[sources.my_source_id] # "数据源"名称
type = "kafka" # 类型
bootstrap_servers = "10.x.x.1:9092,10.x.x.2:9092,10.x.x.3:9092" # kafka链接地址
group_id = "consumer-group-name" # 消费组id
topics = [ "^(prefix1|prefix2)-.+" ] # topic,支持正则
# 变换[可选](transforms)
[transforms.my_transform_id] # "变换" 名称
type = "remap" # 类型
inputs = ["my_source_id"] # "来源"名称
source = ". = parse_key_value!(.message)" # 以键/值格式解析值
# 打印输出到console
[sinks.print]
type = "console"
inputs = ["my_transform_id"]
encoding.codec = "json"
# 水槽(sinks)
[sinks.my_sink_id] # "水槽"名称(数据往哪发送)
type = "clickhouse" # 类型
inputs = [ "my_transform_id" ] # 输入,这里的输入是上一层的“变换”名称
endpoint = "http://127.0.0.1:8123" # 输出的地址
database = "default" # clickhouse 数据库名称
table = "table" # clickhouse 表名称
auth.strategy = "basic" # 身份验证策略
auth.user = "user"
auth.password = "password"
compression = "gzip" # 压缩配置
skip_unknown_fields = true # 允许丢弃表中不存在的字段
1. Vector 自带的自动均衡 topic 功能可以保证数据基本均匀分布
2. 合理设置数据批次大小和写入频率,以控制数据写入的速度和频次,降低 parts 数量、减少服务器 merge、避免 Too many parts 异常的发生。使用阈值控制数据的写入量和频次,超过 10w 记录写一次或者 10s 写一次。
batch.max_bytes = 2000000000 # 限制每个批次的最大字节数
batch.max_events = 100000 # 限制每个批次的最大事件数
batch.timeout_secs = 10 # 限制批处理操作的最大等待时间
3. 使用分布式表可以将数据拆分成多个 parts 并在不同服务器上进行写入,可以提高写入速度和可靠性。
4. 在建表时,根据业务需求和数据特性合理设置 partition,避免过多的 partition 和异常的发生。
5. 合理设置主键和索引,避免数据乱序,从而提高写入速度和数据的可查询性。
具有高写入吞吐量:对比 Elasticsearch (ES),ClickHouse 在写入吞吐量方面更加高效。
具有高吞吐量的单个大查询能力
服务器成本更低
更稳定,运维成本更低
ClickHouse 采用 SQL 语法,比 ES 的 DSL 更加简单,学习成本更低。
数据规模和实时性:包括数据量、数据写入频率以及实时性要求。
查询负载和性能需求:包括查询负载、查询复杂度、查询频率、并发性以及对集群性能的需求。
集群管理和维护:包括集群的可靠性、容错性、监控和维护等方面。
重视字段索引创建:将公共约定的常用名称独立成字段,方便添加索引,提升查询效率。
合理选择分区字段:根据业务实际场景,灵活定制设置分区键,针对性优化提高性能。
合并树引擎与排序字段:选用合适的合并树引擎 如MergeTree,排序字段尽可能是查询的字段,充分利用主键索引。
选择合适的压缩算法:更强悍的压缩算法,往往需要牺牲一定的性能为代价。经测试,LZ4查询响应要比ZSTD快30%左右,而LZ4的磁盘占用空间要比ZSTD多2.5倍左右。如果使用LZ4查询耗时为1秒,而ZSTD查询性能为1.5秒左右,虽然秒级的影响对使用方来说,体感并不明显,但高达2.5倍的存储开销确耗费不少。选择合适的压缩算法可以在保证查询性能的情况下,降低存储开销。
创建clickhouse 分布式表
# 创建本地表
CREATE TABLE [IF NOT EXISTS] [db.]local_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 = engine_name()
[PARTITION BY expr]
[ORDER BY expr]
[PRIMARY KEY expr]
[SAMPLE BY expr]
[SETTINGS name=value, ...];
# 创建分布式表:
CREATE TABLE [db.]d_table_name ON CLUSTER cluster
AS db.local_table_name ENGINE = Distributed(cluster, db, local_table_name [, sharding_key])
提供接近 Kibana/阿里云日志服务SLS 的界面,减少用户的迁移成本;
作为排障的入口,和内部其他组件打通,如监控告警,分布式追踪等。
目前的日志平台实现了查询语句高亮和提示、日志时间分布预览、查询高亮以及日志略缩展示等等。
SQL 查询中的查询服务支持。
通过自适应使用 PreWhere 和 Where 子句,微调索引粒度,探索跳数索引,并根据更多收集的统计数据微调查询设置,积极改善查询延迟的差异性。
冷热分层存储,提高数据保留率并降低成本。
1)新日志的接入、性能优化;
2)过期日志的清理,按TTL 自动清理
3)ClickHouse的监控,使用prometheus+Grafana的实现;
4)数据迁移,一般不搬迁历史数据,只要将新的数据接入新集群,随着时间的推移,历史数据会被清理下线,当老集群数据全部下线后,新老集群的迁移就完成了。确实需要迁移数据时,采用ClickHouse_copier或者复制数据的方式实现。
5)常见问题处理:
慢查询,通过kill query终止慢查询的执行,并通过前面提到的优化方案进行优化
Too many parts异常:Too many parts异常是由于写入的part过多part的merge速度跟不上产生的速度,导致part过多的原因主要包括几个方面:
a. 设置不合理
b. 小批量、高频次写ClickHouse
c. 写的是ClickHouse的分布式表
d. ClickHouse设置的merge线程数太少了
将日志从ES迁移到ClickHouse可以节省更多的服务器资源,总体运维成本更低
优化日志查询性能,让ClickHouse在日志分析领域提供更大的价值。
但是ClickHouse毕竟不是ES,在很多业务场景中ES仍然不可替代;