天天看點

MySQL核心月報 2014.12-MySQL· 捉蟲動态·Opened tables block read only

<b>背景</b>

mysql通過read_only參數來設定db隻讀,這樣mysql執行個體就可以作為slave角色,隻應用binlog,不接受使用者修改資料。這樣就可以保護master-slave結構中的資料一緻性,防止雙寫風險。

<b>global read_only的實作方式</b>

mysql5.5版本通過三個步驟來設定read_only:

<dl></dl>

<dd>步驟1:擷取global read lock,阻塞所有的寫入請求</dd>

<dd>步驟2:flush opened table cache,阻塞所有的顯示讀寫鎖</dd>

<dd>步驟3:擷取commit lock,阻塞commit寫入binlog</dd>

<dd>步驟4:設定read_only=1</dd>

<dd>步驟5:釋放global read lock和commit lock。</dd>

mysql 5.5的版本,通過這5步完成設定read only的功能。

<b>bug描述</b>

比如如下場景:

先執行session1,然後session2會一直被session1阻塞。

原因是:session1的顯示鎖,雖然與步驟1中的global read lock相容, 但session2因為session1一直持有讀鎖并保持t表opened而被阻塞。

但是,實際上,顯示的讀寫鎖産生的opened table并不影響read_only的功能,這裡的flush tables也并非是必須的。

這也是我們的實際應用環境中,因主備切換而要在master執行個體上設定read_only的時候,經常被大查詢所阻塞的原因。

<b>修複方法</b>

修複方法非常簡單,隻需要把步驟2删除即可,不影響read only的語義。

官方在mysql 5.6.5中進行了修複:

if tables were locked by lock tables ... read in another session, set global read_only = 1 failed to complete. (bug #57612, bug #11764747)

<b>rds功能增強</b>

設定read_only阻塞使用者寫入,但隻能阻塞普通使用者的更新,rds為了最大可能的保護資料一緻性,增強了read_only功能,通過設定super read only,阻塞除了slave線程以為的所有使用者的寫入,包括super使用者。

繼續閱讀