关于云原生:新一代云原生日志架构-Loggie的设计与实践

51次阅读

共计 6344 个字符,预计需要花费 16 分钟才能阅读完成。

Loggie 萌芽于网易严选业务的理论需要,成长于严选与数帆的长期共建,继续倒退于网易数帆与网易传媒、中国工商银行的严密合作。宽泛的生态,使得我的项目可能基于业务需要不断完善、成熟。目前曾经开源:https://github.com/loggie-io/…

1. 背景

严选日志平台初期,应用 filebeat 采集云内日志,用 flume 采集云外日志。期间经验了一段 苦楚的运维排障 期间,被问的最多的几个问题:

  • 某条日志为何没有采集?
  • 某条日志为何反复采集了?
  • 是否将漏采集的那条日志补采集?
  • 某个日志文件为何没有采集?
  • 某个日志文件的采集速度怎么这么慢(提早超过 30s)?
  • 服务从新公布后,之前的日志怎么没有了?

而且同时保护了 2 套日志采集 agent,保护老本高。不论是 filebeat 还是 flume 都存在以下几点重大的问题:

  • 采集性能低: 大促工夫,局部节点的日志打印速度超过 100MB/s,然而 filebeat 的采集性能下限只有 80MB/ s 左右,flume 更差一点。
  • 资源占用高: filebeat 单节点采集文件超过 100 个,cpu 使用率超 800%;flume 空跑内存就得占用 200MB+,大促期间不得不开启限流以防止影响外围业务零碎。
  • 扩展性差: fliebeat 简单的架构以及单 output 设计无奈满足多变的业务需要。

同时也调研其余开源的日志采集 agent,或多或少都存在上述问题,且都没有足够的可观测性和运维伎俩(工具)来帮忙运维排障,更不用说残缺的日志解决方案。

因而咱们走向了自研的路线。

loggie 在 2022 年初已开源:https://github.com/loggie-io/…

欢送大家应用,与社区一起成长!

2. 架构设计

基于 golang,借鉴经典生产者 - 消费者模式的微内核设计。一个 pipeline 只有 source、queue、sink、interceptor4 个组件概念,且 interceptor 也不是必须的。pipeline 反对配置热加载,组件热插拔,pipeline 之间强隔离,避免相互影响。

2.1 pipeline 设计

pipeline 的设计初衷次要是为了 隔离性。之前运维遇到的一个重大问题:云内应用 filebeat 采集多个业务的多个日志文件,然而其中一个日志文件的采集配置的 topic 被误删,导致发送到 kafka 失败而阻塞,进而导致整个物理机几点的所有日志都阻塞。因而咱们须要一种泳道隔离伎俩,来隔离不必业务、不同优先级的日志,防止相互影响。

2.1.1 易扩大

pipeline 的简洁设计使得咱们的扩大极其便捷。在概念上,一个 pipeline 只有 4 种组件:source、queue、sink、interceptor,而且 interceptor 不是必须的。越少的概念,扩大者者就有越少的学习老本。并且,为了进一步提高扩展性,pipeline 中的所有组件都形象为 component,所有的组件领有统一的生命周期与实现形式。不仅不便了扩大,也不便了 loggie 对组件的对立治理。

2.1.2 隔离性与 reload

基于 pipeline,咱们实现了配置热更新,组件热加载。reloader 与 discovery 组件能够基于 K8S CRD、http 监听等形式(预留接口,能够对接例如 zookeeper、consul、apollo 等配置核心),以 pipeline 维度进行 reload。因而,在保障了 reload 能力的同时依然满足了 pipeline 隔离的目标。

2.1.3 性能加强:interceptor

interceptor 在 loggie 中是一个可选的组件,却在 loggie 中扮演着十分重要的角色。loggie 中绝大多数的加强性能都是基于 interceptor 实现的,例如限流、背压、日志切分、encode&decode、字符编码、结构化等。用户能够依据理论状况抉择对应的 interceptor 晋升 loggie 的适应能力。

残缺内置 interceptor:https://loggie-io.github.io/d…

3. 日志采集

对于一个日志采集 agent 来说,通常须要重点关怀以下 3 点的设计与实现:

  • 高效采集: 高效指的是高性能的同时低能耗,即如何采集的快服务器资源占用有小。
  • 公平性: 例如写入快的文件不能影响写入慢的文件采集、最近更新的文件不能影响之前更新的文件的采集,删除文件的正当采集与开释。
  • 可靠性: 日志不失落。包含过程解体重启、服务公布 & 迁徙 & 容器漂移、上游阻塞等状况。

3.1 高效采集

日志采集,咱们关怀的是这么几个问题:

  • 如何及时发现新创建的文件?
  • 如何及时发现最新的写入?
  • 如何疾速读取文件?

这其实是两方面的问题:

  • 事件感知: 及时发现文件事件。例如文件新建、删除、写入。
  • 文件读取: 高效读取文件内容。尽可能快的读取文件内容,缩小磁盘 io,cpu 可控。

3.1.1 事件感知

如何做到文件事件感知呢?业界有两种做法:

  • 定时轮询: 定时查看目录文件状态。
  • OS 事件告诉: 注册 OS 文件事件,由 OS 告诉具体的文件事件。

两种形式各有利弊:

  • 定时轮询:

    • 长处:实现简略,安全可靠。
    • 毛病:轮询的工夫距离不太好确定,距离太短耗 cpu,距离太长发现事件就太慢。
  • OS 事件告诉:

    • 长处:可能第一工夫发现文件事件
    • 毛病:

      • 实现老本高(不同 OS 的实现形式不同,须要适配)。
      • 存在 bug:例如在最罕用的 linux 零碎中存在一些 bug(https://man7.org/linux/man-pa…),其中影响最大的几点:告诉失落、注册数量有下限、文件改名事件无奈告诉改名后的文件名。
      • 应用有限度:例如无奈对通过 NFS(Network File System)挂载的网盘 & 云盘失效,无奈对 FUSE(filesystem in userspace)失效等。

因而 loggie 联合两者独特实现了一个安全可靠,却又能及时感知事件的计划:

同时启用定时轮询和 OS 告诉,应用 OS 告诉而后搭配一个绝对较长(loggie 默认为 10s)的定时轮询,将两者发现的事件进行合并以缩小反复解决,这样就能同时兼具两者的长处。

然而理论测试下来,咱们发现了 cpu 占用回升,剖析起因:

  • OS 事件过多: 特地是写文件的时候,对应有两个 os 事件(chmod+write),一旦文件写得频繁,os 的事件将十分多,loggie 疲于解决零碎事件。

所以,咱们从新剖析,什么样的事件是咱们真正关怀并须要及时感知的呢?

  • 文件写事件?

当咱们无奈及时发现文件写事件,会有什么影响呢?有两种状况:

  • 如果这个文件正处于采集中(持有文件句柄),那这个文件的写事件没有影响。因为正在读这个文件,后续的写入天经地义能被读到。
  • 如果这个文件处于不沉闷状态(即文件曾经读取到了开端,并且肯定工夫内没有发现新内容,甚至文件的文件句柄被开释了),这个状况咱们心愿能及时感知文件的写事件以不便咱们及时采集最新的写入内容。

因而,重要的是“不沉闷”文件的写事件。

  • 文件新建(滚动)事件?

当咱们没有及时发现新建事件,会有什么影响呢?

首条日志写工夫到发现工夫之间的日志将会提早采集(对于 loggie 来说,最大提早在 10s 左右,因为默认的轮询工夫距离为 10s),然而一旦感知到事件,采集能够很快追上进度。因而新建事件不那么重要。

  • 文件删除事件?

当咱们没有及时发现删除事件,会有什么影响呢?有 3 种场景:

  • 文件被删除后,心愿未采集实现的文件持续采集:这种状况,删除事件早退不总要。因为当文件还未采集完,及时发现的删除事件没有意义;当文件采集完后,未及时发现的删除事件仅影响文件句柄开释提早。
  • 文件被删除后,心愿尽快开释磁盘空间:仅仅导致文件句柄开释提早,即磁盘空间开释提早(大略在 10s 左右)。
  • 文件被删除后,心愿未采集完的文件给予肯定的容忍工夫再开释磁盘空间:这种状况近会导致文件最终开释提早的工夫 = 容忍工夫 + 事件早退工夫。

因而,删除事件不重要。

  • 文件改名事件?

同上,不重要。然而如何得悉文件改名以及改成什么名的确个值得好好思考的问题!(暂不开展)

所以,真正重要的是不沉闷的文件写事件。因而咱们的架构调整为:

成绩:

  • 节俭大量不必要的目录和文件的零碎事件注册和监听以及对应监听产生的大量事件,进一步升高了 CPU 的损耗。
  • 事件处理这一层去掉了事件合并这一步,因为所有事件都是无效事件,进一步升高了 CPU 的损耗。

3.1.2 文件读取

文件读的快的准则:

  1. 缩小磁盘 io: 意味着每次须要读取更多的字节数缓冲在内存,再按行宰割解决。
  2. cpu 可控: 缩小 gc 和线程调度。

矛盾点:

  • 准则 1 注定了咱们须要反复调配长数组来承载读取的内容。这象征了很多大对象。
  • 准则 2 中的 gc 最胆怯的恰好是转瞬即逝的大对象。

因而文件读取的原理为:

  • 复用读取缓存数组: 反复利用大对象。
  • 读取字节数: 4k 的 n 倍,充分利用 os 的 page cache。

成绩: 读取性能达到 2G/s(本地 macbook ssd 环境测试)。

3.2 公平性

公平性咱们关怀的是文件之间的读取均衡,不要造成文件读取饥饿(长时间得不到读取而造成数据提早)。业界这块的做法有两种:

  • 每个文件对应一个读取线程,有 os 调度文件读取保障公平性

    • 长处:可能保障公平性。
    • 毛病:同时采集的文件数量多的时候 cpu 耗费太大。
  • 匹配到的文件依照更新事件倒序,依照程序挨个读取文件

    • 长处:实现简略。
    • 毛病:无奈保障公平性,更新工夫早的文件必然会饥饿。

因而 loggie 实现了基于“工夫片”的读取形式:

成绩: 仅仅用一个线程(goroutine)就解决了 loggie 所有的日志读取工作,且最大可能的保障了公平性。

3.3 可靠性

loggie 保障了数据的不失落,实现了 at least once 保障。对于文件读取来说,可靠性的实现有肯定特殊性:须要保序 ack,即咱们对于采集点位记录的长久化前提是以后 ack 之前的 ack 全副 done。因而为了进步保序 ack 的性能,咱们的这块的设计进行了一些优化:

对于 sink 端提交的 ack 不立刻进行长久化,而且进行了双重压缩:

  • 在 ack chain 阶段只会提交最尾端的 ack 到 db。
  • db 中会对提交的 ack 再进一步压缩。

成绩: 大大减少了 cpu 的耗费和 ack 长久化的磁盘 io 次数。

3.4 性能比照

比照 filebeat,等同状况下,发送至 Kafka(单行、单文件、雷同发送并发度、无解析场景):

  • 单文件采集比照,Loggie 和 Filebeat 耗费的 CPU 相比,大略仅为后者的 1 /4,同时发送吞吐量为后者的 1.6~2.6 倍。
  • Filebeat 的极限吞吐量存在瓶颈,80MB/ s 后很难晋升,而 Loggie 的极限值更高,多文件采集下能轻松达到 200MB/s+。

4. 运维治理

基于 loggie 咱们做了很多运维治理,以及利用剖析的事件:

4.1 可观测

依据长期运维、排障教训演绎提炼的内置指标,能够领导帮忙咱们疾速发现定位问题:

提供了 grafana 模版,能够一键配置:https://github.com/loggie-io/…

4.2 完整性

日志从采集到最终的存储,链路可能比拟简短,两头任何一个环节出问题都可能导致日志失落。因而须要有一个日志完整性校验的机制来判断日志的采集状况。通常咱们比较关心两方面问题:

  • 某个服务的某个日志数据有没有丢?
  • 丢的数据是否补?

那如何计算日志有没有丢呢?准确完整性计算的外围原理:

  • 计算维度: 机器 ip+ 日志文件惟一标识

机器 ip 是确定的,然而如何惟一标识日志文件呢?

文件名可能反复,因而须要文件名 + 文件 inode(文件标识)。然而 inode 只在磁盘分区中惟一,因而须要批改为文件名 + 文件 inode(文件标识)+dev(磁盘标识)。然而 inode 存在复用的状况,如果文件被采集完后被删除了,inode 被复用给一个同名的文件,这样就变相的造成反复,因而咱们须要减少文件内容的前 n 个字符编码。最终的计算维度为:机器 ip+ 文件名称 +inode+dev+{fistNBytes}。

  • 近实时计算: 小时级批工作计算

之所以用小计批工作计算,次要有两个起因:

  • 日志的完整性计算不须要太实时,因为采集的日志可能因为种种原因而早退,实时计算的话很可能会存在太多的数据失落的状况。而且计算的量级十分大,不适宜实时计算。
  • 另一面,不应用更大的工夫距离(例如 T +1)计算的起因是,通常日志都会配置轮转和清理。如果距离过大,计算出有失落的日志可能因为轮转和清理被删除了,那就失去了补数据的机会。
  • 计算逻辑: 日志行首 offset+ 日志 size= 下一行日志行首 offset
  • 补数据: 通过调用 loggie 原生的文件数据读取接口获取(指定 offset 和读取的 size)。

计算须要的所有 metric 都附带在 loggie 采集的的日志元数据中。

成绩: 简略易用的平台化展现与补数据。

4.3 日志提早

咱们计算了日志在整个链路环节中的提早状况,重点日志还会依据提早状况及时的报警:

端到端的提早计算意义:

  • 帮忙咱们扫视剖析链路机器资源瓶颈。
  • 领导大促期间的正当扩缩容。
  • 布局将来增长的日志所需的容量。

4.4 日志品质

因为日志采集后,可能被后续的业务监控报警以及大数据数仓解决剖析计算利用,因而日志的品质变得愈发重要。那如何掂量日志品质呢?实质上,日志从非结构化数据被采集后通过一系列解决计算变成了结构化数据,因而咱们在日志结构化的过程中定义了日志品质分的计算:

  • 日志切分(字段提取)解决:切分失败扣 1 分
  • 字段不存在扣 1 分
  • 类型转换解决:转换失败扣 1 分
  • 字段束缚失败扣 1 分

成果:

日志品质治理的意义:

  • 量化日志品质,继续推动服务进化。
  • 为上游日志的解决极大提高效率。
  • 进步了要害日志的精确数。

4.5 剖析利用

基于采集的日志数据咱们做 2 个重量级的利用,使得日志的重要水平回升了一个维度,让日志真正领有强烈的业务含意。

4.5.1 业务实时监控

思考以下需要:

  • 实时监控主站交易是否上涨
  • 实时监控主站 UV 拜访
  • 实时监控主站的加购、下单状况
  • 实时监控风控的拦挡状况
  • 实时监控服务的 qps、异常情况

通常实现这些需要须要不小的开发周期,然而基于业务实时监控,只须要花 5 -10 分钟的工夫在平台上配置即可展现与报警:

外围原理:

  • 打印对应的业务日志
  • 在平台配置采集对应的日志
  • 在平台配置对应日志的数据模型以及对应指标的计算逻辑(反对明细、聚合等丰盛计算)
  • 配置报警规定

成绩:

大大降低了业务服务对要害业务过程的监控报警的开发成本,通过配置即可领有业务实时监控报警的能力。

4.5.2 业务全链路监控

以后微服务流行,用户的一个操作可能波及底下多个微服务调用,思考以下问题:

  • 如何从业务全局视角察看对应服务的运行状况?
  • 如何从业务链路视角发现上下游占用比例和依赖?

业务全链路监控应运而生:

以交易链路为例,从首页 -> 搜寻 & 举荐 -> 商详 -> 加购 -> 下单 -> 领取这个主链路以及辐射进去的几条支链路,整体的流量是怎么样的?调用 qps 是怎么样的?均匀 rt 是什么样的?谬误状况如何?通过业务全链路监控高深莫测。

外围实现原理:

  • 严选所有服务默认开启拜访日志,默认采集所有服务的拜访日志
  • 在平台配置业务链路流程对应的服务以及接口
  • 配置要害链路节点的监控报警规定
  • 平台一键生成全链路实时监控报警

业务全链路实时监控的意义不凡,使得咱们可能站在更高的维度,以全局视角扫视整个业务流程下的服务调用状况,及时发现链路中的薄弱环节以及异常情况,帮忙咱们优化服务依赖,晋升服务稳定性。

5. 结语

严选基于 loggie 的日志平台化建设,咱们一方面在满足基于日志的问题剖析诊断这一根底需要之余,进一步了晋升日志品质、问题排查效率、全链路可观测可运维能力。另一方面,咱们扩大能力与丰盛利用场景,只须要简略配置就使得日志领有强烈的业务含意与监控语义,使得咱们可能站在更高的维度扫视 & 监控业务链路中的异样,提前发现链路服务与资源问题。

作者:严选技术产品团队

起源:新一代云原生日志架构 – Loggie 的设计与实际

正文完
 0