MySQL因Arm弱内存序读写死锁问题说明
问题说明
使用Sysbench对MySQL 5.7社区版进行读写测试,在测试一段时间后,MySQL 5.7出现死锁现象,导致测试停止。
测试环境说明
- 网络拓扑
Sysbench安装在一台x86服务器上,MySQL数据库安装在一台Arm服务器上,通过交换机连接。
软件类型
CPU
DDR
磁盘类型
操作系统
Sysbench
E5-2695 v4/2.10GHz/72core
384GB
SATA
Euler 2.0(4.16.2)
MySQL
Kunpeng 920/2.5GHz/96core
512GB
SSD
Ubuntu 16.04(4.4.0)
- 数据集
- 测试脚本
使用Sysbench自带的oltp.lua进行测试,具体测试命令如下:
1
/ssd/zqsource/rds-perf/source/sysbench-0.5/sysbench/sysbench --test=/ssd/zqsource/rds-perf/source/sysbench-0.5/sysbench/tests/db/oltp.lua --oltp-tables-count=64 --oltp-table-size=10000000 --mysql-host=$HOST --mysql-port=$PORT --mysql-db=$TABLE --mysql-user=$USER --mysql-password=$PASSWD --oltp-read-only=off --oltp-point-selects=10 --oltp-simple-ranges=1 --oltp-sum-ranges=1 --oltp-order-ranges=1 --oltp-distinct-ranges=1 --max-requests=0 --max-time=$TIME --report-interval=5 --num-threads=$THREAD run
- MySQL配置文件为:
[mysqld_safe] log-error=/data/mysql/log/mysql.log pid-file=/data/mysql/run/mysqld.pid [client] socket=/data/mysql/run/mysql.sock default-character-set=utf8mb4 [mysqld] basedir=/home/mysql-8.0.17-linux-glibc2.12-x86_64 basedir=/usr/local/mysql tmpdir=/data/mysql/tmp datadir=/data/mysql/data socket=/data/mysql/run/mysql.sock port=3306 user=root default_authentication_plugin=mysql_native_password innodb_page_size=4k max_connections=2000 back_log=2048 performance_schema=OFF max_prepared_stmt_count=128000 file innodb_file_per_table innodb_log_file_size=2048M innodb_log_files_in_group=32 innodb_open_files=10000 table_open_cache_instances=64 buffers innodb_buffer_pool_size=230G innodb_buffer_pool_instances=16 innodb_log_buffer_size=2048M tune sync_binlog=1 innodb_flush_log_at_trx_commit=1 innodb_use_native_aio=1 innodb_spin_wait_delay=180 innodb_sync_spin_loops=25 innodb_flush_method=O_DIRECT innodb_io_capacity=30000 innodb_io_capacity_max=40000 innodb_lru_scan_depth=9000 innodb_page_cleaners=16 innodb_spin_wait_pause_multiplier=25 perf special innodb_flush_neighbors=0 innodb_write_io_threads=24 innodb_read_io_threads=16 innodb_purge_threads=32 sql_mode=STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION,NO_AUTO_VALUE_ON_ZERO,STRICT_ALL_TABLES log-bin=mysql-bin ssl=0 table_open_cache=15000
复现方法
问题复现步骤如下:
- 通过mysqld_safe运行MySQL。
- 在Sysbench服务器上通过测试命令进行读写测试。
- 进行长时间测试观察,测试经过一段时间后,Sysbench返回显示TPS为0,在MySQL服务器上连接MySQL查询测试表内数据,长时间无返回。
问题分析
出现死锁问题时,通过gdb查看MySQL的线程栈信息,绝大部分线程在等待锁。
通过对代码进行分析,Arm属于Relaxed Memory Models,而x86是基于Total Store Ordering(TSO) model的更强保序的模型。
对于以下伪代码:
经过抽象后为如下伪代码:
在x86上不可能出现r1=1,r2=0的情况,但是在Arm上可能出现r1=1并且r2=0的情况,MySQL的Mutex和RWLock都是基于原子操作+无锁算法自行实现的,这个模块的乱序情况就特别突出。对于其他模块/程序,如果临界区是由正确实现的锁保护的就会正常运行,为了保证逻辑正确,需要在Arm版本额外增加内存屏障,额外关注关键字的读写顺序。
MariaDB在2017年测试高通Arm服务器后,使用_atomic系列函数修改了RWLock和Mutex的实现_atomic系列函数,可以保证SC(需指明内存序)并可以跨平台使用,可以保护lock_word、lock->waiters等关键字的读写顺序,解决MySQL死锁问题。
父主题: MySQL