---
title: MySQL因ARM弱内存序读写死锁问题说明
description: "使用Sysbench对MySQL 5.7社区版进行读写测试，在测试一段时间后，MySQL 5.7出现死锁现象，导致测试停止。"
url: https://www.hikunpeng.com/document/detail/zh/kunpengdbs/ecosystemEnable/databasepg/kunpengdbsolution_12_0019.html
sourcePath: /source/zh/kunpengdbs/ecosystemEnable/databasepg/kunpengdbsolution_12_0019.html
indexId: d7fb47f60049a003804da668f0b82d4680ae57f9a6ee953120222ce8c8040d3479
---
# 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死锁问题。


#### 结论

- 当前只有  MariaDB官方(https://mariadb.com/resources/blog/mariadb-server-102-now-available-qualcomm-centriqtm-2400-server-processor)
支持ARM服务器
- MySQL 8.0版本在  官方文档(https://www.mysql.com/support/supportedplatforms/database.html)
中已明确说明支持ARM服务器
