Doris在百度商业大规模微服务全链路监控的实践
三寸九州 发布于2021-04-01 浏览:829 回复:0
0
收藏

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年上线,通过不断努力,接入一个应用的成本从3pd降到0pd,接入的容器也呈现了从100+到2万+的爆炸增长。在2019年已经接入了1600多个应用,覆盖百度内部包括凤巢在内的30条产品线,每天采集的数据在1000亿,峰值流量每秒4000万条。写入Doris的数据每天有150亿,峰值流量在每秒300万条、50M每秒,存储总量到达300T。

 

 

 

大数据查询的性能优化实践

如何将架构进行进一步优化以适应大数据下的存储和分析呢?

 

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,并按照业务查询场景调整基础表索引。同时增加上卷表,满足不同业务场景。具体示例如下:


//基础表
CREATE TABLE 'log_rpc_provider'(
'app_id' int(11) COMMENT "",//更改索引位置
'log_date' datetime NOT NULL COMMENT "log_date",
'method_id' int(11) NOT NULL COMMENT "method_id",
.....
'cost'bigint(20) SUM NOT NULL COMMENT "cost time",
'pv'bigint(20) SUM NOT NULL DEFAULT "1" COMMENT "all 1; for count and sum pv"
) ENGINE=OLAP
AGGREGATE KEY()
PARTITION BY RANGE('log_date')
(...)
DISTRIBUTED BY HASH('app_id','trace_id')BUCKETS 10//更改分桶索引
PROPERTIES(
"storage_type"="COLUMN"
);

//调用链上卷表-方法为条件
ALTER TABLE log_rpc_provider ADD ROLLUP log_data_trace_query_rollup(trace_id,log_date,mehtod_id,log_id,local_bns,remote_ip,user_id,start,END,status,parentid,cost);

//时序分析上卷表
ALTER TABLE log_rpc_provider ADD ROLLUP logdata_analyse_rollup('log_date','app_id','mehtod_id','user_id','return_code','status','cost','pv');


//调用链上卷表-应用为条件
ALTER TABLE log_rpc_provider ADD ROLLUP logdata_trace_rollup('trace_id','log_date','app_id','mehtod_id','parentid','log_id','pv');


上层业务模型的典型场景如下:

场景1: 通过指定TraceId查询TraceId相关的调用链数据。

优化方案:建立TraceId为第一列的Rollup,优化SQL增加GROUP,使SQL直接命中Rollup增加查询效率。

收益:此类型查询平均耗时降低80%。

 

具体实现:

SELECT method_id AS methodId,log_id AS logId, trace_id AS traceId
FROM #TABLE_NAMW1 WHERE log_date BETWEEN '#START_DATE' AND '#END_DATE' AND trace_id=''GROUP BY trace_id, method_id, log_id
union SELECT method_id AS methodId,log_id AS logId, trace_id AS traceId
FROM #TABLE_NAME2 WHERE log_date BETWEEN '#START_DATE' AND '#END_DATE' AND trace_id=''GROUP BY trace_id, method_id, log_id
union SELECT method_id AS methodId, log_id AS logId, trace_id AS traceId
FROM #TABLE_NAME3 WHERE log_date BETWEEN '#START_DATE'
AND '#END_DATE' AND tracer_id ='' GROUP BY trace_id, method_id, log_id


场景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

收藏
点赞
0
个赞
快速回复
TOP
切换版块