<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之旅 廣告
                ## 背景 并行復制可以大大提高備庫的 binlog 應用速度,內核月報也多次對并行復制特性進行介紹,感興趣的朋友可以回顧下:[5.6 并行復制實現分析](http://mysql.taobao.org/monthly/2015/08/09/)、[5.6 并行復制恢復實現](http://mysql.taobao.org/monthly/2015/09/07/)?和?[5.6并行復制事件分發機制](http://mysql.taobao.org/monthly/2015/09/09/)。 在早期的內核月報,有一篇?[并行復制外建約束問題](http://mysql.taobao.org/index.php?title=MySQL%E5%86%85%E6%A0%B8%E6%9C%88%E6%8A%A5_2014.12#MySQL.C2.B7.E3.80.80.E6.80.A7.E8.83.BD.E4.BC.98.E5.8C.96.C2.B7.E5.B9.B6.E8.A1.8C.E5.A4.8D.E5.88.B6.E5.A4.96.E5.BB.BA.E7.BA.A6.E6.9D.9F.E9.97.AE.E9.A2.98),介紹阿里在 5.5 版本中自己實現并行復制時遇到的外鍵約束問題,本文接著前作繼續介紹并行復制外鍵約束問題,這次場景不一樣,并且目前官方 5.6 最新版本(5.6.30)中也有這個問題。 ## 問題描述 一般情況的復制是 A->B 這樣一主一備,本文要描述的場景是 A->B->C 這樣一主兩備,并且備庫級聯,其中備庫 C 開啟了并行復制,B 可以串行也可以并行,binlog_fomat 都是 row。 在主庫A上執行如下語句: ~~~ CREATE DATABASE db1; CREATE DATABASE db2; USE db1; CREATE TABLE `parent` ( `id` int(11) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB; USE db2; CREATE TABLE `child` ( `id` int(11) DEFAULT NULL, `parent_id` int(11) DEFAULT NULL, KEY `par_ind` (`parent_id`), CONSTRAINT `child_ibfk_1` FOREIGN KEY (`parent_id`) REFERENCES `db1`.`parent` (`id`) ON DELETE CASCADE ) ENGINE=InnoDB; INSERT INTO db1.parent VALUES(1); INSERT INTO db2.child VALUES(1, 1); ~~~ 備庫 C 上會報錯如下,非常明顯的一個外鍵約束的錯誤: ~~~ Last_SQL_Errno: 1452 Last_SQL_Error: Worker 7 failed executing transaction '' at master log mysqld-bin.000001, end_log_pos 1008; Could not execute Write_rows event on table db2.child; Cannot add or update a child row: a foreign key constraint fails (`db2`.`child`, CONSTRAINT `child_ibfk_1` FOREIGN KEY (`parent_id`) REFERENCES `db1`.`parent` (`id`) ON DELETE CASCADE), Error_code: 1452; handler error HA_ERR_NO_REFERENCED_ROW; the event's master log mysqld-bin.000001, end_log_pos 1008 ~~~ ## 問題分析 如前文[并行復制外建約束問題](http://mysql.taobao.org/index.php?title=MySQL%E5%86%85%E6%A0%B8%E6%9C%88%E6%8A%A5_2014.12#MySQL.C2.B7.E3.80.80.E6.80.A7.E8.83.BD.E4.BC.98.E5.8C.96.C2.B7.E5.B9.B6.E8.A1.8C.E5.A4.8D.E5.88.B6.E5.A4.96.E5.BB.BA.E7.BA.A6.E6.9D.9F.E9.97.AE.E9.A2.98)?所述,5.6 并行復制已經解了外鍵問題,遇到被外鍵約束的表,會先切為串行,當前事務執行完成后,再開始并行,為什么還會出問題呢?分析這個問題前,我們先來看下,5.6 是怎么解決外鍵約束問題的。 5.6 并行復制是基于db進行分發的,不同的db分發到不同的 worker 線程,對 row 格式的 binlog,分發信息是體現在 table_map event 中的。5.6 對 table_map 中加了一個專門的 flag?`TM_REFERRED_FK_DB_F`,表示當前表被外鍵約束(具體參考commit?[299ccba1e145c29ed3c242c152ced4cc345328b7](https://github.com/mysql/mysql-server/commit/299ccba1e145c29ed3c242c152ced4cc345328b7)),這樣備庫分發線程(Coordinator)在遇到有這種標志的 table_map,就切換為串行,具體邏輯參考`Log_event::get_slave_worker()`?和`apply_event_and_update_pos()`。 這個機制是沒問題的,如果 flag 能從 A 傳到 B 再傳到 C,就不會出現這個問題,現在問題的出現是因為備庫 B 執行完父表(parent)的更新后,寫 binlog 時 flag 沒寫進去,導致 C 在并行模式下執行 parent 表更新時,沒有切換到串行模式,和 child 表的更新同時在跑,如果執行 child 表更新的 worker 先做,那么就會出現外鍵約束報錯。 ## 問題解決 `TM_REFERRED_FK_DB_F`?這個 flag 是在?`Table_map_log_event::Table_map_log_event()`?構造函數中設置的,邏輯如下: ~~~ /* Marking event to require sequential execution in MTS if the query might have updated FK-referenced db. Unlike Query_log_event where this fact is encoded through the accessed db list in the Table_map case m_flags is exploited. */ uchar dbs= thd->get_binlog_accessed_db_names() ? thd->get_binlog_accessed_db_names()->elements : 0; if (dbs == 1) { char *db_name= thd->get_binlog_accessed_db_names()->head(); if (!strcmp(db_name, "")) m_flags |= TM_REFERRED_FK_DB_F; } ~~~ 如果當前訪問到的 db 個數為1,并且 db 是空字符串?`""`?的話,就設置這個 flag。`binlog_accessed_db_names`?中只有?`""`?這一個元素是一個特殊構造的場景,正常情況下db不會是?`""`的,構造這樣 db 的邏輯在?`THD::decide_logging_format`,如下: ~~~ if (is_write && lex->sql_command != SQLCOM_END /* rows-event applying by slave */) { /* Master side of DML in the STMT format events parallelization. All involving table db:s are stored in a abc-ordered name list. In case the number of databases exceeds MAX_DBS_IN_EVENT_MTS maximum the list gathering breaks since it won't be sent to the slave. */ for (TABLE_LIST *table= tables; table; table= table->next_global) { if (table->placeholder()) continue; DBUG_ASSERT(table->table); if (table->table->file->referenced_by_foreign_key()) { /* FK-referenced dbs can't be gathered currently. The following event will be marked for sequential execution on slave. */ binlog_accessed_db_names= NULL; add_to_binlog_accessed_dbs(""); break; } if (!is_current_stmt_binlog_format_row()) add_to_binlog_accessed_dbs(table->db); } } ~~~ 可以看到,如果有當前表被外鍵約束的話(`table->table->file->referenced_by_foreign_key()`),會清掉`binlog_accessed_db_names`,只放一個空字符串進去。 但是 SQL 線程在應用 row_event 時,不會走到上面的邏輯,因為?`lex->sql_command`?的值為?`SQLCOM_END`,所以備庫 B 生成的 parent 表的 table_map 就不包含這個 flag。 修復也比較簡單,把?`lex->sql_command != SQLCOM_END`?這個條件去掉即可,或者參考官方?[bug](http://bugs.mysql.com/bug.php?id=80474)?這里提供的修復方法,也是可以的。
                  <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>

                              哎呀哎呀视频在线观看