<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                ## 背景 系統為了加速對象的訪問,通常都會增加一層緩存,以緩解下一層IO的瓶頸,OS的page cache和數據庫的buffer pool都基于此。 但對象的刪除,如果同步清理對象的緩存的話,不僅大大增加了延時,同時可能因為緩存過大導致IO blooding。所以針對緩存的清理,都會采用lazy drop的優化,下面我們就來對比下percona和官方針對drop table的lazy drop 優化。 假設使用`innodb_file_per_table`為表創建獨立的tablespace,在業務處理過程中,有刪除表的動作,會發現`drop table`操作不僅僅持續比較長,而且在刪除過程中,實例的QPS也有所降低,主要是因為在清理buffer pool過程中,持有buffer pool的mutex導致,percona server在5.1版本開始引入?`lazy drop table`來消除drop table過程中帶來的影響,但也并沒有完全消除,MySQL 官方在5.5.23以后也引入了?`lazy drop table`?來優化drop 操作,下面我們就來對比一下這兩種方式的差異。 值得一提的是:在日常的運維中,drop的操作并非核心需求,我們也都建議DBA在 off-peak 時間去做這樣的操作。 ## 同步模式 在討論lazy模式之前,我們先看看MySQL在5.5.23版本之前的處理方式即同步模式: 當要drop table的時候,會在整個操作過程中持有buffer pool的mutex,然后掃描兩次LRU鏈表,把屬于這個table的page失效掉,buffer pool中page的個數越多,持有mutex時間就會越長,對在線業務的影響也就越明顯。 簡短看下核心處理代碼: ~~~ fil_delete_tablespace buf_LRU_invalidate_tablespace( ulint id) /*!< in: space id */ { ulint i;() for (i = 0; i < srv_buf_pool_instances; i++) { buf_pool_t* buf_pool; buf_pool = buf_pool_from_array(i); buf_LRU_drop_page_hash_for_tablespace(buf_pool, id); buf_LRU_invalidate_tablespace_buf_pool_instance(buf_pool, id); } } ~~~ 1. `buf_LRU_drop_page_hash_for_tablespace`會掃描一次LRU list,需要從adaptive hash中刪除對要刪除的表的page的引用; 2. `buf_LRU_invalidate_tablespace_buf_pool_instance`會掃描一次LRU list: 如果是dirty block,需要從flush list remove掉,然后從page hash中刪除,最后從LRU list中刪除。 可以看到,這種同步清理掉內存結構的操作,在業務高峰期,對系統的吞吐能力會產生不小的波動。 ## Percona lazy模式 percona實現了一個`lazy drop table`模式,使用參數控制: ~~~ mysql> show global variables like '%lazy%'; +------------------------+-------+ | Variable_name | Value | +------------------------+-------+ | innodb_lazy_drop_table | 0 | +------------------------+-------+ ~~~ 其處理drop table的過程如下: 1. 持有buffer pool的lru list mutex鎖; 2. 開始掃描LRU list中的page; 1. 如果這個page屬于要刪除的table的,就設置一個flag,表示這個page所在的表正在被刪除 3. 釋放lru list mutex鎖; 4. 持有一個adaptive hash index的shared latch; 5. 開始掃描buffer pool中的block; 6. 如果這個page被AHI索引; 1. 釋放AHI 鎖 2. 持有page的exclusive lock 3. 刪除AHI中索引這個page的entries 4. 釋放page鎖 5. 持有AHI的shared lock進行下一個page的判斷 相比較同步模式,Percona的lazy drop table在掃描lru list過程中,只set了一個flag,隨后在lru正常的淘汰過程中或者flush dirty block的時候如果碰到這中block,直接就做刪除處理了,這也就是lazy的核心。 其核心代碼如下: ~~~ buf_LRU_mark_space_was_deleted( ulint id) /*!< in: space id */ { ulint i; /* 這一部分代碼就是持有lru鏈表mutex,進行第一步,第二步操作。*/ for (i = 0; i < srv_buf_pool_instances; i++) { mutex_enter(&buf_pool->LRU_list_mutex); while (bpage != NULL) { if (buf_page_get_space(bpage) == id) bpage->space_was_being_deleted = TRUE; } mutex_exit(&buf_pool->LRU_list_mutex); /* 這里掃描的是buf_pool中的chunk,也就是啟動的時候,根據buffer pool的大小預分配好的blocks,不能更改, 所以并不需要持有buffer pool mutex,或者lru list mutex。 */ btr_search_s_lock_all(); chunk = buf_pool->chunks; for (j = buf_pool->n_chunks; j--; chunk++) { buf_block_t* block = chunk->blocks; for (k = chunk->size; k--; block++) { if (buf_block_get_state(block) != BUF_BLOCK_FILE_PAGE || !block->index || buf_page_get_space(&block->page) != id) { continue; } /* 這里把AHI的鎖釋放掉了,但在btr_search_drop_page_hash_index中會持有AHI的lock對AHI結構進行變更。*/ btr_search_s_unlock_all(); rw_lock_x_lock(&block->lock); btr_search_drop_page_hash_index(block, NULL); rw_lock_x_unlock(&block->lock); btr_search_s_lock_all(); } } btr_search_s_unlock_all(); } } ~~~ ## MySQL lazy模式 在MySQL 5.5.23以后的版本,也實現了一個`lazy drop table`的方式,和percona的方式有所區別,下面來看一下具體的過程: 1. 持有`buffer pool mutex`; 2. 持有buffer pool中的`flush list mutex`; 3. 開始掃描flush list; 1. 如果dirty page屬于drop table,那么就直接從flush list中remove掉; 2. 如果刪除的page個數超過了`#define BUF_LRU_DROP_SEARCH_SIZE 1024`?這個數目的話,釋放`buffer pool mutex`,`flush list mutex`,釋放cpu資源; * 釋放`flush list mutex`; * 釋放`buffer pool mutex`; * 強制通過pthread_yield進行一次OS context switch,釋放剩余的cpu時間片; 3. 重新持有`buffer pool mutex`; 4. 重新持有`flush list mutext`; 4. 釋放`flush list mutex`; 5. 釋放`buffer pool mutex`; 相比較percona的lazy方式,這里掃描的是dirty block,在LRU list中進行淘汰的時候,就不再判斷當前fil_space是否存在的問題了,因為不牽涉到寫入。 這里邊有兩個相關的bug,[bug#51325](http://bugs.mysql.com/bug.php?id=51325)、[bug#64284](http://bugs.mysql.com/bug.php?id=64284),有興趣可以參考一下。 其核心的代碼如下: ~~~ buf_LRU_flush_or_remove_pages(id, BUF_REMOVE_FLUSH_NO_WRITE, 0); buf_pool_mutex_enter(buf_pool); err = buf_flush_or_remove_pages(buf_pool, id, flush, trx); ...... buf_pool_mutex_exit(buf_pool); /* BUF_REMOVE_FLUSH_NO_WRITE:意思表示,只對dirty block進行remove操作,不做寫入。 ~~~ ## 對比 從上面的percona和oracle的MySQL版本比較來看,percona是持有了`LRU list mutex`和`AHI lock`,而MySQL官方版本是持有了`buffer pool mutex`和`flush list mutex`,從鎖的保護范圍來看,`buffer pool mutex`直觀上瓶頸會比較明顯,但具體還要跟表的大小、dirty block的比例來看,如果dirty block比較少的話,官方版本并不掃描LRU list,所以可能持有的時間并不會太久。 Percona的開發人員還針對這兩個不同版本進行了Benchmarks, 大家可以看下他們測試出來的結果: 這個圖是 MySQL 官方版本測試在系統壓力下,進行頻繁drop table的系統抖動: ![](https://box.kancloud.cn/2016-02-18_56c56b7bc3ddf.png) 這個圖是 Percona 版本測試在系統壓力下,進行頻繁drop table的系統抖動: ![](https://box.kancloud.cn/2016-02-18_56c56b7c151ea.png) 但對于這樣的測試,小編想說,哪個DBA/開發人員這么變態,要這么頻繁的drop table -_-||
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看