大家好,我是百度运维部平台研发工程师颜志杰,名称服务(BNS),监控(收集和计算);今天很高兴和大家分享在做“监控”过程中的一些心得和教训。 现在开始分享,本次分享的主题是《多维度数据监控采集&计算》,大纲如下,分为3个部分: 1.监测目标与挑战 2.多维数据监控 2.1.采集设计与挑战 2.2.聚合计算设计与挑战 2.3.提出问题,摆出门面,提高分享水平(个人理解,欢迎挑战)。 监控期望做到:快速发现问题、定位问题(运维层面)、解决问题,甚至在问题发生之前,预知/预防问题,形成处理闭环,减少人工决策-进行干预。 首先解释一下“定位问题(优先运维级别)”,意思是从运维的角度来“定义故障”。它不需要在代码层面定位异常,只需要定位到哪个运维操作可以恢复故障即可。比如确定是变更引起的,就在线回滚,机房故障,切换流量等等…… 不代表监控不应该定位到代码层面的问题。进球后,我们可以更深入。 解释“事前预测/预防”。很多人的第一反应是大数据挖掘。其实可以做的事情有很多,比如把变更的发布和监控联系起来。”维度来展示。(记住“分级”维度,先卖了:) “监控目标”这个话题太大了,有很多挑战。克制一下自己,说说我们遇到的一些问题我们在做监控的时候,挑了两个大头,相信其他在大公司做监控的同学也有同感: 1.监控指标多,告警多 2.告警多并且它们是相关的。如何从众多的异常中找到“根本原因” 今天抛出两个让人头疼的问题,下面我们就从“多维数据监控”这个话题开始吧,这两个问题大家可以听听,看看解决方案能不能“缓解”这两个问题。 进入正题: 先来看第一个问题:监控数据很多。监测数据符合28定律,需要区别对待“关键”和“次要”指标。我们不应该为我们处理了多少数据而感到自豪。我们需要根据重要性对它们进行分类处理,分配资源给重要的数据进行分析处理。#p# 监控一个服务,关注20%的关键指标数据,80%的次要指标用于分析问题根源。如何采集关键指标留到采集章节。下面以百度产品线接入服务为例,说明对“关键”指标的处理要求。以下以百度地图产品线访问日志为例(典型的nginx日志):223.104.13.177--[27/Jul/2015:16:08:21+0800]"GET/static/apisdkHTTP/1.1"20036224"-""-""Dalvik/1.6.0(Android4.4.2;HUAWEIMT7)"0.0020501076098223.104.13.17710.202.19.4010.202.68.25:8210www.baidu.com百度地图访问服务需要这些监控:根据运营商、省份、省份和运营商pv/ping环;不同机房不同的urihttp_codepv/ping环,请求手机操作系统版本的pv... 可以看到一个指标会变成多个指标,比如PV监控项会根据生成900个指标数据5大运营商*36个省*5个机房。这种配置手工管理难度很大,如果新增机房,需要增加5*36=180个配置。这已经不是人类可以做到的了。 同时,这些指标是相互关联的。自然要知道地图pv数据,哪些运营商、省份、机房有数据,就需要对监控项进行元管理。 综上所述,“关键”指标数据需要多角度/多维度观察,一个点会变成更多点。这些多点数据相互关联,需要进行元管理和简单配置。那么如何解决呢? DatamodelGoahead*3(重要的事情说三遍),选择一个好的数据模型来组织监控数据,解决上面提到的问题,会有不同的效果,下面是优缺点两个数据模型(也是我们自己的监控历史)。 贴图: 监控数据需要多角度观察,这是一个强烈的需求。在一维数据模型中,维度信息放在监控项的名称中。例如nginx_pv_city_beijing_isp_unicom表示北京联通的PV,nginx_pv_city_beijing_isp_cmnet表示北京移动的PV。 这种数据模型,监控项之间是没有关系的。除非对名称进行一系列规定,并增加对名称的拆分操作,否则很难将上述两个数据联系起来;并且配置的数量是的维度笛卡尔积。 参考aws的cloudwatch,多维度的数据模型,通过tag扩展维度,比如在tags字段中放入运营商和省份,这样一次配置就可以生成900个关联的监控数据;并且增加了product字段,在数据分类和权限控制方面很有用,后面会扩展。 日志中没有运营商、省份、机房信息。你怎么得到它们?这些统称为“运维要素信息”。这样的印象,标签中“维度”的值可以很“可扩展”。 所以结论是监控数据符合28条规律,重要数据需要多角度观察,会产生多个相关数据,需要进行元管理,需要动态简单的配置。多维数据模型可以很好地解决这些问题。在内部,我们将这种数据模型的监控称为“多维数据监控”。 多维数据监控并没有减少处理/资源消耗,900个数据中的一个是很多的,所以我们把这个解决方案定位为处理“关键”数据和倾斜资源;而只关注不同维度的聚合数据,Stand-alone数据可以存储在单机上,这是基于资源的考虑。 说了这么久,现在来看看“多维数据监控”的框架拆解: 典型的分层处理架构,采集=>计算=>存储=>告警+展示,没什么特别的说起来,我想强调两点: 1。数据模型是第一位的。任何一个层次只要符合“多维数据模型”就可以独立使用,每个层次都是面向服务的。再次强调“数据模型优先”。 2.聚合流计算的分布式架构,没有开源实现。在开源之上有一个适配层。许多过程可以在适配层进行。这个好处在可用性章节中有具体的扩展。 以下章节将依次介绍多维采集&聚合计算&高可用保障: 先介绍采集,如果你对logstash比较熟悉那么***,采集代理的很多功能都是参考logstash写的,当然网站的设计有一些改动,欢迎拍砖。 数据收集是一个标准化的过程。服务以一定的方式吐出数据,采集负责将数据转化为监控数据模型,发送给下游进行处理;所以最理想的情况是推监控标准,服务链路监控lib,lib将服务的核心指标吐出来。 理想情况下,我们正在努力,但是……所以,目前大部分的关键指标都是通过日志获取的。一种减少数据传输的方法。 2.如何对日志进行正则化=>参考logstash,使用命名规范进行正则化。 3.标签必须非常“可扩展”=>代理端需要支持标签的定制。 来谈谈如何按顺序减少数据传输。首先在单机上做聚合,即在一个周期内(比如10s),将所有具有相同tag值的监控合并为一次数据传输。比如在百度地图接入服务中,北京联通的请求在10秒内就变成了一条监控数据。实践证明,这种策略对于减少数据是非常明显的。 数据归约方式包括ETL和公式计算。代理端决定哪些数据不需要传输。比如实现dict映射,只释放字典dict中的值,其余归于other。 比如其实有20+个算子,但是OP一般都集中在4大算子上,所以其他算子可以通过dict归于“other”,并且还支持重命名,不仅规范了tag的提取value,减少传输数据,比如下面的dict:"dict":["CHINANET=>Telecom","UNICOM=>Unicom","CMNET=>Mobile","CRTC=>Railcom"] #p#公式计算也是如此。尽快过滤不需要的数据。我们支持四种逻辑运算。当agent端有了这样的表达能力,就扩展了agent的收集能力,采集很多有趣的监控项: 例如,根据nginx响应时间${cost}和http错误码${errno},定义pv损失,使用公式:${cost}>2000||${errno}!=200时间大于2s或errno不等于200,保证聚合计算函数的纯分片,减少数据传输量。 第二个问题是如何对日志进行正则化,通过命名正则化格式化文本日志。用c++写的客户端性能比logstash快很多。这里要强调一下,我们不支持像logstash这样的多线程做正则化,只有一个线程计算。对此的考虑是: 正则匹配成功性能还不错,一般性能能耗都在不匹配的日志中,当出现不匹配时,正则化会执行一些回溯算法之类的耗时操作,agent是这样设计的尽可能少地进入“不匹配日志”的处理过程。 加入“pre-match”功能,类似于去grep日志时,“greptimestamp|grep–P'regular'”,字符串搜索和正则匹配的性能有很大的不同。agent端借鉴了这个思路,通过指定一个字符串进行搜索过滤,保证后面的日志基本匹配成功,尽量避免“常规回溯”等耗时操作,在正确的地方解决问题。 这样的设计保证了agent最多占用一个cpu。实践证明,通过“预匹配”,保证进入正则日志基本匹配成功,上千qps无压力,一般只占一个CPU核的30%。 第三个问题是Tags的扩展性。标签是整个多维监控的本质。首先,我们支持用户自定义任意标签属性,并提供统一的接口。你可以在监控数据上定义任意标签,比如searchlibrary层属性可以添加到服务中。 对于上面提到的运营商和省份,这是通过在代理端使用一个ip库来实现的。当然ip库的更新是个问题。目前是随着代理的升级而更新,时效性不高。可以考虑一下为什么不在服务器端处理:) 日志采集代理通过以上方式基本满足了关键指标的采集要求,完成了数据“标准化”和“简单化”的要求. 综上所述,日志收集是一个标准化的流程。通过采集配置,将日志中的信息转化为多维度的数据模型,发送给后端模块进行处理。 相对于logstash,我想强调的是预匹配功能。我没有借鉴它的多线程处理设计,坚持单线程处理。如果监控需要消耗太多的资源来实现,那么我就怀疑这样做的合理性。 这里介绍采集,下面介绍实时聚合计算。 前面说过,多维数据监控不关注“单机”数据,只关注聚合数据。那么第一个问题就是,如何划定“聚合”的范围?这个功能是在名称服务中实现的,名称服务没有扩展。 如上图所示,通过名称服务完成聚合作用域的划定,支持三级作用域划定(实例id=>服务=>服务组)。一台机器上的一个模块称为一个实例,实例发送的数据就是上面所说的采集代理发送的每条数据都标有一个id,称为实例id。 范围划定后,通过指定聚合规则,我们组成聚合所需的数据结构。该数据是自包含的,即包含监控数据+聚合规则,如下图: 将多维数据+聚合配置成为聚合自包含数据。自包含数据包括如何计算此数据。上面标明按ISP运营商聚合,按运营商和城市聚合。 聚合的自包含数据可用后,开始聚合计算,如下图: 首先我们只支持一些特定的运维算子,比如计算count,sum,avg,quantilevalue,min/max基本可以覆盖运维需求。比如count就是pv,sum/avg/quantile值等于level等等。 遇到的挑战包括: 1.单机收集的数据量太大。比如计算10w机器的cpu_idle,需要按照filed累加。如果数据缓存堆积过大容易OOM,这就需要考虑Storm的算子设计了。 2.数据范围的划定支持三层,即如何支持数据rollup操作。 我们先来看第一个问题,介绍下风暴算子的设计。请看下图: 整个拓扑是无状态的,处理后的数据是自包含的。其次,在计算中增加了一层预处理bolt,先用shuffle处理一层,减少从field到aggregationbolt的计算量。比如计算10w机器的10sclockcpu_idle(1wqps),先用10个预处理bolt,每个bolt只需要累加1/10的数据,那么下一层的计算量就会小一些。#p# 算子可以这样设计,因为不影响avg的计算,avg=sum/count,把10s的和相加,先加上2s的和,再把2s的中间结果相加,除以count,精度没有损失,但是点位值有精度损失,这是一种权衡。 storm算子设计就介绍到这里,下面再介绍datarollup操作。 在接入层做数据roll-up,将数据一维扁平化。在接入层,名称服务的划定范围变成了多个自包含的数据,比如实例1=>服务2=>服务组3,那么来自实例1的数据就变成了两条数据。 这两个数据的范围属于服务2,一个属于服务组3,其他一样,就是牺牲计算资源,保证整个计算数据不相关。其实还有优化的空间。大家可以自己想想。 多维采集&计算的基本功能介绍到此结束。下面介绍稳定性方面的考虑。 这里有一张图: 已经强调了数据是符合28定律的,所以这个系统首先要支持流量控制,支持根据数据的重要程度进行优先级处理。有以下措施: ***,然后进入适配层,实现以产品线为基本单位的流量控制,使用统计。谁用得多,谁就得付更多的钱。通过设置黑白名单,当出现紧急情况时,会降级。 其次,聚合计算做到完全无状态,水平扩展,多机房互为备份。因为kafka+storm不是专家,所以做了一些应用架构方面的文章,主要是: data按照名称服务的范围圈出来后,发现只要圈出来的“相同范围”的数据是可以保证的在同一个计算单元中计算,没有问题。 例如建立两个机房集群1和2,每个机房建立三个kafkatopic/storm计算单元,分别命名为A、B、C计算单元,接收到的数据通过adapter进行映射,可以如下映射: 比如地图产品线的接入服务命名为:map.nginx,只要将map.nginx范围内的数据映射到一个计算单元,如下规则即可used:map.nginxaccess=>cluster2,1计算单元A 这样所有的map访问nginx数据都是直接写到集群2机房的A计算单元完成的。如果集群2的计算单元B宕机了,当然不会影响map.nginx。 综上所述,整个计算是无状态的,可以水平扩展;支持流控,异常时可以在两个机房之间切换。如果有100%的冗余资源,如果没有,就选择屏蔽部分产品线,降级服务。 到这里,整个多维监控采集计算介绍就完成了:)下面说说总结和展望! 收集是一个标准化的过程。用正规的文字名字真的很无奈。期望是pb日志,这样正则化不会因为日志变化而失败,性能也会有所提升;APM也是如此,它类似于lib功能,可以在不记录日志的情况下收集核心数据。 个人非常看好pb日志。如果有通用的pb模板和pb日志规范推的好,那还是有市场的。以后只要这样打日志,用这个模板分析,就可以得到很多内部数据,不需要写正则表达式了。 收藏是标准纠纷的取舍。我猜你不会骂Linus把进程监控信息放在/proc/pid/stat中,进程名只有16个字节;thestandardisin然后,你需要写一个代理来把这个标准转换成你的内部标准。 当你自己引入监控标准,在公司内部大量使用,RD/op需要努力去适应你,他们需要把数据格式改成监控标准;那么,谁来采取额外的步骤呢?,这个就看大家的监控能力了:) 聚合计算的考虑是各种算子的丰富性,比如uv,二次计算,也就是在storm计算出来的数据上,再做一次计算;比如service=>servicegroup的rollup操作可以通过两次计算完成。 比如服务组包括服务1和服务2,那么我们只能先计算服务1和服务2的pv数据,然后再通过二次计算计算出整个服务组的pv数据,因为有二次计算没有大数据的压力,能做些什么来支撑更多的运营商,灵活性,这个就不展开了。 总结一下: 1.28规律,监控需要倾斜资源处理“关键”指标数据。2、关键指标数据需要多维度观察,一点变成多点。这些数据相互关联,需要元数据和配置管理。3、设计系统时,数据模型是第一位的,功能性的,面向服务的,层次化的,无状态的。4.对开源系统的态度需要调整,尽可能屏蔽开源的细节。除了啃源码,还要在整个应用架构上做文章,保证高可用。 问答环节 1.抓取数据需要在客户端安装代理吗?有必要吗? 用两种方式回答这个问题!首先,系统设计是分层的,你可以直接推送到我们的计算接入层,不需要代理;第二,如果你的数据需要采集,那么就是一个标准化的适配过程,比如你的监控数据用http端口暴露了,需要另外一个人去http端口去取。方法不重要,重要的是你们两个人的转换过程,所以不用担心有没有代理人,谁做这个就需要做。 2.收集后,日志如何处理? 日志采集后,通过命名规则格式化成k:v对,然后将这些k:v对作为相似参数,直接填充到多维数据模型中,然后发送到聚合计算模块进行处理。相当于统计日志中相同的字段,比如上面提到的mapnginx日志的处理。 3.百度用的是elesticsearch+logstash吗?而kafka在百度运维平台中的地位如何呢? ELK用在小产品线上。在替换ELK的情况下,更有信心,我们重写的agent性能比logstash快十倍,符合我们的配置分发系统,整个运维元数据定义等;kafka在刚才的系统中是配合storm作为聚合计算的实现架构。 但是我要强调的是尽量屏蔽开源的细节,我们在kafka+storm上踩了很多坑。通过上述应用框架,可以保证高可靠性。 4.多维数据监控会用在哪些场景?你能详细描述几个案例吗? 今天说的是多维数据监控的采集和计算。这个应用我没说,但是可以透露一下,我们现在的智能监控系统就是基于刚才说的那套采集计算架构;在这个模型上,可以做根本原因定位和同比监控,我就不展开了。 5.能介绍一下百度监控相关的数量级吗? 这个我就不说了,但是三台BAT机器的规模大家都知道,而且在百度运维平台开发部,我们的平台是针对百度全产品线的;所以,有志于做大规模数据分析处理的同学,一定不会让你们失望(又是一道硬题:) 6.不同产品线的聚合计算规则如何管理。不同的聚合规则对应不同的bolt甚至拓扑。在storm开发中如何协调这个问题? 我看到了一个很好的问题。首先,我们设计的时候是通用的聚合计算,计算sum/count/avg/min/max分位数,可以覆盖普通运维;我们通过agent做了公式计算,表达力也足够,同时还有二次计算。它不必在风暴层解决。 我提倡“摆正姿势解决问题”。当然,对于这个正确的位置,每个人都有不同的理解。 7.拓扑无状态不是很清楚。stormtopology的状态管理不是由自己的nimbus控制的吗?百度的应用架构在这里做了哪些工作或设计?在应用架构方面,我们控制发送到stormtopology的数据;多房间相互备份等;我说的是应用架构师在这场风暴中的架构。相当于认为整个storm拓扑就是我接入adapter层的调度单元。
