

1. 引言
日志是设备或者程序对自身状态和运作行为的记录(From 维基百科),比较常见的如:
服务器的系统日志
应用的访问日志、业务日志
客户端的埋点日志
……
在严选,开发人员几乎每天都会和日志打交道,我们将日志应用在业务监控、线上问题诊断、用户行为分析、运维审计等各类场景。业务和产品日常使用的数据中有很大一部分也是基于日志生产出来,因此如何使用日志数据以及围绕日志构建的各类基建与产品长期以来一直是一个非常重要的技术话题与研究方向。
2. 前世:追求小而美
2.1 问题诊断
grep较难实现比较复杂的查询条件,使用门槛较高。 grep采用全文顺序扫描,在文件较大时查询速度较慢且比较消耗服务器资源。 grep基于服务器上存储的文件,而服务器磁盘空间有限,文件一般只能保留几天,在应用容器化之后更是加剧了这个问题。
2.2 日志监控
2.3 业务指标实时统计
将日志数据同步到Kafka中暂存:这个阶段主要解决日志采集的问题,在15年前后,Flume无疑是开源社区的最佳选择之一。 将Kafka数据源同步到ES(Elasticsearch)中:这个阶段我们引入了ELK stack,Logstash对Kafka中的日志数据进行清洗并保存到ES中,ES存储结构化的日志数据并作为搜索和分析引擎,Kibana则提供数据分析与可视化能力。
2.4 日志审计、用户行为分析及风控
3. 严选为什么需要自建
使用便捷高效:提供一个一站式的日志平台,用户可以独立完成日志需求开发测试发布与日常维护,也可以使用日志检索、分析、诊断以及监控报警功能,而系统也应该具备异常自主发现能力,提供产品化的运维工具及自动化的运维能力,帮助系统运营人员实现高效运维。 资源消耗低、性能强:严选有1000+的服务,每天会产生PB级的日志,因此减少资源开销和提升性能也意味着我们可以用更少的资源来实现更大的日志吞吐量,可以大大减少硬件方面的成本投入。 日志数据质量高:既要求日志链路上的所有组件具备较高的稳定性与可靠性、确保日志不丢失,同时也需要我们能快速的判断采集上来的日志是完整的。 支持容器化日志采集:19年严选开始启动应用容器化及业务上云,因此基建需要全面适配混合云场景,现有的解决方案不支持容器化日志采集,也无法满足迅速增加的日志采集、业务诊断以及可观测性等方面的需求。
首先来看一下集团内部的兄弟部门,发展阶段与严选大体一致,其中采集组件的选择存在开源和自研两个方向,开源派以Flume使用最为广泛,自研派比较典型的是Datastream,控制面基本上都与各自的系统有较大的耦合,没有元数据管理,任务驱动,配置无法自动生成与下发,使用与维护成本普遍较高。 其次可以看一下开源社区主流的解决方案,绝大部分只具备日志采集能力,同样没有提供元数据管理,运维成本高,很难应对大规模的日志采集与应用场景(下文也会做更进一步的对比)。 最后,我们也对比了公有云PaaS(比较有代表性的如阿里云的日志系统),这类系统都依赖公有云的IaaS,同时价格又极其昂贵。
支持PB级的日志采集与处理,提供日志数据采集、解析、投递、数据质量检查、日志分析与检索、可视化及监控告警等功能。 可以一键完成从日志采集、投递、处理到存储,屏蔽环境与底层架构的复杂性。
4. 今生:统一的日志平台
4.1 日志元数据统一管理
严选日志平台的基石是对日志元数据进行统一管理,并借助元数据实现了对日志数据质量的管理以及日志平台的全链路管控。
我们调研的大部分解决方案并不提供日志元数据的统一管理能力,主要有两方面的原因:
开源社区中大部分日志采集组件只提供将本地日志传输到各类数据源的功能,对日志的解析、结构化则交给日志处理组件,在此之上缺少可用于统一管理与调度的控制面,这并不是说控制面的实现技术门槛更高,而是因为统一调度要求各类组件遵循相同的标准,同时又与用户的使用场景有着千丝万缕的关联,因此,缺少统一标准与规范的现状使得日志元数据很难被定义。
早期日志被采集后集中存储的最重要目的是用于大数据离线分析,因此日志相关的基建主要面向有大数据背景的工程师,然而日志却往往又是由业务的开发工程师来打印,在这种大背景下,数据开发工程师将日志抽象为类似于MySQL、Kafka之类的数据源、将日志采集和处理的配置抽象为任务来进行管理确实是一个比较不错的通用设计,而基于数据源和任务的通用日志管理模式并不需要日志元数据。

日志归属:保存日志所属的租户、产品、服务等信息。 文件元信息:保存日志对应的文件目录、文件名等信息。 数据模型:保存日志数据模型,包括字段名、字段描述、类型、约束条件、是否用于索引等信息。 扩展信息:保存是否敏感信息、是否是审计日志、日志保留时间等扩展信息。

可以结合CMDB数据判断当前登陆用户在各类使用场景下对各类数据的访问权限,确保权限一致性,也省去了繁杂的权限申请流程,比如控制用户可以检索日志的范围、可以查询的业务监控报表等。 可以自动生成虚拟机环境、容器环境中各类日志采集配置文件,即使调整日志组件,也可以实现低成本平滑替换。 可以自动生成并部署Flink计算任务。 可以自动创建Kafka、数据湖、ES等各类数据源并生成相关配置。
4.2 日志数据质量管理
数据质量管理(Data Quality Management),是指对数据从计划、获取、存储、共享、维护、应用、消亡生命周期的每个阶段里可能引发的各类数据质量问题,进行识别、度量、监控、预警等一系列管理活动,并通过改善和提高组织的管理水平使得数据质量获得进一步提高。
提升日志数据质量是严选建设日志平台一个非常重要的目标,在此之前,业务对于数据指标经常持怀疑态度,尤其是基于日志统计的业务指标,背后的根本原因是日志采集及处理链路不可靠,经常因组件故障或者应用扩容造成日志数据缺失,进而引起业务指标异常波动。
要提升日志数据质量,需要从生产日志的源头抓起,在此基础上对日志的全生命周期进行管控。
19年初,严选各类系统打印的日志格式五花八门,以访问日志为例,无论是保存的目录、文件名、字段顺序、字段数量等都存在较大的差异,一方面,给日志采集任务的开发和维护额外增加了大量的成本,另一方面,也会时不时出现因日志格式、日志滚动方法调整造成之前的日志采集任务失效。
这些乱象的根源是缺少行之有效的规范以及确保规范得到有效落地的工具或系统。
4.2.1 建立日志规范
规范是治理的基石,没有规范,日志质量便是空谈。因此,管控源头的第一步我们从建立有效的日志规范入手。
结合业务的实际使用诉求,我们将日志分成三类,即访问日志、业务日志和应用日志,同时,为了强化大家的数据质量意识,我们在日志规范中引入了数据湖的概念,访问日志、业务日志进入数据湖,应用日志不进入数据湖,入湖日志数据的保障等级高于不入湖的日志数据,比如变更或者删除的限制、告警等级等。
数据湖(data lake)并不是一个新词,这个概念最早由Pentaho的CTO James Dixon 在2011年提出,最初是为了解决数仓高昂的开发、维护成本以及丢失很多细节数据等问题。与数仓不同的是,数据湖将大量的原始数据保存了下来,而越来越廉价的存储也是数据湖更多的进入了大家的视野。
2019年,数据湖在严选的应用刚刚起步,但考虑到类似业务监控、日志监控、操作审计等场景的日志数据使用数仓显然不太妥帖,因此,我们也是借着日志规范落地,将数据湖的概念推向了更多的人。
当然,从产品功能层面,我们允许全局、租户、产品级别为这三类日志定义规范,我们认为,在一个组织内部,日志是可以而且也应该规范到一种或多种固定的格式。以严选为例,分别为tomcat、nginx等七个不同的服务类型定义了访问日志规范模板,为业务应用定义了两套业务日志规范模板及六套应用日志规范模板。
4.2.2 工具与系统支持
开发阶段: 提供SDK,辅助打印业务日志和应用日志,技术上最大的挑战是兼容原有的日志打印框架,使开发者可以低成本切换。 在日志平台中为开发者提供快速添加日志的入口并提供测试与发布功能。 维护阶段: 根据日志元数据中定义的数据模型检查实际打印的日志是否符合预期,实时识别异常日志数据。 实现日志质量指标化,并纳入到稳定性日常运营。 实时监控日志采集延迟及日志采集完整性,业务开发、平台运营以及数据开发可以通过可视化的方式判断目前日志采集的状态。 提供日志回溯能力,系统或者用户可以在识别到日志存在丢失的情况下发起日志回溯,通过完整性检查计算出需要回溯的日志片段(offset),容器环境内还需要计算出需要回溯采集的物理机节点,Agent需要支持根据指定offset采集指定文件的对应日志片段。 将数据血缘与日志数据源打通,串联上游日志,下游报表,一方面,实现日志平台与大数据平台质量信息联动,另一方面,通过血缘,日志数据源的变更或者删除可以及时准确给出告警,数据开发也可快速正反向查询日志与报表的关联关系,从而提升运维和研发效率。
4.3 日志检索
4.3.1 搜索模式



4.3.2 实时日志流

4.3.3 全链路检索

4.4 日志监控



4.5 可拓展的应用场景
今天截止到现在总的下单量是多少?总销售额是多少?每个渠道的下单量和销售额是多少? 过去一段时间总支付成功率是多少?每个渠道的支付成功率是多少? 当前总峰值QPS是多少?下单接口的峰值TPS有多少?流量排名前十的是哪些接口?
这个时候我们就需要用到业务实时监控系统。
严选业务实时监控系统提供了海量数据的实时监控能力,支持日志、Kafka、binlog等多数据源接入、数据模型构建、监控大盘定制和报警配置。
其中日志数据源使用最为广泛,我们基于日志元数据和CMDB的基础数据抽象了语义非常简单极易上手的监控数据模型,包括时间、维度、度量、预聚合指标、计算指标、筛选条件及可见范围(业务域),通过监控数据模型可以生成实时计算任务及聚合索引,并最终通过业务监控大盘呈现。
还有一类在互联网产品中比较常见的应用场景是埋点。
埋点是指针对特定用户的行为或事件进行捕获、处理并最终存储到数仓,一般可以分为服务端埋点和前端(客户端或H5等)埋点两类,以严选为例,服务端埋点记录业务行为操作,可用于审计场景,前端埋点记录用户行为,多用于用户行为分析、风控等场景。
以前端埋点为例,日志平台解决了埋点日志采集和入仓的问题。

另外,我们还将日志数据应用在DevOps平台、APM、全链路排障平台等多个系统,从而构建起了完善的日志应用生态。
5. 架构剖析
严选日志平台的核心功能主要包括面向运维人员的控制面和面向普通用户的产品功能,其中:
控制面:主要包括模板管理、权限管理、下发配置管理、日志存储管理、系统监控、资源管控、OpenAPI等功能。
产品功能:主要包括日志元数据统一管理、日志数据质量管理、日志检索、日志监控、业务监控等功能。
接下来我们剖析下的支撑这些核心功能的底层架构(如图所示):

5.1 日志采集
Sidecar:每个业务应用Pod部署的时候增加一个Sidecar用于运行日志采集的Agent,采集该Pod产生的日志。 DaemonSet:在K8S的每个节点上部署日志采集的Agent,采集节点上所有容器的日志。
5.2 日志缓存
日志最终会应用到各类场景,比如被转移到数据湖用于离线分析、存储到ES集群用于日志检索或聚合计算各类业务指标等等,通过消息队列可以完美实现日志数据的接收、存储与分发,避免重复采集日志,极大减少资源开销。 日志数据与业务的流量波动几乎一致,电商场景有明显的流量峰谷,消息队列可以帮助我们实现削峰填谷。 消息队列可以将日志数据保存一段时间,如下游日志处理出现故障或日志数据出现丢失,可以从消息队列中快速恢复数据。
高性能:Kafka是一款高吞吐量、低延时的分布式消息订阅中间件,即使用普通的硬件,也可以同时为发布方和订阅方提供每秒百万级别的吞吐量,也可以轻松支持数千个客户端同时读写。 可扩展性:Kafka集群可以实现热扩展。 容错性:Kafka集群可以在部分节点失效的情况下继续提供稳定服务。 高可靠性:消息被持久化到本地磁盘,且支持数据备份防止数据丢失。
5.3 数据路由
扩展性差:一旦Kafka集群发生变更或者任何配置参数发生变更,所有Agent端的配置都需要修改。 稳定性差:如果大量Agent直连Kafka集群,会对Kafka集群造成非常大压力。
日志采集端的Agent可以做到轻量级,无需引入太多的处理逻辑(比如日志分流、权限验证等),保证日志采集效率的同时不会占用太多应用服务器资源。 避免大量Agent直连Kafka集群,提升稳定性。 每个日志都会发送到独立的topic,随着日志数量的不断增加,Kafka集群扩容或者新增集群将是大概率事件,引入数据路由层可以避免日志采集端Agent出现大面积Reload。 由于Kafka集群有大量的消费者,通过调整Kafka来实现资源隔离或者流量管控成本太大,而通过数据路由层可以更高效的实现资源隔离或者流量管控,避免让Kafka集群直面突发流量。
不仅可以实现日志数据分流、流量削峰填谷、简单的数据校验、协议转换、安全控制等功能。 也可以实现全局日志流量与资源的可视化,并在此基础上实现限流、资源隔离、流量调度及扩缩容。
5.4 日志实时处理
Logstash即ELK中的L,可以将日志切分成结构化的日志数据后再存储到ES中,是严选19年之前的解决方案,已经部署了一个小集群,但Logstash性能较差,并不适合大规模部署。 Flink是一款大数据流式处理引擎,满足大数据规模、高吞吐、低延时、易于扩展、故障后可快速恢复等特点,当时已经比较成熟并在严选内部正逐步扩大应用规模,因此资源上相对也比较宽裕。
Flink任务可以很轻松的实现日志格式检查、文本匹配、业务指标聚合等扩展功能,也可以实现日志存储(存储到数据湖、ES),而Logstash的功能职责则比较单一,因此,Flink更符合我们的使用需求。 Flink是严选大数据实时计算平台的底层引擎,和大数据共用实时计算集群可以实现资源的最大化利用,相对而言,Logstash的使用场景则会非常单一,会造成很大的资源浪费。
5.5 日志存储
日志平台提供了三个最常用的数据源:Hbase集群(数据湖)、检索ES集群及聚合指标ES集群。
离线场景的日志数据都会进入Hbase集群,比如埋点分析、日志审计、日志归档等,这里不做进一步展开。
在准实时应用场景,主要以检索和监控场景为主,其中检索场景我们选择了ES,监控场景我们主要从Hbase、ES和TSDB中做了选型,我们从灵活性、稳定性以及团队的运维经验综合考量,最终也选择了ES。
无论是检索还是监控场景都会建立大量的索引,且在索引创建阶段往往很难预测未来的数据量,这也给ES集群的稳定性以及性能调优带来了非常大的挑战,目前我们主要基于峰值流量等数据设置分片数、刷盘频率等来进行优化。
存储这块未来还有比较大的探索和优化空间,也可以根据特定场景的需要引入类似ClickHouse等新的存储引擎。
6. 面临哪些挑战
19年底,严选日志平台的功能已基本成型,然而要做到真正好用却并不容易,在冰山之下,我们需要解决大量的核心技术问题,比如如何高效率的采集和处理大规模日志并确保稳定性、如何持续提升性能降低延迟、如何降低运维成本等等。
接下来,我会从三个方面来谈一谈我们面对这些挑战的一些实践与思考。
6.1 限流与资源隔离
6.1.1 限流
Flume可通过扩展Interceptor来限制单位时间内每个日志文件采集的行数,因此,如果一台服务器采集的日志数量比较多、日志打印的总量又比较大时,仍然有可能会出现CPU和Load较高的情况出现。不过从严选生产环境的实际情况来看,这种情况极少出现,而且一般出现之后,即使没有日志采集Agent,日志打印也同样会给磁盘和IO的较大的压力,所以,我们认为Flume的这种限流策略配合上监控报警仍然是有效的。
而Filebeat在解决限流问题的理念则完全不同,它通过背压敏感协议可以灵活的根据下游日志的消费速度来调节Agent的读取速率,这种方式会极致的利用采集端的CPU和内存,因此,我们需要同步限制Agent最大可使用的CPU和内存以达到更好的限流效果。
Loggie则汲取了两者的优势,我们可以根据场景需要向配置文件中注入不同的Interceptor来灵活启用限流或背压敏感协议,同时也可以利用容器化的优势限制CPU和内存。
6.1.2 资源隔离
在Flume架构(如下图所示)中,Channel可以将Source和Sink连接在一起,可以确保数据收发的一致性,不同的Channel之间可以做到逻辑上的隔离,因此,在日志采集端,我们为每一个日志文件抽象为一组独立的Source-Channel-Sink,从而实现了日志文件级别的资源软隔离。

同一个Filebeat不能将数据同时发送到多个不同的Kafka集群,也不能同时发送到Kafka集群、ES集群或其他Output。 如果某个日志的日志量剧增造成中转机的某一条链路阻塞,会造成Filebeat Agent所在节点上所有的日志全部发送失败、Queue堆积。


6.2 全链路可观测与可管控
在日志平台查询到的日志、配置的日志监控或者业务监控延迟有多大? 日志或者大盘为什么没数据了? 日志是完整的吗?如果不完整的话,是在哪个环节出现异常了?如何补全?
首先是采集全链路各组件的运行状态,主要包括为每一类组件定义出标准化的metrics,并结合实际运维过程中遇到的问题,定义出丰富的异常码以辅助问题快速定位,基于这些数据或事件,可以构建独立的系统监控闭环: 不仅可以实时观测各个节点上各个组件的运行状态,比如采集Agent是否存活、是否存在阻塞、是否存在采集异常以及存在哪种异常等等。 也可以从全链路的视角来实现异常的自主发现,比如通过Agent上报的文件校验信息与实际采集的日志信息可以判断采集延迟、当前采集进度以及判断当前日志是否存在丢失等。 其次是数据路由网关化,前文提到,我们在架构中引入了数据路由(即中转机),借鉴API网关的设计理念,通过管道将服务器的资源网格化,通过平台控制面规则配置可灵活控制资源隔离的粒度,通过监控管道的流量实现对全局水位的监控和预警。

最后是实现全链路资源可管控,日志平台通过自带的控制面可直接管控采集端Agent和数据路由的资源,控制流速及水位,通过运维工具来管控Kafka、Flink和ES的资源,比如调整Kafka的分区、合并Flink任务、调整ES的分片等。
6.3 自动化运维
6.3.1 资源弹性伸缩
提前设置日志等级,明确可被降级采集的日志清单。 主要包括三个等级的日志:需要重保的日志、进入数据湖的业务日志和访问日志、应用日志,一般情况下应用日志可以被降级采集,降级将带来全链路资源的释放,包括数据路由、Kafka、Flink、ES等等。 根据不同的日志等级配置不同的资源超售,减少重点日志的资源竞争。 通过控制面设置每个管道的基础配额与上限配额,基于水位、预警线等信息进行弹性伸缩。
重保日志设置为高优先级,支持资源独占,低优先级可被降级(如大促峰值到来前)。 一个Flink任务同时处理一组日志,同时允许动态调整分组。 结合Flink任务资源使用率、日志流量等信息,自动调整资源。
6.3.2 大日志自动巡检与日志自动清理
大日志打印:日志采集时会同步计算每行日志的大小,因此,可以借助自动化巡检工具,轻松发现大日志。 日志文件清理: 传统的方法是发现磁盘不足后,根据时间序列删除更早的文件或者根据文件大小删除较大的文件,这样带来的隐患是日志可能还没有备份,影响问题排查或者指标计算。 而日志平台可以判断日志是否已经被完全采集,在判定采集完成(日志不活跃N天)之后,根据配置的保留时间或者容器迁移、销毁事件,触发自动清理。
7. 未来:反哺社区
强隔离:多管道设计,减少互相干扰,可同时发送多个不同数据源,也可实现管道级别的Reload。 轻量级、高性能:基于Golang,并充分发挥了Golang的性能优势,实现了极少的资源占用与强大的吞吐性能,我们与同样基于Golang的Filebeat进行了压测性能对比,CPU消耗仅为Filebeat的1/4,发送吞吐量为Filebeat的1.6~2.6倍。 灵活的可插拔和可扩展能力:使用了微内核、组件化的架构,可以通过配置不同的Source(输入端)、Interceptor(拦截器)、Sink(输出端),快速拥有数据路由、过滤、解析、切分、日志报警等能力,开发者也可以根据自己的需求快速开发新的Source、Interceptor、Sink。 更好的云原生支持、开箱即用:支持Kubernetes容器日志采集,支持Agent和Aggregator两种形态,支持Sidecar和Daemonset等多种部署架构,兼容Filebeat配置,支持动态配置下发,可轻松接入到各类容器云平台。 更好的稳定性、更完善的可观测性、更便捷的排障方式: 通过配置interceptor可支持限流、背压,通过配置不同的管道可实现日志级别的资源隔离。 结合我们在生产环境中出现的各类实际问题,沉淀了丰富的可观测指标,可快速发现文件异常增长、发生延迟等常见问题。 支持原生Prometheus metrics,无需额外部署exporter;同时提供了完善的Grafana监控图表,可以方便快速接入使用。

现在,Loggie已在传媒、邮箱等集团内多个兄弟事业部落地,也吸引了10多位来自不同公司的Contributor参与开源贡献,相信在大家的共同努力下,未来Loggie可以发展到新的高度。
8. 写在最后
本文由作者授权严选技术团队发布






