MySQL优化:可配置选项的WAIT_FOR_READ


innodb层使用一个常量WAIT_FOR_READ来控制当需要等待从磁盘读取数据时,需要等待的时间,其默认值在5.55.1的版本中都是5000us5ms),而现在比较牛的存储设备(flush/ssd)一般能在100us内完成读操作,BUG64258认为这个值应该是个可配置的选项,通过设定符合的值以符合我们的硬件设备性能。

这是个static静态变量,在文件buf0buf.c中会用到WAIT_FOR_READ:

  1. buf/buf0buf.c:280:staticconst int WAIT_FOR_READ = 5000;  
  2. buf/buf0buf.c:2091: os_thread_sleep(WAIT_FOR_READ);  
  3. buf/buf0buf.c:2632: os_thread_sleep(WAIT_FOR_READ);  
  4. buf/buf0buf.c:2880: os_thread_sleep(WAIT_FOR_READ);  

在两个函数buf_page_get_genbuf_page_get_zip会被调用到,这里我们只考虑前者,看看在什么情况下会进入sleep状态

这是个通用的获取数据库page的函数,比较冗长,在经过检查bufferpool、异步请求磁盘页以及对压缩页的处理等一大堆代码后,调用如下代码段:

  1. 2858     switch (rw_latch) {  
  2. 2859     case RW_NO_LATCH:  
  3. 2860         if (must_read) {  
  4. 2861             /* Let us wait until the read operation 
  5. 2862             completes */  
  6. 2863   
  7. 2864             if (innobase_get_slow_log() && trx && trx->take_stats)  
  8. 2865             {  
  9. 2866                 ut_usectime(&sec, &ms);  
  10. 2867                 start_time = (ib_uint64_t)sec * 1000000 + ms;  
  11. 2868             } else {  
  12. 2869                 start_time = 0;  
  13. 2870             }  
  14. 2871             for (;;) {  
  15. 2872                 enum buf_io_fix io_fix;  
  16. 2873   
  17. 2874                 mutex_enter(&block->mutex);  
  18. 2875                 io_fix = buf_block_get_io_fix(block);  
  19. 2876                 mutex_exit(&block->mutex);  
  20. 2877   
  21. 2878                 if (io_fix == BUF_IO_READ) {  
  22. 2879   
  23. 2880                     os_thread_sleep(WAIT_FOR_READ);  
  24. 2881                 } else {  
  25. 2882                     break;  
  26. 2883                 }  
  27. 2884             }  
  28. 2885             if (innobase_get_slow_log() && trx && trx->take_stats && start_time)  
  29. 2886             {  
  30. 2887                 ut_usectime(&sec, &ms);  
  31. 2888                 finish_time = (ib_uint64_t)sec * 1000000 + ms;  
  32. 2889                 trx->io_reads_wait_timer += (ulint)(finish_time - start_time);  
  33. 2890             }  
  34. 2891         }  

io_fix的含义不是很了解,看看注释:

  1. 56/** Flags for io_fix types */  
  2. 57enum buf_io_fix {  
  3. 58 BUF_IO_NONE = 0, /**< no pending I/O */  
  4. 59 BUF_IO_READ, /**< read pending */  
  5. 60 BUF_IO_WRITE /**< write pending */  
  6. 61};  

其中这里用到的是BUF_IO_READ,应该是read pending,可能是正在等待磁盘读的一个IO状态标识。

从代码里,我们可以看到,当当前的block->page->io_fixBUF_IO_READ时,会不停的在一个for(;;)里循环,每次检查后,会sleep WAIT_FOR_READ us后再次检查。如果这是一个高速存储设备,sleep的时间太长显然是不合理的。


以下是一个简单的patch,增加了一个选项innobase_wait_for_read,来���制sleep的时间,基于percona5.5.18

手头有ssd测试环境的同学,帮忙测试看看有木有效果...

  1. diff -ur Percona-Server-5.5.18.stock/storage/innobase/buf/buf0buf.c Percona-Server-5.5.18.sleep/storage/innobase/buf/buf0buf.c  
  2. --- Percona-Server-5.5.18.stock/storage/innobase/buf/buf0buf.c  2012-01-07 16:38:37.000000000 +0800  
  3. +++ Percona-Server-5.5.18.sleep/storage/innobase/buf/buf0buf.c  2012-02-17 16:22:05.000000000 +0800  
  4. @@ -57,6 +57,8 @@  
  5.  /* prototypes for new functions added to ha_innodb.cc */  
  6.  trx_t* innobase_get_trx();  
  7.    
  8. +extern innobase_wait_for_read;  
  9. +  
  10.  inline void _increment_page_get_statistics(buf_block_t* block, trx_t* trx)  
  11.  {  
  12.     ulint           block_hash;  
  13. @@ -276,8 +278,6 @@  
  14.  */  
  15.    
  16.  #ifndef UNIV_HOTBACKUP   
  17. -/** Value in microseconds */  
  18. -static const int WAIT_FOR_READ = 5000;  
  19.  /** Number of attemtps made to read in a page in the buffer pool */  
  20.  static const ulint BUF_PAGE_READ_MAX_RETRIES = 100;  
  21.    
  22. @@ -2088,7 +2088,7 @@  
  23.    
  24.             if (io_fix == BUF_IO_READ) {  
  25.    
  26. -               os_thread_sleep(WAIT_FOR_READ);  
  27. +               os_thread_sleep(innobase_wait_for_read);  
  28.             } else {  
  29.                 break;  
  30.             }     
  31. @@ -2629,7 +2629,7 @@  
  32.             Try again later. */  
  33.             //buf_pool_mutex_exit(buf_pool);   
  34.             mutex_exit(block_mutex);  
  35. -           os_thread_sleep(WAIT_FOR_READ);  
  36. +           os_thread_sleep(innobase_wait_for_read);  
  37.    
  38.             goto loop;  
  39.         }     
  40. @@ -2877,7 +2877,7 @@  
  41.    
  42.                 if (io_fix == BUF_IO_READ) {  
  43.    
  44. -                   os_thread_sleep(WAIT_FOR_READ);  
  45. +                   os_thread_sleep(innobase_wait_for_read);  
  46.                 } else {  
  47.                     break;  
  48.                 }  
  49.   
  50. diff -ur Percona-Server-5.5.18.stock/storage/innobase/handler/ha_innodb.cc Percona-Server-5.5.18.sleep/storage/innobase/handler/ha_innodb.cc  
  51. --- Percona-Server-5.5.18.stock/storage/innobase/handler/ha_innodb.cc   2012-01-07 16:38:37.000000000 +0800  
  52. +++ Percona-Server-5.5.18.sleep/storage/innobase/handler/ha_innodb.cc   2012-02-17 16:33:46.000000000 +0800  
  53. @@ -198,6 +198,7 @@  
  54.  static my_bool innobase_buffer_pool_shm_checksum   = TRUE;  
  55.  static uint    innobase_buffer_pool_shm_key        = 0;  
  56.   
  57. +ulong innobase_wait_for_read = 0;  
  58.   
  59.  static char*   internal_innobase_data_file_path    = NULL;  
  60.   
  61. @@ -12098,6 +12099,11 @@  
  62.  //  " or 2 (write at commit, flush once per second).",   
  63.  //  NULL, NULL, 1, 0, 2, 0);   
  64.   
  65. +MYSQL_SYSVAR_ULONG(wait_for_read, innobase_wait_for_read,  
  66. +  PLUGIN_VAR_OPCMDARG,  
  67. +  "set a value to decide how long when read page operation need to sleep",  
  68. +  NULL, NULL, 5000, 0, 5000, 0);  
  69. +  
  70.  static MYSQL_SYSVAR_BOOL(use_global_flush_log_at_trx_commit, srv_use_global_flush_log_at_trx_commit,  
  71.    PLUGIN_VAR_NOCMDARG,  
  72.    "Use global innodb_flush_log_at_trx_commit value. (default: ON).",  
  73. @@ -12656,6 +12662,7 @@  
  74.    MYSQL_SYSVAR(corrupt_table_action),  
  75.    MYSQL_SYSVAR(lazy_drop_table),  
  76.    MYSQL_SYSVAR(fake_changes),  
  77. +  MYSQL_SYSVAR(wait_for_read),  
  78.    NULL  
  79.  };  

相关内容