MongoDB 索引操作引起的 Crash

news2025/2/10 7:40:38

摘要:本文详细阐述了根据引起 Crash 操作进行从配置到源码的分析过程,层层递进,定位复现并给出解决故障方案。

作者:徐耀荣

爱可生南区交付服务部 DBA 团队成员,主要负责 MySQL 故障处理以及相关技术支持。爱好电影,旅游。

本文来源:原创投稿

  • 爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源。

故障现象

近日,朋友遇到一个 MongoDB 实例 Crash 的问题,找到我帮忙一起分析原因,事情经过以及分析过程如下,可供学习。

操作过程

运维人员在优化慢查询时针对性创建了一个索引,语句如下:

db.c1.createIndex('name':1,background:true)

随后又将表上一个没能用上的索引删除,语句如下:

db.c1.dropIndex('idx_age')

在主节点上很顺利的就完成了,但是不久后就发现从节点发生了 Crash,日志中包含下列崩溃信息。

2023-04-13T07:00:50.752+0000 E STORAGE  [conn3569849] WiredTiger error (-31802) [1681369250:752455][9937:0x7fe740144700], WT_CONNECTION.open_session: __open_session, 2058: out of sessions, configured for 20030 (including internal sessions): WT_ERROR: non-specific WiredTiger error Raw: [1681369250:752455][9937:0x7fe740144700], WT_CONNECTION.open_session: __open_session, 2058: out of sessions, configured for 20030 (including internal sessions): WT_ERROR: non-specific WiredTiger error
2023-04-13T07:00:50.752+0000 I NETWORK  [listener] connection accepted from xxx.xxx.xxx.xxx #3570023 (20576 connections now open)
2023-04-13T07:00:50.753+0000 F -        [conn3569849] Invariant failure: conn->open_session(conn, NULL, "isolation=snapshot", &_session) resulted in status UnknownError: -31802: WT_ERROR: non-specific WiredTiger error at src/mongo/db/storage/wiredtiger/wiredtiger_session_cache.cpp 111

其它信息

  • 变更表是一张几千万的大表;
  • 数据库架构为 MongoDB 4.0.14 的 PSA 架构;
  • 应用开启了读写分离,从节点也存在大量只读请求。

问题分析

根据日志信息,初步怀疑是连接打满了,检查最大连接数配置。

初步排查

shard1:PRIMARY> db.serverStatus().connections;
{ "current" : 7, "available" : 29993, "totalCreated" : 7, "active" : 2 }

最大连接数是由 maxIncomingConnections 参数和 ulimit 决定的。

net:
  maxIncomingConnections: 30000

在测试环境模拟连接数打满的情况,发现在连接数满了的情况下实例只会拒绝新的连接,而非直接 Crash。

connecting to: mongodb://10.186.64.88:27017/admin?gssapiServiceName=mongodb
2023-04-19T13:59:26.578+0000 I NETWORK  [js] DBClientConnection failed to receive message from 10.186.64.88:27017 - HostUnreachable: Connection closed by peer
2023-04-19T13:59:26.579+0000 E QUERY    [js] Error: network error while attempting to run command 'isMaster' on host '10.186.64.88:27017'  :
connect@src/mongo/shell/mongo.js:344:17
@(connect):2:6
exception: connect failed

根据 SERVER-30462 描述怀疑是 WT_SESSION 打满的情况。

WT_SESSION 是 MongoDB Server 和 WiredTiger 存储引擎内部交互使用的会话,几乎所有操作都是在 WT_SESSION 的上下文中执行的。因此 WT_SESSION 在超过限制后将会触发较为严重的情况。

源码分析

在源码 mongo/wiredtiger_kv_engine.cpp 中可以看到 WT_SESSION 硬编码指定为 20000。

std::stringstream ss;
    ss << "create,";
    ss << "cache_size=" << cacheSizeMB << "M,";
    ss << "cache_overflow=(file_max=" << maxCacheOverflowFileSizeMB << "M),";
    ss << "session_max=20000,";
    ss << "eviction=(threads_min=4,threads_max=4),";
    ss << "config_base=false,";
    ss << "statistics=(fast),";

这一点也能在启动日志中进一步得到验证。

如果 WT_SESSION 数量超过 20000,将会触发 out of sessions 的报错。

    /* Find the first inactive session slot. */
    for (session_ret = conn->sessions, i = 0; i < conn->session_size; ++session_ret, ++i)
        if (!session_ret->active)
            break;
    if (i == conn->session_size)
        WT_ERR_MSG(session, WT_ERROR, "out of sessions, configured for %" PRIu32
                                      " (including "
                                      "internal sessions)",
          conn->session_size);

提出疑问

分析到这开始疑惑 WT_SESSION 打满与索引操作存在什么样的关系?为什么相同的操作在主节点可以正常完成,而从节点会发生 Crash?

在创建索引时指定 background:true 可以在后台构建索引,不会加锁阻塞集合上的其它操作,这也是我们日常添加索引常用的方式。

但在删除索引时,我们有一点需要注意,但又常常被忽略,在主节点删除索引后同步到从节点回放时,如果从节点正在跑同一个集合上后台创建索引的操作,那么删除索引的操作将会被阻塞,更严重的是这时候实例上所有 namespace 的访问都将会被阻塞。针对这一现象在官网 dropIndex 文档中有提及:

Avoid dropping an index on a collection while any index is being replicated on a secondary. If you attempt to drop an index from a collection on a primary while the collection has a background index building on a secondary, reads will be halted across all namespaces and replication will halt until the background index build completes.

当任何创建索引操作复制到 Secondary 时,应避免在集合上删除索引。如果你试图在 Primary 上删除一个索引,而该集合在 Secondary 上有一个索引正在后台创建,那么所有 namespace 的访问将被停止,复制也会停止,直到后台索引建立完成。

回到错误日志中查找更多内容,就能发现从节点在后台创建索引时,又执行了同一个集合上的删除索引操作。

2023-04-13T05:34:27.002+0000 I - [repl index builder 178] Index Build (background): 122873800/640018757 19% 
2023-04-13T05:34:30.002+0000 I - [repl index builder 178] Index Build (background): 122976300/640018769 19% 
2023-04-13T05:34:30.434+0000 I COMMAND [repl writer worker 11] CMD: dropIndexes test.c1

初步结论

到此,我们得出初步结论。事情起因是主节点在同一个集合上执行创建索引和删除索引后,在从节点回放时出现了很严重的阻塞,大量的只读请求开始不断积压,最后导致 WT_SESSION 消耗殆尽,Server 无法与 WiredTiger 进行内部通信,最终导致实例 Crash。

问题复现

下面的案例在测试环境复现 WT_SESSION 超过限制的情况,dropIndex 导致从节点锁阻塞的问题有兴趣可自己测试复现,这里就不做演示了。

WT_SESSION 上限是由 wiredtiger_open 配置中的 session_max 决定的,但 MongoDB 并未直接暴露 session_max的 配置方式,只能通过下列方式进行覆盖设置。

mongod -f /etc/mongod.conf --wiredTigerEngineConfigString="session_max=5"

然后在数据库内部发起一个全局排它锁。

mongo> db.fsyncLock()

编写下列 Python 脚本模拟并发线程。

#!/usr/bin/python
# -*- coding: UTF-8 -*-
import multiprocessing
import pymongo

def find():
    cnx_args = dict(username='root', password='abcd123#', host='127.0.0.1', port=27018, authSource='admin')
    client=pymongo.MongoClient(**cnx_args)
    db=client['test']
    results=db.tab100.insert_one({"name":"jack"})
if __name__ == "__main__":
    x=1
    while x<350:
        p=multiprocessing.Process(target=find)
        p.start()
        print("start thread:",x)
        x+=1
    p.join()

这时 MongoDB 实例还在正常运行,因为我们的请求还没有真正的进入到 WiredTiger 引擎层,但一旦我们手动释放排它锁,所有请求都会在短时间内进入 WiredTiger 引擎,WT_SESSION 瞬间超过限制,实例紧接着发生 Crash。

mongo> db.fsyncUnlock()

错误日志如下,与生产日志相同。

总结

  1. net.maxIncomingConnections 设置应小于 WT_SESSION;
  2. 可以根据实际需求调整游标超时时间,避免出现大面积积压的情况;
  3. 避免创建索引和删除索引先后执行,特别是先执行后台创建索引的情况下;
  4. 4.2 版本中废弃了 background 选项,对索引创建过程进行了优化,只会在索引创建的开始和结束时持有 exclusive lock;并且 4.0 版本官方已经停止提供服务了,建议尽快升级。

本文关键字:#MongoDB# #WiredTiger# #源码#

关于 SQLE

爱可生开源社区的 SQLE 是一款面向数据库使用者和管理者,支持多场景审核,支持标准化上线流程,原生支持 MySQL 审核且数据库类型可扩展的 SQL 审核工具。

SQLE 获取

类型地址
版本库https://github.com/actiontech/sqle
文档https://actiontech.github.io/sqle-docs/
发布信息https://github.com/actiontech/sqle/releases
数据审核插件开发文档https://actiontech.github.io/sqle-docs-cn/3.modules/3.7_auditplugin/auditplugin_development.html

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

c++学习之多态

目录 1&#xff0c;什么是多态&#xff1f; 2&#xff0c;什么是虚函数&#xff1f; 1.如何实现父类对各个派生子类的操作&#xff1f; 2&#xff0c;父类指针保存子类空间产生的问题。 3&#xff0c;虚函数的定义 4&#xff0c;虚函数的动态绑定机制 5&#xff0c;重载&…

创新方案|时尚品牌企业应用生成式AI的6大机会领域

探讨生成式人工智能&#xff08;Generative AI&#xff09;在时尚产业中的应用&#xff0c;以及它对设计、生产和销售过程的影响。通过使用生成式AI技术&#xff0c;时尚品牌可以更快地设计和生产出更加个性化和符合潮流趋势的产品&#xff0c;同时减少浪费和成本。文章还介绍了…

掌握Python文件操作:从基础到高阶的全方位探索

在本篇博客中&#xff0c;我们将全面、深入地探讨Python中的文件操作。文件操作在Python编程中是不可或缺的一部分&#xff0c;它包含了打开、读取、写入和关闭文件等各种操作。我们将从基础的文件操作讲解到高级的文件处理技巧&#xff0c;以及如何优雅地使用Python进行文件操…

前端vue入门(纯代码)07

【07.TodoList案例】 1 拆分组件 一共拆分为4个组件&#xff1a;【因为header和HTML内置的标签<header>重名&#xff0c;故在之前都加了Todo】 TodoHeaderTodoItem【item是list的子组件】TodoListTodoFooter 2 组件化编码流程 实现静态组件&#xff1a;抽取组件&…

金融行业项目信息化建设方案:人效提升300%

一、行业背景 在大数据、云计算、人工智能等技术的推动下数字化转型正快速改变着金融行业&#xff0c;特别在当下金融与科技深度交互融合的新阶段&#xff0c;“金融科技”正成为金融市场新的趋势。但是在众多传统的金融业务领域&#xff0c;特别是在“投融贷”相关的业务中&a…

深度学习5 -- 循环神经网络(代码实现篇+付详细流程文件)

引言 本文是使用pytorch对循环神经网络RNN(Recurrent Neural Network)的代码实现&#xff0c;作为之前介绍RNN原理的一个代码补充。 RNN原理介绍 本文代码相关介绍相对较为详细&#xff0c;也为自己的一个学习过程&#xff0c;对RNN的理解还是比较浅显&#xff0c;有错误的地…

迪赛智慧数——饼图(环形饼图):哪个年龄段的人最爱存钱?

效果图 50岁到60岁是存钱黄金10年,你存下钱了吗? 据央行发布的2022年金融统计数据报告显示&#xff0c;全年人民币存款额增加26.26万亿元&#xff0c;其中住户存款增加17.84万亿&#xff0c;刷新历史记录。 2022年在全国2200名40岁以下的人中&#xff0c;90后这一职场主力军…

电压放大器在无损检测中的作用和应用有哪些

电压放大器在无损检测中扮演着重要的角色&#xff0c;可以帮助实现信号的放大和增强&#xff0c;从而提高检测的灵敏度和准确性。下面&#xff0c;我们将详细探讨电压放大器在无损检测中的作用和应用。 图&#xff1a;ATA-2000系列高压放大器 电压放大器是一种用于放大电压信号…

Flink SQL之Interval Joins

1.Interval Joins&#xff08;区间Join&#xff09; 区间是双流join的优化&#xff0c;基于处理时间或事件时间&#xff0c;在一定时间区间内数据&#xff0c;相同的key进行join&#xff08;支持 Batch\Streaming&#xff09;。Interval Join 可以让一条流去 Join 另一条流中前…

BFT 最前线|北京智源发布悟道3.0大模型;马克龙会见Meta谷歌人工智能专家;马斯克:特斯拉市值未来将超过苹果与沙特阿美总和

文 | BFT机器人 AI视界 TECHNOLOGY NEWS 01 天垓100完成百亿级参数大模型训练 在第五届智源大会AI系统分论坛上&#xff0c;上海天数智芯半导体有限公司对外宣布&#xff0c;在天垓100加速卡的算力集群&#xff0c;基于北京智源人工智能研究院70亿参数的Aquila语言基础模型&am…

flink + Atlas 任务数据血缘调通

据此修改 Flink 源码 版本Flink1.13.5Atlas1.2.0 将 atlas 配置文件打进 flink-bridge&#xff1b;atlas 相关的 jar 放进 flink/lib jar uf flink-bridge-1.2.0.jar atlas-application.properties flink-conf.yaml 注册监听 org.apache.flink.configuration.ExecutionOpti…

6月第2周榜单丨飞瓜数据B站UP主排行榜(哔哩哔哩)发布!

飞瓜轻数发布2023年6月5日-6月11日飞瓜数据UP主排行榜&#xff08;B站平台&#xff09;&#xff0c;通过充电数、涨粉数、成长指数三个维度来体现UP主账号成长的情况&#xff0c;为用户提供B站号综合价值的数据参考&#xff0c;根据UP主成长情况用户能够快速找到运营能力强的B站…

51、C++ 学习笔记

1、引用类型 引用类型是C引入的新类型&#xff0c;根据汇编的知识进行理解&#xff0c;程序在汇编后&#xff0c;变量名将失去意义&#xff0c;因为汇编码将替换成用内存的(链接地址or运行地址)访问变量。在C/C语言中&#xff0c;用变量名表示变量所占的那块内存&#xff0c;为…

仓储管理小程序开发 实现不同行业不同规模的仓管需求

在电子商务快速发展的时代&#xff0c;仓库管理对于一个企业的经营发展来说至关重要。如今互联网技术深入发展&#xff0c;很多企业都开发了信息化管理系统&#xff0c;仓库管理APP小程序就是企业结合自身的运算法则开发的一款线上应用软件&#xff0c;通过智能智慧仓库内人、物…

网络安全是一个好的专业吗?高考之后怎么选择?

目录 一.始于大学 二.一路成长 三. 如何学习网络安全 学前感言 零基础入门 尾言 本人信息安全专业毕业&#xff0c;在甲方互联网大厂安全部与安全乙方大厂都工作过&#xff0c;有一些经验可以供对安全行业感兴趣的人参考。 或许是因为韩商言让更多人知道了CTF&#xff0…

linuxOPS基础_LAMP开源项目实战

LAMP概述 LAMP&#xff1a;Linux Apache MySQL PHP LAMP 架构&#xff08;组合&#xff09; LNMP&#xff1a;Linux Nginx MySQL php-fpm LNMP 架构&#xff08;组合&#xff09; LNMPA&#xff1a;Linux Nginx(80) MySQL PHP Apache Nginx 代理方式 Apache&#…

Markdown编辑器使用

这里写自定义目录标题 欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题&#xff0c;有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants 创建一个自定义列表如何创建一个…

这所Top3顶尖院校,专业课太简单了,比双非还要简单!

一、学校及专业介绍 复旦大学&#xff08;FDU&#xff0c;简称旦旦&#xff09;&#xff0c;除清北之外的顶尖学府&#xff0c;想必不用我过多介绍&#xff0c;Top3之一&#xff08;众所周知&#xff0c;Top3有好多所图片&#xff0c;但我心目中的Top3永远是上海交大图片&#…

element-ui中表头添加自定义按钮以及其他自定义展示

可以使用&#xff1a;render-header方法即可 添加一个按钮如下&#xff1a; renderHeader (h) { return ( <div> <span>操作</span> <el-button type"primary" style"margin-left:90px" size"small" icon"el-icon-pl…

在测试外包干了4年,我废了...

外包公司值不值得去&#xff0c;是很多同行关心的话题。在职场一直流传着“外包不被当人看”“外包没有归属感”的言论。 客观来看&#xff0c;外包岗位确实存在一些缺点&#xff0c;比如&#xff1a;公积金&#xff0c;社保缴纳基数低&#xff0c;没有稳定的涨薪通道&#xff…