@gaoxiaoyunwei2017
2018-01-17T14:47:32.000000Z
字数 4200
阅读 508
毕宏飞
陈晓鹏
我今天分享的是关于微信后台系统现状,我们现在月用户数已经有9亿了,在这基础上产生的后台调用数每分钟可能有超过200亿次,现有的模块数有5000个以上,它是在超过5万台服务器上,面临这么大的数据不可能对大规模服务器做监控和处理,所以我们很依赖我们运维监控系统。
我们的运维监控系统主要有三个功能:
今天我们的分享主题,主要有以下三部分:
第一个就是监控数据收集轻量化;
第二个是微信数据监控的发展过程;
第三个海量监控分析下的数据存储设计思路。
先看一下常见数据收集流程,一般常见的采集流程来说从日志里面采集,然后本地汇总打包,再发到全局服务器里面汇总。
但是对于微信来说,我们面对的是每一分钟就有2000亿次以上的上报,这个可能还是比较保守的估计。如果还是用文本性的数据来说,不管是CPU还是网络方面都是非常大的压力。我们监控的业务有很多,所以这个日志格式也非常多,基本上是难以维护的,如何才能实现分钟级、甚至秒级的数据监控呢?
对于我们内部监控数据处理分为两个步骤:
我们对数据进行分类,在我们内部来说有三种数据:
第一是实时故障监控分析;
第二种是非实时数据统计,比如说业务报表等;
第三种是单用户异常分析,比如说用户一个报障过来还要单独对用户故障进行分析。
对于非实时数据来说,我们有一个统计管理页面。
用户在上报的时候会先申请 logid + 自定义数据字段,数据上报的时候不能使用日志的方式,所以我们上报的时候在后台服务里面,会有共享内存队列,然后对这个数据进行采集。因为数量太大,只能批量发送,再发到数据中心区,把数据写到我们的分布式存储里面,再使用一些定时的统计,这就是我们统计的一些处理,非实时数据统计流程。
对于单个用户异常分析来说,我们关注的是异常,所以上报路径跟刚才非实时的路径比较相近。
采用固定的格式: logid + 固定数据字段(服务器IP+返回码等),数据上报量比刚才的非实时日志还要大很多,所以我们是抽样上报的,除了把数据存入到Tdw分布式存储里面,还会把它转发到另外一个缓存里面进行一个查询缓存。
实时监控数据是重点分享的一个数据,在实时监控数据中我们的监控数据不是只有一种,还有很多类的监控数据,而且它的数据量占了2000亿的绝大部分,那么这个肯定不能采取定义的格式,所以同样需要先把数据分类搞清楚。我们有什么样的监控数据,需要对我们数据进行简化,再对简化后的数据采取一些最优的数据策略。
对我们数据来说,我们觉得有下面几种:
对于我们后台数据监控来说,我们觉得按层次来说分为四种:
对数据格式进行简化,按不同层次定义不同的方面。
比如说对IP定义成三个维度的ID,模块间调用链是5个模块的接口,还有一些具体的业务指标,变成了两个维度数据,为什么是两个维度?因为我们觉得有些数据肯定是有关联的,这个ID就是一个组的概念,方便我们进行分析。
我们重点说一下IDKey数据,上报次数是2000亿次,可能还远超这个。所以日志式数据处理是肯定不行的,因此定制了一个比较简化的快速上报方式,用快速的内存汇总,具体上报方案可以看下面这个图。
每个机器里面都申请了两块共享内存,这个就是ID的数量,是0到3万Key的数量。有两块的原因是方便收集数据的时候对数据进行上报,我们内部只允许有三种上报方式:累加、设置新值、设置最大值。这三种方式是操作一个,其实性能消耗非常小,而且还有一个最大的优点,就是内存里面已经集成了汇总,实际上每分钟数据从内存出来之后只有1000条,大幅度降低秒级汇总难度。
后台数据里面还有一个最关键的就是调用关系数据,用于对故障分析定位的时候有非常大的作用。
具体到了A模块a机b进程,调用到B模块x机y接口,调用数、失败数、耗时,可以定位故障点(机器、进程、接口)及影响面。这个数据是非常有用的数据,虽然它的数据量没有刚才所说的 IDKey 那么大,但也不小,所以使用日志方式还是很难处理。我们内部用了另外一种跟 IDKey 更接近的方式,也是用共享内存,不是全局共享内存,是共享内存的上报方式。比如说一个服务有N个,每个 Worker 有响应的Mem匿名共享内存,发到一个 Collector Agent 里面,让数据更容易进行一个全局的汇总。在后台容易实现是因为我们都用了,微信99%都是我们自己开发的,所以非常容易实现统一。
后台数据我们介绍完了,再说一下终端监控数据。这个我们可能关注的是手机端的APP,或者微信方面一些具体的性能、具体的异常;另外还有调用到我们后台产生耗时,异常方面的数据也要关注;网络异常出现问题没有到达我们的后台,都是需要了解的。
这样的数据对上报来说,在手机终端是对数据进行上报,它不是全量也不是实时的上报,会先从我们后台一个产业配制服务里面拉取一个采样配制,再根据这个采样配制上报。它不会马上发出去,而是用一个临时的存储把比较多的数据累积起来,隔一段时间打一个包到后台,再把数据发到全局的汇总服务进行汇总,这就是我们终端智能监控的上报处理流程。
下面介绍一下我们最新的对外监控服务,这个方案参考了一些同样的方案,用户可以自行配制数据格式及监控,具体的格式有 UID、METRIC 等等,用户可以定义的是它的维度的数量还有维度的名字方便进行日常使用还有上报。
现在在我们的商户管理界面还有小程序开发者工具的页面都已经有了,这个监控的查看还有打开的功能。其实我们现在自定义上报还没有固定的上报,如果有腾讯云可以了解云监控的一个上报的处理流程。
我们具体是怎么样用这个数据进行监控的?
首先一般异常检测来说,可能都会用到三个办法:
第一个是阈值,甚至在早上和晚上都是有很大差异的,这个阈值本身没法去划分的,所以这个对于我们来说只适用于少量的场景;
第二个是同比,这个问题是我们的数据都不是很稳定,甚至周一到周六都有很大的差异。如果要准确,只能说降低敏感度才能报警,只有这样才能保证它的准确性;
第三个是环比,相邻的数据并非平稳变化,数量级比较小时尤其明显,同样只有降低敏感度才能保证准确性。
这三种常见的数据处理方法可能都不是很适用我们的场景,我们做了算法改进。在内部有一个均方差,就是拿过去一个月每天同一时间的数据计算平均值与均方差,用多天数据适应数据的抖动情况,去修改一下允许方位。比如说抖动比较小允许范围就比较窄,抖动比较大范围就比较大。如果波动比较大的曲线,敏感度就比较低了,容易漏报。
我们改进的第二个算法就有点像改进的环比了,只是多项式拟合预测,适用于周期稳定曲线,通过历史数据预测数据趋势。
但是它的问题对于我们内部来说,比较容易出现的情况是数量不是突然抖动,出现很长时间的缓慢变化也不会判断为异常,所以我们还在做其他的尝试。
算法之外我们配置还是存在很多问题的,因为我们的服务非常多,所以可能超过了30万的监控项要人手配置,观察曲线选择不同算法,不同的敏感度。过一段时间之后,又要调整了,选择不同的敏感度。
这个就是对监控数据自动分类算法的一个参数,比如说是拿历史数据,还有历史异常样本,抽取特征,进行数据分类,再套用响应的适配算法服务。这个我们正在尝试取得了一些成果,但还不是很完善,还在改进中。
上面分享了数据怎么采集,数据怎么来监控,最后再提一些数据怎么存储。数据存储很重要,刚才的数据是要拿一个月数据出来每分钟都要监控,比如说我们的故障分析页面在没有自动化分析之前,我们是人工靠页面分析的。一个模块有异常,可能要读取所有机器调用信息,还有它的各个CPU各种进程信息出来,在一个界面里展示。
对于机器数特别多,一次读取就是50w的数据,这个要求非常高。对于我们监控数据存储来说,基本要求是首先入库量可能一分钟有2亿条以上,单机至少要求500w/min能入到这个数据量。对于数据读取量来说没有支撑我们那个50w×22天的数据,故障定位读取任务时间是50w×2天。还有我们各种数据是多个维度的,结构分析的时候,我们要读取一个模块所有的相关数据,那必然要求是跟其他可能一些存储不同的地方,就一定要实现多维度的key,还有部分匹配的查询。
比如说我们监控数据入库来说,大家可以想像如果一分钟一条记录,数据量过大。所以都是先缓存一定时间的数据,再合并成一天一条记录。我们是内存缓存一个小时再到记录存储里面,具体是自行实现 Key-Value 存储,Key常驻内存,Hash加速批量查询。
在这个里面我们是对主key进行存储,只要主key使用得当也可以起到很好的作用。要实现一部分匹配查询,key使用二分查找,支持前置匹配查询,就很容易实现一个东西,基本达到一半的性能。可以看到这个存储很简单,它的性能基本很小,所以很容易达到单次100万以上的查询量,还自带一些缓存,但它还是有问题的,它的 Hash 数据极不均衡。
由于上面的问题,我们做了第二个改进。
第二个改进的方法是把 Key-Value 拆分成 key-id-value ,通过id分配服务控制 values 数据均衡,key-id 7天重新分配一次,常驻内存,对于我们数据查询来说都是非常接近的一个性能来算的。
对于存储来说还有一个最大的问题就是容灾,既然是对服务器进行监控,自身的容灾能力也一定很强,一般来说这个都是比较难。微信后台已经开源了一个协议的框架,很容易就可以实现数据容灾,就是使用微信开源的 phxpaxos 框架进行容灾, phxpaxos 框架的多 master 都可以找得到。