中文
注册
我要评分
文档获取效率
文档正确性
内容完整性
文档易理解
在线提单
论坛求助

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)

  • 数据集

    测试数据库包含64个表,每张表包含10000000行数据。

  • 测试脚本

    使用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

复现方法

问题复现步骤如下:

  1. 通过mysqld_safe运行MySQL。
  2. 在Sysbench服务器上通过测试命令进行读写测试。
  3. 进行长时间测试观察,测试经过一段时间后,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死锁问题。

结论