Fork me on GitHub

曹东:携程日志系统索引构建之路

图片

分享嘉宾:曹东 携程 高级软件开发工程师
编辑整理:桑小晰 深交所
出品平台:DataFunTalk

导读: 携程每天处理数以亿级日志,如何做到实时低延迟、不丢失、查询高效,具有一定的技术挑战。本次分享抛砖引玉,将从下面四点切入希望能解开携程内部落地实践的面纱:Overview(携程监控体系整体架构)、Clog(携程日志系统)、CAT和TSDB。

01 Overview(携程监控体系整体架构)

图片

此图为携程甚至是业界较为通用的广义日志监控系统整体架构。数据采集主要使用Agent和SDK(支持多种语言和协议)两种模式,而SDK支持厂商颇为丰富:CAT、Clog、Promethues、Opentelemetry等。客户端将采集到的日志传输至Collector中聚合与简单预处理。随后,Collector根据元信息与数据特征分发至Kafka的不同topic queue中,从而起到数据隔离与系统解耦的效果。

广义日志从数据模型上可被分为Log、Metric和Trace三类,这也是业界监控的三大基石。Log通常是一条一条的,用于提供系统/进程最精细化的信息。例如某个事件、访问记录等;Metric通常是可聚合的指标,例如某个站点每分钟访问次数;Trace则主要是跨进程、跨线程的调用链信息,用于全链路追踪。不同数据类型进入不同的通道(ETL、Analyzer等)进行处理,最终持久化在HIVE等离线数仓工具用于大数据分析,或TSDB进行时序聚合,或ES+HDFS构建检索系统。携程可视化UI主要使用Grafana(开源)和BAT(自研)。

02 Clog(携程日志系统)

Clog是一个应用日志不落本地磁盘,实时传输的日志系统,每天处理约2PB的日志数据,机器规模约40台物理机(32C128G)。下图(右)为日志检索的UI,用户可以使用任意分词搜索,也可以指定Tag或者标题等进行检索。

图片

1. Clog系统的特点

图片

图片

日志系统通常需要处理的数据量大,系统设计时应在保证数据不丢失的条件下尽可能保证吞吐量。因此,Clog系统具有以下特性:

①写多查少

决定了系统应该具有高吞吐,以及支持多条件组合的丰富查询功能。

②高性能写

为了提升写入性能,减少延迟,我们主要从内存缓存和磁盘IO两个方向入手。考虑到成本,我们采用HDD而非SSD。HDD性能依赖磁盘转速和机械臂的寻址速度,而随机写将引发多次寻址从而吞吐上不来。因此,我们在内存中维护Mem Block,当一个Block满或定时超时后,顺序写入磁盘。

索引上,对每一条日志建立一个索引(稠密索引)是可行的,缺点是索引空间开销大,优点是O(1)查询速度;Kafka是稀疏索引的代表,优点在于节省索引空间,缺点是O(logn)查询速度。考虑到日志系统写多查少的使用特点,且查询多为用户UI界面操作,对延迟敏感度不高,因此,稀疏索引的优势更为明显。

③条件组合查

结合具体的使用场景, 此系统最终的架构如上图(右)所示。数据进入Log Indexer时,首先会进入Mem Block中,Block含有几个元信息字段:appid(用于确定此Block属于哪一个应用)、time(时间偏移量)、size(该Block大小)。当Block装满或者到了固定的刷新时间,顺序写入磁盘。磁盘数据由后台线程定时进行Upload,包括日志数据和索引数据。日志数据存储于HDFS中;索引数据存储于ES中。一个Block对应一条到HDFS文件位置的索引,而为了支持条件检索,我们将日志中抽取的条件(例如应用、机器、时间、日志的title,tag等)构建到ES的倒排索引中。

查询时,Engine会根据查询条件到ES中匹配(可能会匹配到多条索引)。根据这些索引可以追踪到它们是由哪个Indexer标记,然后询问对应的Indexer机器是否可以提供数据。由于Indexer异步Upload到HDFS,因此Engine不直接访问HDFS,而是通过Indexer代理的方式获取日志数据。

03 CAT

Tracing,携程使用CAT。由140台物理机(32C128G)每天处理近2PB的数据。

图片

1. CAT系统的特点

①写多查少

CAT系统的特点与日志系统相似,都具有写多查少的特性。

②Traceid点查

Traceid用于精准的单点查询某个trace瀑布流数据(上图左)。它的来源方式很多,比如通过日志tag得到,从报错信息中采集,或者根据CAT系统提供的样本中采样得来。

2.CAT系统的存储

①HDFS

CAT系统使用HDFS文件系统来存储trace数据。

②文件数限制

使用HDFS系统时,有出现存储文件数量过多导致性能急速下降的问题。

③索引

CAT系统的索引也涉及到稠密与稀疏的选择。

3. 最初使用的CAT系统(V5版本)

图片

V5存储方案由数据和索引两部分组成。若干条数据打包成一个Block写入Data文件中。V5采用稠密索引,即每条数据计算一条索引,占6字节,由Block在Data文件的Position(4字节)和数据写入Block的位置(2字节)组成,索引ID和CAT的message index一一对应。

  • 写入流程 :数据写入Block中,当Block达到64KB(2字节索引)后,刷入Data文件;根据CAT message index计算出Index文件偏移量(index*6),写入6字节索引数据(BlockAdd,BlockOffset)。
  • 读取流程 :根据CAT的message index计算出Index文件偏移量(index*6),从Index文件中解析出索引数据。利用索引便能从Data文件中快速获取对应Block中指定ID的数据。
  • 数据文件名和索引文件名使用同样的编码格式 :由appId(客户端应用)、appIp(客户端机器ip)和catIp(Cat Server的ip)组成。此种文件名编码方式产生的文件数是笛卡尔乘积(appId,appIp,catIp)*保留小时数时间。尤其在容器化场景下,应用ip不固定,将导致HDFS文件数目过渡膨胀,HDFS的IO性能急速下降。

4. V6版本的CAT系统

V6旨在解决由V5存储方案引入HDFS文件膨胀后性能急速下降的问题。

图片

携程应用总量和CAT服务端IP集合基本稳定,因此,我们去掉了V5文件名编码中的Ip维度,便能起到控制HDFS中文件数目的效果。

由于客户端ip从文件名编码中移除,意味着同一个应用的多个ip的索引数据将使用同一个Index文件,亦意味着V5中CAT message index与索引ID一一对应的条件不再成立,因此需要一个二级索引机制。

索引文件由多组4096个Segment组成,一组Segment中第一个Segment被称为Header,每个Segment包含4096条索引,每个索引占8个字节(5字节BlockAdd,3字节BlockOffset,相比V5的6字节变大主要是为了扩大Block大小)。Header的引入是为了解决某个客户端数据索引定位的问题,其存储了ip与Segment的映射关系。

  • SegmentIndex :由CAT message index除4096得到;
  • SegmentOffset :由CAT message index模4096得到;
  • SegmentID :HeaderSegmentOffset / 8 + 4096 * 第几个Header;
  • SegmentAdd :Index文件中的物理偏移量。SegmentID * 4096 * 8。
  • 索引写入流程 :计算SegmentIndex和SegmentOffset,如果当前ip的SegmentIndex是新的(内存映射表是否存在判断),向Header中写入一条记录;如果Header已满,则在新Segment(segment数量已达到4096倍数)开始写入新的Header。根据SegmentID和SegmentOffset找到具体位置,写入BlockAdd和BlockOffset。
  • 索引读取流程 :计算SegmentIndex和SegmentOffset,根据SegmentIndex从内存映射表中得到SegmentID。根据SegmentID计算SegmentAdd,最终由SegmentAdd + SegmentOffset处读取BlockAdd和BlockOffset。

04 TSDB

图片

Metric作为聚合指标数据,一般用于阈值告警通知。在Promethues出现前,携程借鉴了OpenTSDB的思路实现了一套内部的TSDB。该系统将所有数据和索引存储到HBase数据库,我们通过将Tag编码到HBase的rowkey中,来实现快速检索。后来,我们相关技术向VictorialMetrics时序数据库和ClickHouse列存数据库迁移。目前的VictorialMetrics系统规模是200台物理机(40C256G,4T SSD)。当基数(Tag维度组合)较多时,VictorialMetrics的性能会急剧下降,这是因为Metric到ID的映射关系缓存在内存中,当Miss后,将从索引文件中读取,大量文件解码将导致CPU持续高位,影响性能,因此内存决定了VM支持的基数有限。对于高基数的数据,我们引入了ClickHouse,当前规模600台物理机(32C128G)。

05 Q&A

Q:日志的分词器用的是什么?

A:我们的倒排索引使用的是ES,我们的日志有一部分是支持倒排索引给出的维度的检索的,包括应用、机器、时间、等预设的固定维度。如果是用户info某一不带有任何标记的句子时,考虑到句子可能会很长(存储索引会很庞大),我们只截取前128个字节进行分词,并以message的方式放入倒排中进行检索。128字节之后的内容不支持精确检索,因此当查询到多条结果时,需要用户在浏览器中自行过滤。

Q:日志ETL 使用的是什么框架?

A:ETL使用的是内部自研的框架,主要用于做格式Format和预聚合。

Q:ClickHouse用做日志存储的优点是什么?

A:我们的日志包括比较杂乱的普通日志(例如:今天是个好天气)和较为规整的业务日志(例如:包含多维度信息的订单日志)。ClickHouse主要用于存储业务日志,它会提前为这些业务日志中的维度建立列,当然它也用于存储高基数据。ClickHouse的优缺点取决于需要使用的场景。例如,ClickHouse维度的列是固定的,当其维度增多时,性能会明显下降。相比之下,Clog的限制就比较小,并且它支持分词功能。

分享嘉宾:

图片


本文地址:https://www.6aiq.com/article/1656000694524
本文版权归作者和AIQ共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出