<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>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                ## 業務背景 MySQL 主備通過 binlog 實現數據同步的功能,主庫將生成的 binlog 通過 binlog send 線程發送到備庫,備庫通過應用這些 binlog 來更新數據,實現主備數據一致,其應用 binlog 的讀取操作與更新操作的堆棧分別如下。 讀取操作: ~~~ #0 row_search_for_mysql #1 0x0000000000c200c2 in ha_innobase::index_read #2 0x0000000000c21c57 in ha_innobase::rnd_pos #3 0x000000000090c5d3 in handler::rnd_pos_by_record #4 0x0000000000a574c3 in Rows_log_event::find_row #5 0x0000000000a589da in Delete_rows_log_event::do_exec_row #6 0x0000000000a50dcc in Rows_log_event::do_apply_event #7 0x00000000005d0bb8 in Log_event::apply_event #8 0x00000000005b9782 in apply_event_and_update_pos ... ~~~ 更新操作: ~~~ #0 row_update_for_mysql #1 0x0000000000c1f466 in ha_innobase::delete_row #2 0x000000000090b64a in handler::ha_delete_row #3 0x0000000000a58a4b in Delete_rows_log_event::do_exec_row #4 0x0000000000a50dcc in Rows_log_event::do_apply_event #5 0x00000000005d0bb8 in Log_event::apply_event #6 0x00000000005b9782 in apply_event_and_update_pos ... ~~~ * 由堆棧可以看出,sql 線程首先將數據從磁盤加載到內存,然后調用引擎層的接口執行相應的操作,當iops 及 buffer pool 較小時,讀磁盤需要較多的時間,容易造成主備延遲問題; * 當系統重啟后,需要對系統進行預熱,提高 buffer pool 的命中率,因此需要提供有效的方法來對系統進行預熱; 綜上,我們需要一種可以在 DML 操作之前將數據從磁盤加載到內存的功能,以實現數據庫的快速操作。 ## 解決方法 我們需要找到一種將數據加載到內存的方法,但又不對數據進行修改,需要滿足以下的條件: * 在庫上更新的數據應該在備庫操作之前被加載到內存中; * 對于重啟的mysqld實例,應該將啟動之前所用的數據頁加載到內存中; * 加載操作對數據本身不進行修改,類似于select 語句。 因此,我們可以在mysqld啟動時啟動額外的線程對 relay log 進行特殊處理,以達到數據加載的目的。 ## 設計思路 & 使用方法 RDS MySQL 利用 relay log 來解決上述兩個問題,當系統啟動后,可以在后臺開啟一個獨立于SQL thread之外的線程將 relay log 相關的數據從磁盤加載到內存中,從而使備庫在查找數據的時候直接利用buffer pool,而不需要從磁盤中進行加載,同理,使用這種方法也可以解決系統預熱的問題。 當啟動后,如果發現延遲且 buffer pool 命中率較低時,可以啟用 relay fetch thread, 具體語法為: ~~~ 啟動 relay_fetch_thread: start slave relay_fetch_thread; 停止 relay_fetch_thread: stop slave relay_fetch_thread; ~~~ relay fetch thread 讀取relay log, 并將要執行的數據從磁盤上加載到內存中,所以只能對包含數據部分的 log_event 進行操作,對 Query_log_event,Write_rows_log_event 是無法進行預讀的,前者是因為Query_log_event 只是SQL語句,不包含具體的數據信息;后者則是event中沒有的數據,所以不需要進行加載,另外為了防止 buffer pool 中讀取的 page 被 evict 出去,我們需要對兩種情況進行分別處理: 1. relay fetch thread 不能領先 sql thread 過多,如果領先過多的 relay log files,當 buffer pool 較小時,新加載進來的數據頁會將老的數據頁從內存中 evict 出去,對 sql thread 的命中率會有直接的影響; 2. 當 sql thread 領先 relay fetch thread 時,此時 relay fetch thread 不需要將已執行完的 relay log 加載到內存,繼續加載不僅會有命中率的問題,同時會造成 CPU 不必要的資源浪費。 因此,relay fetch thread 與 sql thread 應該相差的距離不太遠,我們的策略是 relay fetch thread 與 sql thread 應該在同一個 relay log 上,具體策略如下: 1. 如果 relay fetch thread 領先, 則當 relay fetch thread 讀完一個文件后要等待 sql thread,直到 sql thread 應用完此relay log 再繼續加載; 2. 如果 sql thread 領先,則會通知 relay fetch thread 跳過當前執行的文件并用 sql thread 的位點來初始化自己將要執行的起點; relay fetch thread 執行過程的偽碼如下: ~~~ handle_slave_relay_fetch { init_thd_and_rli(); while (!relay_fetch_killed(eli)) { ev= Log_event::read_log_event(&rli->relay_log_buf, 0, rli->relay_log.description_event_for_relay_fetch); if (ev == NULL) { deal with situations like hot_log, relay log purged, eof of relay log etc. } else { switch(ev->get_type_code()) { case QUERY_EVENT: deal with begin, commit break; case XID_EVENT: deal with xid(commit) break; case TABLE_MAP_EVENT: init table info for rows log event break; case UPDATE_ROWS_EVENT: case DELETE_ROWS_EVENT: find_row(); break; case FORMAT_DESCRIPTION_EVENT: init description_event_for_relay_fetch for reading binlog event; default: break; } delete ev; } } } ~~~ ## 實現過程中注意的細節 * 由于 relay fetch thread 在加載數據的過程中會對記錄進行加鎖,所以在遇到begin, commit 的事件時,需要釋放在讀取過程中獲取的所有鎖資源,否則有可能會引起 sql 線程鎖超時錯誤; * 由于 relay fetch thread 的位點是使用 sql thread 的位點進行初始化的,所以需要處理 relay log 不是完整事務的情況; * 釋放 relay fetch thread 在執行過程中使用到的內存,否則會有內存問題; * 在 relay fetch thread 執行的過程中需要特別注意 log_lock、run_lock 等鎖問題,以避免備庫的死鎖; * 需要對 relay log 的purge進行特殊處理; * 如果是系統預熱的功能,則需要對 relay fetch thread 與 sql thread 的領先策略進行調整。
                  <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>

                              哎呀哎呀视频在线观看