网易数帆云原生日志平台架构实践
导读:网易从 2015 年就开始了云原生的探索与实践,作为可观测性的重要一环,日志平台也经历了从主机到容器的演进,支撑了集团内各业务部门的大规模云原生化改造。本文会讲述在这个过程中我们遇到的问题,如何演进和改造,并从中沉淀了哪些经验与最佳实践。
主要内容包括:
Operator 化的⽇志采集
⼤规模场景下的困境与挑战
开源 Loggie 的现在与未来
01 云原⽣最初的探索 Operator 化的⽇志采集
早期公司内部业务跑在物理机上时,各业务使用的日志采集工具、日志中转和存储、配置下发都比较混乱,选型种类多。公司内基于轻舟平台推进了各服务容器化和云原生化,随着服务不断地迁移到 K8s 上,我们关于采集 K8s 容器日志和日志平台方面积累很多实践经验。
云原生日志是什么样的,容器日志采集和主机上服务的日志采集有什么差异?首先 Pod 在 K8s 中会频繁地发生迁移,手动去节点上变更配置日志采集配置不太切实际。 同时,云原生环境中日志存储的形式多样,有容器标准输出和 HostPath,EmptyDir,PV 等。另外,采集日志后,一般会根据云原生环境的 Namespace、Pod、Container、Node 甚至容器环境变量、Label 等维度进行检索和过滤,这些元信息需要在日志采集时被注入。
常见的云原生环境日志采集有以下三种思路:
1.只采集标准输出图片
日志打印到标准输出的操作虽然符合云原生十二要素,但是很多业务还是习惯输出到日志文件中,而且只采集标准输出日志难以满足一些复杂业务的需求。常规的采集标准输出日志的方式是挂载/var/lib/docker,/var/log/pods 下的目录。同时需要注意选型的日志 Agent 是否支持注入 k8s 元信息。
2. Agent⽇志路径全局挂载
日志可以放在 EmptyDir,HostPath 或 PV 存储中,通过 DaemonSet 方式把日志采集 Agent 部署到每一台 k8s 节点上。EmptyDir 等存储映射到节点的目录可以通过通配的方式配置到 Agent 进行采集,由 Agent 读取配置路径下的日志文件。但这种通用匹配的方式无法根据服务级别进行单独配置。如果需要配置只采集某些服务的日志、或是某一个应用和其他应用的格式不同,例如某个应用的日志是多行的日志,此时需要单独修改配置,管理成本比较高。
3. Sidecar⽅式
每个业务 Pod 在部署时都增加一个日志采集的 Agent SideCar,可以通过容器平台或 k8s webhook 的方式把日志采集 Agent 注入到 Pod 内。Agent 可以通过挂载相同的 HostPath 或 EmptyDir 的方式采集到业务容器的日志。
这种方式的弊端是对 Pod 侵入性强,Pod 数量多时资源消耗较大。
对比 DaemonSet 和 SideCar 两种部署方式,DaemonSet 在稳定性、侵入性、资源占用方面有优势,但隔离性、性能方面 SideCar 方式更好。我们实践中会优先使用 DaemonSet 方式采集日志。如果某个服务日志量较大、吞吐量较高,可以考虑为该服务的 Pod 配置 Sidecar 方式采集日志。
针对日志采集方面的痛点,我们提出的第一个初步方案是:自研的 Ripple Operator 配合开源的日志采集客户端 Filebeat 进行业务日志采集。
部署方面,FileBeat、Ripple 通过 SideCar 方式部署在一起,Ripple 监听 k8s。在使用方面,用户通过 CRD,一个 CRD 可以表示一个服务的日志采集配置,Ripple 可以和 k8s 交互感知到 Pod 生命周期。Ripple 可以下发配置到 Agent,自动添加 Pod 相关元信息并注入到日志中。存储方面 HostPath、EmptyDir、PV、Docker Rootfs 都可以支持。
图中日志采集的架构先在网易严选进行了应用, 后面逐渐地被公司内绝大多数部门参考落地,具体架构会根据实际环境有所区别。首先日志平台下发配置,Ripple 监听到 K8s 的 CRD 配置变动后,把配置下发给 Filebeat。Filebeat 把采集到的日志发送到中转机,中转机发送给 Kafka,Flink 消费 Kafka 数据进行处理后转发给后端日志存储。
02 进⼊深⽔区 ⼤规模场景下的困境与挑战
随着接入的业务越来越多,1.0 版本的日志架构逐渐暴露了一些问题:超大规模下系统的稳定性问题、日志平台性能问题、排障困难和排障需求不断增多、维护人力成本直线升高等。
在前面介绍的架构中,Filebeat 会把每个服务的日志发送给中转机。但是 Filebeat 是一个单一的队列架构,在中转机的阻塞会影响整个节点的 Filebeat 日志上报。
我们尝试把 Filebeat 改造成多队列的模式增强隔离性,但是由于 Filebeat 本身的设计架构局限,重构的效果和运行状态都不理想,同时与开源版本的维护和升级存在很大困难。
Filebeat 只支持单个 Output,当用户需要把日志发送到多个 Kafka 集群时,只能在同一个节点上部署多个 Filebeat。导致运维成本高、计算资源消耗大、水平扩展困难。
Filebeat 设计之初是为了解决 Logstash 的问题,作为轻量级的日志采集端运行,不适合作为中转。Logstash 在日志切分、解析等方面表现出色,但是问题在于性能较弱。虽然 Flink 性能和表现出色,但我们的很多场景只需要简单的日志切分,Flink 一般依赖流式处理基础平台的支持,同时在交付过程中用户要额外付出 Flink 的机器和运维成本,所以我们需要一个更轻量、成本更低的方案。
此外,日志采集过程的可观测性和稳定性也很重要。在用户使用过程中经常会遇到日志没有按预期采集、日志采集延迟、日志丢失、日志量增长速度过快磁盘爆满等问题,Filebeat 没有提供这些完善等监控指标,同时还需要额外部署 prometheus exporter。
我们以一个线上问题为例。线上某集群经常遇到磁盘使用量短时间内暴增到 90%以上并触发报警的情况。实际登录节点排查问题后,发现报警的原因在于下游 Kafka 吞吐量不够,一些日志文件没有完全采集完毕,Filebeat 进程默认保留文件句柄直到文件采集完毕,由于文件句柄没有释放,底层的文件无法被真正删除。但在这种情况下,Filebeat 缺乏输入延迟、发送延迟和堆积情况等指标,影响稳定性。
在一个大流量的节点,我们发现 Filebeat 发送数据到下游 Kafka 时整体数据处理速度不理想,于是进行了很多优化的尝试,比如换 SSD 的 Kafka 集群、改 Kafka 配置、优化 Filebeat 配置等调优。我们发现在 Filebeat 不打开数据压缩的情况下,最大数据发送速度达到 80MB/s 后很难再有提升,打开数据压缩后 Filebeat 的 CPU 的消耗又暴增。调整 Kafka 或 Filebeat 参数、机器等配置的优化效果不明显。
那么除了 Filebeat 外,其他的日志采集工具能不能满足需求?当前主流的日志采集 Agent 对容器化场景下的日志采集支持不太理想,大部分开源日志采集工具仅支持到容器标准输出的采集,对云原生下日志采集也没有整体解决方案。
03 新的征程 开源 Loggie 的现在和未来
基于 Filebeat 和现有主流数据采集工具的情况,我们决定自研日志采集 Agent——Loggie。它是基于 Golang 的轻量级、⾼性能、云原⽣⽇志采集、聚合 Agent,⽀持多 Pipeline 和组件热插拔,整体架构如图。
我们加强了 Agent 的监控和稳定性,可以利用 Monitor EventBus 上报 Agent 运行情况,同时暴露了可调用的 Restful API 和 Prometheus 拉取监控数据的接口。配置管理方面,目前使用 K8S 进行配置下发和管理,后续会接入更多配置中心供用户管理配置。
Loggie 提供了一栈式日志解决方案,新 Agent 不再分开维护 Agent 和中转机。作为一个可插拔组件,Agent 既可以作为日志采集端使用,也可以作为中转机使用,同时支持日志中转、过滤、解析、切分、⽇志报警。Loggie 同时提供了云原生日志采集完整解决方案,比如通过 CRD 的形式利用 K8s 的能力下发配置、部署等。基于我们长期的大规模运维日志收集服务的经验,Loggie 沉淀了全⽅位的可观测性、快速排障、异常预警、⾃动化运维能⼒的功能。Loggie 基于 Golang 开发,性能非常好,它资源占⽤小、吞吐性能优异、开发效率高维护成本低。
1.⼀栈式⽇志解决⽅案
Agent 既可以作为日志采集客户端,也可以作为中转机使用。在日志中转方面,我们通过实现 Interceptor 模块逻辑实现日志的分流、聚合、转存、解析、切分等。通过 K8s 的 CRD 可以下发日志采集 Agent 配置。新的日志采集架构整体维护成本更低。
在采用 Loggie 之前我们有两种报警方案:第一种是基于 ElastAlert 轮询 Elasticsearch 进行日志报警,该方案存在配置下发需要手动配置、告警接入不能自动化和高可用不完善等问题;第二种是基于 Flink 解析关键字或是对日志进行正则匹配进行报警,在前面我们已经介绍过,对于整体日志采集服务而言 Flink 是比较重量级的。
在采用 Loggie 后,我们可以使用 logAlert Interceptor,在日志采集过程中就可以通过关键字匹配识别 info 或 error 进行报警。也可以通过单独部署 Elasticsearch Source 的 Loggie Aggregator 对 Elasticsearch 进行轮询,把信息发送到 Prometheus 进行报警。新版日志报警架构更轻量,维护起来也更简单。
在项目开发方面,我们秉承微内核、插件化、组件化的原则,把所有组件抽象为 component。开发者通过实现生命周期接口,可以快速开发数据发送端逻辑、数据源读取逻辑、处理逻辑和服务注册逻辑。这样的设计让需求能更快更灵活地实现,大大了日志采集侧的开发效率。
基于灵活高效的 Agent 数据源设计,我们可以配置 kubeEvent source 采集 K8S Event 数据作为监控报警的补充。相比重新实现一个采集 K8S Event 项目,只需要在 Loggie 上实现对应的 source,其他如队列缓存、解析日志、发送日志的逻辑都可以复用。
2.云原⽣的⽇志形态
用户通过配置 LogConfig CRD,可以指定采集 Pod、节点、集群日志信息。图中的例子是通过 labelSelector 匹配要采集的 Pod,并配置容器内日志路径;通过 Sink CRD 和 Interceptor CRD 可以配置日志发送和日志处理、解析方式。
通过 CRD 的方式打通日志处理链路,用户可以通过配置 CRD 定义日志中转、聚合和发送的方案,可以配置日志的解析、限流、报警规则,在进行私有化部署和将日志服务平台化时大大降低了配置管理的复杂度,一旦有配置变更,k8s 可以快速地把配置同步到日志采集服务中。
在 k8s 中我们提供了多种部署方案, 作为 Agent 部署时,我们提供了 DaemonSet 或 SideCar 方式进行部署。作为中转节点部署时可以作为 StatefulSet 部署。日志采集的架构上更加灵活,可以直接发送到 ES,也可以发送给 Kafka 再交给中转节点,部署方便。
3.⽣产级特性图片
我们为日志采集 Agent 添加了完善的指标,包括日志采集进度、长期采集未完成、采集发送延迟、FD 数量、输出 QPS 和其他服务级别指标,提供了原生 Prometheus 格式的接口、RestAPI 和指标发送 Kafka 等方式暴露指标。
日志采集服务大规模部署的稳定性和排障两方面有很大提升。我们通过独立各个采集任务 Pipeline 增强服务隔离性,还可以通过 Interceptor 提供了 QPS 限制,定时清理日志防止磁盘写满,增加了日志文件突发增长检测和合理的 Fd 保留机制等。
4.资源与性能图片
我们利用 Filebeat 进行了基准测试,在处理单⾏、单⽂件、相同发送并发度、⽆解析的场景下,发送日志⾄Kafka。
测试结果上看 Loggie 性能大幅度提升,消耗 CPU 为 Filebeat 的 1/4、吞吐量为 Filebeat 的 1.6-2.6 倍,且极限吞吐量与 Filebeat 的 80MB/s 瓶颈提升到 200MB/s 以上。
04 Loggie 开源计划
Loggie 已经开源,下面是我们项目推进的 RoadMap 和正在做的事,欢迎感兴趣的开发者一起参与项目。
Loggie 项目地址:https://github.com/loggie-io/loggie/
分享嘉宾:傅轶 网易数帆 轻舟日志平台负责人、架构师
目前专注网易数帆轻舟云原生日志平台研发,致力于云原生技术及其生态体系建设和商业化落地,对 Kubernetes、Serverless、可观测性等有较深入研究,具有丰富的云原生分布式架构设计开发经验与项目实践。
版权声明: 本文为 InfoQ 作者【网易数帆】的原创文章。
原文链接:【http://xie.infoq.cn/article/f5b016156b62e48bb1c636d7a】。文章转载请联系作者。
评论