记某核心MongoDB集群索引优化实践

本文记录了针对某核心MongoDB集群的索引优化过程,通过六轮优化,包括删除无用、重复和非最优索引,最终将索引数量从30个减少到8个,显著提升了性能,节省了90%以上的CPU资源和85%的磁盘IO资源,降低了20%的存储成本。优化策略包括分析查询模型、删除低效索引、创建最优索引等。
摘要由CSDN通过智能技术生成

腾讯云数据库MongoDB天然支持高可用、分布式、高性能、高压缩、schema free、完善的客户端访问均衡策略等功能。云上某重点用户基于MongoDB这些优势,选用MongoDB作为主存储服务,该用户业务场景如下:

· 存储电商业务核心数据

· 查询条件多变、查询不固定,查询较复杂,查询组合众多

· 对性能要求较高

· 对存储成本有要求

· 流量占比:insert较少、update较多、find较多、峰值流量较高

· 高峰期读写流量数千/秒

通过和业务沟通,了解业务使用场景和业务述求后,通过一系列的索引优化,最终完美解决读写性能瓶颈问题。本文重点分析该核心业务索引优化过程,通过本文可以学习到以下知识点:

· 如何确定无用索引?

· 如何确定重复索引?

· 如何创建最优索引?

· 对索引的一些错误认识?

· 索引优化收益(节省90%以上CPU资源、85%磁盘IO资源、20%存储成本)

问题分析过程

收到用户集群性能瓶颈反馈后,通过集群监控信息及服务器监控信息可以看出集群存在如下现象:

· Mongod节点CPU消耗过高,CPU时不时消耗接近90%,甚至100%

· 磁盘IO消耗过高,单节点IO资源消耗占整服务器60%

· 大量慢日志(主要集中在find和update),高峰期每秒数千条慢日志

· 慢日志类型各不相同,查询条件众多

· 所有慢查询都有匹配到索引

登录服务器对应节点后台,获取慢日志信息,发现mongod.log中包含大量不同类型find和update的慢日志,慢日志都有走索引,任意提取一条慢日志其内容如下:

Mon Aug  2 10:34:24.928 I COMMAND  [conn10480929] command xxx.xxx command: find { find: "xxx", filter: { $and: [ { alxxxId: "xxx" }, { state: 0 }, { itemTagList: { $in: [ xx ] } }, { persxxal: 0 } ] }, limit: 3, maxTimeMS: 10000 } planSummary: IXSCAN { alxxxId: 1.0, itemTagList: 1.0 } keysExamined:1650 docsExamined:1650 hasSortStage:0 cursorExhausted:1 keyUpdates:0 writeConflicts:0 numYields:15 nreturned:3 reslen:8129 locks:{ Global: { acquireCount: { r: 32 } }, Database: { acquireCount: { r: 16 } }, Collection: { acquireCount: { r: 16 } } } protocol:op_command 227ms   Mon Aug  2 10:34:22.965 I COMMAND  [conn10301893] command xx.txxx command: find { find: "txxitem", filter: { $and: [ { itxxxId: "xxxx" }, { state: 0 }, { itemTagList: { $in: [ xxx ] } }, { persxxal: 0 } ] }, limit: 3, maxTimeMS: 10000 } planSummary: IXSCAN { alxxxId: 1.0, itemTagList: 1.0 } keysExamined:1498 docsExamined:1498 hasSortStage:0 cursorExhausted:1 keyUpdates:0 writeConflicts:0 numYields:12 nreturned:3 reslen:8039 locks:{ Global: { acquireCount: { r: 26 } }, Database: { acquireCount: { r: 13 } }, Collection: { acquireCount: { r: 13 } } } protocol:op_command 158ms  

从上面的日志打印可以看出,查询都有走 { alxxxId: 1.0, itemTagList: 1.0 } 索引,走该索引扫描的keysExamined为1498行,扫描的docsExamined为1498行,但是返回的doc文档数却只有nreturned=3行。

通过上面的日志核心信息可以看出,满足条件的数据只有3条,但是却扫描了1498行数据和索引,说明查询有走索引,但是不是最优所有。

获取用户SQL查询模型及已有索引信息

上面的分析可以确定问题出现在索引不是最优,大量查询找了很多无用数据。

3.1. 和用户接触,了解用户SQL模型

通过和用户沟通,收集到用户查询、更新主要涉及以下SQL类型:

· 常用查询、更新类SQL

基于AlxxxId(用户ID)+itxxxId(单个或多个)  基于AlxxxId查询count  基于AlxxxId通过时间范围(createTime)进行分页查询,部分查询会拼接state及其他字段基于AlxxxId,ParentAlxxxId,parentItxxxId,state组合查询  基于ItxxxId(单个或多个)查询数据  基于AlxxxId, state, updateTime组合查询  基于AlxxxId, state,createTime, totalStock(库存数量)组合查询  基于AlxxxId(用户ID)+itxxxId(单个或多个)+任意其他字段组合  基于AlxxxId, digitalxxxrmarkId(水印ID), state进行查询基于AlxxxId, itemTagList(标签ID),state等进行查询基于AlxxxId+itxxxId(单个或多个) +其他任意字段进行查询其他查询

· 统计类count查询SQL​​​​​​​

AlxxxId,state, persxxal 组合  AlxxxId, state,itemType 组合  AlxxxId(用户ID)+itxxxId(单个或多个)+任意其他字段组合

3.2. 获取集群已有索引

通过db.xxx.getindex({})获取到该表的索引信息如下,总计30个索引:​​​​​​​

{ "alxxxId" : 1, "state" : -1, "updateTime" : -1, "itxxxId" : -1, "persxxal" : 1, "srcItxxxId" : -1 }          { "alxxxId" : 1, "image" : 1 }                                                             { "itexxxList.vidxxCheck" : 1, "itemType" : 1, "state" : 1 }                                              { "alxxxId" : 1, "state" : -1, "newsendTime" : -1, "itxxxId" : 1, "persxxal" : 1 }                           { "_id" : 1 }                                                                              { "alxxxId" : 1, "createTime" : -1, "checkStatus" : 1 }                                                      { "
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值