饿了么的技能也伴随着业务的飞速增长也不断突飞年夜进。
据公开宣布,2014年5月的日订单量只有10万,但短短几个月之后就冲到了日订单百万,到当今日订单上千万单。
在短短几年的技能发展进程上,饿了么的技能体系、稳定性培植、技能文化培植等都有长足的发展。
各位可查看往期文章一探个中发展进程,在此不再赘述:

《饿了么技能往事(上)》《饿了么技能往事(中)》《饿了么技能往事(下)》

而可不雅观测性作为技能体系的核心环节之一,也跟随饿了么技能的飞速发展,不断自我改造,从“全链路可不雅观测性ETrace”扩展到“多活下的可不雅观测性体系ETrace”,发展成目前“一站式可不雅观测性平台EMonitor”。

EMonitor经由5年的多次迭代,现在已经建成了集指标数据、链路追踪、可视化面板、报警与剖析等多个可不雅观测性领域的平台化产品。
EMonitor逐日处理约1200T的原始可不雅观测性数据,覆盖饿了么绝大多数中间件,可不雅观测超5万台机器实例,可不雅观测性数据时延在10秒旁边。
面向饿了么上千研发职员,EMonitor供应精准的报警做事和多样化的触达手段,同时运行约2万的报警规则。
本文就细数饿了么可不雅观测性的培植进程,回顾下“饿了么可不雅观测性培植的那些年”。

饿了么php饿了么 EMonitor 演进史 Java

1.0:混沌初开,万物兴起

翻看代码提交记录,ETrace项目的第一次提交在2015年10月24日。
而2015年,正是饿了么发展的第七个年头,也是饿了么业务、技能、职员开始发达发展的年头。
彼时,饿了么的可不雅观测性系统依赖Zabbix、Statsd、Grafana等传统的“轻量级”系统。
而“全链路可不雅观测性”正是当时的微做事化技能改造、后端做事Java化等技能发展趋势下的必行之势。

我们可不雅观测性团队,在调研业界主流的全链路可不雅观测性产品--包括著名的开源全链路可不雅观测性产品“CAT”后,吸取众家之所长,在两个多月的爆肝开拓后,推出了初代ETrace。
我们供应的Java版本ETrace-Agent随着新版的饿了么SOA框架“Pylon”在饿了么研发团队中的推广和遍及开来。
ETrace-Agent能自动网络运用的SOA调用信息、API调用信息、慢要求、慢SQL、非常信息、机器信息、依赖信息等。
下图为1.0版本的ETrace页面截图。

在经历了半年的爆肝开拓和各中间件兄弟团队的大力支持,我们又开拓了Python版本的Agent,更能适应饿了么当时各措辞百花齐放的技能体系。
并且,通过和饿了么DAL组件、缓存组件、组件的密切合营与埋点,用户的运用增加了多层次的访问信息,链路更加完全,故障排查过程更加清晰。

整体架构体系

ETrace整体架构如下图。
通过SDK集成在用户运用中的Agent定期将Trace数据经Thrift协议发送到Collector(Agent本地不落日志),Collector经初步过滤后将数据打包压缩发往Kafka。
Kafka下贱的Consumer消费这些Trace数据,一方面将数据写入HBase+HDFS,一方面根据与各中间件约定好的埋点规则,将链路数据打算成指标存储到韶光序列数据库-- LinDB中。
在用户端,Console做事供应UI及查询指标与链路数据的API,供用户利用。

全链路可不雅观测性的实现

所谓全链路可不雅观测性,即每次业务要求中都有唯一的能够标记这次业务完全的调用链路,我们称这个ID为RequestId。
而每次链路上的调用关系,类似于树形构造,我们将每个树节点上用唯一的RpcId标记。

如图,在入口运用App1上会新建一个随机RequestId(一个类似UUID的32位字符串,再加上天生时的韶光戳)。
因它为根节点,故RpcId为“1”。
在后续的RPC调用中,RequestId通过SOA框架的Context通报到下一节点中,且下一节点的层级加1,变为形如“1.1”、“1.2”。
如此反复,同一个RequestId的调用链就通过RpcId还原成一个调用树。

也可以看到,“全链路可不雅观测性的实现”不仅依赖与ETrace系统自身的实现,更依托与公司整体中间件层面的支持。
如在要求入口的Gateway层,能对每个要求天生“自动”新的RequestId(或根据要求中特定的Header信息,复用RequestId与RpcId);RPC框架、Http框架、Dal层、Queue层等都要支持在Context中通报RequestId与RpcId。

ETrace Api示例

在Java或Python中供应链路埋点的API:

/记录一个调用链路/Transaction trasaction = Trace.newTransaction(String type, String name);// business codestransaction.complete();/记录调用中的一个事宜/Trace.logEvent(String type, String name, Map<String,String> tags, String status, String data)/记录调用中的一个非常/Trace.logError(String msg, Exception e)Consumer的设计细节

Consumer组件的核心任务便是将链路数据写入存储。
紧张思路因此RequestId+RpcId作为主键,对应的Data数据写入存储的Payload。
再考虑到可不雅观测性场景是写多读少,并且多为文本类型的Data数据可批量压缩打包存储,因此我们设计了基于HDFS+HBase的两层索引机制。

如图,Consumer将Collector已压缩好的Trace数据先写入HDFS,并记录写入的文件Path与写入的Offset,第二步将这些“索引信息”再写入HBase。
特殊的,构建HBase的Rowkey时,基于ReqeustId的Hashcode和HBase Table的Region数量配置,来天生两个Byte长度的ShardId字段作为Rowkey前缀,避免了某些固定RequestId格式可能造成的写入热点问题。
(因RequestId在各调用源头天生,如运用自身、Nginx、饿了么网关层等。
可能某运用缺点设置成以其AppId为前缀RequestId,若没有ShardId来打散,则它所有RequestId都将落到同一个HBase Region Server上。

在查询时,根据RequestId + RpcId作为查询条件,依次去HBase、HDFS查询原始数据,便能找到某次详细的调用链路数据。
但有的需求场景是,只知道源头的RequestId须要查看整条链路的信息,希望只排查链路中状态非常的或某些指定RPC调用的数据。
因此,我们在HBbase的Column Value上还额外写了RPCInfo的信息,来记录单次调用的简要信息。
如:调用状态、耗时、高下游运用名等。

此外,饿了么的场景下,研发团队多以订单号、运单号作为排障的输入,因此我们和业务干系团队约定分外的埋点规则--在Transaction上记录一个分外的"orderId={实际订单号}"的Tag--便会在HBase中新写一条“订单表”的记录。
该表的设计也不繁芜,Rowkey由ShardId与订单号组成,Columne Value部分由对应的RequestId+RpcId及订单基本信息(类似上文的RPCInfo)三部分组成。

如此,从业务链路到全链路信息到详细单个链路,形成了一个完全的全链路排查体系。

Consumer组件的另一个任务则是将链路数据打算成指标。
实现办法是在写入链路数据的同时,在内存中将Transaction、Event等数据按照既定的打算逻辑,打算成SOA、DAL、Queue等中间件的指标,内存稍加聚合后再写入时序数据库LinDB。

指标存储:LinDB 1.0

运用指标的存储是一个范例的韶光序列数据库的利用场景。
根据我们以前的履历,市情上主流的韶光序列数据库-- OpenTSDB、InfluxDB、Graphite--在扩展能力、集群化、读写效率等方面各有缺憾,以是我们选型利用RocksDB作为底层存储引擎,借鉴Kafka的集群模式,开拓了饿了么的韶光序列数据库--LinDB。

指标采取类似Prometheus的“指标名+键值对的Tags”的数据模型,每个指标只有一个支持Long或Double的Field。
某个范例的指标如:

COUNTER: eleme_makeorder{city="shanghai",channel="app",status="success"} 45

我们紧张做了一些设计实现:

指标写入时根据“指标名+Tags”进行Hash写入到LinDB的Leader上,由Leader卖力同步给他的Follower。
借鉴OpenTSDB的存储设计,将“指标名”、TagKey、TagValue都转化为Integer,放入映射表中以节省存储资源。
RocksDB的存储设计为:以"指标名+TagKeyId + TagValueId+韶光(小时粒度)“作为Key,以该小时时间线内的指标数值作为Value。
为实现Counter、Timer类型数据聚合逻辑,开拓了C++版本RocksDB插件。

这套存储方案在初期很好的支持了ETrace的指标存储需求,为ETrace大规模接入与可不雅观测性数据的时效性供应了坚固的保障。
有了ETrace,饿了么的技能人终于能从全链路的角度去排查问题、管理做事,为之后的技能升级、架构演进,供应了可不雅观测性层面的支持。

个中架构的几点解释

1. 是否担保所有可不雅观测性数据的可靠性?

不,我们承诺的是“尽可能不丢”,不担保100%的可靠性。
基于这个条件,为我们设计架构时供应了诸多便利。
如,Agent与Collector若连接失落败,多少次重试后便丢弃数据,直到Collector规复可用;Kafka高下游的生产和消费也不必Ack,避免影响处理效率。

2. 为什么在SDK中的Agent将数据发给Collector,而不是直接发送到Kafka?

避免Agent与Kafka版本强绑定,并避免引入Kafka Client的依赖。
在Collector层可以做数据的分流、过滤等操作,增加了数据处理的灵巧性。
并且Collector会将数据压缩后再发送到Kafka,有效减少Kafka的带宽压力。
Collector机器会有大量TCP连接,可针对性利用高性能机器。

3. SDK中的Agent如何掌握对业务运用的影响?

纯异步的API,内部采取行列步队处理,行列步队满了就丢弃。
Agent不会写本地日志,避免占用磁盘IO、磁盘存储而影响业务运用。
Agent会定时从Collector拉取配置信息,以获取后端Collector详细IP,并可实时配置来开关是否实行埋点。

4. 为什么选择侵入性的Agent?

选择寄生在业务运用中的SDK模式,在当时看来更利于ETrace的遍及与升级。
而从现在的眼力看来,非侵入式的Agent对用户的集成更加便利,并且可以通过Kubernates中SideCar的办法对用户透明支配与升级。

5. 如何实现“只管即便不丢数据”?

Agent中根据得到的Collector IP周期性数据发送,若失落败则重试3次。
并定期(5分钟)获取Collector集群的IP列表,随机选取可用的IP发送数据。
Collector中实现了基于本地磁盘的Queue,在后真个Kafka不可用时,会将可不雅观测性数据写入到本地磁盘中。
待Kafak规复后,又会将磁盘上的数据,连续写入Kafka。

6. 可不雅观测性数据如何实现多措辞支持?

Agent与Collector之间选择Thrift RPC框架,并定制全体序列化办法。
Java/Python/Go/PHP的Agent依数据规范开拓即可。

2.0:异地多活,大势初成

2016年底,饿了么为了欢迎业务快速增长带来的调度,开始推进“异地多活”项目。
新的多数据中央架构对既有的可不雅观测性架构也带来了调度,ETrace亦经由了一年的开拓演进,升级到多数据中央的新架构、拆分出实时打算模块、增加报警功能等,进入ETrace2.0时期。

异地多活的寻衅

随着饿了么的异地多活的技能改造方案确定,对可不雅观测性平台提出了新的寻衅:如何设计多活架构下的可不雅观测性系统?以及如何聚合多数据中央的可不雅观测性数据?

经由一年多的推广与接入,ETrace已覆盖了饿了么绝大多数各措辞的运用,逐日处理数据量已达到了数十T以上。
在此数据规模下,决不可能将数据拉回到某个中央机房处理。
因此“异地多活”架构下的可不雅观测性设计的原则是:各机房处理各自的可不雅观测性数据。

我们开拓一个Gateway模块来代理与聚合各数据中央的返回结果,它会感知各机房间内Console做事。
图中它处于某个中心的云上区域,实际上它可以支配在各机房中,通过域名的映射机制来做切换。

如此支配的架构下,各机房中的运用由与机房相绑定的环境变量掌握将可不雅观测性数据发送到该机房内的ETrace集群,网络、打算、存储等过程都在同一机房内完成。
用户通过前端Portal来访问各机房内的数据,利用体验和之前类似。

纵然考虑极度情形下--某机房完备不可用(如断网),“异地多活”架构可将业务流量切换到存活的机房中,让业务连续运转。
而可不雅观测性上,通过将Portal域名与Gateway域名切换到存活的机房中,ETrace便能连续事情(虽然会缺失落故障机房的数据)。
在机房网络规复后,故障机房内的可不雅观测性数据也能自动规复(由于该机房内的可不雅观测性数据处理流程在断网时仍在正常运作)。

可不雅观测性数据实时处理的寻衅

在1.0版本中的Consumer组件,既卖力将链路数据写入到HBase/HDFS中,又卖力将链路数据打算成指标存储到LinDB中。
两个流程可视为同步的流程,但前者可接管数分钟的延迟,后者哀求达到实时的时效性。
当时HBase集群受限于机器性能与规模,常常在数据热点时会写入抖动,进而造成指标打算抖动,影响可用性。
因此,我们急迫须要拆分链路写入模块与指标打算模块。

在选型实时打算引擎时,我们考虑到需求场景是:

能灵巧的配置链路数据的打算规则,最好能动态调度;能水平扩展,以适应业务的快速发展;数据输出与既有系统(如LinDB与Kafka)无缝衔接;

很遗憾的是,彼时业界无现成的拿来即用的大数据流处理产品。
我们就基于繁芜事宜处理(CEP)引擎Esper实现了一个类SQL的实时数据打算平台--Shaka。
Shaka包括“Shaka Console”和“Shaka Container”两个模块。
Shaka Console由用户在图形化界面上利用,来配置数据处理流程(Pipeline)、集群、数据源等信息。
用户完成Pipeline配置后,Shaka Console会将变更推送到Zookeeper上。
无状态的Shaka Container会监听Zookeeper上的配置变更,根据自己所属的集群去更新内部运行的Component组件。
而各Component实现了各种数据的处理逻辑:消费Kafka数据、处理Trace/Metric数据、Metric聚合、运行Esper逻辑等。

Trace数据和Metric格式转换成固定的格式后,剩下来按需编写Esper语句就能天生所需的指标了。
如下文所示的Esper语句,就能将类型为Transaction的Trace数据打算成以“{appId}.transaction”的指标(若Consumer中以编码办法实现,约须要近百行代码)。
经由这次的架构升级,Trace数据能快速的转化为实时的Metric数据,并且对付业务的可不雅观测性需求,只用改改SQL语句就能快速知足,显著降落了开拓本钱和提升了开拓效率。

@Name('transaction')@Metric(name = '{appId}.transaction', tags = {'type', 'name', 'status', 'ezone', 'hostName'}, fields = {'timerCount', 'timerSum', 'timerMin', 'timerMax'}, sampling = 'sampling')select header.ezone as ezone, header.appId as appId, header.hostName as hostName, type as type, name as name, status as status, trunc_sec(timestamp, 10) as timestamp, f_sum(sum(duration)) as timerSum, f_sum(count(1)) as timerCount, f_max(max(duration)) as timerMax, f_min(min(duration)) as timerMin, sampling('Timer', duration, header.msg) as samplingfrom transactiongroup by header.appId, type, name, header.hostName, header.ezone, status, trunc_sec(timestamp, 10);新的UI、更丰富的中间件数据

1.0版本的前端UI,是集成在Console项目中基于Angular V1开拓的。
我们急迫希望能做到前后端分离,各司其职。
于是基于Angular V2的多少个月开拓,新的Portal组件登场。
得益于Angular的数据绑定机制,新的ETrace UI各组件间联动更自然,排查故障更方便。

饿了么自有中间件的研发进程也在不断前行,在可不雅观测性的打通上也不断深化。
2.0阶段,我们进一步集成了--Redis、Queue、ElasticSearch等等,覆盖了饿了么所有的中间件,让可不雅观测性无去世角。

杀手级功能:指标查看与链路查看的无缝整合

传统的可不雅观测性系统供应的排障办法大致是:吸收报警(Alert)--查看指标(Metrics)--上岸机器--搜索日志(Trace/Log),而ETrace通过Metric与Trace的整合,能让用户直接在UI上通过点击就能定位绝大部分问题,显著拔高了用户的利用体验与排障速率。

某个排查场景如:用户创造总量非常溘然增加,可在界面上筛选机房、非常类型等找到实际突增的某个非常,再在曲线上直接点击数据点,就会弹出对合时光段的非常链路信息。
链路上有详细的高下游信息,能帮助用户定位故障。

它的实现事理如上图所示。
详细的,前文提到的实时打算模块Shaka将Trace数据打算成Metric数据时,会额外以抽样的办法将Trace上的RequsetId与RpcId也写到Metric上(即上文Esper语句中,天生的Metric中的sampling字段)。
这种Metric数据会被Consumer模块消费并写入到HBase一张Sampling表中。

用户在前端Portal的指标曲线上点击某个点时,会构建一个Sampling的查询要求。
该要求会带上:该曲线的指标名、数据点的起止韶光、用户选择过滤条件(即Tags)。
Consumer基于这些信息构建一个HBase的RegexStringComparator的Scan查询。
查询结果中可能会包含多个结果,对应着该韶光点内数据点(Metric)上发生的多个调用链路(Trace),继而拿着结果中的RequestId+RpcId再去查询一次HBase/HDFS存储就能得到链路原文。
(注:实际构建HBase Rowkey时Tag部分存的是其Hashcode而不是原文String。

浩瀚转岗、离职的饿了么小伙伴,最念念不忘不完的便是这种“所见即所得”的可不雅观测性排障体验。

报警Watchdog 1.0

在运用可不雅观测性基本全覆盖之后,报警的需求自然成了题中之义。
技能选型上,根据我们在实时打算模块Shaka上收成的履历,决定再造一个基于实时数据的报警系统--Watchdog。

实时打算模块Shaka中已经将Trace数据打算成指标Metrics,报警模块只需消费这些数据,再结合用户配置的报警规则产出报警事宜即可。
因此,我们选型利用Storm作为流式打算平台,在Spount层次根据报警规则过滤和分流数据,在Bolt层中Esper引擎运行着由用户配置的报警规则转化成Esper语句并处理分流后的Metric数据。
若有符合Esper规则的数据,即天生一个报警事宜Alert。
Watchdog Portal模块订阅Kafka中的报警事宜,再根据详细报警的触达办法关照到用户。
默认Esper引擎中数据聚合时间窗口为1分钟,以是全体数据处理流程的时延约为1分钟旁边。

Metrics API与LinDB 2.0:

在ETrace 1.0阶段,我们只供应了Trace干系的API,LinDB仅供内部存储利用。
用户逐步的意识到如果能将“指标”与“链路”整合起来,就能发挥更大的功用。
因此我们在ETrace-Agent中新增了Metrics干系的API:

// 计数器类型Trace.newCounter(String metricName).addTags(Map<String, String> tags).count(int value);// 耗时与次数Trace.newTimer(String metricName).addTags(Map<String, String> tags).value(int value);// 负载大小与次数Trace.newPayload(String metricName).addTags(Map<String, String> tags).value(int value);// 单值类型Trace.newGauge(String metricName).addTags(Map<String, String> tags).value(int value);

基于这些API,用户可以在代码中针对他的业务逻辑进行指标埋点,为后来可不雅观测性大一统供应了实现条件。
在其他组件同步开拓时,我们也针对LinDB做了多少优化,提升了写入性能与易用性:

增加Histogram、Gauge、Payload、Ratio多种指标数据类型;从1.0版本的每条指标数据都调用一次RocksDB的API进行写入,改成先在内存中聚合一段韶光,再通过RocksDB的API进行批量写入文件。
3.0:推陈出新,交融贯通可不雅观测性系统大一统

在2017年的饿了么,除了ETrace外还有多套可不雅观测性系统:基于Statsd/Graphite的业务可不雅观测性系统、基于InfluxDB的根本举动步伐可不雅观测性系统。
后两者都集成Grafana上,用户可以去查看他的业务或者机器的详细指标。
但实际排障场景中,用户还是须要在多套系统间来回切换:根据Grafana上的业务指标感知业务故障,到ETrace上查看详细的SOA/DB故障,再到Grafana上去查看详细机器的网络或磁盘IO指标。
虽然,我们也开拓了Grafana的插件来集成LinDB的数据源,但因实质上差异巨大的系统架构,还是让用户“疲于奔命”式的来回切换系统,用户难以有统一的可不雅观测性体验。
因此2018年初,我们下定决心:将多套可不雅观测性系统合而为一,打通“业务可不雅观测性+运用可不雅观测性+根本举动步伐可不雅观测性”,让ETrace真正成为饿了么的一站式可不雅观测性平台。

LinDB 3.0:

所谓“改造”未动,“存储”先行。
想要整合InfluxDB与Statsd,先要研究他们与LinDB的异同。
我们创造,InfluxDB是支持一个指标名(Measurement)上有多个Field Key的。
如,InfluxDB可能有以下指标:

measurement=census, fields={butterfiles=12, honeybees=23}, tags={location=SH, scientist=jack}, timestamp=2015-08-18T00:06:00Z

若是LinDB 2.0的模式,则须要将上述指标转换成两个指标:

measurement=census, field={butterfiles=12}, tags={location=SH, scientist=jack}, timestamp=2015-08-18T00:06:00Zmeasurement=census, field={honeybees=23}, tags={location=SH, scientist=jack}, timestamp=2015-08-18T00:06:00Z

可以想见在数据存储与打算效率上,单Field模式有着极大的摧残浪费蹂躏。
但变动指标存储的Schema,意味着全体数据处理链路都须要做适配和调度,事情量和改动极大。
然而不改就意味着“姑息”,我们不能忍受对自己哀求的降落。
因此又经由了几个月的爆肝研发,LinDB 3.0开拓完成。

这次改动,除了升级到指标多Fields模式外,还有以下优化点:

集群方面引入Kafka的ISR设计,办理了之前机器故障时查询数据缺失落的问题。
存储层面支持更加通用的多Field模式,并且支持对多Field之间的表达式运算。
引入了倒排索引,显著提高了对付任意Tag组合的过滤查询的性能。
支持了自动化的Rollup操作,对付任意韶光范围的查询自动选取得当的粒度来聚合。

经由这次大规模优化后,从最初的逐日5T指标数据涨到如今的逐日200T数据,LinDB 3.0都经受住了磨练。
指标查询的相应韶光的99分位线为200ms。
详细设计细节可参看文末的分布式时序数据库 - LinDB。

将Statsd指标转成LinDB指标

Statsd是饿了么广泛利用的业务指标埋点方案,各机房有一个数十台机器规模的Graphite集群。
考虑到业务的核心指标都在Statsd上,并且各个AppId以ETrace Metrics API更换Statsd是一个漫长的过程(也确实是,前前后后更换完造诣花了将近一年韶光)。
为了减少对用户与NOC团队的影响,我们决定:用户更新代码的同时,由ETrace同时“兼容”Statsd的数据。

得益于饿了么强大的中间件体系,业务在用Statsd API埋点的同时会“自动”记一条分外的Trace数据,携带上Statsd的Metric数据。
那么只要处理Trace数据中的Statsd埋点,我们就能将大多数Statsd指标转化为LinDB指标。
如下图:多个Statsd指标会转为同一个LinDB指标。

// statsd:stats.app.myAppName.order.from_ios.success 32stats.app.myAppName.order.from_android.success 29stats.app.myAppName.order.from_pc.failure 10stats.app.myAppName.order.from_openapi.failure 5// lindb:MetricName: myAppName.orderTags: "tag1"=[from_ios, from_android,from_pc, from_openapi] "tag2"=[success, failure]

之前我们的实时打算模块Shaka就在这里派上了大用场:只要再新增一起数据处理流程即可。
如下图,新增一条Statsd数据的处理Pipeline,并输出结果到LinDB。
在用户的代码全部从Statsd API迁移到ETrace API后,这一起处理逻辑即可移除。

将InfluxDB指标转成LinDB指标

InfluxDB紧张用于机器、网络设备等根本举动步伐的可不雅观测性数据。
饿了么每台机器上,都支配了一个ESM-Agent。
它卖力采集机器的物理指标(CPU、网络协议、磁盘、进程等),并在特定设备上进行网络嗅探(Smoke Ping)等。
这个数据采集Agent起因Python开拓,在不断需求堆叠之后,已弘大到难以掩护;并且每次更新可不雅观测逻辑,都须要全量发布每台机器上的Agent,导致每次Agent的发布都令民气惊胆战。

我们从0开始,以Golang重新开拓了一套ESM-Agent,做了以下改进:

可不雅观测性逻辑以插件的形式,推送到各宿主机上。
不同的设备、不同运用的机器,其上运行的插件可以定制化支配。
制订插件的交互接口,让中间件团队可定制自己的数据采集实现,解放了生产力。
移除了etcd,利用MySql做配置数据存储,减轻了系统的繁芜度。
开拓了便利的发布界面,可灰度、全量的推送与发布Agent,运维事情变得轻松。
最主要的,网络到的数据以LinDB多Fields的格式发送到Collector组件,由其发送到后续的处理与存储流程上。

从ETrace到EMonitor,不断升级的可不雅观测性体验

2017年底,我们团队终于迎来了一名正式的前端开拓工程师,可不雅观测性团队正式从后端开拓写前真个状态中分开出来。
在之前的Angular的开拓体验中,我们深感“状态转换”的掌握流程甚为繁琐,并且开拓的组件难以复用(虽然其后版本的Angular有了很大的改进)。
在调用当时盛行的前端框架后,我们在Vue与React之中选择了后者,辅以Ant Design框架,开拓出了媲美Grafana的指标看版与便利的链路看板,并且在PC版本之外还开拓了移动真个定制版本。
我们亦更名了全体可不雅观测性产品,从“ETrace”更新为“EMonitor”:不仅仅是链路可不雅观测性系统,更是饿了么的一站式可不雅观测性平台。

可不雅观测性数据的整合:业务指标 + 运用链路 + 根本举动步伐指标 + 中间件指标

在指标系统都迁移到LinDB后,我们在EMonitor上集成了“业务指标 + 运用链路 + 根本举动步伐指标 + 中间件指标”的多层次的可不雅观测性数据,让用户能在一处不雅观测它的业务数据、排查业务故障、深挖底层根本举动步伐的数据。

可不雅观测性场景的整合:指标 + 链路 + 报警

在可不雅观测性场景上,“指标看板”用于日常业务盯屏与宏不雅观业务可不雅观测性,“链路”作为运用排障与微不雅观业务逻辑透出,“报警”则实现可不雅观测性自动化,提高应急相应效率。

灵巧的看板配置与业务大盘

在指标配置上,我们供应了多种图表类型--线图、面积图、散点图、柱状图、饼图、表格、文本等,以及丰富的自定义图表配置项,能知足用户不同数据展示需求。

在完成单个指标配置后,用户须要将多少个指标组合成所需的指标看板。
用户在配置页面中,先选择待用的指标,再通过拖拽的办法,配置指标的布局便可实时预览布局效果。
一个指标可被多个看板引用,指标的更新也会自动同步到所有看板上。
为避免指标配置缺点而引起歧义,我们也开拓了“配置历史”的功能,指标、看板等配置都能回滚到任意历史版本上。

看板配置是静态图表组合,而业务大盘供应了生动的业务逻辑视图。
用户可以根据他的业务场景,将指标配置整合成一张宏不雅观的业务图。

第三方系统整合:变更系统 + SLS日志

因每条报警信息和指标配置信息都与AppId关联,那么在指标看板上可同步标记出报警的触发韶光。
同理,我们拉取了饿了么变更系统的运用变更数据,将其标注到对应AppId干系的指标上。
在故障发生时,用户查看指标数据时,能根据有无变更记录、报警记录来初步判断故障缘故原由。

饿了么的日志中间件能自动在记录日志时加上对应的ETrace的RequestId等链路信息。
如此,用户查看SLS日志做事时,能反查到整条链路的RequestId;而EMonitor也在链路查看页面,拼接好了该运用所属的SLS链接信息,用户点击后能直达对应的SLS查看日志高下文。

利用场景的整合:桌面版 + 移动版

除供应桌面版的EMonitor外,我们还开拓了移动版的EMonitor,它也供应了大部分可不雅观测性系统的核心功能--业务指标、运用指标、报警信息等。
移动版EMonitor能内嵌于钉钉之中,打通了用户认证机制,帮助用户随时随地节制所有的可不雅观测性信息。

为了极致的体验,精益求精

为了用户的极致利用体验,我们在EMonitor上各功能利用上细细打磨,这里仅举几个小例子:

我们为极客开拓者实现了多少键盘快捷键。
例如,“V”键就能展开查看指标大图。
图上多条曲线时,点击图例是默认单选,目的是让用户只看他关心的曲线。
此外,若是“Ctrl+鼠标点击”则是将其加选择的曲线中。
这个功能在一张图几十条曲线时,比拟几个关键曲线时尤为有用。
为了让色弱开拓者更随意马虎区分成功或失落败的状态,我们针对性的调度了对应颜色的比拟度。

成为饿了么一站式可不雅观测性平台

EMonitor开拓完成后,凭借精良的用户体验与产品集成度,很快在用户中遍及开来。
但是,EMonitor要成为饿了么的一站式可不雅观测性平台,还剩下末了一战--NOC可不雅观测性大屏。

NOC可不雅观测性大屏更换

饿了么有一套完善的应急处理与保障团队,包括724值班的NOC(Network Operation Center)团队。
在NOC的办公区域,有一整面墙上都是可不雅观测性大屏,上面显示着饿了么的实时的各种业务曲线。
下图为网上找的一张示例图,实际饿了么的NOC大屏比它更大、数据更多。

当时这个可不雅观测大屏是将Grafana的指标看版投影上去。
我们希望将NOC大屏也更换成EMonitor的看版。
如前文所说,我们逐步将用户的Statsd指标数据转换成了LinDB指标,在NOC团队的帮忙下,一个一个将Grafana的可不雅观测性指标“搬”到EMonitor上。
此外,在原来白色主题的EMonitor之上,我们开拓了玄色主题以适配投屏上墙的效果(白色背景投屏太刺眼)。

终于赶在2018年的双十一之前,EMonitor正式入驻NOC可不雅观测大屏。
在双十一当天,浩瀚研发挤在NOC室看着墙上的EMonitor看版上的业务曲线不断飞涨,作为可不雅观测性团队的一员,这份自满之来由衷而生。
经此一役,EMonitor真正成为了饿了么的“一站式可不雅观测性平台”,Grafana、Statsd、InfluxDB等都成了过去时。

报警Watchdog 2.0

同样在EMonitor之前,亦有Statsd与InfluxDB对应的多套报警系统。
用户若想要配置业务报警、链路报警、机器报警,须要辗转多个报警系统之间。
各系统的报警的配置规则、触达体验亦是千差万别。
Watchdog报警系统也面临着统一领悟的寻衅。

在调研其他系统的报警规则实现后,Watchdog中仍以LinDB的指标作为元数据实现。
针对其他报警系统的有显著差异的订阅模式,我们提出了"报警规则+一个规则多个订阅标签+一个用户订阅多个标签"的办法,完美迁移了险些其他系统所有的报警规则与订阅关系。
其他各系统在报警触达与触达内容上也略有不同。
我们统一整合成“邮件+短信+钉钉+语音外呼”四种关照办法,并且供应可参数化的自定义Markdown模板,让用户可自己定时报警信息。

经由一番艰巨的报警配置与逻辑整合后,我们为用户“自动”迁移了上千个报警规则,并终极为他们供应了一个统一的报警平台。

报警,更精准的报警

外卖行业的业务特性是业务的午高峰与晚高峰,在业务曲线上便是两个波峰的形状。
这样的可不雅观测数据,自然难以大略利用阈值或比率来做判断。
纵然是根据历史同环比、3-Sigma、移动均匀等规则,也难以适应饿了么的可不雅观测性场景。
由于,饿了么的业务曲线并非一成不变,它受匆匆销、景象成分、区域、压测等成分影响。
开拓出一个自适应业务曲线变革的报警算法,势在必行。

我们经由调研既有规则,与饿了么的业务场景,推出了全新的“趋势”报警。
简要算法如下:

打算历史10天的指标数据中值作为基线。
个中这10天都取事情日或非事情日。
不取10天的均值而取中值是为了减少压测或机房流量切换造成的影响。
根据二阶滑动均匀算法,得到滑动均匀值与当前实际值的差值。
将基线与差值相加作为预测值。
根据预测值的数量级,打算出颠簸的幅度(如上界与下界的数值)。
若当前值不在预测值与颠簸幅度确定的高下界之中,则触发报警。

如上图所示,22点01分的实际值因不在高下界所限定的区域之中,会触发报警。
但从后续趋势来看,该低落趋势符合预期,因此实际中还会辅以“偏离持续X分钟”来改动误报。
(如该例中,可增加“持续3分钟才报警”的规则,该点的数据便不会报警)算法中部分参数为履历值,而个中颠簸的阈值参数用户可按照自己业务调度。
用户针对具备业务特色的曲线,再也不用费心的去调度参数,配置上默认的“趋势”规则就可以覆盖大多数的可不雅观测性场景,目前“趋势”报警在饿了么广泛利用。

智能可不雅观测性:根因剖析,大显神威

作为AIOPS中主要的一环,根因剖析能帮助用户快速定位故障,缩短故障相应韶光,减少故障造成的丢失。
2020年初,我们结合饿了么场景,攻坚克难,攻破“指标下钻”、“根因剖析”两大难关,在EMonitor上成功落地。

根因剖析最大的难点在于:包含繁芜维度的指标数据难以找到真正影响数据颠簸的详细维度;伶仃的指标数据也难以剖析出运用高下游依赖引起的故障根因。
例如,某个运用的非常指标突增,当前我们只能知道突增的非常名、机房维度的非常分布、机器维度的非常分布等,只有用户手工去点击非常指标看来链路之后,才能大致判断是哪个SOA方法/DB要求中的非常。
继而用户根据非常链路的环节,去追溯上游或下贱的运用,重复类似的排查过程,末了以人工履历判断出故障点。

因此,在“指标下钻”上,我们针对目标指标的曲线,细分成最风雅的每个维度数据(指标group by待剖析的tag维度),利用KMeans聚类找出故障数据的各维度的最大公共特色,依次打算找到最优的公共特色,如此便能找到曲线颠簸对应的维度信息。

其次,在链路数据打算时,我们就能将额外的高下游附加信息附加到对应的指标之中。
如,可在非常指标中追加一个维度来记录产生非常的SOA方法名。
这样在根据非常指标剖析时,能直接定位到是这个运用的那个SOA方法抛出的非常,接下来“自动”剖析是SOA下贱故障还是自身故障(DB、Cache、GC等)。

在2020.3月在饿了么落地以来,在剖析的上百例故障中,根因剖析的准确率达到90%以上,显著缩短的故障排查的韶光,帮助各业务向稳定性培植目标向前跨进了一大步。

4.0:承前启后,乘势而上

经由4、5年的发展,风云变幻但团队初心不改,为了让用户用好可不雅观测性系统,EMonitor没有停下脚步,自我改造,希望让“天下没有难用的可不雅观测性系统”。
我们向集团的可不雅观测性团队请教学习,结合本地生活自己的技能体系培植,力争百尺竿头更进一步,方案了以下的EMonitor 4.0的设计目标。

一、进行多租户化改造,保障核心数据的时延和可靠性

在本地生活的技能体系与阿里巴巴集团技能体系的不断深入的领悟之中,单元化的支配环境以及对可不雅观测性数据不同程度的可靠性哀求,催生了“多租户化”的设计理念。
我们可以根据运用类型、数据类型、来源等,将可不雅观测性数据分流到不同的租户中,再针对性配置数据处理流程及分配处理能力,实现差异化的可靠性保障能力。

初步我们可以划分为两个集群--核心运用集群与非核心运用凑集,根据在运用上标记的“运用等级”将其数据自动发送到对应集群中。
两套集群在资源配置上优先侧重核心集群,并且完备物理隔离。
此外通过配置开关可动态掌握某个运用归属的租户,实现业务的柔性降级,避免当下偶尔因个别运用的禁绝确埋点办法会影响整体可不雅观测可用性的问题。

未来可根据业务发展进一步发展出业务干系的租户,如到家业务集群、到店业务集群等。
或者按照区域的划分,如弹内集群、弹外集群等。

二、打通集团弹内、弹外的可不雅观测性数据,成为本地生活的一站式可不雅观测性平台

目前本地生活很多业务领域已经迁入集团,在Trace链路可不雅观测方面,虽然在本地生活上云的项目中,EMonitor已经通过中间件改造实现鹰眼TraceId在链路上的通报,并记录了EMonitor RequestId与鹰眼TraceId的映射关系。
但EMonitor与鹰眼在协议上的天然隔阂仍使得用户须要在两个平台间跳转查看同一条Trace链路。
因此,我们接下来的目标是与鹰眼团队互助,将鹰眼的Trace数据集成到EMonitor上,让用户能一站式的排查问题。

其次,本地生活上云后,浩瀚中间件已迁移到云上中间件,如云Redis、云Kafka、云Zookeeper等。
对应的可不雅观测性数据也须要额外上岸到阿里云掌握台去查看。
云上中间的可不雅观测性数据大多已存储到Prometheus之中,因此我们操持在完成Prometheus协议兼容后,就与云上中间件团队互助,将本地生活的云上可不雅观测性数据集成到EMonitor上。

三、拥抱云原生,兼容Prometheus、OpenTelemetry等开源协议。

云原生带来的技能改造势不可挡,本地生活的绝大多数运用已迁移到集团的容器化平台--ASI上,对应带来的新的可不雅观测环节也亟需补全。
如,ASI上Prometheus协议的容器可不雅观测性数据、Envoy等本地生活PaaS平台透出的可不雅观测性数据与Trace数据等。

因此,我们操持在原来仅支持LinDB数据源的根本上,增加对Prometheus数据源的支持;扩展OpenTelemetry的otel-collector exporter实现,将Open Telemetry协议的Trace数据转换成EMonitor的Trace格式。
如此便可补全云原生技能升级引起的可不雅观测性数据缺失落,并供应高度的适配性,知足本地生活的可不雅观测性培植。

结语

纵不雅观各大互联网公司的产品演进,技能产品的走向与命运都离不开公司业务的发展轨迹。
我们饿了么的技能人是幸运的,能遇上这一波技能变革的大潮,能够发挥聪明才智,打磨出一些为用户津津乐道的技能产品。
我们EMonitor可不雅观测性团队也为能参与到这次技能变更中深感自满,EMonitor能被大家认可, 离不开每位参与到饿了么可不雅观测性体系培植的差错,也感谢各位对可不雅观测性系统供应帮助、支持、建议的伙伴!

作者简介:柯圣,花名“炸天”,饿了么监控技能组卖力人。
自2016年加入饿了么,长期深耕于可不雅观测性领域,全程参与了ETrace到EMonitor的饿了么可不雅观测性系统的发展进程。

本文为阿里云原创内容,未经许可不得转载。