当前位置:首页 > 文章列表 > 数据库 > MySQL > 菜鸟小白要怎么排查数据库异常?(方法分享)

菜鸟小白要怎么排查数据库异常?(方法分享)

来源:SegmentFault 2023-01-17 19:14:29 0浏览 收藏

知识点掌握了,还需要不断练习才能熟练运用。下面golang学习网给大家带来一个数据库开发实战,手把手教大家学习《菜鸟小白要怎么排查数据库异常?(方法分享)》,在实现功能的过程中也带大家重新温习相关知识点,温故而知新,回头看看说不定又有不一样的感悟!

这件事情起源于上个月做的微信公众号项目,在项目上线初期,运行平稳,数据库并没有出现异常。

问题出现在微信公众号推送活动消息后,数据库cpu直接满载,而且连接数到达了设置的最大值,新用户打不开或者打开很慢。当时监控显示的情况很糟糕。

数据库服务器负载

数据库服务器连接数

面对这样的情况,运维的兄弟多开了几台tomcat试图来缓减,当时后来的情况是并没有luan用,新开的服务器的负载很快也变的很高,情况依旧。而且当时的情况也很赶,各方面都在催,我们选择了将数据库读写操作量大的用户表的操作转移到redis中这样一种方式避开对数据的操作,上线后情况得到改善,线上的事情告一段落,后面就是排查问题的阶段了。


到了秋后算账的时间,要排查问题的所在,首先抓取了一些可能有用的日志,当时的日志情况是这样的。

SEVERE: Servlet.service() for servlet [web-dispatcher] in context with path [/******] threw exception [Request processing failed; nested exception is org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.exceptions.PersistenceException:
### Error querying database.  Cause: org.springframework.jdbc.CannotGetJdbcConnectionException: Could not get JDBC Connection; nested exception is com.alibaba.druid.pool.GetConnectionTimeoutException: wait millis 5000, active 73

这个日志所反映的问题,而且考虑到出问题的时候都是在并发量大的情况下,第一反应是druid的连接池出了问题(在上线的时候也是这么认为的,运维哥们专业黑druid 500年啊...),由于连接池没有及时回收无用的连接,导致连接池的连接数达到了maxActive(设置的连接池最大使用连接数),使新的连接一直处在等待中,直至等待时间超过了获取连接最大等待时间从而抛出异常。从这一角度出发,在做单元测试的时候,将druid的timeout的时间大大的延长,并将清除无用连接的等待时间缩短,寄希望于druid的连接池处理大量连接时将无用的连接释放掉,在跑单元测试的时候确实跑出异常的情况有所改善,抛出异常的时间延后了,给人的感觉是稳定跑的时间长了,但是从实际情况来说,只是连接等待时间的阈值提高了,对问题的解决没有帮助,从这一方面来排查的结果以失败告终。

由于原先装的是Mysql的衍生版本mariadb,运维兄弟说排查下是不是mysql自身的问题,就给配了一台装了原版5.6的服务器。把测试数据库上的数据dump到了5.6里,然后进行压测,在监控上,同样是数据库连接数很高,而且cpu基本上满载了,问题没有得到改善,可以认为这个问题基本与数据库的版本无关。

断断续续的测试了几天,总是不得要领,事情到这里我这个菜鸟就感觉无从下手了。问了师傅,他老人家说从慢查询日志上看看情况,其实很久以前他就说过,只是我看了以后也没看出啥问题(菜鸟就是菜鸟啊),当时看日志只关注了sql语句,只是时间确实很长,但对于为啥这么慢却一直不知道从哪里入手。这期间,也优化过一些东西,比如把查询的时候UNION的操作从原来在数据库级别搞到在后台进行,在数据库级只是进行select的操作,union的操作人工的进行,也有很大的提升,但是由于在慢查询日志中大量的是单条select的查询操作,union只占了一小部分,所以最根本的问题没有解决,测试的时候负载依旧会很高,然后超时导致错误率很高。

回头想想,几天前犯了个大错误,看日志只片面的看一部分,没有对各个参数有所了解,漏了重要的一些参数。某天睡醒是后看了慢查询日志,发现以前没注意到的一个参数,就是Rows_examined,日志每条信息中它的值都很大,可以认为是目标表里的所有数据的数目了,换句话说,在查询的时候,没有任何优化做了全表的检索,时间耗在了这里。这时候就有了一点点的思路,既然问题出在查询的时候特别慢,那么在数据库中对查询的性能影响很大的索引就成为了重点关注对象。

Query_time: 4.107505  Lock_time: 0.000154  Rows_sent: 1  Rows_examined: 259017

有了这样一个初步的排查的目标,下面就是验证阶段了,看了不同服务器上数据库的表,发现建立的索引都不一致,有些是建立正确的,有些是错误的(造成不一致的原因可能是某个时间看到了发现了问题,就改正了这一错误,但是当时没有将所有的数据库改过来,测试时候用的服务器仍旧是有问题的)。验证的话就是简单的对比实验:代码和压测的线程数和服务器等条件都一致,唯一的不同就在于数据库索引的不同,一个是正确的索引,一个是出问题时候的索引,进行压力测试,在测试期间利用jstack抓取进程,并对日志进行分析。结果如下,通过对比,基本得出是因为索引的问题了,如果后面还发现了这样的异常,那就另外排查了。

error

right

mysql> explain select *  from   user_info where  openid = 'aaaaaaaaaaaaaaaaaaaaaaaa';
+------+-------------+-------------------+------+---------------+------+---------+------+---------+-------------+
| id   | select_type | table             | type | possible_keys | key  | key_len | ref  | rows    | Extra       |
+------+-------------+-------------------+------+---------------+------+---------+------+---------+-------------+
|    1 | SIMPLE      | lottery_user_info | ALL  | NULL          | NULL | NULL    | NULL | 1182759 | Using where |
+------+-------------+-------------------+------+---------------+------+---------+------+---------+-------------+
1 row in set (0.01 sec)

mysql> explain select *  from   user_info where  openid = 'aaaaaaaaaaaaaaaaaaaaaaaa';
+------+-------------+-------------------+------+---------------+--------------+---------+-------+------+-----------------------+
| id   | select_type | table             | type | possible_keys | key          | key_len | ref   | rows | Extra                 |
+------+-------------+-------------------+------+---------------+--------------+---------+-------+------+-----------------------+
|    1 | SIMPLE      | user_info | ref  | openid_index  | openid_index | 98      | const |    1 | Using index condition |
+------+-------------+-------------------+------+---------------+--------------+---------+-------+------+-----------------------+
1 row in set (0.01 sec)

对于这样一个状况的排查直到初步得出结论,感觉自己走了好多的弯路,选择了从上倒下的排查这样一个步骤,当初如果选择从最基础的数据库设计和语句方面入手的话,可能会节约很多的时间。不过排查的时间久也有好处,最起码学习了很多新知识(自我安慰下)。

学识浅薄,如果有不对的地方,烦请不吝赐教,谢谢。

理论要掌握,实操不能落!以上关于《菜鸟小白要怎么排查数据库异常?(方法分享)》的详细介绍,大家都掌握了吧!如果想要继续提升自己的能力,那么就来关注golang学习网公众号吧!

版本声明
本文转载于:SegmentFault 如有侵犯,请联系study_golang@163.com删除
MySQL学习:聊聊日志管理MySQL学习:聊聊日志管理
上一篇
MySQL学习:聊聊日志管理
Out of range value for column 'ref_time' at row 1
下一篇
Out of range value for column 'ref_time' at row 1
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • ChatExcel酷表:告别Excel难题,北大团队AI助手助您轻松处理数据
    ChatExcel酷表
    ChatExcel酷表是由北京大学团队打造的Excel聊天机器人,用自然语言操控表格,简化数据处理,告别繁琐操作,提升工作效率!适用于学生、上班族及政府人员。
    3167次使用
  • Any绘本:开源免费AI绘本创作工具深度解析
    Any绘本
    探索Any绘本(anypicturebook.com/zh),一款开源免费的AI绘本创作工具,基于Google Gemini与Flux AI模型,让您轻松创作个性化绘本。适用于家庭、教育、创作等多种场景,零门槛,高自由度,技术透明,本地可控。
    3380次使用
  • 可赞AI:AI驱动办公可视化智能工具,一键高效生成文档图表脑图
    可赞AI
    可赞AI,AI驱动的办公可视化智能工具,助您轻松实现文本与可视化元素高效转化。无论是智能文档生成、多格式文本解析,还是一键生成专业图表、脑图、知识卡片,可赞AI都能让信息处理更清晰高效。覆盖数据汇报、会议纪要、内容营销等全场景,大幅提升办公效率,降低专业门槛,是您提升工作效率的得力助手。
    3409次使用
  • 星月写作:AI网文创作神器,助力爆款小说速成
    星月写作
    星月写作是国内首款聚焦中文网络小说创作的AI辅助工具,解决网文作者从构思到变现的全流程痛点。AI扫榜、专属模板、全链路适配,助力新人快速上手,资深作者效率倍增。
    4513次使用
  • MagicLight.ai:叙事驱动AI动画视频创作平台 | 高效生成专业级故事动画
    MagicLight
    MagicLight.ai是全球首款叙事驱动型AI动画视频创作平台,专注于解决从故事想法到完整动画的全流程痛点。它通过自研AI模型,保障角色、风格、场景高度一致性,让零动画经验者也能高效产出专业级叙事内容。广泛适用于独立创作者、动画工作室、教育机构及企业营销,助您轻松实现创意落地与商业化。
    3789次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议隐私政策
返回登录
  • 重置密码