MySQL8.0增加了一个新功能resource group, 可以对不同的用户进行资源控制,例如对用户线程和后台系统线程给予不同的CPU优先级。

用户可以通过SQL接口创建不同的分组,这些分组可以作为sql的hit,也可以动态的绑定过去。本文主要简单介绍下用法,至于底层如何实现的,其实比较简单:创建的分组被存储到系统表中;在linux系统底层通过CPU_SET来绑定CPU,通过setpriority来设置线程的nice值

相关worklog: WL#9467: Resource Groups

创建resource group

首先系统自带两个resource group并且不可被修改

  1. root@(none) 05:54:22>SELECT * FROM INFORMATION_SCHEMA.RESOURCE_GROUPS\G
  2. *************************** 1. row ***************************
  3. RESOURCE_GROUP_NAME: USR_default
  4. RESOURCE_GROUP_TYPE: USER
  5. RESOURCE_GROUP_ENABLED: 1
  6. VCPU_IDS: 0-63
  7. THREAD_PRIORITY: 0
  8. *************************** 2. row ***************************
  9. RESOURCE_GROUP_NAME: SYS_default
  10. RESOURCE_GROUP_TYPE: SYSTEM
  11. RESOURCE_GROUP_ENABLED: 1
  12. VCPU_IDS: 0-63
  13. THREAD_PRIORITY: 0
  14. 2 rows in set (0.00 sec)

如果你想设置thread priority,可能需要使用超级账户来启动Mysqld,这是系统限制,如果以非super账户启动,只能降低而不能提升优先级。在非super启动时,thread_priority会被忽略掉并报一个warning出来。

对于类型为system的系统后台线程,cpu priority只能从-20 ~0,而普通user线程,则在0~19之间,这样就保证了系统线程的优先级肯定比用户线程高。

如果设置不在范围内,就会报错

  1. root@(none) 10:27:09>CREATE RESOURCE GROUP test_user_rg TYPE = USER VCPU = 0-32,48-63 THREAD_PRIORITY = -10;
  2. ERROR 3654 (HY000): Invalid thread priority value -10 for User resource group test_user_rg. Allowed range is [0, 19].
  3. 我们尝试为user类线程创建一个resource group,使用0-32 48-63cpu, 线程优先级为10
  4. root@(none) 10:27:14>CREATE RESOURCE GROUP test_user_rg TYPE = USER VCPU = 0-32,48-63 THREAD_PRIORITY = 10;
  5. Query OK, 0 rows affected (0.01 sec)
  6. root@(none) 10:55:19>SELECT * FROM INFORMATION_SCHEMA.RESOURCE_GROUPS WHERE RESOURCE_GROUP_NAME = 'test_user_rg'\G
  7. *************************** 1. row ***************************
  8. RESOURCE_GROUP_NAME: test_user_rg
  9. RESOURCE_GROUP_TYPE: USER
  10. RESOURCE_GROUP_ENABLED: 1
  11. VCPU_IDS: 0-32,48-63
  12. THREAD_PRIORITY: 10
  13. 1 row in set (0.00 sec)
  14. CREATE/DELETE/ALTER RESOURCE GROUP都需要RESOURCE_GROUP_ADMIN权限,具体的语法见官方文档

使用resource group

创建好后,我们该如何使用resource group呢,主要有两种方式,一种是SET RESOURCE GROUP, 一种是通过SQL HINT的方式,以下是简单的测试:

设置当前session:

  1. root@(none) 11:01:08>SET RESOURCE GROUP test_user_rg;
  2. Query OK, 0 rows affected (0.00 sec)
  3. 也可以指定hint的方式来设置:
  4. root@sb1 11:07:53>select /* + RESOURCE_GROUP(test_user_rg) */ * from sbtest1 where id <10;
  5. 还可以通过thread id来设置其他运行中的session,注意这里的thread id不是show processlist看到的id,而是通过performance_schema.threads表看到的id
  6. xx@performance_schema 11:30:21>SELECT THREAD_ID, TYPE FROM performance_schema.threads WHERE PROCESSLIST_ID = 26\G
  7. *************************** 1. row ***************************
  8. THREAD_ID: 71
  9. TYPE: FOREGROUND
  10. 1 row in set (0.00 sec)
  11. xx@performance_schema 11:30:43>SET RESOURCE GROUP test_user_rg for 71;
  12. Query OK, 0 rows affected (0.00 sec)

如果你想对InnoDB的后台线程来进行设置呢 ? 可以去查看performance_schema.threads表,例如我们对page cleaner进行优先级设置:

  1. xx@performance_schema 11:19:43>CREATE RESOURCE GROUP test_system_rg TYPE = SYSTEM VCPU = 49 THREAD_PRIORITY = -10;
  2. Query OK, 0 rows affected (0.00 sec)
  3. xx@performance_schema 11:24:11>SELECT THREAD_ID, TYPE FROM performance_schema.threads WHERE NAME LIKE '%page_flush_coor%'\G
  4. *************************** 1. row ***************************
  5. THREAD_ID: 13
  6. TYPE: BACKGROUND
  7. 1 row in set (0.00 sec)
  8. xx@performance_schema 11:24:07>SET RESOURCE GROUP test_system_rg for 13;
  9. Query OK, 0 rows affected (0.00 sec)

可以看到,通过resource group,我们可以为任意的线程指定不同的计算资源。在未来我们甚至可以对这一功能进行扩展,例如某个线程的最大iops,读入数据占用buffer pool的百分比,或者对运维程序指定独立的cpu,避免干扰到正常的业务负载等等,还是有不少的想象空间的。