微信海量数据查询如何从1000ms降到100ms?

88ff7aaa887b56fe18cff929e16dc07c.png

1755c920f8be414730162c5dfa359730.gif

👉腾小云导读

微信的多维指标监控平台,具备自定义维度、指标的监控能力,主要服务于用户自定义监控。作为框架级监控的补充,它承载着聚合前 45亿/min、4万亿/天的数据量。当前,针对数据层的查询请求也达到了峰值 40万/min,3亿/天。较大的查询请求使得数据查询遇到了性能瓶颈:查询平均耗时 > 1000ms,失败率居高不下。针对这些问题,微信团队对数据层查询接口进行了针对性的优化来满足上述场景,将平均查询速度从1000ms+优化到了100ms级别。本文为各位分享优化过程,希望对你有用!

👉

1 背景介绍

2 优化分析

    2.1 用户查询行为分析

    2.2 数据层架构

    2.3 为什么查询会慢

3 优化方案设计

    3.1 拆分子查询请求

    3.2 拆分子查询请求+Redis Cache

    3.3 更进一步-子维度表

4 优化成果

    4.1 缓存命中率>85%

    4.2 查询耗时优化至 100ms

5 结语

01、 背景介绍

微信多维指标监控平台(以下简称多维监控),是具备灵活的数据上报方式、提供维度交叉分析的实时监控平台。

在这里,最核心的概念是“协议”、“维度”与“指标”。例如,如果想要对某个【省份】、【城市】、【运营商】的接口【错误码】进行监控,监控目标是统计接口的【平均耗时】和【上报量】。在这里,省份、城市、运营商、错误码,这些描述监控目标属性的可枚举字段称之为“维度”,而【上报量】、【平均耗时】等依赖“聚合计算”结果的数据值,称之为“指标”。而承载这些指标和维度的数据表,叫做“协议”。

多维监控对外提供 2 种 API:

  • 维度枚举查询:用于查询某一段时间内,一个或多个维度的排列组合以及其对应的指标值。它反映的是各维度分布“总量”的概念,可以“聚合”,也可以“展开”,或者固定维度对其它维度进行“下钻”。数据可以直接生成柱状图、饼图等。

  • 时间序列查询:用于查询某些维度条件在某个时间范围的指标值序列。可以展示为一个时序曲线图,横坐标为时间,纵坐标为指标值。

然而,不管是用户还是团队自己使用多维监控平台的时候,都能感受到明显的卡顿。主要表现在看监控图像或者是查看监控曲线,都会经过长时间的数据加载。

团队意识到,这是数据量上升必然带来的瓶颈。目前,多维监控平台已经接入了数千张协议表,每张表的特点都不同。维度组合、指标量、上报量也不同。针对大量数据的实时聚合以及 OLAP 分析,数据层的性能瓶颈越发明显,严重影响了用户体验。于是这让团队人员不由得开始思考:难道要一直放任它慢下去吗?答案当然是否定的。因此,微信团队针对数据层的查询进行了优化。

02、 优化分析

   2.1 用户查询行为分析

要优化,首先需要了解用户的查询习惯,这里的用户包含了页面用户和异常检测服务。于是微信团队尽可能多地上报用户使用多维监控平台的习惯,包括但不限于:常用的查询类型、每个协议表的查询维度和查询指标、查询量、失败量、耗时数据等。

在分析了用户的查询习惯后,有了以下发现:

  •  【时间序列】查询占比 99% 以上

出现如此悬殊的比例可能是因为:调用一次维度枚举,即可获取所关心的各个维度。但是针对每个维度组合值,无论是页面还是异常检测都会在查询维度对应的多条时间序列曲线中,从而出现「时间序列查询」比例远远高于「维度枚举查询」。

  • 针对1天前的查询占比约 90%

出现这个现象可能是因为每个页面数据都会带上几天前的数据对比来展示。异常检测模块每次会对比大约 7 天数据的曲线,造成了对大量的非实时数据进行查询。

   2.2 数据层架构

分析完用户习惯,再看下目前的数据层架构。多维监控底层的数据存储/查询引擎选择了 Apache-Druid 作为数据聚合、存储的引擎,Druid 是一个非常优秀的分布式 OLAP 数据存储引擎,它的特点主要在于出色的预聚合能力和高效的并发查询能力,它的大致架构如图:

65c50bdbc13060b70ed7db6e54209aa8.png

节点解析
Mater节点

Overlord:实时数据摄入消费控制器

Coordinator:协调集群上数据分片的发布和负载均衡
实时节点

MiddleManager:实时数据写入中间管理者,创建 Peon 节点进行数据消费任务并管理其生命周期

Peon:消费实时数据,打包并发布实时数据分片
存储节点Historical:存储数据分片

DeepStorage:分片中转存储,不对外查询

MetaDataStorage:元信息,如表结构

Zookeeper:存储实时任务和状态信息

   2.3 为什么查询会慢

查询慢的核心原因,经微信团队分析如下:

  • 协议数据分片存储的数据片段为 2-4h 的数据,每个 Peon 节点消费回来的数据会存储在一个独立分片。

  • 假设异常检测获取 7 * 24h 的数据,协议一共有 3 个 Peon 节点负责消费,数据分片量级为 12*3*7 = 252,意味着将会产生 252次 数据分片 I/O。

  • 在时间跨度较大时、MiddleManager、Historical 处理查询容易超时,Broker 内存消耗较高。

  • 部分协议维度字段非常复杂,维度排列组合极大 (>100w),在处理此类协议的查询时,性能就会很差。

03、优化方案设计

根据上面的分析,团队确定了初步的优化方向:

  • 减少单 Broker 的大跨度时间查询。

  • 减少 Druid 的 Segments I/O 次数。

  • 减少 Segments 的大小。

   3.1 拆分子查询请求

在这个方案中,每个查询都会被拆解为更细粒度的“子查询”请求。例如连续查询 7 天的时间序列,会被自动拆解为 7 个 1天的时间序列查询,分发到多个 Broker,此时可以利用多个 Broker 来进行并发查询,减少单个 Broker 的查询负载,提升整体性能。

30eae4b8e314a63a4f2308da3e586545.png

但是这个方案并没有解决 Segments I/O 过多的问题,所以需要在这里引入一层缓存。

   3.2 拆分子查询请求+Redis Cache

这个方案相较于 v1,增加了为每个子查询请求维护了一个结果缓存,存储在 Redis 中:

2eb261d9c8d6a579725a479b313b65dd.png

假设获取 7*24h 的数据,Peon 节点个数为 3,如果命中缓存,只会产生 3 次 Druid 的 Segments I/O (最近的 30min)数据,相较几百次 Segments I/O 会大幅减少。

接下来看下具体方法:

   3.2.1 时间序列子查询设计

针对时间序列的子查询,子查询按照「天」来分解,整个子查询的缓存也是按照天来聚合的。以一个查询为例:

{"biz_id": 1, // 查询协议表ID:1"formula": "avg_cost_time", // 查询公式:求平均"keys": [ // 查询条件:维度xxx_id=3{"field": "xxx_id", "relation": "eq", "value": "3"} ], "start_time": "2020-04-15 13:23", // 查询起始时间"end_time": "2020-04-17 12:00" // 查询结束时间
}

其中 biz_id、 formula,、keys 了每个查询的基本条件。但每个查询各不相同,不是这次讨论的重点。

本次优化的重点是基于查询时间范围的子查询分解,而对于时间序列子查询分解的方案则是按照「天」来分解,每个查询都会得到当天的全部数据,由业务逻辑层来进行合并。

举个例子,04-15 13:23 ~ 04-17 08:20 的查询,会被分解为 04-15、04-16、04-17 三个子查询,每个查询都会得到当天的全部数据,在业务逻辑层找到基于用户查询时间的偏移量,处理结果并返回给用户。

每个子查询都会先尝试获取缓存中的数据,此时有两种结果:

结果解析
缓存未命中

如果子查询结果在缓存中不存在,即 cache miss。只需要将调用 DruidBorker 获取数据,异步写入缓存中,同时该子查询缓存的修改的时间即可。

缓存命中

在谈论命中之前,首先引入一个概念「阈值时间(threshold_time)。它表示缓存更新前的一段时间(一般为10min)。我们默认缓存中的数据是不被信任的,因为可能因为数据积压等情况导致一部分数据延迟入库。

如果子查询命中了缓存,则存在两种情况:「缓存部分命中」和「缓存完全命中」。其中部分命中如下图所示。

  • 缓存部分被命中:

end_time > cache_update_time - threshold_time:这种情况说明了「缓存部分被命中」,从 cache_update_time-thresold_time 到 end_time 这段时间都不可信,这段不可信的数据需要从 DruidBroker 中查询,并且在获取到数据后异步回写缓存,更新 update 时间。

d733ec18bf335c932565e60cdac8f2d3.png

  • 缓存完全命中:

    而缓存完全命中则是种理想形式:end_time > cache_update_time - threshold_time。这种情况说明了缓存被完全命中,缓存中的数据都可以被相信,这种情况下直接拿出来就可以了。

91e3efad84ab355b03cb96dfb9b2b888.png

经过上述分析不难看出:对于距离现在超过一天的查询,只需要查询一次,之后就无需访问 DruidBroker 了,可以直接从缓存中获取。

而对于一些实时热数据,其实只是查询了cache_update_time-threshold_time 到 end_time 这一小段的时间。在实际应用里,这段查询时间的跨度基本上在 20min 内,而 15min 内的数据由 Druid 实时节点提供。

   3.2.2 维度组合子查询设计

维度枚举查询和时间序列查询不一样的是:每一分钟,每个维度的量都不一样。而维度枚举拿到的是各个维度组合在任意时间的总量,因此基于上述时间序列的缓存方法无法使用。在这里,核心思路依然是打散查询和缓存。对此,微信团队使用了如下方案:

缓存的设计采用了多级冗余模式,即每天的数据会根据不同时间粒度:天级、4小时级、1 小时级存多份,从而适应各种粒度的查询,也同时尽量减少和 Redis 的 IO 次数。

每个查询都会被分解为 N 个子查询,跨度不同时间,这个过程的粗略示意图如下:

97f4235c300a4f94063cb7553f0ef684.png

举个例子:例如 04-15 13:23 ~ 04-17 08:20 的查询,会被分解为以下 10 个子查询:

04-15 13:23 ~ 04-15 14:00

04-15 14:00 ~ 04-15 15:00

04-15 15:00 ~ 04-15 16:00

04-15 16:00 ~ 04-15 20:00

04-15 20:00 ~ 04-16 00:00

04-16 00:00 ~ 04-17 00:00

04-17 00:00 ~ 04-17 04:00

04-17 00:00 ~ 04-17 04:00

04-17 04:00 ~ 04-17 08:00

04-17 08:00 ~ 04-17 08:20

这里可以发现,查询 1 和查询 10,绝对不可能出现在缓存中。因此这两个查询一定会被转发到 Druid 去进行。2~9 查询,则是先尝试访问缓存。如果缓存中不存在,才会访问 DruidBroker,在完成一次访问后将数据异步回写到 Redis 中。

维度枚举查询和时间序列一样,同时也用了 update_time 作为数据可信度的保障。因为最细粒度为小时,在理想状况下一个时间跨越很长的请求,实际上访问 Druid 的最多只有跨越 2h 内的两个首尾部查询而已。

   3.3 更进一步-子维度表

通过子查询缓存方案,我们已经限制了 I/O 次数,并且保障 90% 的请求都来自于缓存。但是维度组合复杂的协议,即 Segments 过大的协议,仍然会消耗大量时间用于检索数据。

所以核心问题在于:能否进一步降低 Segments 大小?

维度爆炸问题在业界都没有很好的解决方案,大家要做的也只能是尽可能规避它,因此这里,团队在查询层实现了子维度表的拆分以尽可能解决这个问题,用空间换时间,具体做法为:

● 对于维度复杂的协议,抽离命中率高的低基数维度,建立子维度表,实时消费并入库数据。

● 查询层支持按照用户请求中的查询维度,匹配最小的子维度表。

a282c6e112ed8c9fd0a021e5a7df8ae1.png

04、 优化成果

   4.1 缓存命中率>85%

在做完所有改造后,最重要的一点便是缓存命中率。因为大部分的请求来自于1天前的历史数据,这为缓存命中率提供了保障:

  • 子查询缓存完全命中率(无需查询Druid):86%

  • 子查询缓存部分命中率(秩序查询增量数据):98.8%

最明显的效果就是,查询访问 Druid 的请求,下降到了原来的 10% 左右。

   4.2 查询耗时优化至 100ms

在整体优化过后,查询性能指标有了很大的提升:

平均耗时 1000+ms -> 140ms;P95:5000+ms -> 220ms。

999d164d29d11ef0565fcb4187c81c9a.png

5dda57bc7182f6964f5f3bc4d7bdd7ac.png

05、结语

微信多维指标监控平台 ,是微信监控平台的重要组成部分。在分析了用户数据查询行为之后,我们找到了数据查询慢的主要原因,通过减少单 Broker 的大跨度时间查询、减少 Druid 的 Segments I/O 次数、减少 Segments 的大小。我们实现了缓存命中率>85%、查询耗时优化至 100ms。当然,系统功能目前也或多或少尚有不足,在未来团队会继续探索前行,力求使其覆盖更多的场景,提供更好的服务。

以上是本次分享全部内容,欢迎大家在评论区分享交流。如果觉得内容有用,欢迎转发~

-End-

原创作者|仇弈彬

技术责编|仇弈彬

10af8d715563daa51ec4e7ed7dbf9860.png

你有哪些「性能优化」经历或经验分享?又或者想要了解更多微信其他的技术?都可以在腾讯云公众号评论区中留言。我们将选取1则最有创意的评论,送出腾讯云开发者-棒球帽1个(见下图)。6月7日中午12点开奖。

11eb4d61b7adb63c167c70c48598db7d.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/66856.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何处理百亿级别的数据信息

导读:本次分享将从以下几个方面进行分享,首先讲一下我们目前所做的工作,目前平台架构是怎么样的,第二个是大量日志情况下如何收集,第三个涉及百亿数据后如何快速存储以及快速查询,第四个讲一下数据存储后如…

数据总量 40 亿+,报表分析数据 10 亿+,TiDB 在中通的落地与进化

作者:luzizhuo 原文来源: https://tidb.net/blog/3da1aed9 本文根据中通快递数据智能部基础架构负责人朱友志在【PingCAP DevCon 2021】上的演讲整理而成。 视频回顾: https://www.bilibili.com/video/BV1f3411678v 讲义下载&#…

海量数据处理:在100亿个数中找出top 10000

经典的TOP K问题,借助堆排序进行 前两天面试3面学长问我的这个问题(想说TEG的3个面试学长都是好和蔼,希望能完成最后一面,各方面原因造成我无比想去鹅场的心已经按捺不住了),这个问题还是建立最小堆比较好…

数据特征分析

数据特征分析主要包括分布分析、对比分析、统计量分析、周期性分析、贡献度分析、相关性分析几种分析。 分布分析 分布分析的最终成果是形成能体现数据的图表 分布分析主要有两种类型:对定量数据的分布分析和对定性数据的分布分析 对定量数据的分布分析 要形成一个图表的话…

国货之光,处女座的福音!最详细华强北洛达1562M悦虎版二代蓝牙耳机评测

2016年,随着苹果发布初代AirPods,原来一直不愠不火的蓝牙耳机市场一时大热,“真无线蓝牙耳机”(简称TWS,True Wireless Stereo)开始走进人们的视野。随着各大手机厂商(奸商)取消手机上的3.5mm耳机插口,真无线蓝牙耳机加速普及,直至今天变成人们手中不可或缺的电子产品…

DayDayUp:计算机技术与软件专业技术资格证书之《系统集成项目管理工程师》软考考试简介及其知识点架构总结、课程讲解目录(立项-整体-范围-进度-成本-质量-人力资源-沟通-干系人-风险-采购等)

DayDayUp:计算机技术与软件专业技术资格证书之《系统集成项目管理工程师》软考考试简介及其知识点架构总结、课程讲解目录(立项-整体-范围-进度-成本-质量-人力资源-沟通-干系人-风险-采购等) 目录 术语简称简介 计算机软件资格考试【软考】的简介及其知识点架构总…

DL之RNN:基于RNN实现模仿贴吧留言

DL之RNN:基于RNN实现模仿贴吧留言 目录 输出结果 代码设计 输出结果 更新…… 代码设计 注:CPU上跑的较慢,建议GPU运行代码

CSDN:2020年度CSDN博客之星评选竞赛——180号【一个处女座的程序猿】,感谢您,投上的宝贵一票,感谢!感恩!

CSDN:2020年度CSDN博客之星评选竞赛——180号【一个处女座的程序猿】,感谢您,投上的宝贵一票,感谢!感恩! 导读:新的一年,改革春风吹满地,新的一年要争气! 博…

使用BottomNavigationView底部导航栏、添加数量角标提醒

度娘了一圈发现基本上都是TabLayout或者其他的导航栏添加角标,所以写这篇博客记录下来。 先来看下实现的效果图: 代码也是很简单的 BottomNavigationMenuView中的每一个Tab就是一个FrameLayout,所以我们可以在上面随意添加View、这样也就可以…

CSDN:2019年度CSDN博客之星评选竞赛——105号【一个处女座的程序猿】,感谢您,投上的宝贵一票,感谢!感恩!

CSDN:2019年度CSDN博客之星评选竞赛——105号【一个处女座的程序猿】,感谢您,投上的宝贵一票,感谢!感恩! 导读:新的一年,改革春风吹满地,新的一年要争气! 博…

DayDayUp:《复仇者联盟4:终局之战》娱乐闲谈——当灭霸碰上一个处女座的程序猿

DayDayUp:《复仇者联盟4:终局之战》娱乐之谈——当灭霸碰上一个处女座的程序猿 目录 《复联4》简介 《复联4》相关—片段 《复联4》相关—网友搞笑图片 《复联4》相关—娱乐闲谈 《复联4》简介 《复仇者联盟4:终局之战》(Aven…

嫁人当嫁处女男 - 解构处女座男人

2019独角兽企业重金招聘Python工程师标准>>> 解构处女座男人 想要对那位处女座的男人、善于吹毛求疵的分析大师示爱吗?嗯,在你开始诱惑这位处女男之前,你得先搞懂几件事。抛开偏见,本文将告诉你所有关于处女男的一切细节。 “偏见者的心灵,就像眼睛的瞳孔,你给…

DayDayUp:我是CSDN开发者生态联盟成员“一个处女座的程序猿”:渡己是一种能力,渡人是一种格局

DayDayUp:我是CSDN开发者生态联盟成员“一个处女座的程序猿”:渡己是一种能力,渡人是一种格局 目录 CSDN开发者生态联盟成员简介 个人2020年度工作总结 CSDN开发者生态联盟成员简介 问:请简单自我介绍(公司姓名职位…

CSDN TOP1“一个处女座的程序猿“如何通过写作成为百万粉丝博主

文章目录 如何通过写作成为百万粉丝博主 前言 一、什么内容是受欢迎的写作内容? 二、介绍一些经典的技术文章逻辑框架设计? 三、如何系统地输出技术内容? 四、技术创作给我带来的变化和成长 五、现场问题答疑(Q&A) 六、最后 如…

关于软件界面设计、控件颜色搭配、一些实用建议(偷懒技巧)总结——针对C# WinForm/WPF技术

之前的文章讲了很多控件包的用法,我们做C#WinForm工程师的,基本都是做上位机的,很多都是公司没有专门的设计团队,界面做成什么样,基本全凭自己审美。 但我们只是个程序员,又不懂设计,不可能在界…

装修到底要不要请设计师?

例如想把自己的家装修的漂亮一点,或者遇到了自己实在无法解决的装修问题,例如想划分出一些房间或者某些功能没有解决好。都可以找设计师 但如果是比较大型的空间,例如酒店或办公室,自己没有太多的想法来指导施工队,那么…

上海人设提示访问接口出错

我自己苹果手机,更新了系统导致CA证书没有了,“上海人设”App 业务经办打不开,提示访问接口出错,我试着卸载重装,然后重新领取CA证书,问题解决,希望可以帮助到大家。 也可以不用卸载重置&#x…

李彦宏15年前专利曝光 Google模仿百度?

8月9日晚间消息,位于弗吉尼亚州的美国专利局总部档案库的一角,存放着几页看似毫不起眼的纸张。但如果拿出去拍卖的话,这几页纸将价值连城。因为其上记载着的,或将是全球最值钱的技术专利之一,正是它,催生并…

8月20科技资讯|李彦宏内部信曝光;三大运营商否认 4G 降速;ThinkPHP 6.0 RC4 版本发布

「CSDN 极客头条」,是从 CSDN 网站延伸至官方微信公众号的特别栏目,专注于一天业界事报道。风里雨里,我们将每天为朋友们,播报最新鲜有料的新闻资讯,让所有技术人,时刻紧跟业界潮流。 「CSDN 极客头条」&a…

算力至上?AI芯片大对决

作者 | 老石谈芯的老石 来源 | 老石谈芯(ID:laoshi_tanxin) 头图 | CSDN 下载自东方IC 目前,全世界超过90%的数据都是在过去的两三年之内产生的。随着人工智能、自动驾驶、5G、云计算等各种技术的不断发展,海量数据都…