【遇见 Doris】Apache Doris 在百度商业大规模微服务全链路监控的实践
Doris 线下沙龙完美收官!本次沙龙邀请了来自百度、美团、京东的技术大牛带来实战分享。了解更多详情请关注 Doris 官方公众号,嘉宾分享回顾会陆续放出。公众号后台回复“1222”立即 get 现场录像及嘉宾 PPT。
2019 年 12 月 22 日,Doris 本年度最后一场线下沙龙在百度大厦顺利举办。本次邀请了来自美团、京东、百度的技术大牛来分享实战经验,快来跟随小编一起回顾吧!
现场视频和嘉宾 PPT 会在近日放出,欢迎大家关注 Apache Doris 官方公众号。
本次由来自百度凤巢的李奇原 同学为大家带来 Apache Doris 在百度商业大规模微服务全链路监控的实践 。
来自百度凤巢的李奇原负责的工作分为两个阶段。第一阶段负责凤巢广告 API 平台,承载了百度所有的信息流广告和搜索广告投放业务,第二个阶段是负责整个商业平台部所有微服务的监控系统。
百度技术栈有 C++、JAVA、PHP。商业平台大部分是广告业务系统,技术栈主要是 JAVA 语言,因此监控平台也是基于 JAVA 语言来开发的。
因为监控规模非常大,分析需求又复杂,经过一些历史经验后,最后选型了 Doris 来做底层的存储系统,现在看来 Doris 确实能够满足我们大部分的需求。
Doris 的语法和 MySQL 基本一致,所以学习成本不高;
Doris 对于部署的机器性能要求不是很高,所以搭建一套支撑大规模数据存储和分析的系统资源要求并不高;
Doris 的运维难度很低,可以让我们集中精力做上层的业务开发和数据分析。
凤睛-筑巢引凤,更要明察秋毫
上面是这张图是从系统中选取的一张全局拓扑图,在真实的系统中是一个实时动态的拓扑图。其中每个节点代表一个微服务应用,不同颜色区分不同的产品线,节点间的连线是他们的调用关系。其中红色代表凤巢产品线,天蓝色代表 CRM 平台,深蓝色是品牌广告检索端。目前监控平台支持了 30 条产品线,2 万台实例,1100 多个应用。
从这张图上看到整个商业平台的模块关系很复杂,当出现问题的时候从这些复杂的关系中快速定位到关键节点并且能精确定位到代码所在行,单靠人力是难以完成的,这也是凤睛系统的价值。凤睛能通过系统 7*24 小时的工作,来自动化完成所有的监控分析任务:实时完成调用链路数据的采集、存储和分析,从而发现潜在的风险点,并能够对风险达到临界值的问题进行及时预警,最终保证整个微服务平台的稳定性。
接下来从业界的产品框架层面来看下凤睛监控系统。
2017 分布式追踪峰会将分布式追踪系统用三个概念来进行了描述。按照对监控数据处理的抽象程度,从低到高依次是监控日志流(Logging)、调用链数据(Tracing)、时序数据(Metrics)。
Logging 监控日志数据的数据量比较庞大,并且大部分没有相关性,所以我们需要从中分析出特定和关心的事情来存储,这些数据处理和存储的要求是低延迟、存储成本不高。
Tracing 调用链数据,在采集的时候就进行了加工,发送到后端的是性能数据、调用关系、关键业务指标这些数据,这些数据量比日志数据量小很多,和应用流量成正比,按照追踪的深度来决定调用链数据是流量数据的多少倍。它对存储的要求是能够支持比较复杂的查询和分析、查询耗时少。
Metrics 时序数据是抽象层次最高的,主要是对采集的性能数据进行了深度的统计分析,最终形成流量报表、性能分析报表等稳定统计指标。它对存储的要求是需要能够支持多维度不同粒度的查询和分析。
凤睛对于这些相关概念都有对应的监控产品,底层的存储和分析大部分基于 Doris。
从系统架构图中可以看出,Doris 处于一个存储基石的位置。凤睛的整体架构按照监控数据处理阶段可以分为采集、传输、存储、分析和展现四个阶段。
凤睛的采集是通过对应用植入一个监控探针,在用户完成无感知的情况下,完成所有的数据采集工作。包括安装、升级和卸载,对于用户来说都是完全无感知的,从而降低了接入成本。
数据传输主要 Flume+Kafka ,Flume 转储模块的存在意义是为了降低监控探针的外部依赖,从而完成无侵入采集的目的。而 Kafka 转储主要是为了能够平滑应用流量突增带来的冲击。无论是时序数据还是日志数据,都和用户流量成正比的关系,所以需要平滑流量的转储消息队列。Dumper 是一个实时导入的模块。
数据分析模块主要是按照监控的业务来完成需求多样的统计报表和调用链分析报表。监控系统对于数据展现也有很高的要求。
凤睛路线图
大数据查询的性能优化实践
2017 年刚上线的时候,凤睛的目标在于降低用户的接入成本,而经过一年多的努力后,随着热插拔无侵入探针的上线,接入成本大幅下降,随之而来,存储的数据总量也在不断上涨。凤睛的架构瓶颈转移到存储和分析环节。基于原有架构,如何优化查询性能呢?
首先在导入环节,原来架构的导入频率很高,对导入没有进行控制,生成大量的文件碎片,合并起来很慢,从而导致在查询时有可能无法查询到合并文件,而查询到很多小文件,从而导致 I/O 被打满,查询性能很低。
在存储环节我们发现数据倾斜问题比较严重。数据分区的 Hash Key 选择不合理而导致个别分区数据量很大,一次查询可能需要扫描大量的数据,导致查询性能很低,从而影响 I/O 和其他小查询。监控数据的存储更加需要重视性价比,因此凤睛尝试在有限的资源上来解决更多的问题、更高效地支撑应用。
在查询上,大部分查询都需要全表扫描。业务场景包含 Tracing 和 Metric 两个部分。
Tracing 主要是调用链数据,因此使用 Trace Id 作为第一索引。
Metric 主要是时序数据,对应的上层应用主要有两种。第一种是是故障预警,由于其需要扫面全局时间窗口的数据,对所有数据进行分析,因此将 Log Date 作为第一索引。第二种应用是应用详情分析,主要在发现应用出现问题之后,来定位问题所在,因此对应的第一索引是和 App Id。
在导入、存储、查询这三个环节中分别有一些优化措施:
在导入优化上,主要控制了导入频率。对 Dumper 进行了一系列优化,分层、分队列、多级队列地进行导入,严格控制频率:一分钟提交一次或消息超过 40 万条提交一次。
在导入方式上,原来在数据量较小的时候,Mini Load 可以满足需求。随着数据量增大以及对延时要求的不断提高,我们采用了 Streaming Load 来替换 Mini Load。
调用链(Tracing)业务流如下:一个请求对于我们来说是一个调用链。一个请求会跨越多个系统来完成工作,而每个系统中产生的多个请求子节点都是调用链中的叶子节点。
这样对应到存储模型中即如下图所示。
Start 和 End 为时间;
AppId 为应用的 ID;
MethodId 为本请求到应用的方法 ID;
TracingID 为本请求对应的调用链 ID;
SpanID 为叶子节点的 ID;
ParentSpanID 为父叶子节点的 ID;
还有一些与业务相关的关键性指标。
存储优化
由于之前提到的 Hash Key 选择不合理,因此我们调整了分桶的 Hash Key,并按照业务查询场景调整基础表索引。同时增加上卷表,满足不同业务场景。具体示例如下:
上层业务模型的典型场景如下:
场景 1: 通过指定 TraceId 查询 TraceId 相关的调用链数据。
优化方案:建立 TraceId 为第一列的 Rollup,优化 SQL 增加 GROUP,使 SQL 直接命中 Rollup 增加查询效率。
收益:此类型查询平均耗时降低 80%。
具体实现:
场景 2: 根据时间和请求接口 、应用查询应用详情
优化方案:将 appid 作为前置索引第一列,同时优化 SQL,将每个 SQL 都加上 appid 限制条件。
收益:此类型 SQL 平均耗时降低 60%。
具体实现:
SELECT SUM(pv) FROM #TABLE_NAME WHERE log_date>'#START_DATE'
AND log_date<'#END_DATE' AND app_id=#APP_ID AND method_id=#METHOD_ID
SELECT * FROM #TABLE_NAME WHERE log_date>'#START_DATE'
AND log_date<'#END_DATE' AND app_id=#APP_ID AND method_id=#METHOD_ID
SELECT log_date_lm AS logDatelm, SUM(pv) AS totalPv, SUM(cost)/SUM(pv) AS avgCost
FROM #TABLE_NAME WHERE log_date BETWEEN '#START_DATE' AND '#END_DATE' SND method_id=#METHOD_ID AND app_id=#APP_ID GROUP BY log_date_1m ORDER BY log_date_1m ASC
场景 3: 滑动窗口分析数据,每隔 2-10 分钟分析一次数据,分析所有应用所有接口的流量平响等。
优化方案:根据常用的聚合字段建立 Rollup,使 SQL 直接命中 Rollup 增加查询效率
收益:此类型 SQL 平均耗时降低 40%。
具体实现:
SELECT app_id ASS appId, method_id AS MethodId, SUM(cost)/SUM(pv)
AS costAvg, SUM(pv) AS pv FROM #TABLE_NAME1 WHERE log_date>'#START_DATE'
AND log_date<'#END_DATE' GROUP BY app_id, method_id EAVING pv>10 AND costAvg>3000
SELECT app_id AS appId, method_id AS methodId, SUM(cost)/SUM(pv) AS costAvg, SUM(pv) AS pv FROM #TABLE_NAME1 WHERE log_date>'#START_DATE' AND log_date<'#END_DATE' GROUP BY app_id, method_id
强大的数据读写能力是支撑大规模微服务监控的基础。虽然数据规模很大,但实际上现在 Doris 的集群规模只有十几台,提供了非常稳定的服务,已经有半年的时间没有再处理过底层的问题。
图的初尝试-拓扑分析
同时团队也在做新的尝试,我们试图用 Doris 来建立一些图的存储。上图是现在商业平台部托管微服务的全景拓扑图。应该如何基于 Doris 构建拓扑图呢?
拓扑图的几大需求如下:
功能要求:上下游依赖关系;展示调用的流量、错误率等;支持从应用、平台、接口多个维度查询;能够分分钟、分小时、分天粒度汇聚数据
性能要求:实时查询、低延时
资源要求:有效利用计算资源和存储资源
因此,我们需要构建
拓扑分析任务:每分钟定时汇总增量调用链数据,分析任务平均耗时约 10s
基础表数据:分钟、小时、天三种拓扑数据表
分析上卷表:增加出入度应用和方法的上卷表
相对应的表和建表语句如下:
ALTER TABLE daily_trace_topology_summary
ADD ROLLUP dest_mehtod_rollup_index('dest_metod_id','log_date','source_method_id','dest_group_id','source_group_id','dest_app_id','source_app_id','is_depend','method_type','pv','error_pv','cost','count')
PROPERTIES("storage_type"="column");
ALTER TABLE daily_trace_topology_summary
ADD ROLLUP source_app_rollup_index('source_app_id','log_date','dest_app_id','is_depend','method_type','pv','error_pv','cost','count')
PROPERTIES("storage_type"="column");
ALTER TABLE daily_trace_topology_summary
ADD ROLLUP dest_app_rollup_index('dest_app_id','log_date','source_app_id','is_depend','method_type','pv','error_pv','cost','count')
PROPERTIES("storage_type"="column");
拓扑:应用拓扑、接口拓扑。10s 内完成亿流量应用的拓扑查询,延时保证在 2-3 分钟
概览分析:慢请求、错误率、数据库访问流量
衍生应用:精准测试平台,RD 更新接口代码后,可快速定位影响的其他系统,以便 QA 进行测试
欢迎扫码关注:
Apache Doris(incubating)官方公众号
相关链接:
Apache Doris 官方网站:
http://doris.incubator.apache.org
Apache Doris Github:
https://github.com/apache/incubator-doris
Apache Doris Wiki:
https://github.com/apache/incubator-doris/wiki
Apache Doris 开发者邮件组:
dev@doris.apache.org
版权声明: 本文为 InfoQ 作者【ApacheDoris】的原创文章。
原文链接:【http://xie.infoq.cn/article/f05f3f6da9a75c2864cfaaca3】。文章转载请联系作者。
评论