MySQL数据库连接超时问题排查报告

news2024/11/15 17:38:40

1、问题描述

边端设备访问云端过程中有概率出现MySQL数据库连接超时报错,具体报错代码如下:

[2024-08-13 13:47:44,036] ERROR in app: Exception on /est-tasks/start [POST] Traceback (most recent call last): File "/usr/local/lib/python3.10/site-packages/sqlalchemy/engine/base.py", line 1971, in _exec_single_context self.dialect.do_execute( File "/usr/local/lib/python3.10/site-packages/sqlalchemy/engine/default.py", line 919, in do_execute cursor.execute(statement, parameters) File "/usr/local/lib/python3.10/site-packages/pymysql/cursors.py", line 153, in execute result = self._query(query) File "/usr/local/lib/python3.10/site-packages/pymysql/cursors.py", line 322, in _query conn.query(q) File "/usr/local/lib/python3.10/site-packages/pymysql/connections.py", line 558, in query self._affected_rows = self._read_query_result(unbuffered=unbuffered) File "/usr/local/lib/python3.10/site-packages/pymysql/connections.py", line 822, in _read_query_result result.read() File "/usr/local/lib/python3.10/site-packages/pymysql/connections.py", line 1200, in read first_packet = self.connection._read_packet() File "/usr/local/lib/python3.10/site-packages/pymysql/connections.py", line 748, in _read_packet raise err.OperationalError( pymysql.err.OperationalError: (2013, 'Lost connection to MySQL server during query') The above exception was the direct cause of the following exception: Traceback (most recent call last): File "/usr/local/lib/python3.10/site-packages/flask/app.py", line 1463, in wsgi_app response = self.full_dispatch_request() File "/usr/local/lib/python3.10/site-packages/flask/app.py", line 872, in full_dispatch_request rv = self.handle_user_exception(e) File "/usr/local/lib/python3.10/site-packages/flask/app.py", line 870, in full_dispatch_request rv = self.dispatch_request() File "/usr/local/lib/python3.10/site-packages/flask/app.py", line 855, in dispatch_request return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args) # type: ignore[no-any-return] File "/flask/app/api/est_task.py", line 99, in send_test_start RequestDao().create([request_record]) File "/flask/app/dao/base_dao.py", line 268, in create model = schema.load(obj, partial=True) File "/usr/local/lib/python3.10/site-packages/marshmallow_sqlalchemy/load_instance_mixin.py", line 100, in load return super().load(data, **kwargs) File "/usr/local/lib/python3.10/site-packages/marshmallow/schema.py", line 722, in load return self._do_load( File "/usr/local/lib/python3.10/site-packages/marshmallow/schema.py", line 897, in _do_load result = self._invoke_load_processors( File "/usr/local/lib/python3.10/site-packages/marshmallow/schema.py", line 1095, in _invoke_load_processors data = self._invoke_processors( File "/usr/local/lib/python3.10/site-packages/marshmallow/schema.py", line 1225, in _invoke_processors data = processor(data, many=many, **kwargs) File "/usr/local/lib/python3.10/site-packages/marshmallow_sqlalchemy/load_instance_mixin.py", line 76, in make_instance instance = self.instance or self.get_instance(data) File "/usr/local/lib/python3.10/site-packages/marshmallow_sqlalchemy/load_instance_mixin.py", line 60, in get_instance return self.session.get(self.opts.model, filters) File "/usr/local/lib/python3.10/site-packages/sqlalchemy/orm/scoping.py", line 1060, in get return self._proxied.get( File "/usr/local/lib/python3.10/site-packages/sqlalchemy/orm/session.py", line 3637, in get return self._get_impl( File "/usr/local/lib/python3.10/site-packages/sqlalchemy/orm/session.py", line 3817, in _get_impl return db_load_fn( File "/usr/local/lib/python3.10/site-packages/sqlalchemy/orm/loading.py", line 694, in load_on_pk_identity session.execute( File "/usr/local/lib/python3.10/site-packages/sqlalchemy/orm/session.py", line 2306, in execute return self._execute_internal( File "/usr/local/lib/python3.10/site-packages/sqlalchemy/orm/session.py", line 2191, in _execute_internal result: Result[Any] = compile_state_cls.orm_execute_statement( File "/usr/local/lib/python3.10/site-packages/sqlalchemy/orm/context.py", line 293, in orm_execute_statement result = conn.execute( File "/usr/local/lib/python3.10/site-packages/sqlalchemy/engine/base.py", line 1422, in execute return meth( File "/usr/local/lib/python3.10/site-packages/sqlalchemy/sql/elements.py", line 514, in _execute_on_connection return connection._execute_clauseelement( File "/usr/local/lib/python3.10/site-packages/sqlalchemy/engine/base.py", line 1644, in _execute_clauseelement ret = self._execute_context( File "/usr/local/lib/python3.10/site-packages/sqlalchemy/engine/base.py", line 1850, in _execute_context return self._exec_single_context( File "/usr/local/lib/python3.10/site-packages/sqlalchemy/engine/base.py", line 1990, in _exec_single_context self._handle_dbapi_exception( File "/usr/local/lib/python3.10/site-packages/sqlalchemy/engine/base.py", line 2357, in _handle_dbapi_exception raise sqlalchemy_exception.with_traceback(exc_info[2]) from e File "/usr/local/lib/python3.10/site-packages/sqlalchemy/engine/base.py", line 1971, in _exec_single_context self.dialect.do_execute( File "/usr/local/lib/python3.10/site-packages/sqlalchemy/engine/default.py", line 919, in do_execute cursor.execute(statement, parameters) File "/usr/local/lib/python3.10/site-packages/pymysql/cursors.py", line 153, in execute result = self._query(query) File "/usr/local/lib/python3.10/site-packages/pymysql/cursors.py", line 322, in _query conn.query(q) File "/usr/local/lib/python3.10/site-packages/pymysql/connections.py", line 558, in query self._affected_rows = self._read_query_result(unbuffered=unbuffered) File "/usr/local/lib/python3.10/site-packages/pymysql/connections.py", line 822, in _read_query_result result.read() File "/usr/local/lib/python3.10/site-packages/pymysql/connections.py", line 1200, in read first_packet = self.connection._read_packet() File "/usr/local/lib/python3.10/site-packages/pymysql/connections.py", line 748, in _read_packet raise err.OperationalError( sqlalchemy.exc.OperationalError: (pymysql.err.OperationalError) (2013, 'Lost connection to MySQL server during query') [SQL: SELECT core_device_request.device_number AS core_device_request_device_number, core_device_request.request_id AS core_device_request_request_id, core_device_request.request_type AS core_device_request_request_type, core_device_request.start_time AS core_device_request_start_time, core_device_request.end_time AS core_device_request_end_time, core_device_request.state AS core_device_request_state, core_device_request.created_at AS core_device_request_created_at, core_device_request.created_by AS core_device_request_created_by, core_device_request.updated_at AS core_device_request_updated_at, core_device_request.updated_by AS core_device_request_updated_by, core_device_request.is_deleted AS core_device_request_is_deleted FROM core_device_request WHERE core_device_request.request_id = %(pk_1)s] [parameters: {'pk_1': '99da21c6-e76f-4595-b0a6-32061934938d'}] (Background on this error at: https://sqlalche.me/e/20/e3q8)

该报错在云端所有接口调用中都有出现,出现频率不定,有时频发有时偶发,并且具有两个特点

  1. 发生超时错误后不进行任何操作,一段时间后会服务自动恢复正常

  2. 发生超时错误后重启数据库或licloud-api服务,服务立即恢复正常

  3. 发生超时错误时licloud-api所在主机与MySQL数据库主机之间网络连接正常

  4. 发生超时错误时可以正常使用Navicat、DataGrip等GUI工具连接至MySQL数据库

2、排查过程

频繁发生超时问题后技术部采取了如下措施进行问题排查

2.1 协调移动云技术支持排查网络日志

最初发生该问题时,怀疑是移动云服务器网络连接问题,联系移动云技术支持人员进行问题排查,跟踪观察了licloud-api服务器与mysql服务器之间的网络流量,未发现有明显问题,根据移动云技术人员的建议,修改了如下配置:

2.1.1 排查网络带宽问题

  1. 数据传输速度:如果数据库服务器和客户端之间的网络带宽有限,大数据的传输速度可能会变慢。这可能导致客户端在尝试读取或写入大量数据时超过了 net_read_timeoutnet_write_timeout 的设置,从而导致连接超时。

  2. 响应时间:网络带宽限制可能导致数据包的延迟增加,尤其是在数据量大或者连接数多的情况下。这可能使得客户端请求的响应时间变长,进而可能触发超时设置

解决方案: 增加网络带宽从原有的50MB,增加到100M

超时问题没有改善

2.1.2 修改无状态安全组

由于底层设备有个会话3600s老化的机制,两端没有交互的话会话是会断开的,所以需要配置keepalived或者改成无状态安全组.

配置内核里的这个参数net.ipv4.tcp_keepalive_time,内核会发送保活探测包检查连接是否仍然有效

net.ipv4.tcp_keepalive_time 
net.ipv4.tcp_keepalive_intvl 
net.ipv4.tcp_keepalive_probes

 

 

超时问题没有改善

2.1.3 交互与非交互超时时间过长导致

mysql数据库服务器上部署的数据库访问异常问题,经过前期的排查服务器网络、服务器操作系统的TCP连接保活参数、数据库服务端的会话超时时间参数;

1、排查服务器网络正常,排除这个主机网络原因

2、根据我们的经验,可能是访问链路上不同节点的超时时间不一致导致MySQL会话超时,前期记录的数据是安全组存在3600s的超时时间、服务器系统默认是7200s的会话超时时间,数据库服务端配置的是30天的会话超时时间,会出现TCP连接长时间没有交互的情况下,安全组已经中断连接的情况下,服务器和数据库服务端的连接依旧保活;7月29日调整了服务器操作系统TCP会话保活探测时间、8月2日调整了数据库服务端的会话超时时间为1200s,

[mysqld] wait_timeout = 1200 interactive_timeout = 1200 
#这里是8小时 我们改成了3小时

2.2 网络配置、服务配置排查优化

查阅网络资料以及参考移动云技术人员的建议,考虑了如下一些可能原因并进行了针对性优化

2.2.1 查询中大量数据被发送,由于数据传输时间不够导致

增加net_read_timeout的值。

修改 MySQL 的配置文件(通常是 my.cnfmy.ini 文件)。

在配置文件中,找到 [mysqld] 部分,并添加或修改以下行:

iniCopy Code [mysqld]net_read_timeout = 60 #这里是60 我们修改成了600

保存文件后,重新启动 MySQL 服务

超时问题没有改善

2.2.2 交互与非交互超时时间过短导致

  1. wait_timeout

    1. 作用:控制非交互式连接的超时时间。这类连接通常是由应用程序或脚本通过连接池管理的,比如 Web 应用与数据库之间的连接。

    2. 影响:如果一个连接在设定的 wait_timeout 秒内没有任何活动(例如查询、更新等),MySQL 会自动关闭这个连接。这可以避免长时间空闲的连接占用数据库资源。

  2. interactive_timeout

    1. 作用:控制交互式连接的超时时间。这类连接通常是用户直接通过命令行或 GUI 工具与数据库交互的连接。

    2. 影响:与 wait_timeout 类似,但 interactive_timeout 更适用于用户交互时的连接。如果一个用户连接在设定的 interactive_timeout 秒内没有任何活动,MySQL 会自动关闭这个连接。

在 MySQL 的配置文件(如 my.cnfmy.ini)中,设置 wait_timeout,interactive_timeout:

[mysqld] wait_timeout = 31536000 interactive_timeout = 31536000

# 这里是八小时 我们改成了30天

超时问题没有改善

2.2.3 初次连接时,连接时间设定太少

增加connect_timeout的值改善。

永久改变 connect_timeout 的值,使其在 MySQL 重启后仍然生效,需要修改 MySQL 的配置文件(通常是 my.cnfmy.ini 文件)。

在配置文件中,找到 [mysqld] 部分,并添加或修改以下行:

iniCopy Code [mysqld]connect_timeout = 20 # 这里是20 我们设置成120

保存文件后,重新启动 MySQL 服务

超时问题没有改善

2.2.4 BLOB值太大的问题

调整配置文件max_allowed_packet。

就更新大量的数据来说,可以进行两个方面的设置:将系统变量net_read_timeout设置得大一点,再将配置文件中的max_allowed_packet设置大一点。

max_allowed_packet 是 MySQL 服务器允许的最大数据包大小。默认情况下,这个值为 4MB。如果你的更新操作涉及到更大的数据量,例如大型 BLOB 数据的插入或更新,可能需要增加这个参数的设置。

在 MySQL 的配置文件(如 my.cnfmy.ini)中,设置 max_allowed_packet

[mysqld] max_allowed_packet = 4M # 这里是4M ,设置 max_allowed_packet 为 100MB

超时问题没有改善

2.2.5 索引、连接池问题

根据移动云技术人员建议,考虑数据库创建时的索引和连接池配置

在flask项目中添加了如下代码;

SQLALCHEMY_ENGINE_OPTIONS = { "poolclass": QueuePool, "pool_size": 10, "max_overflow": 20, "pool_timeout": 30, "connect_args": {"connect_timeout": 10}, "pool_recycle": 8, }

后续没有发现过超时问题

2.3 腾讯云/阿里云服务器测试

为确定是移动云服务器还是代码导致报错,将相同代码分别部署在腾讯云、阿里云服务器上进行长时间测试,从2024年8月9日下午2-3时至2024年8月13日下午2-3时,期间每隔三分钟向云服务器服务发送一次模拟容量检测请求

从结果来看,腾讯云、阿里云服务器均未出现数据库连接超时及其他错误

 

2.4 本地开发服务器测试

为保障产品部正常进行新版上位机、边端的联调测试,将相同代码部署在本地开发服务器上

2024年8月8日至2024年8月13日的联调测试中未出现过数据库超时问题

3、问题分析及解决方案

根据排查及复现过程进行推论分析,可以确定造成数据库连接超时的原因是:Flask项目中没有正确配置Flask-sqlalchemy连接池参数,尤其是连接池中的连接回收时间,使得MySQL与Flask-sqlalchemy之间的连接被提前意外关闭

具体来说:

  • 云端工作过程中,flask项目通过sqlalchemy和pymysql模块与mysql数据库建立连接,该连接以连接池的形式被sqlalchemy模块创建、维护

  • sqlalchemy默认不会对连接池中的连接进行回收,即不会主动关闭长时间未进行任何操作、通讯的空闲连接

  • mysql默认会关闭28800秒(8小时)内未进行任何操作、通讯的空闲连接

综合上述三点,当sqlalchemy连接池中某个连接在8小时内都没有任何操作时,mysql会主动关闭该连接,但是sqlalchemy并不知道该连接已经被关闭,在下一次需要连接数据库时仍然会调用一个实际数据库上已经被关闭的连接,就会出现连接mysql数据库超时的报错。

根据上述分析,在移动云和腾讯云主机上修改sqlalchemy的pool_recycle参数为-1(默认不回收连接,等价于超时时间为无限长)、mysql的wait_timeout为10秒,进行长时间测试,成功复现了数据库超时问题。

上述问题的解决方案是合理设置sqlalchemy连接池回收时间、mysql数据库的等待超时时间,目前将sqlalchemy的pool_recycle设置为1200秒,mysql数据库的wait_timeout设置为1800秒,在测试中未再发现超时报错。

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

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

相关文章

Java 入门指南:Map 接口

Map 接口是 Java 集合框架中的一个接口,它表示了一种键值对的映射关系。Map 接口提供了一种以键为索引的数据结构,通过键可以快速查找对应的值。在 Map 中,每个键只能对应一个值,键是唯一的,但值可以重复。 常用的实现…

在vscode上便捷运行php文件

目录 前言 1. 准备工作 2. 创建文件 3. 下载插件 4.设置访问配置文件 5. 配置默认浏览器 6. 进行验证 前言 对于学习安全的我们来说,部署环境,靶场,和配置环境都是习以为常的一件事情,平时访问靶场都是通过小皮来,今天突想着最近需要对一些漏洞的原理进行研究,所以需要能够…

ESP-WHO C++程序分析基础(七)

以按键部分的程序做为分析基础 先看app_button.hpp文件,文件的路径如下 examples/esp32-s3-eye/main/include/app_button.hpp // AppButton 类,继承自 Subject 类,表示应用程序按钮 首先是先定义了一个 appbutton的按键类,这个…

【计算机组成原理】汇总三、存储系统

三、存储系统(存储器层次结构) 文章目录 三、存储系统(存储器层次结构)1.存储器的分类1.1按在计算机中的作用(层次)❗多级存储结构(层次化结构)1.2按存储介质1.3按存取方式1.4按信息…

抢单源码修正版,带教程,自动抓取订单,十几种语言可自动切换

亚马逊抢单源码自动抓取订单任务邀请英文,西班牙语可自动切换语言亲测修正版。带完整开源的前后台。 西班牙,英文,巴西,中文,德国,拉法兰西,荷兰,缅甸,Sverige,日本,Trk…

C_02基础学习

c 语言 基础 gcc编译器 作用: 将代码文件编译为可执行文件 分类: 一步到位gcc 要编译的代码文件 -o 生成的可执行文件注意:要编译的代码文件可以是多个-o 生成的可执行文件:可以忽略不写,默认生成a.out文件 分步实现预编译:头文件展示,宏替换,选择型编译gcc -E 要编译的代码…

VMware NET Service在虚拟机关闭后仍然占用CPU - 解决方案

问题 VMware NET Service(即vmnat.exe)在虚拟机关闭后仍然占用CPU,这是VM 17.5.0 和 VM 17.5.1 软件本身存在的Bug,此问题已在 VM 17.5.2 版本修复,下文介绍解决方案。 时间:2024年8月 解决方案 临时方…

百度网盘网页提示页面过期请刷新 - 解决方案

问题 当打开百度网盘网页的分享链接后,点击下载会提示页面过期请刷新,点击保存到网盘没有响应,刷新后存在同样问题。 原因 这通常是因为浏览器中安装了屏蔽广告的插件,此插件不只拦截了百度网盘的广告,还拦截了一部…

零基础构建 AI 大模型数字人:开启智能交互新时代

人工智能技术的飞速发展,数字人正逐渐成为连接虚拟与现实世界的桥梁。无论是作为客户服务代表、教育助手还是娱乐伙伴,数字人都以其独特的方式丰富着我们的生活。今天,我们将介绍一个基于Dify生态系统的开源数字人技术框架——awesome-digita…

iis部署服务时,发现只能进行get请求,无法发起post、put请求

问题描述: iis部署服务时,发现只能进行get请求,无法发起post、put请求 问题原因: iis部署时,webDAV模块限制 解决方法: 1.搜索【服务器管理器】 2.点击【删除角色功能】 3.选中WebDAV,点…

MinIO实战攻略:轻松构建私有云存储解决方案

OSS 简介 OSS(Object Storage Service)通常指的是对象存储服务,它是一种数据存储架构,用于存储和检索非结构化数据,如图片、视频、文档和备份等。对象存储服务与传统的块存储和文件存储不同,它将数据作为对…

用户画像标签服务设计

背景 用户画像中不论是实时标签还是离线标签,对需要对外提供查询服务,以便外部接口可以重新用户的标签,本文就来看一下用户标签服务的设计 用户标签服务设计 不论是离线标签还是实时标签,我们都需要先把他们从hive表或者实时re…

OpenCV(第二关--读取图片和摄像头)实例+代码

以下内容,皆为原创,制作不易,感谢大家的关注和点赞。 一.读取图片 我们来读取图片,当你用代码读取后,可能会发现。怎么跟上传的图片颜色有些许的不一样。因为OpenCV的颜色通道是BGR,而我们平常用的matplotl…

华为云通过自定义域名访问桶内对象

问题:通过将自定义域名绑定至OBS桶实现在线预览文件 例如index.html入口文件 且记 自定义域名绑定暂时不支持HTTPS访问方式,只支持HTTP访问方式 自定义域名就先不用部署https证书。 配置完毕之后,将obs桶设置为公开的即可访问 如何在浏览…

若依代码生成器生成的界面查询和导出突然报错了

之前用的好好的,查询的时候也有数据,但是把参数给分页插件的时候就报错了,我忘了啥错误了,很奇怪。 ha在对应Mapper上加上:CacheNamespace注解,完。 Mapper CacheNamespace public interface BaseGoodsMa…

使用Python做一个脚本自动化机器人(二)

刚发现一个好用的Python库DrissionPage,使用该库不区分浏览器,也无需下载driver文件。 import logging from DrissionPage import WebPage from DrissionPage import ChromiumPage,ChromiumOptionsclass BaiduPage():# 创建对象page ChromiumPage()# 访…

SpringBoot项目定义Bean常见方式

1. spring原生的xml 配置bean 现在几乎淘汰,忽略!! 2. Component 及其衍生注解 (Controller、Service、Repository) Component public class Cat { }3. Configuration Bean Configuration public class AnimalConf…

【OpenGL】xcode+glfw画三角形

环境搭建 1. 执行brew install glfw 2. 项目中Build Settings中header Search Paths中添加glfw的include路径 3. 项目中Build Phases中的Link Binary With Libraries中添加glfw的lib文件(路径/opt/homebrew/Cellar/glfw/3.4/lib/libglfw.3.4.dylib)及…

21.缓存穿透

缓存穿透 客户端请求的数据在缓存中和数据库中都不存在,这样缓存永远不会生效,这些请求都会到达数据库。会造成数据库宕机。 解决方案 1.缓存空对象 例如查询数据的id,发现数据库中没有,那么就在redis中缓存空对象。但是会有额…

springboot项目读取 resources 目录下的文件的9种方式

1. 使用 ClassLoader.getResourceAsStream() 方法 InputStream inputStream getClass().getClassLoader().getResourceAsStream("file.txt"); 2. 使用 Class.getResourceAsStream() 方法 InputStream inputStream getClass().getResourceAsStream("/file.txt&…