您的位置  > 互联网

(干货)微信海量数据查询如何从降到100ms?

本文由微信技术团队邱一斌分享。 原标题是《如何将微信海量数据的查询时间降低到100ms?》。 即时通讯网修改了内容,优化了布局。

1 简介

微信多维度指标监控平台具备自定义维度和指标监控能力,主要服务于用户自定义监控。 作为框架级监控的补充,聚合前承载的数据量为45亿/分钟、4万亿/天。

目前,数据层的查询请求峰值已达到40万/分钟、3亿/天。 大查询请求导致数据查询遇到性能瓶颈:平均查询时间 > ,失败率居高不下。

针对大数据量带来的查询性能问题,微信团队对数据层查询接口进行了针对性优化,将平均查询速度从+优化到了100ms。 本文与您分享优化过程,希望对您有用!

2. 技术背景

微信多维度指标监测平台(以下简称多维度监测)是一个数据上报方式灵活、跨维度分析的实时监测平台。

这里,核心概念是“协议”、“维度”和“指标”。

例如:想要监控某个【省份】、【城市】、【运营商】界面的【错误码】,监控目标是统计【平均耗时】和【报告数量】界面的。 这里,省份、城市、运营商、错误码,这些描述监控目标属性的可枚举字段被称为“维度”,【上报量】、【平均耗时】等数据依赖于“聚合计算”的结果” 该值称为“指标”。 承载这些指标和维度的数据表称为“协议”。

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

1)维度枚举查询:用于查询某一时间段内一个或多个维度及其对应指标值的排列组合。 它体现了各个维度分布的“总量”的概念,可以“聚合”,也可以“扩展”,也可以将某个固定维度“下钻”到其他维度。 数据可以直接生成条形图、饼图等。

2)时间序列查询:用于查询一定时间范围内某些维度条件的指标值序列。 可以显示为时间序列图,横坐标为时间,纵坐标为指标值。

但无论是用户还是团队本身在使用多维监控平台时,都能感受到明显的滞后。 主要表现是查看监控图像或查看监控曲线会需要很长的时间来加载数据。

团队意识到这是数据量增加带来的不可避免的瓶颈。

目前:多维度监控平台已接入上千张协议表,每张协议表各具特色。 维度、指标量和报告量的组合也不同。 对于大量数据的实时聚合和OLAP分析,数据层的性能瓶颈日益明显,严重影响用户体验。

所以这让团队成员开始思考:我们是否应该让它一直慢下来? 答案当然是否定的。 因此,微信团队对数据层的查询进行了优化。

3.优化分析1:用户查询行为分析

要进行优化,首先需要了解用户的查询习惯。 这里的用户包括页面用户和异常检测服务。

因此,微信团队尽可能多地汇报了用户使用多维度监控平台的习惯,包括但不限于:常用的查询类型、各协议表的查询维度和查询指标、查询量、失败量、时间-消耗数据等

通过分析用户的查询习惯,我们得出以下结论:

1)时间序列查询占比99%以上:

这种差异可能是由于每个感兴趣的维度都可以通过调用维度枚举一次来获得。

但对于每一个维度组合值,无论是页面还是异常检测,都会处于查询维度对应的多条时序曲线中,因此“时序查询”的占比远高于“维度枚举查询” ”。

2) 大约 90% 的查询来自 1 天前:

出现这种现象的原因是每页数据都会与前几天的数据进行比较显示。 异常检测模块每次都会比较大约7天数据的曲线,导致查询大量的非实时数据。

4.优化分析2:数据层架构

分析完用户习惯,我们再来看看目前的数据层架构。

多维监控底层数据存储/查询引擎选择Druid作为数据聚合和存储引擎。 Druid是一个非常优秀的分布式OLAP数据存储引擎。 其主要特点是优秀的预聚合能力和高效的并发查询能力。 。

其总体结构如下:

具体解释是:

5.优化分析3:查询为什么慢?

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

1)协议数据分片存储的数据分片为2-4h的数据,每个Peon节点消费的数据会存储在独立的分片中。

2)假设异常检测获取7*24h数据,协议共有3个Peon节点负责消费,数据分片级别为12*3*7 = 252,也就是说会产生252个数据分片I/O生成的。

3)当时间跨度较大时,查询处理容易超时,内存消耗较高。

4)某些协议维度字段非常复杂,维度排列组合极大(>100万)。 当处理此类协议的查询时,性能会很差。

6.优化实践一:拆分子查询请求

基于以上分析,团队初步确定优化方向:

在这种情况下,每个查询都被分解为更细粒度的“子查询”请求。 例如,7天时间序列的连续查询将自动分解为7个1天时间序列查询并分发到多个查询。 这时可以使用多个查询来进行并发查询,减少单次查询负载,提高整体性能。

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

7.优化实践2:拆分子查询请求+Redis缓存

7.1 概述

与v1相比,该方案为每个子查询请求维护一个结果缓存,并将其存储在Redis中(如下图所示)。

假设获取7*24h的数据,Peon节点数为3,如果命中缓存,只会产生3条Druid I/O数据(最近30分钟),相比数百条I/O数据会明显减少/Os。

我们来看看具体的方法。

7.2 时间序列子查询设计

对于时间序列的子查询,子查询是按照“天”来分解的,整个子查询的缓存也是按照天来聚合的。

以查询为例:

{
    "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" // 查询结束时间
}

其中,、、键代表每个查询的基本条件。 但每个查询都是不同的,不是本次讨论的重点。

本次优化的重点是基于查询时间范围的子查询分解。 时间序列子查询分解的解决办法是按照“日”进行分解。 每个查询都会获取当天的所有数据,这些数据会被业务逻辑层合并。 。

例如:从04-15 13:23到04-17 08:20的查询将被分解为三个子查询:04-15、04-16和04-17。 每次查询都会获取当天的所有数据。 业务逻辑层根据用户的查询时间找到偏移量,处理结果并返回给用户。

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

经过上面的分析,我们不难看出:对于距离现在一天以上的查询,只需要查询一次,之后就不需要访问了,直接从缓存。

对于一些实时热点数据,实际上只是短时间的查询。 实际应用中,查询时间跨度基本在20分钟以内,15分钟内的数据由Druid实时节点提供。

7.3 维度组合子查询设计

维度枚举查询和时间序列查询的区别在于,每分钟每个维度的数量都不一样。

维度枚举获取任意时刻各个维度组合的总量,因此无法使用基于上述时间序列的缓存方法。 这里,核心思想仍然是把查询和缓存打散。

对此,微信团队采用了以下解决方案。

缓存设计采用多级冗余模式,即每天的数据会按照不同的时间粒度进行多副本存储:日级、4小时级、1小时级,从而适应各种粒度的查询,同时尽量减少与Redis的交互。 IO 次。

每个查询将被分解为N个子查询,跨越不同的时间。 这个过程的粗略图如下:

例如: 例如,从 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,首先尝试访问缓存。 如果缓存中不存在,则会访问它。 完成一次访问后,数据会异步写回Redis。

维度枚举查询与时间序列相同,也是作为数据可信度的保证。 因为最精细的粒度是小时,所以在理想情况下,跨越很长时间的请求实际上只会访问 Druid 最多两个跨越 2 小时的第一个和最后一个查询。

8.优化实践3:更进一步(子维度表)

通过子查询缓存方案,我们限制了I/O数量,保证90%的请求来自缓存。 然而,具有复杂维度组合的协议,即太大的协议,仍然会消耗大量的时间来检索数据。

那么核心问题是:尺寸能否进一步缩小?

对于维度爆炸问题,业界目前还没有很好的解决方案。 我们能做的就是尽可能避免它。 因此,这里团队在查询层实现了分维表的拆分来尽可能解决这个问题,用空间来改变时间。

具体步骤是:

9. 优化结果

9.1 缓存命中率>85%

说了这么多修改之后,最重要的一点就是缓存命中率。 由于大部分请求来自于一天前的历史数据,这为缓存命中率提供了保证。

具体是:

9.2 查询耗时优化至100ms

整体优化后,查询性能指标得到了大幅提升:

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

10.相关文章

[1] 基于时间序列的海量数据冷热分层架构微信后台设计实践

[2] IM开发基础知识补修课(三):快速理解服务器端数据库读写分离原理及实用建议

[3]社交软件红包技术解密(六):微信红包系统存储层架构演进实践

[4]微信后台基于时间序列的新一代海量数据存储架构设计实践

[5]陌陌技术分享:陌陌IM在后端KV缓存架构的技术实践

[6]现代IM系统中聊天消息的同步和存储方案探讨

[7]微信海量用户背后的后端系统存储架构(视频+PPT)【附件下载】

[8]腾讯TEG团队原创:分享基于MySQL的分布式数据库TDSQL十年锻造经验

[9] IM全文检索技术专题(四):微信iOS上最新全文检索技术优化实践

[10]微信IM消息数据库优化实践:查询慢、体积大、文件损坏等。

[11]微信技术分享:揭秘微信后端安全特性数据仓库的架构设计

[12]现代IM系统中聊天消息的同步和存储方案探讨

11.微信团队其他文章

《微信安装包“减肥”实战记录》

《iOS微信安装包“减肥”实战记录》

《移动IM实践:iOS微信界面卡顿监控解决方案》

《微信“红包照片”背后的技术难点》

《IPv6技术详解:基本概念、应用现状与技术实践(上)》

《微信技术分享:微信海量IM聊天消息序列号生成实践(算法原理)》

《微信团队分享:逐渐被认可,微信的技术尝鲜之旅》

《社交软件红包技术解密(二):解密微信摇红包从0到1的技术演进》

《社交软件红包技术解密(十一):微信红包随机算法解密(含代码实现)》

《QQ设计团队分享:新版本背后的功能设计思路.0语音消息改版》

《微信团队分享:极致优化,iOS版微信编译速度提升3倍实用总结》

《IM的“扫一扫”功能好用吗?看一下微信“扫一扫识别物体”的完整技术实现

《微信团队分享:微信支付代码重构带来的移动软件架构思考》

《IM开发指南:史上最全的微信各种功能参数和逻辑规则资料大全》

《微信团队分享:单间1500万在线用户的微信直播间消息架构演进》

《企业微信IM架构设计揭秘:消息模型、千人千面、已读回执、消息撤销等》

《微信团队分享:微信后端如何在海量并发请求下不崩溃》

《IM跨平台技术学习(九):全面解密新QQ桌面版内存优化实践》

《百万级组织架构的企业微信客户端性能优化实践》

《揭秘企业微信如何支撑超大规模IM组织架构——四维关系链技术解读》

《微信团队分享:iOS微信视频号直播帧率异常导致耗电问题详解》