由于从 Mysql 5.7.23 迁移到 Mysql 8.0(包括状态、配置)而导致的极端性能损失

Joh*_*ohn 7 mysql innodb mysql-8.0

已经连续坐了 12 个小时(现在是中午,所以当我再次醒来时我会阅读/回复)。
我犯了一个大错误,建议升级我们的生产环境的数据库以提高性能。
我们不能回去,它有将近 6 TB 的存储空间,而且 mysql 8.0 无法降级。
使用升级前快照备份也不是解决方案(工作天数)。

我想解决将服务器切换到最新版本导致的可怕性能

一些细节:
环境:Linux Stretch on AWS i3.8xlarge(32 cpu,240gb ram)
服务器:mysql/Docker 容器中的 Mysql 8.0,使用绑定安装和主机网络
存储:Amazon AWS EBS IO1 存储(6 TB),预留 20,000 IOPS .
存储在 fio 测试中提供 500mb/sec-600mb/sec。
CPU:通常 32 核使用 50-60%,但自 mysql 8.0 以来它处于空闲状态(使用 10-15%)
RAM:200GB 专用于 mysql,在 8.0 之前不久就被使用了。现在需要好几个小时,mysql 才能填满缓冲区。

核心问题: 速度比5.7下降了20倍左右
Innodb/mysql 没有有效地使用磁盘。
使用它以 15 mb/sec 读取的原始配置(简单计数需要几分钟才能运行,因为 IBD 文件未正确读取)
我已经禁用了性能模式,这有助于至少以 10% 的负载再次运行服务器。
我禁用了 bin 日志记录,也许这有帮助,但不确定。
我尝试将读/写线程增加到 64(这完全停止了服务器)

我花了 8 个小时来尝试调整 mysql 配置,我设法将 mysql 从仅使用 5mb/sec 的速度“推”到了现在的 50mb/sec。

确保:
当然,我确实从 docker 内部测试了磁盘 IO,它与外部完全相似。
主盘大部分空闲,其他盘完全空闲。
当系统应该被占用时,它有 90% 的空闲。

Innodb 状态:https :
//pastebin.com/XDgyNbk0

mysql配置:

[mysqld]
user=mysql
pid-file        = /var/run/mysqld/mysqld.pid
socket          = /var/run/mysqld/mysqld.sock
datadir         = /var/lib/mysql

tmpdir          = /mysql_tmp  

# compatibility
default_authentication_plugin=mysql_native_password
character_set_server=latin1
collation_server=latin1_swedish_ci



log-error       = /var/log/mysql_error.log
bind-address    = 0.0.0.0
sql_mode= "NO_ENGINE_SUBSTITUTION"

interactive_timeout     = 3600
wait_timeout            = 900

max_allowed_packet      = 64M
thread_stack            = 256K
thread_cache_size       = 192

max_connections         = 1600
max_user_connections    = 1500

#query_cache_limit       = 3M
#query_cache_size        = 200M
#query_cache_type       = 1
table_open_cache        = 2500


key_buffer_size          = 64M   # index in memory for myisam
innodb_buffer_pool_size = 190G
innodb_log_file_size = 256M
tmp_table_size = 250M
max_heap_table_size = 250M
join_buffer_size = 2M
#pagecleaners  - those were uncommented on 5.7
#innodb_buffer_pool_instances=8
#innodb_page_cleaners=2
innodb_io_capacity=5000
innodb_io_capacity_max=20000

# tried 64, that totally stalled the database
innodb_read_io_threads = 8
innodb_write_io_threads = 8

#in pre 5.7 times I had consistent 300mb/sec writes, now it's useless
innodb_lru_scan_depth=256

skip-name-resolve

secure_file_priv=""
#innodb_checksum_algorithm = crc32
#binlog_checksum = CRC32

# this one at least made it possible so I can go to bed, with performance_schema the database was unuseable    
performance_schema=OFF
skip-log-bin 
Run Code Online (Sandbox Code Playgroud)

Sysctl fs

fs.aio-max-nr = 1048576
fs.aio-nr = 139264
fs.binfmt_misc.status = enabled
fs.dentry-state = 355223        335269  45      0       0       0
fs.dir-notify-enable = 1
fs.epoll.max_user_watches = 51660308
fs.file-max = 25224638
fs.file-nr = 19136      0       25224638
fs.inode-nr = 70145     5686
fs.inode-state = 70145  5686    0       0       0       0       0
fs.inotify.max_queued_events = 16384
fs.inotify.max_user_instances = 128
fs.inotify.max_user_watches = 8192
fs.lease-break-time = 45
fs.leases-enable = 1
fs.mqueue.msg_default = 10
fs.mqueue.msg_max = 10
fs.mqueue.msgsize_default = 8192
fs.mqueue.msgsize_max = 8192
fs.mqueue.queues_max = 256
fs.nr_open = 1048576
fs.overflowgid = 65534
fs.overflowuid = 65534
fs.pipe-max-size = 1048576
fs.protected_hardlinks = 1
fs.protected_symlinks = 1
fs.quota.allocated_dquots = 0
fs.quota.cache_hits = 0
fs.quota.drops = 0
fs.quota.free_dquots = 0
fs.quota.lookups = 0
fs.quota.reads = 0
fs.quota.syncs = 62
fs.quota.warnings = 1
fs.quota.writes = 0
fs.suid_dumpable = 0
Run Code Online (Sandbox Code Playgroud)

iostat 快照:

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
          13.86    0.71   10.84    3.23    0.11   71.26

Device:            tps    kB_read/s    kB_wrtn/s    kB_read    kB_wrtn
xvdh           1795.31     13923.89     26159.95  256609017  482112504
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,它只是以 14mb/sec 的速度读取,以 26mb/sec 的速度写入……
使用 mysql 5.7,它的读取和写入速度高达200mb 。

磁盘基本空闲。它可以提供 10 倍的性能,但由于未知原因 innodb/mysql 不再这样做了。

更新: 变量和全局状态:https : //pastebin.com/pzhXV7hq
https://pastebin.com/jBTYLbY6

我被迫做出的另一个改变:
我每秒有 100 个用户通过 apache/php 连接,每个连接通常都会触发“SELECT count(*) FROM information_schema.processlist”新的 mysql 不能再这样做了,它将其中 50 个以上的选择排队,所以我做了一个异步任务,每 5 秒将进程列表插入到 innodb 表中。
这只是新 mysql 反应性能低下的另一个迹象,它甚至被进程列表阻塞。

超限

   core file size          (blocks, -c) 0
    data seg size           (kbytes, -d) unlimited
    scheduling priority             (-e) 0
    file size               (blocks, -f) unlimited
    pending signals                 (-i) 985342
    max locked memory       (kbytes, -l) 64
    max memory size         (kbytes, -m) unlimited
    open files                      (-n) 65536
    pipe size            (512 bytes, -p) 8
    POSIX message queues     (bytes, -q) 819200
    real-time priority              (-r) 0
    stack size              (kbytes, -s) 8192
    cpu time               (seconds, -t) unlimited
    max user processes              (-u) 985342
    virtual memory          (kbytes, -v) unlimited
    file locks                      (-x) unlimited
Run Code Online (Sandbox Code Playgroud)

大更新
花了半天时间阅读 internas,考虑你的建议和我在 IRC 上被告知的内容。
我做了与专业相反的事情:我一次做了 10 次更改,我无法承受在渐变过程中进行这么多次重启:
1) 为系统提供大量并行写入机会而不会使其窒息

innodb_read_io_threads = 16  
innodb_write_io_threads = 16  
innodb_thread_concurrency=64  # cpus*2  
Run Code Online (Sandbox Code Playgroud)

2)加快后台同步:

 innodb_lru_scan_depth=100  
Run Code Online (Sandbox Code Playgroud)

3) 禁用对性能有重大影响的最高可靠性设置

performance_schema=OFF
skip-log-bin 
sync_binlog=0 
innodb_flush_log_at_trx_commit=0  # not crash safe, 0 is crash safe  
Run Code Online (Sandbox Code Playgroud)

4)后端内存中更多的多线程

innodb_buffer_pool_instances=12  
Run Code Online (Sandbox Code Playgroud)

5)显着增加日志文件,适度增加日志文件缓冲区

innodb_log_file_size = 3G # 
innodb_log_buffer_size = 64M
Run Code Online (Sandbox Code Playgroud)

发生了什么:读取性能提高了大约 10 倍,写入性能提高了 1.5 倍,我不是我想要的地方,但它比以前快了 15 倍!
IOPS 使用率从 ~5-6k 翻倍到 9k-12k,所以我处于 60% IO 使用率
CPU 使用率从 7% 增加到 50%

我的目标是数据库的 80% IO 和 CPU 使用率,我认为其他变量是瓶颈。

实时使用:我有一个巨大的插入在更改前后运行(在通常的负载旁边)。
在更改之前,速度约为每秒 3000 行,在上述更改之后,速度为每秒 8000 行。

我想我分享这一点,因为性能的变化是极端的,我只达到了应该可能的 50%。

更新
我觉得问题已经解决了一半,我在上一次成功后又做了一次更新,现在性能可以接受。

最后的更改涉及写/读线程。我已经把它们分别设置为 32 个。
写入缓冲区增加到 128M(对于我的繁重工作量,更高可能更好)
日志文件增加到 8GB
buffer_pool_instances 增加到 64(最大)以获得更好的内存碎片
page_cleaners 增加到 64(最大),以便每个缓冲区实例都有一个。

写入性能再提高约 20%,读取性能再提高约 30%。

让 mysql 的性能可以接受需要 24 小时的车程,绝对不是简单的升级。

最新状态:

Current configuration: https://pastebin.com/9vsbEQxt
show engine status innodb: https://pastebin.com/kCjnmtze
show global variables: https://pastebin.com/aMdQxWcA
global status: https://pastebin.com/VbG1yzHX
Run Code Online (Sandbox Code Playgroud)

Wil*_*uck 0

根据美国中部时间 2019 年 1 月 22 日 15:00 目前的可用数据,考虑不停止/启动服务以立即救济的建议

SET GLOBAL innodb_io_capacity=10000        from your 5000 limit at this time
SET GLOBAL innodb_lru_scan_depth=100        from your 256 to reduce CPU cycles used for this function by 60% EVERY SECOND
Run Code Online (Sandbox Code Playgroud)

发布 SHOW GLOBAL VARIABLES 后;分析完毕还会有更多的建议。

  • 您好,我尝试过 100 到 20000 之间的值,它对观察到的性能没有真正的影响。我会尝试一下这个组合。在我的问题的最后,你会发现一个带有变量的pastebin。服务器大部分空闲,CPU使用率7%,IO使用率10% (2认同)
  • @John 感谢您的积极评论,即使是在活动结束 22 个月后。你很感激。 (2认同)