[MySQL 5.7.7] 拆分LOCK_grant读写锁

Lock_grant锁实际上是一个读写锁,每执行一条sql都要读取执行check_grant来检查权限是否匹配,这时候加的是读锁,而读锁是可以并发的。大多数情况下加锁开销是很不明显的,但是在MySQL将大多数只读场景下的锁都消除掉后,LOCK_grant开始变的比较突出了。

5.7里主要消除掉了几种会影响到只读性能的锁:

#为InnoDB表消除THR_LOCK

#MDL LOCK维护改成LOCK FREE的算法

#为AUTO-COMMIT的SELECT缓存Read View来减少trx_sys->mutex冲突

Stewart Smith report了一个Bug#72829 来描述LOCK_grant在power机型的影响,在他的测试中,LOCK_grant去除掉后,居然有50的性能提升。我相信这是和平台相关的。。。因为我的机器上很难达到这样的提升。。。。

我也在bug上跟着吐槽啦,MySQL 5.7.5的只读测试中,LOCK_grant直接排到第一位了:

root@performance_schema 05:37:18>SELECT COUNT_STAR, SUM_TIMER_WAIT, AVG_TIMER_WAIT, EVENT_NAME FROM events_waits_summary_global_by_event_name where COUNT_STAR > 0 and EVENT_NAME like 'wait/synch/%' order by SUM_TIMER_WAIT desc limit 20;
+------------+----------------+----------------+---------------------------------------------------+
| COUNT_STAR | SUM_TIMER_WAIT | AVG_TIMER_WAIT | EVENT_NAME                                        |
+------------+----------------+----------------+---------------------------------------------------+
|   26086077 | 17068952969200 |         654000 | wait/synch/rwlock/sql/LOCK_grant                  |
|   78512461 | 16715117127344 |         212768 | wait/synch/sxlock/innodb/hash_table_locks         |
|  130770402 | 15605301433540 |         119028 | wait/synch/mutex/sql/THD::LOCK_query_plan         |
|   52314260 | 12553580466128 |         239800 | wait/synch/mutex/sql/LOCK_table_cache             |
|   78446571 |  9825008327284 |         125132 | wait/synch/mutex/sql/THD::LOCK_thd_data           |
|   26175928 |  6455036525220 |         246340 | wait/synch/sxlock/innodb/index_tree_rw_lock       |
|   52299088 |  5974745787424 |         114232 | wait/synch/mutex/sql/THD::LOCK_thd_query          |
|       7568 |     1095036672 |         144316 | wait/synch/mutex/innodb/flush_list_mutex          |
|       7656 |      885055584 |         115540 | wait/synch/mutex/innodb/buf_pool_mutex            |
|       7603 |      638888240 |          83712 | wait/synch/mutex/sql/LOCK_global_system_variables |
|        242 |      354649376 |        1465396 | wait/synch/sxlock/innodb/dict_operation_lock      |
|       3445 |      351421232 |         101588 | wait/synch/mutex/innodb/dict_sys_mutex            |
|       1602 |      339106848 |         211460 | wait/synch/mutex/innodb/innobase_share_mutex      |
|       1602 |      321693008 |         200560 | wait/synch/mutex/sql/LOCK_open                    |
|       2672 |      315876768 |         118156 | wait/synch/mutex/sql/LOCK_plugin                  |
|       1050 |      308335712 |         293428 | wait/synch/mutex/sql/LOCK_connection_count        |
|       1602 |      235623120 |         146932 | wait/synch/mutex/innodb/file_format_max_mutex     |
|       1281 |      217084400 |         169168 | wait/synch/mutex/sql/LOCK_thd_list                |
|        983 |      209930512 |         213204 | wait/synch/mutex/sql/LOCK_status                  |
|       1380 |      199285136 |         144316 | wait/synch/mutex/sql/LOCK_user_conn               |
+------------+----------------+----------------+---------------------------------------------------+

由于只加的LOCK_grant读锁,该锁的并发开销主要来自Cache失效以及原子操作。

 

 

解决:

 

解法也比较简单:创建32个读写锁,当需要加读锁时,根据当前线程的thread_id,模到对应的读写锁对象,加上读锁; 当需要加写锁时,则把32个读写锁对象的写锁都加上。

 

显然加写锁的代价提升了,但是谁会没事儿把类似GRANT语句作为主要的负载呢。

 

在我的优化版本的5.6分支上,加了该改进后,可以将只读QPS从10w推进到10.5w QPS

 

Patch:  https://github.com/mysql/mysql-server/commit/75fd4b3defc68176e3f38407fe9f6aa538424562

时间: 2025-01-20 18:27:42

[MySQL 5.7.7] 拆分LOCK_grant读写锁的相关文章

PHP程序中的文件锁、互斥锁、读写锁使用技巧解析_php技巧

文件锁全名叫 advisory file lock, 书中有提及. 这类锁比较常见,例如 mysql, php-fpm 启动之后都会有一个pid文件记录了进程id,这个文件就是文件锁. 这个锁可以防止重复运行一个进程,例如在使用crontab时,限定每一分钟执行一个任务,但这个进程运行时间可能超过一分钟,如果不用进程锁解决冲突的话两个进程一起执行就会有问题. 使用PID文件锁还有一个好处,方便进程向自己发停止或者重启信号.例如重启php-fpm的命令为 kill -USR2 `cat /usr/

非一致性内存访问的读写锁

原文地址,译文地址,译者: 李杰聪,校对:郑旭东 原文作者: Irina Calciu         Brown University        irina@cs.brown.edu Dave Dice          Oracle Labs             dave.dice@oracle.com Yossi Lev           Oracle Labs             yossi.lev@oracle.com Victor Luchangco    Oracle

读写锁和缓存类实现

提高性能 读写锁:分为读锁和写锁,多个读锁不互斥,读锁与写锁互斥,写锁与写锁互斥,这是由JVM控制的,我们只需要上好相应的锁即可.如果代码只读数据,可以很多人同时读,但不能同时写,那就上读锁:如果代码修改数据,只能有一个人在写,且不能同时读取,那就上写锁.总之,读的时候上读锁,写的时候上写锁. import java.util.Random; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.

Java中的读/写锁

原文链接 作者:Jakob Jenkov 译者:微凉 校对:丁一 相比Java中的锁(Locks in Java)里Lock实现,读写锁更复杂一些.假设你的程序中涉及到对一些共享资源的读和写操作,且写操作没有读操作那么频繁.在没有写操作的时候,两个线程同时读一个资源没有任何问题,所以应该允许多个线程能在同时读取共享资源.但是如果有一个线程想去写这些共享资源,就不应该再有其它线程对该资源进行读或写(译者注:也就是说:读-读能共存,读-写不能共存,写-写不能共存).这就需要一个读/写锁来解决这个问题

php的session读写锁例子

先看一个例子,功能: 1.点击页面中一个按钮,ajax执行php,php中用session记录执行到哪一步. 2.使用ajax轮询另一个php,获取session中数据,输出执行到哪一步. session.html 调用php执行,并输出执行到第几步 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

UNIX环境高级编程:线程同步之读写锁及属性

读写锁和互斥量(互斥锁)很类似,是另一种线程同步机制,但不属于POSIX标准,可以用来同步同一进程中的各个线程.当然如果一个读写锁存放在多个进程共享的某个内存区中,那么还可以用来进行进程间的同步, 互斥量要么是锁住状态要么是不加锁状态,而且一次只有一个线程可以对其加锁.读写锁可以有三种状态:读模式下的加锁状态,写模式下的加锁状态,不加锁状态. 一次只有一个线程可以占有写模式的读写锁,但是多个线程可以同时占有读模式的读写锁. 当读写锁是写加锁状态时,在这个锁被解锁之前,所有试图对这个锁加锁(读或写

并发数据结构: .NET Framework中提供的读写锁

在多线程编程时,开发人员经常会遭遇多个线程读写某个资源的情况.这就需要进行线程同步来保证 线程安全.一般情况下,我们的同步措施是使用锁机制.但是,假如线程只对资源进行读取操作,那么根 本不需要使用锁:反之,假如线程只对资源进行写入操作,则应当使用互斥锁(比如使用 Monitor 类等) .还有一种情况,就是存在多个线程对资源进行读取操作,同时每次只有一个线程对资源进行独占写入操 作.这正是本文主题--读写锁的用武之地.ReaderWriterLock 类 .NET Framework BCL 在

可扩展的快速读写锁

原文链接(需翻墙) ,译文链接,  译者:中麦-张军 ,校对:梁海舰 介绍 读写锁是一种允许多个线程并发地访问一个或一组资源的并发结构,这意味着在实践中如果你有一个或一组几乎是以只读方式访问时,可以考虑使用读写锁(后文统称为RWLocks)来保护它们: Java在java.util.concurrent.locks.ReentrantReadWriteLock中提供了一个很好的RWLocks,是由Doug Lea创建,它有很多特性如:重入,公平锁,锁降级等: 如果你是一个无法摆脱PThreads

Java多线程编程中线程锁与读写锁的使用示例_java

线程锁LockLock  相当于 当前对象的 Synchronized import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /* * Lock lock = new ReentrantLock(); * lock.lock(); lock.unLock(); * 类似于 synchronized,但不能与synchronized 混用 */ public class Lo