作者介绍
彭冬,微博广告基础架构团队负责人。朱伟,微博广告SRE团队技术负责人。刘俊,微博平台部监控技术负责人。王莉,在微博广告团队中致力于用数据分析和机器学习模型优化广告业务策略,洞悉商业价值。陆松林,微博广告数据仓库负责人。车亚强,微博广告大数据开发工程师。
计算广告系统是集智能流量分发、投放、结算、CTR预估、客户关系管理等为一体的大型互联网业务系统,随着微博业务的快速增长,广告系统的复杂度越来越高,成千上万的模块需要不停地进行计算和通信,如何保证这么复杂的系统正常、健康运行是一个巨大的挑战。
微博广告智能监控系统依托两大平台:D+(Data Plus)和Hubble平台。
D+属于商业基础大数据平台,它负责数据采集、存储、计算和分析,并作为底层技术对上层应用提供API数据接口。Hubble(哈勃,其含义是数据如浩瀚宇宙之大,Hubble如太空望远镜,能窥见璀璨的星辰,发现数据的真正价值)平台定位为微博广告智能全景监控、数据透视和商业洞察,与实验平台、效果分析平台、DMP、广告投放后台等共同构成了D+的上层应用生态。
微博广告Hubble平台每日处理TB级别的监控数据和万级别的报警规则,Hubble平台利用机器学习技术进行趋势预测和报警阈值的智能调整,保证商业产品上千台服务器和数百个系统及服务的正常运行。
一、背景介绍
1、监控指标体系
通常,可以用系统处理监控指标的量级(目前已达百万级别)来衡量监控平台的处理能力。这个衡量指标在一定程度上可以反映监控平台的复杂度和能力,但是在实际业务中并不一定需要这么庞大的监控指标体系,很大一部分监控指标是毫无价值或多余的。这些指标要么根本无法真实反映系统或者业务的状态,要么可以直接被其他指标所取代,要么需要结合更多的信息来分析。
总体而言,监控指标有以下几个分类:
机器(系统)指标
机器(系统)指标,主要指从机器资源角度设定的与机器本身比较相关的指标。概括起来,机器(系统)指标包括机器CPU、Memory、Disk IO/Space、Net IO等。
监控系统指标的目的是:发现机器故障、限流与扩容。
应用指标
应用指标分为基础应用指标和非基础应用指标:
基础应用指标是指由通用型的应用程序产生的指标,比如Nginx/Apache服务器的请求状态以及Access日志和端口、MySQL数据库端口、Hadoop集群运行状态等。
非基础应用指标是指非通用型应用程序(业务程序)所产生的指标,比如某个服务的端口号、进程个数等。另外,对于从业务程序产生的日志中抽取出来的指标,也可以归类于非基础应用指标。
业务指标
业务指标是指关注具体业务、产品的指标,如日收入走势、订单数、广告计划数等业务层面的指标。
2、功能设计原则
在设计系统架构之前,应该先从业务和系统等角度深度挖掘架构要解决的核心问题。对于监控平台而言,可以从平台化、业务和系统架构及设计三个视角考虑来解析核心问题。
从平台化视角考虑,监控报警平台要解决的问题如下:
是否能指导RD快速定位问题;
是否为业务发展的预估提供了参考。
从业务视角考虑,监控报警平台所要解决的核心问题主要有以下几个方面:
监控指标:精准性和覆盖率;
报警:实效性和准确性;
故障诊断;
自动处理。
从系统架构及设计视角考虑,监控报警平台要能解决如下几个方面:
大数据分析处理能力,包括数据采集、ETL和数据抽象分析;
数据分析处理的实时性;
大规模监控指标等时序数据存储、报警规则存储及报警触发;
高可用性;
数据聚合能力。
二、整体架构
基于上述监控指标体系和功能需求,Hubble平台的整体架构如图1所示:
图1:Hubble平台的整体架构示意图
Hubble整体架构包含三个层次:
数据采集层(Data Collection Layer)
数据采集层负责对系统日志、系统指标、业务日志、业务指标等数据进行实时采集。
对于日志数据,支持Flume、Scribe等日志收集工具,也支持Filebeat、Metricbeat等文件及指标收集工具。
对于系统及业务指标,可以通过自主开发的w-agent客户端进行数据收集。w-agent是Hubble的轻量级、低资源消耗的数据采集工具,它作为微博广告标准基础工具集的一部分,在服务器初始化时进行安装配置,通过ZooKeeper进行配置管理,支持远程更新数据采集配置和配置变更实时生效。同时,数据采集层支持通过API的方式直接提交数据,方便数据个性化定制以适应不同的业务需求。
数据分析层(Data Analyzation Layer)
数据分析层负责将采集到的数据进行ETL、预处理、分析和聚合。为了提高可用性,采集到的数据将同时被写入HDFS进行持久化,数据分析层可以根据需要,从HDFS中Reload数据并重新进行计算。另外,离线部分的监控预估模块会定时进行模型训练,并将训练后的模型存储在HDFS中。Alert trigger模块负责根据报警规则进行报警触发监测。
可视化层(Visualization Layer)
经过分析处理的数据被写入可视化层的存储系统中(如Druid、Elasticsearch、MySQL及ClickHouse),可视化层负责根据业务方需求,对监控图表进行展示、配置和管理,以及对报警信息及规则进行管理。另外,可视化层提供了API,允许第三方通过API的方式获取聚合分析后的数据,以及对报警进行管理。
三、核心功能分析
1、全景监控
基础监控
基础监控要求实时反映真实的指标波动情况,其中关键技术之一是对时序数据进行聚合,其聚合粒度根据业务的不同而有一定的差异,当然也会受指标及数据处理量等因素的制约。目前Twitter、Facebook等国外公司一般做到30秒甚至分钟级别聚合,大部分公司做到10秒级别聚合就已经可以满足业务需求了。微博广告监控系统根据业务需求,对部分指标的聚合粒度为1秒级别。
基础监控底层使用D+平台提供实时的数据服务。D+平台是微博广告商业数据基础设施,负责数据收集、存储、监测、聚合及管理,提供高可用的实时流和离线数据服务,在D+上可以对不同的数据源及实时数据与离线数据进行关联。
D+的整体架构简图如图2所示:
图2:D+的整体架构简图
基础指标数据、日志数据会从D+流出到ETL部分进行数据处理,然后输入到Druid中提供上层Graph展示,同时输出一部分数据(日志)进入Elasticsearch,以便后续查询。D+位于Hubble整体架构中的数据采集层和数据分析层,请参考图1。
服务全景图
假设对监控平台的要求是只允许用一到两个视图来清楚地展现服务监控状态,对所有的需求和指标进行优先级排序,则可以抽取出两个关键维度,即机器维度和服务维度。
机器维度
在机器维度视图下,核心是要清楚地确定所有机器的基本状态,可以简化为健康、亚健康和病态三种状态:
健康状态:表示对机器资源(CPU、内存、网络I/O、带宽、机器负载等)的使用一切正常,在未来一段时间(如7天)内可能也会正常,机器使用者完全不用担心。
亚健康状态:表示对机器资源的使用存在一定的风险,如高峰期网络I/O太高,但仍然未达到影响机器正常运行的程度,机器使用者需要考虑机器I/O类型或者扩容,以便应对短期内可能产生的压力。
病态:是指对机器的某种资源的消耗已经达到上限,如磁盘已满,需要机器使用者立即处理。
根据这样的需求,设计出的视图如图3所示:
图3:服务全景图(机器维度)
当某台机器出现异常时,能展示当前机器的异常级别、时间及具体的异常信息。
服务维度
在服务维度视图下,我们关心的核心问题是业务应用运行是否正常、整个链路是否通畅、是否有异常和告警、出现异常时影响了多少个节点等。并且,可以查看在命名空间下所有关联服务上下游的整体健康状态,针对异常节点展示异常原因和监控报表。
同时,结合自动化平台,对服务之间的上下游关系(拓扑图)进行展示,如图4所示:
图4:服务全景图(服务维度)
2、趋势预测
目前很多企业都在尝试通过趋势预测的方式,提前预测系统或者业务的未来发展状况,未雨绸缪。业内普遍的做法是采用统计学的方法,如Holter-Winter、ARIMA、3Sigma等。这类方法的特点是简单,能结合部分历史数据进行趋势预测。
然而,它们也有很多不足之处,比如ARIMA算法的一个技术难点就是时间序列的平稳化,平稳化的时间序列对于预测结果的好坏起着至关重要的作用。
微博广告团队率先尝试通过机器学习的方法来预测系统指标的变化趋势,取得了一定的效果,目前已经应用于广告曝光量、互动量的趋势预测。
基于机器学习的趋势预测架构示意图如图5所示:
图5:基于机器学习的趋势预测架构示意图
该架构主要分两部分:离线模型训练和在线计算。离线部分的数据来源是HDFS存储的历史指标数据,输出为模型;在线部分根据模型计算后导入Druid中进行存储和部分聚合,通过Dashboard进行实时展示。
离线模型训练模块的具体处理流程:
监控数据的获取和存储
首先将监控预警平台的监控数据从HDFS中提取出来进行数值化。我们在向该模块提供的获取数据接口中发送带有时间戳的GET请求,获得了连续8天的监控数据作为训练数据集。选取8天这个时间跨度,是充分考虑了监控数据自身可能蕴含的周期性与前后关联性的。
生成模型训练数据集
训练集的窗口长度是指需要几个时间点的值来预测下一个时间点的值。在这里窗口长度为3,即用t-2,t-1,t次的时间间隔进行模型训练,然后用t+1次的时间间隔对结果进行验证。数据集格式为:X为训练数据,Y为验证数据。我们选取数据集中前66.7%的数据作为训练集,后33.3%的数据作为测试样本集。
LSTM模型结构与参数设置
图6展示了LSTM(长短期记忆网络)的一个单元结构:
图6:LSTM单元结构图
LSTM单元是预测模型的一个重要组成部分,用于处理时间序列数据。xt表示输入,ht-1表示上一时刻的状态,ht表示当前时刻的状态,W表示权值。
需要确定LSTM模块的激活函数(在Keras中默认选择tanh作为激活函数);门之间的激活函数一般选择Sigmoid函数,Sigmoid函数输出0~1之间的数值,描述每个部分有多少量可以通过,其中0表示“不许任何量通过”,1表示“允许任意量通过”。
将接收LSTM输出的全连接神经网络(Fully-Connected Neural Network)的激活函数设为linear(线性)函数;将每一层网络节点的舍弃率(dropout的值)设为0.2;使用均方误差(Mean Squared Error)作为误差的计算方式;采用RMSprop算法作为权重参数的迭代更新方案,该算法对RNN网络通常有较好的收敛效果。
选定模型训练的epoch(总的训练轮数)为50和batch size(每次训练的样本数)为1,并在LSTM层的输出后面加入一个普通的神经网络全连接层用于输出结果的降维。
模型训练
为了防止过度拟合,将上述获取到的8天时间跨度的数据集按2:1的比例随机拆分为训练集和测试集。训练模型后将数据的X列作为参数导入模型便可得到预测值,与实际的Y值相比较便可知道该模型的优劣。将整个模型训练完成后的参数保存为h5py格式(Keras标准模型格式)的文件,方便在以后的预测或调用中使用。
保存模型结果
将训练完成后的标准的h5py格式的Keras神经网络模型存入HDFS中,用于离线部分数据处理。
结果展示
实时在线部分从Kafka中获取实时数据,并使用HDFS中训练完成的模型进行计算,将计算结果的数据存入Druid中进行图形化展示。
图7展示了微博广告某产品曝光量(PV)趋势预测曲线效果图:
图7:趋势预测曲线效果图
(注:图中展示了一周(7天)的数据趋势,其中前5天为训练数据走势情况,后2天为预测数据走势情况)
分析最终得到的效果图,前面(5天)画出了训练数据的趋势曲线,后面(2天)画出了预测数据的趋势曲线,可以从图中看到最终的预测曲线与实际的曲线趋势情况基本吻合,拟合效果非常出色,很好地将原始数据的波峰、波谷以及周期性预测出来了。
运维人员可以通过绿色预测曲线来预判监控曲线的整体走势,并且可以了解到可能出现问题的时间点,在可能发生报警的时间点之前做好准备工作,未雨绸缪,做到心中有数。
时间序列预测是一类相对比较复杂的预测建模问题,和回归分析模型的预测不同,时间序列模型依赖事件发生的先后顺序,同样大小的值改变顺序后输入模型产生的结果是不同的。因此,我们选用LSTM模型对监控数据进行预测。
LSTM是RNN(循环神经网络)的变体,LSTM的特点就是在RNN结构基础上添加了各层的阀门节点。这些阀门可以打开或关闭,用于判断模型网络的记忆态(之前网络的状态)在该层输出的结果是否达到阈值,从而加入当前该层的计算中。
阀门节点利用Sigmoid函数将网络的记忆态作为输入进行计算,如果输出结果达到阈值,则将该阀门输出与当前层的计算结果相乘作为下一层的输入;如果没有达到阈值,则将该输出结果遗忘掉。每一层包括阀门节点的权重都会在每一次模型反向传播训练过程中更新。
LSTM模型的记忆功能就是由这些阀门节点实现的。当阀门打开时,前面模型的训练结果就会关联到当前的模型计算,而当阀门关闭时之前的计算结果就不再影响当前的计算。因此,通过调节阀门的开关,我们就可以实现早期序列对最终结果的影响。
在Python中有不少包可以被直接调用来构建LSTM模型,比如:Kears、TensorFlow、Theano等。我们选用Keras作为模型定义与算法实现的机器学习框架,将Keras集成到TensorFlow中,让Keras变成TensorFlow的默认API。让Keras运行在TensorFlow框架上,可以帮助我们快速搭建和实现一个神经网络模型。
相对于现有的预测算法,如Holter-Winter、ARIMA、3Sigma,LSTM对监控数据的预测准确性较高。比如3Sigma算法在实际预测中给出的值往往并不理想,上下文之间的关联性并不强,运维人员如果直接在给出的预测值上进行分析或者预警,效果可能会与实际偏差较大。
而LSTM能很好地抓住时间序列上下文可能存在的联系,并利用这种联系做出预测。我们想利用该模型的前后关联性和数据本身存在的关联性,对监控数据做出合理的预测。
LSTM对未来数据的走势给出了直观的预测,趋势预测的结果可以为运维人员提供良好的参考,对于可能发生报警的情况,运维人员可以较早地采取有针对性的措施,有效地减少报警的次数,减轻了运维人员的工作负担。基本达到了不漏报和不误报的平衡,同时根据大量的历史监控数据训练出的模型有很强的泛化和预测能力,不用实时地加入数据更新训练,也不需要耗费人力、物力进行长期维护。后期的工作只需要将更新的模型替换到预测模块中即可。我们可以将节省下来的监控的人力成本,投入到智能监控的研究当中。
图8展示了微博广告某产品曝光量预测值与实际值偏差占比分布情况:
图8:微博广告某产品曝光量预测值与实际值偏差占比分布情况(单位:PV)
可以看到,对于PV预测值与实际值小于1000的占比约为73%,小于1500的占比约为96%。按照1000次曝光(PV量)转化为广告计量单位为1CPM,1.5CPM内的误差占比为96%。
需要注意的是,目前基于机器学习的趋势预测还不能很好地支持对精度要求非常高的指标,如按点击收费的广告互动数指标。
3、动态阈值
系统报警往往结合监控来做,对于某个指标触发所设定的阈值后向相关人员发送消息提醒。
目前大多数做法是固定阈值,这个阈值是根据经验设定的,其优点是简单、直接、操控性强;其缺点是经验值不准,如果GAP设置得过小,则会增加报警次数,导致误报率增加;如果GAP设置得过大,又会导致漏报。
另外,很多数据指标的波动呈周期性变化,通过经验或者人工很难设定一个合适的GAP。为此,可以结合趋势预测技术,在预测的基础上增加动态阈值,比如报警条件为趋势预测曲线上下10%,这个百分比可以根据业务进行调整。
4、服务治理
要想让一个系统变得健壮,具有高可用性,除需要完善的监控分析、及时的报警策略等被动方式外,还需要主动发现系统中可能存在的隐患。
特别是在微博这样的平台中,无法预知什么时候会有流量高峰,更无法预知这个高峰会有多高。比如一个热门事件就可能导致流量瞬间飙升,如2017年鹿晗、关晓彤公布恋情,微博广告的流量在1分钟内就飙升了近一倍,即使是动态扩容的速度也赶不上这样瞬间突发的流量高峰。
所以,面对这样的场景,如何把控系统,对系统的每个服务、每个节点的承载能力及瓶颈、缺陷都了然于胸,才能及时封堵缺口,快速响应故障。
环境选择
流量压测的方式有很多种,可以对单台机器、单个服务进行流量压测,也可以通过将流量集中转发到线上一小部分服务来提高单台服务器的QPS,还可以搭建一个和线上环境一模一样的系统。但是上述方法都不能模拟生产环境的真实情况。
单台机器和单个服务的流量压测对于测试单机性能和单个服务能够承载的最大QPS是可以的,但是这样的结果永远都只是一个理论值,往往评估出来的结果过高。因为它忽略了上下游服务的依赖,如果一个服务被要求在10ms内响应请求,它自身需要消耗2ms的执行时间,但是下游响应它的时间却超过了8ms,这样,最终结果在上游看来都是超时的。也许所有服务压测出来的结果都能满足要求,但是服务与服务之间的网络质量又有可能成为瓶颈。
将流量集中转发到线上一小部分服务来提高单台服务器的QPS,这样的方法对整个系统一部分服务节点的流量评估可能是合理的,但是不能忽略了服务后端访问的存储类资源,很多时候我们并不能做到对存储类资源也集中流量。
至于搭建一个和线上环境一模一样的系统,依然没法确保服务之间的网络质量都是一样的,也没法确定会不会有一些其他因素可能影响流量评估的结果。更何况对于很多公司来说,在同样的机房中,具有相同的机器数量,拥有相同的软硬件配置和环境,搭建一个测试环境并不是一件容易的事情。
所以,综合来看,只有以线上环境为测试环境,将测试流量直接导入线上环境中,才能真正模拟流量高峰下系统的可用性,无论是前端服务还是计算节点,抑或是后端存储类资源,都可以真实展现它们在流量高峰下的性能和问题。
虽然这样做是一件很冒险的事,但是如果我们做好足够的准备工作,小心翼翼地进行,那么就可以将风险降到最低。
流量压测/容量评估
GoReplay是一款用于捕获和重放实时HTTP流量的开源工具,可以不间断地用线上实时流量来测试系统性能。
采用Go开发的GoReplay部署简单,只需下载一个可执行文件就可以在生产环境中的服务器上捕获指定端口的流量并转发到测试环境中,或者添加一个测试流量的标识,再重新发送到生产环境中,如图9所示:
图9:GoReplay流程示意图
通过GoReplay转发HTTP请求示例如下:
./goreplay
# 从80端口捕获HTTP请求
--input-raw :80
# 设置自动退出时间
--exit-after 60s
# 将请求转发到192.168.1.1的80端口
--output-http "192.168.1.1:80"
# 将10%请求转发到192.168.1.2的8080端口
--output-http "192.168.1.2:8080|10%"
# 自定义测试流量标识
--http-set-header 'User-Agent: Gor'
# 指定超时时间
--output-http-timeout 100ms
# 输出请求状态
--stats
--output-http-stats
性能评估
可以通过GoReplay将线上流量复制一份或者多份,然后导入线上环境中,线上环境通过HTTP Header来区分真实流量和测试流量。接下来要做的就是在线上系统流量翻倍的情况下,通过全链路Trace系统来观察各个服务节点的性能瓶颈。
全链路Trace系统是通过在每个请求中增加全局唯一的Trace ID,在服务与服务之间增加Span ID、Timestamp等信息,来全局跟踪一条流量处理链路的。通过全链路Trace系统还可以统计QPS在各个服务节点的变化,以及每个节点处理请求的耗时占比。
通过全链路Trace系统,可以很直观地发现在流量高峰下,各个服务节点处理请求的QPS、耗时分布、状态码分布等指标信息,为下一步的系统优化提供可靠的数据依据。
四、小结
监控系统首先要解决的问题是指标覆盖率,大而全,然后在此基础上进行深耕,提高准确性,最后是精简和抽象,发现数据后面最本质的东西。微博广告基础架构团队在监控方面有一定的积累,并率先在监控中利用机器学习技术进行了一些尝试,未来将在智能预测和服务自动化处理(降级、恢复等)方面进行更深入的尝试。
特别推荐一个分享架构+算法的优质内容,还没关注的小伙伴,可以长按关注一下:
长按订阅更多精彩▼
如有收获,点个在看,诚挚感谢