天天看點

MySQL 5.7: Innodb 事務子系統優化

mysql5.7 : innodb 事務子系統優化

本文總體介紹了幾個和事務子系統相關的worklog以及其代碼實作。這部分代碼值得細讀,因為他們是5.7 innodb比較核心的改動,極大的提升了隻讀場景下的性能。

這個worklog包含幾點變化:

第一,無需顯示的開啟隻讀事務,所有的事務開始預設為隻讀事務,當遇到讀寫sql時,自動加入讀寫清單。

第二,隻讀事務不為其配置設定事務id,是以如果show engine innodb status時看到大量事務的id表現的很怪異時(非常大的整數值),不要覺得奇怪。

該改進帶來的最大的好處是你無需修改你的業務sql。其實這才是使用者能接受的特性,如果沒有量級别的提升,誰會願意去改代碼呢?

不過顯而易見的,這個優化也帶了某些 運維的‘退化’,例如你再也無法從show engine innodb status中發現一個活躍的長時間不送出的隻讀事務(例如:begin;select;select…),你需要去查詢innodb_trx表來獲得這些資訊。

我們以一個典型的例子來開啟這個話題,首先準備一個簡單的表。隔離級别為read-commit

create table t1 (a int primary key, b int);

insert into t1 values (1,rand()*100),(2,rand()*100);

begin;

以begin顯式開啟一個事務;

b) select * from t1;

配置設定一個事務句柄:

ha_innobase::open ha_innobase::info_low update_thd check_trx_exists innobase_trx_allocate trx_allocate_for_mysql

新配置設定的事務句柄會加入到trx_sys->mysql_trx_list,并重複使用。

開始一個隻讀事務,開啟的事務,不配置設定事務id, 不配置設定復原段

row_search_mvcc->trx_start_if_not_started->trx_start_low

assign read view

row_search_mvcc trx_assign_read_view mvcc::view_open

配置設定的read view會拷貝目前的活躍事務id,設定最高和最低可見事務id,然後加入到活躍事務的read view連結清單上(mvcc::m_views)

c) update t1 set b=b+1 where a=2;

lock_table trx_set_rw_mode

将事務轉換成讀寫事務模式,配置設定復原段,配置設定事務id。加入讀寫事務連結清單(trx_sys->rw_trx_ids, trx_sys->rw_trx_set, trx_sys->rw_trx_list)。

d) commit; 事務送出

代碼:

<a href="http://bazaar.launchpad.net/~mysql/mysql-server/5.7/revision/5209">http://bazaar.launchpad.net/~mysql/mysql-server/5.7/revision/5209</a>

在該worklog種優化了read view的建立,對mvcc控制視圖部分的代碼進行了重構。

具體包括以下幾個方面:

在之前版本中,read view的建立的複雜度為o(n),因為需要掃描讀寫事務連結清單;

現在建立一個read view 需要以下幾步:

step 1:

                view-&gt;prepare(trx-&gt;id);

拷貝事務id(不包含自己的事務id),相當于做一個目前活躍讀寫事務的快照存放在視圖中,直接使用memcpy的方式 (copy_trx_ids(trx_sys-&gt;rw_trx_ids)),這一點和percona的優化是一樣的。

設定m_low_limit_no ,m_low_limit_id

step 2:

                view-&gt;complete();

設定視圖的m_up_limit_id,表示所有小于這個值的修改都可見

step 3:

                ut_list_add_first(m_views, view);

将視圖加入到活躍視圖連結清單中。

b)  在之前版本中是在持有trx_sys mutex時建立的read view。

為了降低配置設定/釋放read view的開銷,維護了兩個read view連結清單,一個用于放目前活躍的視圖連結清單,一個用于放空閑的、可配置設定的視圖連結清單。

當系統啟動時,會初始化一定數量的read view放到空閑連結清單上。

percona實作了類似的方案,不同的是percona的read view在事務完成後不是放到空閑連結清單,而是下次繼續重用(但從活躍連結清單移除,不管是否是讀寫事務)

c) 對于autocommit的隻讀事務,即時目前沒有活躍事務,也可能因為建立read view ,而大量别的線程在釋放read view,導緻trx_sys mutex沖突。

針對該問題,實際上我已經在博文http://mysqllover.com/?p=1087中描述過了,對于自動送出的查詢,在關閉read view時是不從視圖連結清單上移除的,在再次開啟事務重用該read view時,如果這期間沒有讀寫事務,都無需重新初始化read view,直接使用即可。 是以如果一台執行個體上的都是自動送出的隻讀事務,完全可以避免trx_sys mutex的開銷。

d) 需要持有trx_sys mutex來周遊rw_trx_list,以判斷更改是否可見,或者根據事務id擷取事務對象trx_t

由于已經儲存了事務id的快照,是以直接根據二分查找查找有序數組即可,無需周遊讀寫事務連結清單

參考函數readview::changes_visible

trx_sys_t新增成員rw_trx_set,用于維護從trx_id到trx_t的映射。這樣可以根據事務id快速找到對應的事務對象而無需掃描事務連結清單。參考函數trx_get_rw_trx_by_id

主要更改:

<a href="http://bazaar.launchpad.net/~mysql/mysql-server/5.7/revision/6203">http://bazaar.launchpad.net/~mysql/mysql-server/5.7/revision/6203</a>

<a href="http://bazaar.launchpad.net/~mysql/mysql-server/5.7/revision/6204">http://bazaar.launchpad.net/~mysql/mysql-server/5.7/revision/6204</a>

<a href="http://bazaar.launchpad.net/~mysql/mysql-server/5.7/revision/6205">http://bazaar.launchpad.net/~mysql/mysql-server/5.7/revision/6205</a>

<a href="http://bazaar.launchpad.net/~mysql/mysql-server/5.7/revision/6224">http://bazaar.launchpad.net/~mysql/mysql-server/5.7/revision/6224</a>

<a href="http://bazaar.launchpad.net/~mysql/mysql-server/5.7/revision/6236">http://bazaar.launchpad.net/~mysql/mysql-server/5.7/revision/6236</a>

在完成上述修改後,無需再維持ro_trx_list了,因為所有事務預設都被當做隻讀事務,這個連結清單開銷完全可以忽略掉的。

<a href="http://bazaar.launchpad.net/~mysql/mysql-server/5.7/revision/6788">http://bazaar.launchpad.net/~mysql/mysql-server/5.7/revision/6788</a>

該worklog主要實作了隐式鎖向現式鎖轉換的一個優化點。在擷取活躍事務對象時,無需持有lock_sys mutex鎖。

在連續記憶體中預配置設定事務對象,保持記憶體的連續性有利于編譯器或者cpu做出某些優化,例如記憶體預取之類的(不是很了解這一塊,不展開叙述)

為了實作事務對象記憶體配置設定,回收等,在底層分裝了一些pool類,事務對象實際上被管理在一個池結構中。

後面我再單獨寫一篇部落格來介紹新加的這些底層結構。

在啟動時,初始化trx_pools (trx_pool_init),初始化時配置設定4m記憶體,在shutdown時釋放(trx_pool_close())

為了管理事務對象池,設計了三個類:trxfactory,trxpoollock,trxpoolmanagerlock

擷取事務對象:trx_create_low —-&gt; trx_pools-&gt;get()

釋放事務對象:trx_free —-&gt;  trx_pools-&gt;free(trx)

<a href="http://dev.mysql.com/worklog/task/?id=6906">http://dev.mysql.com/worklog/task/?id=6906</a>

相關代碼:

<a href="http://bazaar.launchpad.net/~mysql/mysql-server/5.7/revision/5744">http://bazaar.launchpad.net/~mysql/mysql-server/5.7/revision/5744</a>

<a href="http://bazaar.launchpad.net/~mysql/mysql-server/5.7/revision/5750">http://bazaar.launchpad.net/~mysql/mysql-server/5.7/revision/5750</a>

http://bazaar.launchpad.net/~mysql/mysql-server/5.7/revision/5753

<a href="http://bazaar.launchpad.net/~mysql/mysql-server/5.7/revision/5756">http://bazaar.launchpad.net/~mysql/mysql-server/5.7/revision/5756</a>

<a href="http://bazaar.launchpad.net/~mysql/mysql-server/5.7/revision/5786">http://bazaar.launchpad.net/~mysql/mysql-server/5.7/revision/5786</a>

繼續閱讀