mysql多執行緒slave的演化

myownstars發表於2015-02-08
淘寶內部分享:怎麼跳出MySQL的10個大坑  之  MySQL · 優化改進· 複製效能改進過程

pre-5.6 ,sql_thread的執行堆疊如下,
sql_thread:
exec_relay_log_event
    apply_event_and_update_pos
         apply_event
             rows_log_event::apply_event
                 storage_engine operation
         update_pos
由於其是單執行緒, 經常會造成備庫延遲;
      mysql-transfer

先看一下oracle是怎麼實現logical standby的

其中只有preparer/applier程式可以有多個
  • reader:讀取redo記錄傳遞給preparer程式
  • preparer: 根據redo記錄和資料字典資訊生成LCR
  • builder: 將同一個事務的LCR打包。對於大事務(eager transaction),可能被打成多個事務包(transaction chunk),那麼可能有些包裡是不包含commit的,每一個事務包都可能交給不同的applier程式。
  • analyzer:分析事務包之間的依賴關係
  • coordinator:將分析好的事務包交給applier程式
  • applier:將事務包應用,如果事務包依賴其他事務包,則需要等待相應的事務包完成。事務能否commit,可能還需要根據不同的情況從coordinator獲得相應的資訊。



5.6並行複製
 5.6 中,引入了多執行緒模式,在保留io_thread的前提下,將sql_thread改造為coordinator,並新增多個worker_thread即MTS
  Relay Log File
        -------
        | W01 |                   ---&gt Worker 01 (W01)
        -------
        | W01 |   ---&gt SQL THREAD ---&gt Worker 02 (W02)
        -------
        | W02 |                   ---&gt Worker 03 (W03)
        -------
        | ... |
coordinator_thread: 負責讀取 relay log,將讀取的binlog event以事務為單位分發到各個 worker thread 進行執行,並在必要時以序列方式執行binlog event(Description_format_log_event, Rotate_log_event )。
worker_thread: 執行分配到的binlog event,各個執行緒之間互不影響;
引數slave_parallel_workers用於設定MTS數量;

實現原理
在記憶體中構造一個hash表,維護資料庫和worker_thread的對映關係;
多個資料庫可並行執行,同一個資料庫則只能序列執行;如果事務是跨資料庫行為的,則需要等待已分配的該資料庫的事務全部執行完畢,才會繼續分發,其分配行為的偽碼可以簡單的描述如下:
get_slave_worker
  if (contains_partition_info(log_event))
     db_name= get_db_name(log_event);
     entry {db_name, worker_thread, usage} = map_db_to_worker(db_name);
     while (entry->usage > 0)
        wait();
    return worker;
  else if (last_assigned_worker)
    return last_assigned_worker;
  else
    push into buffer_array and deliver them until come across a event that have partition info

需要注意的細節
記憶體的分配與釋放,relay thread 每讀取一個log_event, 則需要 malloc 一定的記憶體,在work執行緒執行完後,則需要free掉;
臨時表的處理,臨時表是和entry繫結在一起的,在執行的時候將entry的臨時表掛在執行執行緒thd下面,但沒有固化,如果在臨時表操作期間,備庫crash,則重啟後備庫會有錯誤;
維護一個繫結資訊的array , 在分發事務的時候,更新繫結資訊,增加相應 entry->usage, 在執行完一個事務的時候,則需要減少相應的entry->usage;
slave worker 資訊的維護,即每個 worker thread執行了哪些事務,執行到的位點是在哪,延遲是如何計算的,如果執行出錯,mts_recovery_group 又是如何恢復的;
總體上說,5.6 的並行複製打破了5.5 單執行緒的複製的行為,只是在單庫下用處不大,並且5.6的並行複製的改動引入了一些重量級的bug
MySQL slave sql thread memory leak (http://bugs.MySQL.com/bug.php?id=71197)
Relay log without xid_log_event may case parallel replication hang (http://bugs.MySQL.com/bug.php?id=72794)
Transaction lost when relay_log_info_repository=FILE and crashed (http://bugs.MySQL.com/bug.php?id=73482)



5.7
並行複製的實現新增了另外一種並行的方式,即主庫在 ordered_commit中的第二階段的時候,將同一批commit的 binlog 打上一個相同的seqno標籤,同一時間戳的事務在備庫是可以同時執行的(因為這些事務相互不干涉,所以才能在primary併發commit,因此在備庫同樣也能併發執行),因此大大簡化了並行複製的邏輯,並打破了相同 DB 不能並行執行的限制。備庫在執行時,具有同一seqno的事務在備庫可以並行的執行,互不干擾,也不需要繫結資訊,後一批seqno的事務需要等待前一批相同seqno的事務執行完後才可以執行。

5.7實現了MTS下的SLAVE_TRANSACTION_RETRIES 
1 當某個worker thread執行事務遭遇錯誤,則根據引數定義再次執行; 
2 單個worker thread重試期間不影響其他wokrer thread; 
3 若嘗試SLAVE_TRANSACTION_RETRIES仍然失敗,則worker stop,進而通知其他worker和coordinator stop,slave停止更新; 
coordinator照舊將event包裝成Slave_job_item形式轉發,但是多加入event的起始位置資訊(binlog name + offset); 
worker執行事務組時記錄第一個event的起始位置,當執行出錯時,事務組的event可分為3類: 
1 已經執行成功的 
2 引發錯誤的 
3 尚未執行的(仍在job queue中) 
worker無需從relay log讀取整個事務組,只需part 1和part 2部分; 
注: relay thread 每讀取一個log_event, 則需要 malloc 一定的記憶體,在work執行緒執行完後,則需要free掉;因此需要重新讀取; 

typedef struct slave_job_item 

void *data; 
+ uint relay_number; 
+ my_off_t relay_pos; 
} Slave_job_item; 
http://dev.mysql.com/worklog/task/?id=6964 



mysql-transfer
這是淘寶自主開發的一個基於MySQL+patch後得到的主從同步工具。
其主要目的是為了解決原生版本的主從同步裡,從庫是單執行緒apply主庫的binlog,導致的延遲。

 

說明:左上角是Master, 右上角是Transfer,下面是Slave。
1、             由於Transfer是在MySQL基礎上打的patch,因此支援幾乎所有MySQL的監控命令,你原來加在Slave上的監控,可以直接改到Transfer上。
2、             一般我們將Transfer和Slave放在同一個機器上(等於是裝兩個MySQL,一個是Transfer,一個是真正的slave)
3、             Transfer按照表名hash將不同表的更新分配到不同的執行緒,因此在多表環境下才能看得到效能提升
4、             Master的binlog格式必須設定成row
5、             若需要用到多個Master,給每個Master命令一個channel,命令 序列為 change master channel1 to master_log_file=xxx…… ; start slave channel1; 可以單獨對一個chanel執行start\stop等命令
6、             若只需要一個master,則語法格式不變

 transfer 2.0

 Transfer第一版本存在兩個可改進的點:單表併發和事務支援。
a)      Transfer2.0支援單表併發,基本原理就是按照更新行的主鍵id (因此有一個限制是同步的表必須要有主鍵)。
b)      Transfer2.0支援slave回放主庫事務時以事務為單位執行。

 Transfer的推薦配置結構是
      Master  ==> Transfer ==> Slave
也可以將transfer直接patch到slave上,這樣就不必為tranfer單獨建立一個例項;
patch地址


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/15480802/viewspace-1430099/,如需轉載,請註明出處,否則將追究法律責任。

相關文章