写点什么

无需扩容成本,百亿集群数据过期性能优化看这就行

  • 2021-07-15
  • 本文字数:3838 字

    阅读完需:约 13 分钟

无需扩容成本,百亿集群数据过期性能优化看这就行

某百亿级 mongodb 业务只保存近期 7 天的数据,由于数据量大、流量高,数据过期删除点比较集中,同时不能错峰方式解决问题,因此如何利用最小物理成本来满足业务需求就成为了本集群性能优化的难点。


通过几轮和业务配合调优,包括存储引擎调优、数据删除方式调优、业务错峰读写等,最终完美解决了业务痛点,达到 ms 级业务读写访问。

一、业务背景

线上某业务数据量约 100 亿,白天为写流量高峰期,峰值写约 14W/s,如下图所示:




业务每天白天生产数据,同时凌晨批量拉取过去几天数据做大数据分析,整个集群只保存最近七天数据。


单条数据约 800 字节,如下所示:


1.   {  2.        "_id" : ObjectId("608592008bd3dad61675b491"),  3.        "deviceSn" : "xxxxxxxxxxxxx",  4.        "itemType" : 0,  5.        "module" : "xxxxxx",  6.        "userId" : "xxxxx",  7.        "callTimes" : NumberLong(2),  8.        "capacityAdd" : NumberLong(0),  9.        "capacityDelete" : ”xxxxxxxx”,  10.        "capacityDownload" :”xxxxxxxxxxxx”,  11.        "capacityModify" : ”xxxxxxxxxxxx”,  12.        "createTime" : NumberLong("1619366400003"),  13.        "expireAt" : ISODate("2021-05-02T22:53:45.497Z"),  14.        "numAdd" : NumberLong(2),  15.        "numDelete" : NumberLong(345),  16.        "numDownload" : NumberLong(43),  17.        "numModify" : NumberLong(3),  18.        "osVersion" : "xxxx",  19.        "reversedUserId" : "xxxxx",  20.        "updateTime" : NumberLong("1619366402106")  
复制代码

二、mongodb 资源评估及部署架构

通过和业务对接梳理,该集群规模及业务需求总结如下:

  • 数据量百亿级

  • 单条数据 800 字节,100 亿条预计 7.5T 数据

  • 读写分离

所有数据只保留七天

2.1 mongodb 资源评估

分片数及存储节点套餐规格选定评估过程如下:


  • 内存评估

我司都是容器化部署,以以往经验来看,mongodb 对内存消耗不高,历史百亿级以上 mongodb 集群单个容器最大内存基本上都是 64Gb,因此内存规格确定为 64G。


  • 分片评估

 业务流量峰值 10W/s 多,预计需要 3 个分片支持读写。


  • 磁盘评估

100 亿数据 7.5T,由于 mongodb 默认有高压缩,预计真实磁盘占用 2.5~3T 左右。三个分片,一个分片刚好 1T。


  • CPU 规格评估

由于容器调度套餐化限制,因此 CPU 只能限定为 16CPU(实际上用不了这么多 CPU)。


  • mongos 代理及 config server 规格评估

此外,由于分片集群还有 mongos 代理和 config server 复制集,因此还需要评估 mongos 代理和 config server 节点规格。由于 config server 只主要存储路由相关元数据,因此对磁盘、CUP、MEM 消耗都很低;mongos 代理只做路由转发只消耗 CPU,因此对内存和磁盘消耗都不高。最终,为了最大化节省成本,我们决定让一个代理和一个 config server 复用同一个容器,容器规格如下:


8CPU/8G 内存/50G 磁盘,一个代理和一个 config server 节点复用同一个容器。


分片及存储节点规格总结:4 分片/16CPU、64G 内存、1T 磁盘。


mongos 及 config server 规格总结:8CPU/8G 内存/50G 磁盘


节点类型

单个节点容器规格

说明

shardServer存储节点

16CPU64G内存、1T磁盘

1个分片存储约30亿数据

3个分片预计存储100亿数据

mongosconfig server节点

8CPU/8G内存/50G磁盘

一个代理和一个config server节点复用同一个容器

2.2 集群部署架构

该业务数据不是很重要,为了节省成本,因此我们采用 2+1 模式部署,也就是:2mongod+1arbiter 模式,同城机房部署,部署架构图如下图所示:



考虑到数据重要性不高,通过 2mongod+1arbiter 模式即可满足用户要求,同时可以最大化节省成本。

三、性能优化过程

该集群优化过程按照如下两个步骤优化:业务使用集群前的性能优化、业务使用过程中的性能优化。


业务提前建好查询对应的最优索引,同时创建过期索引:



db.dailyCloudOperateInfo.createIndex( { "createTime": 1 }, { expireAfterSeconds: 604800} )
复制代码

3.1  业务使用集群前的性能优化

和业务沟通确定,业务每条数据都携带有一个设备标识 userId,同时业务查询更新等都是根据 userId 维度查询该设备下面的单条或者一批数据,因此片建选择 userId。


  • 分片方式

为了充分散列数据到 3 个分片,因此选择 hash 分片方式,这样数据可以最大化散列,同时可以满足同一个 userId 数据落到同一个分片,保证查询效率。


  • 预分片

mongodb 如果分片片建为 hashed 分片,则可以提前做预分片,这样就可以保证数据写进来的时候比较均衡的写入多个分片。预分片的好处可以规避非预分片情况下的 chunk 迁移问题,最大化提升写入性能。



sh.shardCollection("cloud_track.dailyCloudOperateInfo", {userId:"hashed"}, false, { numInitialChunks: 8192} )
复制代码


  • 就近读

客户端增加 secondaryPreferred 配置,优先读从节点。


  • 禁用 enable Majority Read Concern

禁用该功能后 Read Concern majority 将会报错,Read Concern majority 功能注意是避免脏读,和业务沟通业务没该需求,因此可以直接关闭。


mongodb 默认使能了 enable Majority Read Concern,该功能开启对性能有一定影响,参考:


MongoDB readConcern 原理解析:

https://developer.aliyun.com/article/60553


OPPO 百万级高并发 MongoDB 集群性能数十倍提升优化实践:

https://mongoing.com/archives/29934


  • 存储引擎 cacheSize 规格选择

单个容器规格:16CPU、64G 内存、7T 磁盘,考虑到全量迁移过程中对内存压力,内存碎片等压力会比较大,为了避免 OOM,设置 cacheSize=42G。

3.2  业务使用过程中遇到的问题及性能优化

1)第一轮优化:存储引擎优化

业务高峰期主要是数据写入和更新,内存脏数据较多,当脏数据比例达到一定比例后用户读写请求对应线程将会阻塞,用户线程也会去淘汰内存中的脏数据 page,最终写性能下降明显。


wiredtiger 存储引擎 cache 淘汰策略相关的几个配置如下:



由于业务全量迁移数据是持续性的大流量写,而不是突发性的大流量写,因此 eviction_target、eviction_trigger、eviction_dirty_target、eviction_dirty_trigger 几个配置用处不大,这几个参数阀值只是在短时间突发流量情况下调整才有用。


但是,在持续性长时间大流量写的情况下,我们可以通过提高 wiredtiger 存储引擎后台线程数来解决脏数据比例过高引起的用户请求阻塞问题,淘汰脏数据的任务最终交由 evict 模块后台线程来完成。


全量大流量持续性写存储引擎优化如下:



db.adminCommand( { setParameter : 1, "wiredTigerEngineRuntimeConfig" : "eviction=(threads_min=4, threads_max=20)"})
复制代码

2)第一轮优化后存在的问题

经过存储引擎后台线程数的调优后,数据写入和更新瓶颈解决,写入和更新过程时延都很平滑。但是随着一周后开始数据过期,业务写开始大量抖动,如下所示:



从上图可以看出平均时延极端情况下甚至达到了几百 ms,这是业务完全接受不了的。通过 mongostat 监控发现如下现象:


  • 主节点 mongostat 监控统计



从上面的监控可以看出,三个分片的每个主节点只有 4000 左右的写更新操作(注意:实际上还有 4 万左右的 delete 操作,由于主节点过期 delete 不会统计,因此只能通过从节点查看,详见后面分析,实际单个分片主节点写和删除操作 4.4W/s),写流量很低。但是,监控中的脏数据比例持续性的超过 20%,超过 20%后业务的请求就需要进行脏数据淘汰,最终造成业务请求阻塞抖动。


通过前面的分析可以看出,业务正常峰值写入 3 个分片差不多 10W/s。一星期后,七天前的数据需要过期,这时候过期删除的 ops 也需要 delete 删除 10w/S,由于这时候新数据同样按照 10w/s 写入,因此集群就需要支持 20w/s 的 ops 操作才能支持。


显然,3 个分片支持不了持续性的 20w/s 左右的 ops 操作,因此如何不扩容情况下支撑业务需求将是一大难点。


  • 为何 ttl 过期主节点没用 delete 统计



上图为 mongodb 单机模块架构图,主节点默认启用一个 TTLMonitor 线程,借助查询引起模块实时扫描过期索引,然后把满足条件的数据删除。整个删除过程没有走 command 命令处理模块,而命令计数操作只会在 command 模块计数,因此主节点的过期删除不会有 delete 操作。


命令处理模块处理流程及其计数统计详见:

mongodb 内核源码模块化设计与实现专栏


更多 mongodb 模块化源码设计实现详见:

https://github.com/y123456yz/reading-and-annotate-mongodb-3.6

3.3  第二轮优化(过期删除放凌晨低峰期)-不可行

从前面的分析可以看出,我们三个分片支撑不了持续性 20W/S 的更新和删除操作,因此我们考虑业务改造使用方式,把过期删除确定到凌晨低峰期。


但是业务上线后出现其他的问题,由于业务凌晨会持续性的批量拉取分析过去几天的数据,如果过期和批量读数据叠加到一起,严重影响业务查询效率。最终,该方案不可行,如果不扩容,则需要其他方案。

3.4  第三轮方案优化(天维度建表,过期删表)

为了不增加成本,同时 3 个分片又支撑不了 20W/s 的读写删除等导致,为了尽量通过 3 个分片不扩容条件下来满足用户需求,因此转变方式,通过删表的方式来避免过期,具体实现如下:


  • 业务改造代码,以天为单位建表,每天的数据存到对应的表中。

  • 建表后业务启用预分片功能,确保数据均衡分布到三个分片。

  • 业务保存 8 天数据,第九天凌晨删除第一天的表


    该方案业务时延统计对应收益如下:




如上图所示,通过过期方式的优化,最终问题彻底解决,并且读写时延控制在 0.5ms-2ms。

四、优化收益总结

通过前面的一系列优化,最终没有扩容,并且解决了业务过期和大量数据写入更新引起的时延抖动问题,总体收益如下:


  • 改造优化前时延:经常几百 ms 抖动

  • 改造优化后时延:0.5-2ms


作者介绍

杨亚洲,前滴滴出行专家工程师,现任 OPPO 文档数据库 mongodb 负责人,负责数万亿级数据量文档数据库 mongodb 内核研发、性能优化及运维工作,一直专注于分布式缓存、高性能服务端、数据库、中间件等相关研发。


本文转载自:dbaplus 社群(ID:dbaplus)

原文链接:无需扩容成本,百亿集群数据过期性能优化看这就行!


2021-07-15 13:001365

评论

发布
暂无评论
发现更多内容

零基础如何参加大数据培训

小谷哥

零基础学习java培训是否适合参加

小谷哥

从云计算到函数计算

Serverless Devs

云计算 阿里云 AWS

软件测试 | 测试开发 | 构建测试平台与对应的组织架构需要哪些能力?

测吧(北京)科技有限公司

测试

计算机网络体概念

StackOverflow

编程 计算机网络 9月月更

Dubbo 3 StateRouter:下一代微服务高效流量路由

阿里巴巴中间件

阿里云 开源 微服务 dubbo 中间件

Substrate技术及生态8月大事记 | 波卡发布新版本,XCM协议更新

One Block Community

区块链 技术 开发者 Substrate 更新

首次公开到知乎爆火!基于SpringCloud+SpringBoot+Vue电子版项目实战教程,附完整源码

退休的汤姆

Java spring 程序员 面试题 阿里

分布式团队的高效站立会说明书 | Liga译文

LigaAI

高效工作 敏捷开发 开发团队 每日站会 企业号九月金秋榜

千锋锋友学盟分享会:程序员百万年薪进阶指

千锋IT教育

LeetCode-58. 最后一个单词的长度(java)

bug菌

Leet Code 每日一题 9月月更

在线数据迁移,数字化时代的必修课 —— 京东云数据迁移实践

京东科技开发者

数据 数据迁移 上云 redis'

DevOps 团队如何防御 API 攻击

SEAL安全

DevOps DevSecOps 软件供应链安全

游戏技术加速数实融合,网易伏羲挖掘机器人首次曝光

网易伏羲

人工智能 机器学习 工程实践

在java培训中心怎样才能快速学习?

小谷哥

Apache DolphinScheduler PMC:开源不一定也要九死一生

白鲸开源

海豚调度 开源社区 Apache DolphinScheduler 开源文化 #开源

51单片机定时器原理及相关器件

孤衫

C语言 单片机 9月月更

从零教你使用MindStudio进行Pytorch离线推理全流程

华为云开发者联盟

Python 人工智能 企业号九月金秋榜

软件测试 | 测试开发 | 测试开发基础 mvn test | 利用 Maven Surefire Plugin 做测试用例基础执行管理

测吧(北京)科技有限公司

maven

解锁云原生新场景 | 云原生加速云边端一体化发展

York

容器 云原生 边缘计算 边云协同 边缘云原生

软件测试 | 测试开发 | 持续交付-Blue Ocean 应用

测吧(北京)科技有限公司

二本4年Java经验,五面阿里(定薪45K)

退休的汤姆

Java 程序员 阿里 面经 秋招

学员参加前端培训哪里比较靠谱?

小谷哥

利用GCC插件实现代码分析和安全审计

科技怪咖

音视频开发进阶|第六讲:色彩和色彩空间·上篇

ZEGO即构

音视频开发 色彩 色彩空间

技术分享| 基于RTM 实现的呼叫邀请如何添加推送功能?

anyRTC开发者

音视频 IM 实时消息 呼叫邀请 推送

大数据培训前景怎么样

小谷哥

基于阿里云Serverless函数计算开发的疫情数据统计推送机器人

Serverless Devs

LeetCode-66. 加一(java)

bug菌

Leet Code 每日一题 9月月更

阿里灵杰融合智能算力,全栈AI服务为探索者铺路

阿里云大数据AI技术

人工智能 大数据 企业号九月金秋榜

设计模式的艺术 第十七章命令设计模式练习(开发一个基于Windows平台的公告板系统。该系统提供了一个主菜单(Menu),主菜单包含一些菜单项,Menu类可以增加菜单项。菜单项主要方法是click(),每个菜单项包含一个抽象命令类)

代廉洁

设计模式的艺术

无需扩容成本,百亿集群数据过期性能优化看这就行_大数据_dbaplus社群_InfoQ精选文章