作者丨吴树生:腾讯高级工程师,负责SNG大数据监控平台建设。近十年监控系统开发经验,具有构建基于大数据平台的海量高可用分布式监控系统研发经验。
导语:当前SNG全链路日志监控平台每日数据存储量10TB,可做到1/10的压缩比,峰值流量30GB/s。在构建这样一个平台时,究竟遇到了什么技术困难,以及是如何解决的,请看原文。
背景
全链路日志监控在现在盛行的微服务和分布式环境下,能有效地提高问题定位分析效率,成为开发和运维利器。当前已有开源解决方案和成熟的厂商提供。
比如Twitter的zipkin基于Google的Dapper论文设计开发了分布式跟踪系统,用于采集各处理节点间的日志和耗时信息,帮助用户排查请求链路的异常环节。
在有统一RPC中间件框架的业务部门容易接入zipkin。但腾讯SNG全链路日志监控平台(后成全链路)面对的实际业务场景更为复杂,全链路日志监控实现遇到更多的挑战,全链路技术选型经历了从开源组件到自研的变化。
当前SNG全链路日志监控平台已接入空间和视频云业务日志数据。每日数据存储量10TB,可做到1/10的压缩比,峰值流30GB/s。
我们先分享一个案例场景:
2017年8月31日 21:40~21:50 X业务模块指标异常,成功率由99.988%降为97.325%。如下图所示: 收到成功率异常告警后,在多维监控系统上通过画像下钻发现是空间点播业务的iphone客户端成功率下降,返回码为-310110004。如下图:
通过大盘多维数据分析发现异常原因后,因涉及APP问题,还需要进一步分析用户出现异常的上下文。因而需要查看出现异常的用户在异常时间点的全链路日志数据。在全链路视图上,可以展示查询出来符合异常条件的用户日志和操作过程。
以上是从面到点的异常分析案例。
使用场景
归纳全链路日志监控的使用场景主要有三大类:
- 一是个例分析,主要有处理用户投诉和从面到点的异常分析;
- 二是开发调试,主要用于开发过程中查看关联模块的日志和作为测试提单线索;
- 三是监控告警,主要是从日志数据中提取维度,统计为多维数据用于异常检测和原因分析。
遇到的挑战
在构建全链路日志监控平台时,监控模块经历了从传统监控和质量统计到大数据多维监控平台的转型。踩过大数据套件的坑,也遇到过业务场景的挑战。
业务多样性挑战
QQ体系内有丰富多样的业务,例如:手Q、空间、直播、点播、会员等。这些业务产生的不同样式的日志格式,并且没有一致的RPC中间件框架。这个背景决定系统需要支持灵活的日志格式和多种采集方式。
海量数据挑战
同时在线超2亿用户上报的状态数据,日存储量超10T,带宽超过30GB/s。需要稳定和高效的数据处理、高性能和低成本的数据存储服务。在使用开源组件完成原型开发后,逐渐遇到性能瓶颈和稳定性挑战,驱使我们通过自研逐渐替换开源组件。
应对挑战
▼ 日志多样化
日志的价值除提供查询检索外,还可做统计分析和异常检测告警。为此我们将日志数据规范化后分流到多维监控平台。复用监控平台已有的能力。
基于前面积累的监控平台开发经验,在设计全链路日志监控平台时取长补短。通过自研日志存储平台解决开源存储组件遇到的成本、性能和稳定性瓶颈。
我们的全链路日志监控平台提供了4种数据格式支持,分别是分隔符、正则解析、json格式和api上报:
分隔符、正则解析和json格式用于非侵入式的数据采集,灵活性好。但是服务端的日志解析性能较低,分隔符的数据解析只能做到4W/s的处理性能。而api方式则能达到10W/s处理性能。对于内部业务,我们推荐采用统一的日志组件,并嵌入api上报数据。
▼ 系统自动容灾和扩缩容
对于海量的日志监控系统设计,为做到系统自动容灾和扩缩容,第一步是将模块做无状态化设计。比如系统的接入模块、解析模块和处理模块,这类无需状态同步的模块,可单独部署提供服务。
但对这类无状态业务模块,需要增加剔除异常链路机制。也就是数据处理链路中如果中间一个节点异常,则该节点往后的其他节点提供的服务是无效的,需要中断当前的链路。异常链路剔除机制有多种,如通过zk的心跳机制剔除。
为避免依赖过多的组件,我们做了一个带状态的心跳机制。上游节点A定时向下游节点B发送心跳探测请求,时间间隔为6s。B回复心跳请求时带上自身的服务可用状态和链路状态。上游节点A收到B心跳带上的不可用状态后,如果A下游无其他可用节点,则A的下游链路状态也置为不可用状态。心跳状态依次传递,最终自动禁用整条链路。有状态的服务通常是存储类服务。这类服务通过主备机制做容灾。如果同一时间只允许一个master提供服务则可采用zk的选举机制实现主备切换。 做到系统自动容灾和扩缩容的第二步是实现通过路由机制实现名字服务和负载均衡。使用开源组件zookeeper能快速实现名字服务功能。要求在服务端实现注册逻辑,在客户端实现路由重载逻辑。
▼ 数据通道的容灾
我们采用两种机制:双写方式和消息队列。
● 对于数据质量要求高的监控数据,采用双写方式实现。这种方式要求后端有足够的资源应对峰值请求。提供的能力是低延时和高效的数据处理能力。 ●对于日志数据采用具备数据容灾能力的消息队列实现。使用过的选型方案有kafka和rabbitmq+mongodb。
采用消息队列能应对高吞吐量的日志数据,并带有削峰作用。其副作用是在高峰期数据延时大,不能满足实时监控告警需求。采用消息队列还需要注意规避消息积压导致队列异常问题。
例如使用kafka集群,如果消息量累积量超过磁盘容量,会造成整个队列吞吐量下降,影响数据质量。
我们后来采用rabbitmq+mongodb方案。数据在接入层按1万条或累积30s形成一个数据块。将数据库随机写入由多个mongodb实例构成的集群。将mongodb的ip和key写入rabbitmq中。后端处理集群从rabbitmq获取待消费的信息后,从对应的mongodb节点读取数据并删除。通过定时统计rabbitmq和mongodb的消息积压量,如何超过阈值则实施自动清理策略。
▼ 查询
日志的存储方案为应对高效和低成本查询,我们采用自研的方式实现。全链路上报的数据按用户ID或请求ID作为主key进行hash分片。分片后的数据在缓存模块累积1min或1M大小,然后写入文件服务器集群。文件写入集群后,将hash值与文件路径的映射关系写入ElasticSearch。
查询数据提供两类能力:
第一类是按主key查询。查询方式是对待查询key计算hash值,从ES中检索出文件路径后送入查询模块过滤查找;
第二类查询能力是非主key的关键字查找。根据业务场景,提供的查询策略是查询到含关键字的日志即可。该策略的出发点是平衡查询性能,避免检索全量文本。也就是第一次查询1000个文件,如果有查询结果则停止后续的查询。如果无查询结果返回,则递增查找2000个文件,直到查询10万个文件终止。
为满足多样的业务场景。我们在数据处理模块抽象了ETL能力,做到插件化扩展和可配置实现。并提供统一的任务管理和集群管理能力。
总结
全链路日志监控的开发过程有以下经验可借鉴:
- 使用成熟的开源组件构建初级业务功能;
- 在业务运行过程中,通过修改开源组件或自研提升系统处理能力和稳定性,降低运营成本和提升运维效率;
- 采用无状态化和路由负载均衡能力实现标准化;
- 抽象提炼功能模型,建立平台化能力,满足多样业务需求。