背景需求
- 高峰日志写入压力大:每秒千万级日志条数。
- 实时要求高:日志采集到被检索最好1s内,高峰3s。
- 成本不小:要求保存半年的日志可以回溯查询,百PB级别。
备注:1PB = 1024TB,1TB = 1024GB
设计思路
技术选型
ElasticSearch
简介:
1. ES负责存储和索引日志。
2. 底层依赖Lucene的倒排索引技术。
3. 通过shard数据分片实现分布式。
缺陷:
1. 为了提升写入性能,可以作聚合提交、延迟索引、减少refresh等,但始终要建立索引。日志流量巨大,每秒20GB,千万级日志条数,写入性能瓶颈明显。(写入瓶颈)
2. 需要定期维护索引、数据分片以及检索缓存,会占用大量CPU和内存,日志存储在机器磁盘上,数据量巨大,同时索引后期也会带来数据量暴增,成本不小。(存储媒介不菲)
3. 非格式化日志需要增加额外逻辑处理。存在很多业务日志不规范的情况,难以收敛。(格式单一)
小结:
1. 日志检索场景是 写多读少,维护庞大索引不合适。
自主设计
-
日志分块。
通过日志时间、日志所属实例、日志类型、日志级别等日志元数据对日志进行分块。检索系统可以不对日志格式做任何要求,并且因为没有解析和建立索引(这块开销很大)的步骤, 写入速度也能够达到极致(只取决于磁盘的 IO 速度)。 可以将一个实例产生的同一类日志按时间顺序写入到一个文件中,并按时间维度对文件拆分。不同的日志块会分散在多台机器上,进而支持横向扩容。 日志块内的数据检索,因为保存的是日志原文,可以直接使用 grep 相关的命令直接对日志块进行检索处理。 日志块做追加写入不需要等待索引建立生效,在日志刷入到日志块上时就可以被立刻检索到,保证了检索结果的实时性。
-
当日志块建立时,基于日志块的元数据信息搭建索引。
像服务名称、日志时间, 日志所属实例, 日志类型等信息, 并将日志块的存储位置做为 value 一起存储。通过索引日志块的元数据,当我们需要对某个服务在某段时间内的某类日志发起检索时,就可以快速地找到需要检索的日志块位置,并发处理。
-
按照时间序列分级存储。
日志数据以时间维度的方向可以理解为一种时序数据,离当前时间越近的日志会越有价值,被查询的可能性也会越高,呈现一种冷热分离的情况。 采用压缩和沉降的手段来降低存储成本。 将日志块存储分为本地存储(磁盘)、远程存储(对象存储)、归档存储三个级别。本地存储负责提供实时和短期的日志查询(一天或几个小时),远程存储负责一定时期内的日志查询需求(一周或者几周),归档存储负责日志整个生命周期里的查询需求。 首先日志块会在本地磁盘创建并写入对应的日志数据,完成后会在本地磁盘保留一定时间(保留的时间取决于磁盘存储压力),在保存一定时间后,它首先会被压缩然后被上传至远程存储(一般是对象存储中的标准存储类型),再经过一段时间后日志块会被迁移到归档存储中保存(一般是对象存储中的归档存储类型)。 如果检索涉及到远程存储上的日志块,检索服务会将涉及到的日志块下载到本地存储,然后在本地完成解压和检索。 因为日志分块的设计,日志块的下载同检索一样,我们可以在多台机器上并行操作。 下载回本地的数据复制支持在本地缓存后一定的时间后再删除,这样有效期内对同一日志块的检索需求就可以在本地完成而不需要再重复拉取一遍(日志检索场景里多次检索同样的日志数据还是很常见)。 对于归档存储,在发起检索请求前,需要对归档存储中的日志块发起取回操作,取回操作一般耗时在几分钟左右,完成取回操作后日志块被取回到远程存储上,再之后的数据流转就跟之前一致了。即开发人员如果想要检索冷数据,需要提前对日志块做归档取回的申请,等待取回完成后就可以按照热数据速度来进行日志检索了。
Reference
- https://www.infoq.cn/article/xyDSrOGbg6tVDVEb261O(作业帮PB级低成本日志检索服务)
- https://zhidao.baidu.com/question/508345794.html(1PB等于多少G?)
- https://baijiahao.baidu.com/s?id=1710293939940555354&wfr=spider&for=pc(Elasticsearch 运维 – Shard 原理)