摘要:应用架构开始从单体系统逐步转变为微服务,其中的业务逻辑随之而来就会变成微服务之间的调用与请求。资源角度来看,传统服务器这个物理单位也逐渐淡化,变成了看不见摸不到的虚拟资源模式。
背 景
容器、ServerlESs 编程方式的诞生极大提升了软件交付与部署的效率。在架构的演化过程中,可以看到两个变化:
应用架构开始从单体系统逐步转变为微服务,其中的业务逻辑随之而来就会变成微服务之间的调用与请求。
资源角度来看,传统服务器这个物理单位也逐渐淡化,变成了看不见摸不到的虚拟资源模式。
从以上两个变化可以看到这种弹性、标准化的架构背后,原先运维与诊断的需求也变得越来越复杂。为了应对这种变化趋势,诞生一系列面向 DevOps 的诊断与分析系统,包括集中式日志系统(Logging),集中式度量系统(Metrics)和分布式追踪系统(Tracing)。
服务观测体系的基础
日志、监控、分布式追踪
Logging,Metrics 和 Tracing 有各自专注的部分。
Metrics 的特点是:它是可累加的,具有原子性,每个都是一个逻辑计量单元
Logging 的特点是:它描述离散的 (不连续的) 事件, 非结构化的数据。
Tracing 的最大特点就是:它在单次请求的范围内,处理信息。 任何的数据、元数据信息都被绑定到系统中的单个事务上。
以比喻手段来说的话,日志数据就是系统中的一个个点,追踪数据则是系统中一条条线,而监控数据则是系统中一个个面。
通过日志、监控、追踪服务我们才能全面实时地观测服务运行状态 ; 我们通过日志来查看服务运行中的各个正常和异常的事件, 通过监控来观察服务的总体指标是否符合预期, 通过追踪来确认服务的上下游依赖是否正常。
同时我们需要注意到日志、监控和追踪的数据不是完全独立的,而是互有交集的。一个事件可能是一个可以被量化的指标,也可能是一个请求维度内的数据,日志、监控和追踪间的数据是互通的,通过不同数据间的联系我们从而将日志系统、监控系统、追踪系统互相打通,方便业务研发跳转于各个系统间,快捷且深入地来排查问题。
我们可以通过一次具体排查问题的流程来看它们的数据是如何打通的
收到报警: 最开始服务触发报警然后发送告警出去, 比如某个监控指标超过阈值
报警 =>监控: 报警信息里会携带监控面板的 URL, 点击就可以跳转对应监控指标面板, 查看监控数据的时间变化趋势
监控 =>日志: 通过监控中的关键字 (如错误信息, URL 等), 可以直接跳转到日志系统中直接查询出服务日志包含关键字的日志
监控 =>追踪: 通过监控中的请求信息 (如 URL, 错误码等), 可以直接跳转到追踪系统中, 查看包含对应请求信息的失败请求链路
日志追踪: 日志与追踪数据通过 RequestID 互相打通, 服务日志中均包含了请求的 RequestID 点击可以直接跳转到对应的追踪页面, 在追踪页面处可以点击服务名称查看对应的所有链路日志, 上下游服务对应的请求日志也支持从追踪页面跳转查看, 方便上下游间研发交流和排查问题
服务观测体系的规模
当前作业帮服务观测体系上支撑着海量日志、监控和追踪数据的流转
日志: 支持峰值每秒 4000W+ 的日志数据流通, 每天处理万亿量级的日志数据, 每天的日志数据 PB 级
分布式追踪: 支持峰值每秒 1000W+ 的追踪数据流通, 每天处理千亿量级的追踪数据, 每天的追踪数据 TB 级
监控: 支持峰值每秒 800W+ 的监控数据流通, 每天处理 5 千亿量级的监控数据, 每天的监控数据 TB 级
通过以上数据说明,作业帮服务观测体系的建设在互联网企业有一定的代表性的。
服务观测体系的技术方案
日志
作业帮所有服务节点都会部署自研的 log-agent 组件来采集服务、中间件和节点的日志。
在日志采集后,通过 Kafka 做日志数据传输,后端同时对接着大数据、日志检索、业务监控等多个消费服务。
最后,所有日志数据最终都会上传到对象存储中,以 zstd 的格式压缩保存。
监控
作业帮的监控系统围绕 Prometheus 进行构建,Prometheus 当前已经是云原生监控的事实标准。它在作业帮的监控体系里承担着数据采集的角色, 并将监控数据实时写入到 VictoriaMetrics 时序数据库中。
Prometheus 模块本身不做数据持久化, 从而保证了整个 Prometheus 服务是无状态的, 如果发生机器宕机可以快速自愈。
为了应对庞大的监控数据量, 我们通过 hashmod 的方式对 Prometheus 进行了分片, 按数据量的大小在集群内部署一个或多个 Prometheus 实例。
VictoriaMetrics
我们使用 VictoriaMetrics 做为监控数据的持久化存储。选择它主要有 3 个原因:
兼容 Prometheus 的查询语句: 可以像 Pormetheus 一样使用它, 从而做到对外无感透明
高性能: 相比其他主流的时序数据库, 有着更高的性能和更少的内存使用
高压缩率: 能更有效地使用存储空间, 这个能减少存储监控数据使用的机器成本
分布式追踪
追踪体系在作业帮内部落地时, 采用了 jaeger 作为底层来采集服务请求, 用 Kafka 来传递追踪数据, 最后将追踪数据写入到 ClickHouse 中保存,。
同时还有拓扑分析服务对接着流式追踪数据,提供实时的服务拓扑分析聚合数据,以时序数据的方式保存在 prometheus 中。
服务观测体系落地的核心要素
成本低廉
成本在服务观测体系落地上至关重要,一般来说服务观测成本不能超过业务总体成本的 15%。但是对于大部分企业来说实际应该位于 10% 以下才能说服决策者进行大规模应用。比如全量而非采样进行分布式追踪采集,日志保存时效长短。这些数据对后期高级观测能力的效果至关重要。
作业帮在成本优化上几个探索:
日志检索服务通过自研分布式计算替代 ES
ELK 是大部分公司日构建志体系的基础方案,但现在随着服务和流量的增长,在海量日志数据场景下显得越来越力不从心。最主要的问题在于 ES 上,ES 是一个搜索引擎,会付出大量的资源用于索引的构建和维护,以提升检索速率,最终形成数据膨胀。
日志检索是一个明显的写多读少的场景,绝大部分日志在写入后可能就没有任何访问。为此构建大量索引带来的问题就是写入性能劣化,同时也会导致日志数据的膨胀,这些都会带来额外的成本开销。另外日志检索是一个时延不敏感的场景,查询多花一秒少花一秒对用户体验不会有大的影响。
作业帮的日志检索系统就是基于 indexless 的方向设计实现的。在日志写入阶段,不会对日志做解析格式化,而是直接批量写入到文件中,以实现最大的写入性能。日志文件则会按块切分并压缩,每个压缩日志块大小保证在 8M 左右,同时会按时间、所属服务、实例名、日志类型等数据为日志块编制索引。通过这种设计,单核可以支持 50MB/S 的日志写入。
在用户查询时,日志检索系统会基于检索条件圈定符合条件的日志块,然后并发对这些日志块数据做全文检索。如果检索的并发量足够,即是全文检索也能保证一个相对短的查询时间。作业帮的检索系统可以支持 1TB 的日志在 10s 内完成查询。
日志采集组件性能优化
众所周知大部分互联网企业的用户流量非常巨大,并且有明显的高低峰,高峰时单台机器的日志写入可以到 1GB+/S,并且后端的日志链路要求传输时延要保证在 10S 内。
面对这种需求,市面上的日志采集器都难以满足需求,为此我们自研了日志采集器。主要做了以下几点优化:
第一个是优化了 json 解析逻辑, 容器记录的日志默认就是 json 格式并且格式都是固定的, 我们选择通过字节处理的方式实现日志的对反序列化
第二个是优化容器的生命周期监听, 基于节点 kubectl 实现 Pod 生命周期监听和元数据获取,避免了连接 apiserver 和频繁获取的开销
第三个是针对容器的采集场景进行优化, 让采集流程更加轻量化, 降低采集器的开销
第四个我们保证了每个采集协程资源隔离, 避免资源竞争的情况, 从而不会出现一个 Pod 日志量太大影响到其他 Pod 日志的上送
如此, 全新的采集器单核可以支持 100MB/S 的采集速率, 上线后单机的采集性能提升 3 倍, 采集所使用的 CPU 降低了 70%。
分布式追踪使用 clickhouse 替代 ES
作业帮的分布式追踪采用的是 100% 采样的策略,这样就导致了线上的追踪数据量极其庞大,特别是在晚高峰的时候。作业帮最早存储追踪数据使用的是 ES,实践发现 ES 的写入性能不够理想,在高峰时总是出现写入延迟的情况,影响追踪服务的正常使用。
为此我们调整了 jaeger 服务的写入和查询代码,增加了 clickhouse 的实现,将数据的存储迁移到了 CK 上,得益于 CK 的高性能索引和存储设计,系统性能有了很大的改善:
写入性能提升了 40%
CPU 使用下降了 80%
磁盘占用降低了 50%
整体成本降低为之前的 20%.
稳定可靠
日志可靠性
日志可靠性最重要的就是保证日志不丢失,丢失日志会直接影响到监控、统计、BI 的数据准确性。
为此我们建立了端到端的监控指标,在采集端按日志输出时间统计每个时间段内发送的日志数量,又在消费端同样按日志的输出时间统计每个时间段内接受的日志数量,保证了统计口径的一致, 不会因日志传输延迟而影响统计。
日志 SLA 全年可以保证在 6 个 9 以上。
监控可靠性
监控可靠性的核心在于存储,存储层需要保证高可用,监控数据的延迟和失败都是不可接受的,会直接影响到监控告警的准确性。
为此我们在 VictoriaMetrics 上新增了一层 Proxy 组件,用于代理 prometheus 的读写流量,基于 Proxy 实现了存储多活、归档数据降准、指标自动老化等能力,去掉冗余的监控数据,并通过多活自动切换机制保证监控数据高可用。
监控 SLA 全年可以保证在 5 个 9 以上。
追踪可靠性
相比于日志和监控,对于追踪数据的可靠性要求会相对低一点,我们主要依赖 ClickHouse 来保证数据可靠性。
ClickHouse 更优的稳定性:相比于 ES,CK 的的运维成本相对更低,其架构设计使得日常维护相对简单。
ClickHouse 多副本机制:单点宕机不会影响系统可用性。
追踪 SLA 全年保证在 4 个 9 以上。
无感全覆盖
日志全采集
应采尽采: 日志系统会对系统内的所有日志均进行采集,包括服务日志、中间件日志、系统日志,保证系统中所有发生的事件都能被回溯。
平滑接入, 支持各种语言, 支持非结构化日志:服务可以无感知地接入整个日志系统,对接入的日志格式不做要求,无需调整日志模块,日志对服务来说是一个透明的基础设施。
Serverless 覆盖:云厂商的 serverless 虚拟节点上不支持部署自定义的采集器,为此我们实现了多云上的 daemonset 自动注入能力,serverless 上的 pod 会自动注入日志采集边车,做到无感的采集覆盖。
监控自下而上
作业帮内部的监控指标主要有以下几大类:
资源监控
支持了 Pod 和 Node 的 CPU、内存、磁盘、网络和 GPU 监控,同时会对机器中的内核参数选择性地进行采集和记录
系统监控
采集了 K8S 系统中的各项指标, 包括 apiserver, etcd, k8s 调度器等数据 ; 同时依赖的各种组件和中间件 (Ingess, Egress, DNS 等) 也会统一监控。
存储监控
作业帮内部使用最广泛的存储有 mysql, redis 和 ES; 通过对其数据 Proxy 的监控, 提供了存储视角的监控数据。
Runtime 监控
作业帮内部通过框架收敛让服务暴露了 Runtime 监控数据, 通过持续的 Runtime 监控数据可以更深入地来定位内存泄漏、CPU 打满等深层问题
流量监控
作业帮的所有服务都会接入 ServiceMesh, 通过 ServiceMesh 的监控我们可以看到服务所有出入流量的数据, 包括了 QPS, 请求 / 响应耗时, 成功率, 状态码分布和失败情况等数据
MQ 监控
消息队列作为服务异步通信的核心, 它的健康情况也紧密关系着服务的可用性。通过 MQ-Proxy 和统一框架, 我们支持了服务对 MQ 使用情况的监控, 包括消息生产 / 消费数量, 生产 / 消费失败, 消费延迟及死信数量等数据。
服务监控
通过一致的框架提供了基础的异常监控 (服务 panic, 服务 core) 和业务结果码分布的数据。如果服务有更进一步的业务监控需求,也支持暴露 metrics 指标接口来接入监控体系。
在以上监控指标的落地上, 我们优先选择通过暴露 Metrcis 来采集,K8S 的组件原生都支持 Metrcis 接口, 而我们自研的各种组件和中间件 (gpu-exporter, mysql-proxy, redis-proxy) 也尽量遵循了这一标准。只有在时延非常敏感的模块上,如 Ingress 和 Egress, 通过日志来采集数据。
追踪全采样
追踪上我们采用的是全采样的策略, 这样当研发遇到问题时可以通过 requestID 直接查看请求链路定位问题了。当前提供了 3 种追踪数据采集方式
基于 Mesh 的服务出入流量采集:作业帮 ServiceMesh 组件会对服务的所有出入流量进行埋点,并自动上报到追踪系统中。这种接入方式不受语言限制,对服务透明,只要服务有请求皆可在追踪链路中体现。
基于框架的存储流量采集:因为 mysql 和 redis 等存储的请求对于时延敏感,作业帮内部在框架上做了统一埋点,基于存储访问日志的形式上报相关追踪数据。这种接入方式同样对于服务无感,可以完成存储流量的覆盖。
基于 SDK 的业务行为打点:上述埋点策略可能无法覆盖到服务内部的业务操作部分。对此我们提供了 SDK,服务可以基于 SDK 生成打点数据并自动上报,从而完成业务操作的追踪覆盖。
通过这 3 种埋点方式及全采集的策略,追踪系统可以覆盖到服务和流量的方方面面。
结 语
以上就是作业帮对于整个基础观测能力的一个整体介绍。在基础观测能力上我们认为后续要围绕着这几个方向继续演进:
更低廉的成本
观测的核心成本在于存储,而进一步降低成本的关键我们认为就在于存储介质的演进。在日志的存储实践后上我们认为对象存储是一个理想的存储介质,支持多副本,数据归档,无限扩展等能力。后续我们也计划将监控和追踪的存储与对象存储做整合,系统上存算分离,拥有更低廉的成本和更好的扩展性。
更广泛,更透明的覆盖
当前的观测数据中有不少对语言和框架还存在着依赖,理想中基础观测需要对所有服务提供一致的观测体验,是一个透明层,并覆盖所有服务的核心指标。作业帮后续会在 ServiceMesh 寻求观测能力的进一步拓展,提供出一个不限制语言的观测基础能力。
高级观测能力演化
在有了完善的观测数据后,我们就可以在这些数据上进一步挖掘探索高级观测能力,当前作业帮已经开始做故障预测和根因分析能力等能力的探索和落地。
今日好文推荐
传字节跳动内部开始禁用Cursor了
模型下载量12亿,核心团队却几近瓦解:算力分配不均、利润压垮创新?
印度国家级大模型上线两天仅 300 余次下载,投资人直呼“尴尬”:韩国大学生模型都有20万!
Java 三十周年重磅发声:James Gosling 怒斥 AI 是“一场骗局”,是科技高管“疯狂压榨”程序员的新工具
来源:InfoQ