• 极客专栏正式上线!欢迎访问 https://www.jikewenku.com/topic.html
  • 极客专栏正式上线!欢迎访问 https://www.jikewenku.com/topic.html

记一次生产数据库”意外”重启的经历

技术杂谈 勤劳的小蚂蚁 3个月前 (01-17) 83次浏览 已收录 0个评论 扫描二维码

前言

在一个阳光明媚的下午,电脑右下角传来一片片邮件提醒,同时伴随着微信钉钉的震动,打开一看,应用各种出错,天兔告警,数据库服务器内存爆红,MySql 数据库实例挂掉了。

排查

先交代一下数据库版本:
  1. mysql> status
  2. --------------
  3. mysql  Ver14.14Distrib5.7.22-22,forLinux(x86_64)using  6.2

  4. Connection id:          59568
  5. Current database:
  6. Current user:           root@localhost
  7. SSL:                    Notinuse
  8. Current pager:          stdout
  9. Using outfile:          ''
  10. Using delimiter:        ;
  11. Server version:         5.7.22-22-log PerconaServer(GPL),Release22,Revision f62d93c
  12. Protocol version:       10
崩溃故障排除绝不是一项有趣的任务,特别是如果MySQL没有报告崩溃的原因。例如,当MySQL内存不足时。
数据库邮件告警提醒发来的消息:
  1. Type: mysql
  2. Tags:生产主库
  3. Host:172.16.1.66:3306
  4. Level: critical
  5. Item: connect
  6. Value: down
  7. Message: mysql server down
登录 Grafana 监控面板,数据库连接在哪个时间段曾有幅度的增长。
顺手检查一下之前的服务器邮件监控告警记录,上一个时间点,内存占用率99%,这说明了数据库连接的幅度增长,可能是压垮服务器的最后一根稻草。
其实导致OOM的直接原因并不复杂,就是因为服务器内存不足,内核需要回收内存,回收内存就是kill掉服务器上使用内存最多的程序,而MySQL服务可能就是使用内存最多,所以就OOM了。
  1. Type: os
  2. Tags:66数据库
  3. Host:172.16.1.66:
  4. Level: critical
  5. Item: memory
  6. Value:99%
  7. Message: too more memory usage

查看系统日志

我们带着这个疑问来排查一下日志:
  1. # 查看日志
  2. tail -500f  /var/log/messages
  3. # 以下是 oom-killer
  4. Nov2714:55:48 itstyledb1 kernel: mysqld invoked oom-killer: gfp_mask=0x201da, order=0, oom_score_adj=0
  5. Nov2714:55:48 itstyledb1 kernel: mysqld cpuset=/ mems_allowed=0-1
  6. Nov2714:55:48 itstyledb1 kernel: CPU:2 PID:895Comm: mysqld Kdump: loaded Not tainted 3.10.0-862.3.2.el7.x86_64 #1
  7. Nov2714:55:48 itstyledb1 kernel:Hardware name:Huawei RH1288 V3/BC11HGSC0, BIOS 3.2205/16/2016
  8. Nov2714:55:48 itstyledb1 kernel:CallTrace:
小伙伴们继续往下看:
  1. 0 pages HighMem/MovableOnly
  2. Nov2714:55:48 itstyledb1 kernel:291281 pages reserved
  3. Nov2714:55:48 itstyledb1 kernel:[ pid ]   uid  tgid total_vm      rss nr_ptes swapents oom_score_adj name
  4. Nov2714:55:48 itstyledb1 kernel:[  468]     0   468    28271     4326      62       55             0 systemd-journal
  5. Nov2714:55:48 itstyledb1 kernel:[  490]     0   490    11492        2      24      553         -1000 systemd-udevd
  6. Nov2714:55:48 itstyledb1 kernel:[  787]     0   787    13877       18      27       96         -1000 auditd
  7. Nov2714:55:48 itstyledb1 kernel:[  810]    81   810    14552       81      34       89          -900 dbus-daemon
  8. Nov2714:55:48 itstyledb1 kernel:[  815]     0   815    55956        1      60      466             0 abrtd
  9. Nov2714:55:48 itstyledb1 kernel:[  816]     0   816    55327        9      64      346             0 abrt-watch-log
  10. Nov2714:55:48 itstyledb1 kernel:[  818]     0   818   121607      220      90      495             0NetworkManager
  11. Nov2714:55:48 itstyledb1 kernel:[  822]     0   822     5415       49      16       33             0 irqbalance
  12. Nov2714:55:48 itstyledb1 kernel:[  823]   997   823   134634       97      60     1306             0 polkitd
  13. Nov2714:55:48 itstyledb1 kernel:[  825]     0   825     6594       42      20       41             0 systemd-logind
  14. Nov2714:55:48 itstyledb1 kernel:[  830]     0   830    31578       28      21      139             0 crond
  15. Nov2714:55:48 itstyledb1 kernel:[  839]     0   839    27522        2      10       31             0 agetty
  16. Nov2714:55:48 itstyledb1 kernel:[1142]     0  1142   143454      114      97     2672             0 tuned
  17. Nov2714:55:48 itstyledb1 kernel:[1144]     0  1144    28203       11      59      246         -1000 sshd
  18. Nov2714:55:48 itstyledb1 kernel:[1145]     0  1145    97438      694     103      328             0 rsyslogd
  19. Nov2714:55:48 itstyledb1 kernel:[1369]     0  1369    22526       20      44      256             0 master
  20. Nov2714:55:48 itstyledb1 kernel:[1371]    89  1371    22596       32      46      251             0 qmgr
  21. Nov2714:55:48 itstyledb1 kernel:[5140]     0  5140     5102     1617      15      239             0 mysqld_exporter
  22. Nov2714:55:48 itstyledb1 kernel:[9430]     0  9430    55966      378      62      790             0 snmpd
  23. Nov2714:55:48 itstyledb1 kernel:[30320]    27303202295137613928375   43437  8163662             0 mysqld
  24. Nov2714:55:48 itstyledb1 kernel:[  688]    89   688    22552      271      46        0             0 pickup
  25. Nov2714:55:48 itstyledb1 kernel:Out of memory:Kill process 30320(mysqld) score 984or sacrifice child
  26. Nov2714:55:48 itstyledb1 kernel:Killed process 30320(mysqld) total-vm:91805504kB, anon-rss:55713500kB, file-rss:0kB, shmem-rss:0kB
  27. Nov2714:56:00 itstyledb1 systemd: mysqld.service: main process exited, code=killed, status=9/KILL
  28. Nov2714:56:00 itstyledb1 systemd:Unit mysqld.service entered failed state.
  29. Nov2714:56:00 itstyledb1 systemd: mysqld.service failed.
  30. Nov2714:56:00 itstyledb1 systemd: mysqld.service holdoff time over, scheduling restart.
  31. Nov2714:56:01 itstyledb1 systemd:StartingMySQLServer...
当out of memory发生时,outofmemory函数会选择一个内核认为犯有分配过多内存 “罪行”的进程,并杀死该进程。显然 Mysql 就是哪个“罪人”。
随后 MySql 会自动重启。重启以后,内存是下来了,但是临近下班的时候,差不多又又又占满了。
  1. [root@itstyledb1 ~]# free -m
  2.              total        used        free      shared  buff/cache   available
  3. Mem:          55803       54976         241          10         585         349
  4. Swap:         32064       25036        7028
找到MySql进程,执行以下top -p pid,内存使用52.4g
  1. PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
  2. 935 mysql     20   0   79.7g  52.4g   7336 S   0.396.1255:44.76 mysqld

计算内存使用

1)查看MySQL全局占用多少内存
  1. SELECT (@@innodb_buffer_pool_size
  2. +@@innodb_log_buffer_size
  3. +@@key_buffer_size)/1024/1024 AS MEMORY_MB;
查询结果为:
  1. +----------------+
  2. | MEMORY_MB      |
  3. +----------------+
  4. |20512.00000000|
  5. +----------------+
2)查看performance_schema占用多少内存
  1. SELECT SUBSTRING_INDEX(event_name,'/',2) AS
  2.       code_area, sys.format_bytes(SUM(current_alloc))
  3.       AS current_alloc
  4.       FROM sys.x$memory_global_by_current_bytes
  5.       GROUP BY SUBSTRING_INDEX(event_name,'/',2)
  6.       ORDER BY SUM(current_alloc) DESC;
查询结果为:
  1. +---------------------------+---------------+
  2. | code_area                 | current_alloc |
  3. +---------------------------+---------------+
  4. | memory/performance_schema |349.80MiB    |
  5. +---------------------------+---------------+
3)查看每个线程占用多少内存
  1. SELECT ((@@read_buffer_size
  2. +@@read_rnd_buffer_size
  3. +@@sort_buffer_size
  4. +@@join_buffer_size
  5. +@@binlog_cache_size
  6. +@@thread_stack
  7. +@@max_allowed_packet
  8. +@@net_buffer_length)
  9. )/(1024*1024) AS MEMORY_MB;
查询结果为:
  1. +-----------+
  2. | MEMORY_MB |
  3. +-----------+
  4. |   87.5156|
  5. +-----------+
查看当前线程
  1. show full processlist
最终结果为:
  1. +-----------+
  2. | MEMORY_MB |
  3. +-----------+
  4. |87.5156*37|
  5. +-----------+
4)查看 memory 存储引擎占用多少内存
  1. SELECT SUM(max_data_length)/1024/1024 AS MEMORY_MB FROM information_schema.tables WHERE ENGINE='memory';
查询结果为:
  1. +---------------+
  2. | MEMORY_MB     |
  3. +---------------+
  4. |3857.37713909|
  5. +---------------+
以上四项加起来差不多也就27975MB,差不错28G的样子,但是 MySql 进程显示占用了52.4G,那么剩下24.4G去哪了?

线程池

此线程池非彼连接池,其实两者是有很大区别的,连接池一般在客户端设置,而线程池是在DB服务器上配置;另外连接池可以取到避免了连接频繁创建和销毁,但是无法取到控制MySQL活动线程数的目标,在高并发场景下,无法取到保护DB的作用。比较好的方式是将连接池和线程池结合起来使用。
关于线程池的一些参数:
  1. mysql> show variables like 'thread%';
  2. +-------------------------------+---------------------------+
  3. |Variable_name                 |Value                     |
  4. +-------------------------------+---------------------------+
  5. | thread_handling               | one-thread-per-connection |
  6. | thread_pool_high_prio_mode    | transactions              |
  7. | thread_pool_high_prio_tickets |4294967295                |
  8. | thread_pool_idle_timeout      |60                        |
  9. | thread_pool_max_threads       |100000                    |
  10. | thread_pool_oversubscribe     |3                         |
  11. | thread_pool_size              |12                        |
  12. | thread_pool_stall_limit       |500                       |
  13. +-------------------------------+---------------------------+
thread_handling:
该参数是配置线程模型,默认情况是one-thread-per-connection,也就是不启用线程池。将该参数设置为pool-of-threads即启用了线程池。
threadpoolsize:
该参数是设置线程池的Group的数量,默认为系统CPU的个数,充分利用CPU资源。
threadpooloversubscribe:
该参数设置group中的最大线程数,每个group的最大线程数为threadpooloversubscribe+1,注意listener线程不包含在内。
threadpoolhighpriomode:
高优先级队列的控制参数,有三个值(transactions/statements/none),默认是transactions,三个值的含义如下:
  • transactions:对于已经启动事务的语句放到高优先级队列中,不过还取决于后面的threadpoolhighpriotickets参数
  • statements:这个模式所有的语句都会放到高优先级队列中,不会使用到低优先级队列
  • none:这个模式不使用高优先级队列
threadpoolhighpriotickets:
该参数控制每个连接最多语序多少次被放入高优先级队列中,默认为4294967295,注意这个参数只有在threadpoolhighpriomode为transactions的时候才有效果。
threadpoolidle_timeout:
worker线程最大空闲时间,默认为60秒,超过限制后会退出。
threadpoolmax_threads:
该参数用来限制线程池最大的线程数,超过该限制后将无法再创建更多的线程,默认为100000。
threadpoolstall_limit:
该参数设置timer线程的检测group是否异常的时间间隔,默认为500ms。
最终配置如下:
  1. #thread pool
  2. thread_handling=pool-of-threads
  3. #Group的数量,默认为系统CPU的个数,充分利用CPU资源
  4. thread_pool_size=24
  5. #每个group的最大线程数为thread_pool_oversubscribe+1
  6. thread_pool_oversubscribe=3
  7. performance_schema=off
  8. #extra connection,防止线程池满的情况下无法登录MySQL
  9. extra_max_connections =8
  10. extra_port =33333
备注:线程池在Percona,MariaDB,Oracle MySQL企业版中提供,Oracle MySQL社区版并不提供。
线程池貌似并不会直接导致内存不回收,网上有说同时开启Thread pool和PS会出现内存泄露,但是 目前Percona server 5.7.21-20+版本已经修复了这个问题,显然是不存在的。

慢查询

由于是生产环境,这个问题拖得时间有点长,那么慢查询会不会影响内存使用问题呢?带着这个问题,查看了慢查询后台列表,在数据库奔溃的前一个时间段,的确有不少慢查询语句。但是这并不能在一定程度上说明问题,由于服务器的 MySql 服务在杀死之前,内存已经见底,此时连接数并不多,也就三四十来个左右,大多处于休眠状态,并且此时已经占用了大部分的Swap空间。也就是说,在资源有限的情况下必定会出现不少慢查询语句。

小结

其实这个”意外“一点也不意外,其实已经发生了多次了。但是还是做个小结吧,因为最终没有确认问题出现在哪里,所以还是发布了吧,万一有专业的DBA遇到类似的问题还可以小小的解惑一下。

参考


丨极客文库, 版权所有丨如未注明 , 均为原创丨
本网站采用知识共享署名-非商业性使用-相同方式共享 3.0 中国大陆许可协议进行授权
转载请注明原文链接:记一次生产数据库”意外”重启的经历
喜欢 (0)
[247507792@qq.com]
分享 (0)
勤劳的小蚂蚁
关于作者:
温馨提示:本文来源于网络,转载文章皆标明了出处,如果您发现侵权文章,请及时向站长反馈删除。

您必须 登录 才能发表评论!

  • 精品技术教程
  • 编程资源分享
  • 问答交流社区
  • 极客文库知识库

客服QQ


QQ:2248886839


工作时间:09:00-23:00