您好,登錄后才能下訂單哦!
這篇文章將為大家詳細講解有關MySQL中binlog有什么用,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。
binlog文件主要包括:
mysql-bin.000001
mysql-bin.index
其中:
mysql-bin.index內保存著server中未purge的binlog文件,以“文本”形式保留的。
mysql-bin.index沒啥可說的,我們專門看一下二進制binlog文件。
binlog文件格式有以下特點:
binlog是由event組成,event是binlog的邏輯最小單元。
文件頭的頭四個字節為BINLOG_MAGIC(fe 62 69 6e)
緊接著這四個字節的是 descriptor event : FORMAT_DESCRIPTION_EVENT
文件的末尾是 log-rotation event: ROTATE_EVENT
這兩個event中間是各種不同的event,每個event代表Master上不同的操作。
下面對基本比較關鍵的概念進行說明:
BINLOG_MAGIC
利用hexdump -C 讀取mysql-bin.000005的內容,
這里分別以十六進制和ASCII碼展示顯示,我們可以看到binlog的頭四個字節是固定的:fe 62 69 6e,后三個字符ASCII碼為bin,指明展示一個binlog文件。這四個字節成為 BINLOG_MAGIC。
event
mysqlbinlog -vvv 讀取mysql-bin.000011的內容示例:
這里可以看到,第一個event是FORMAT_DESCRIPTION_EVENT,它記錄了這個binlog的版本(MySQL 5.0以后binlog 的版本都是4)。最后一個event,是ROTATE_EVENT,它記錄了切換到下一個binlog文件的文件名。
在它們兩個之間是各種其他的event,目前的event類型有:
enum Log_event_type {
UNKNOWN_EVENT= 0,
START_EVENT_V3= 1,
QUERY_EVENT= 2,
STOP_EVENT= 3,
ROTATE_EVENT= 4,
INTVAR_EVENT= 5,
LOAD_EVENT= 6,
SLAVE_EVENT= 7,
CREATE_FILE_EVENT= 8,
APPEND_BLOCK_EVENT= 9,
EXEC_LOAD_EVENT= 10,
DELETE_FILE_EVENT= 11,
NEW_LOAD_EVENT= 12,
RAND_EVENT= 13,
USER_VAR_EVENT= 14,
FORMAT_DESCRIPTION_EVENT= 15,
XID_EVENT= 16,
BEGIN_LOAD_QUERY_EVENT= 17,
EXECUTE_LOAD_QUERY_EVENT= 18,
TABLE_MAP_EVENT = 19,
PRE_GA_WRITE_ROWS_EVENT = 20,
PRE_GA_UPDATE_ROWS_EVENT = 21,
PRE_GA_DELETE_ROWS_EVENT = 22,
WRITE_ROWS_EVENT = 23,
UPDATE_ROWS_EVENT = 24,
DELETE_ROWS_EVENT = 25,
INCIDENT_EVENT= 26,
HEARTBEAT_LOG_EVENT= 27,
IGNORABLE_LOG_EVENT= 28,
ROWS_QUERY_LOG_EVENT= 29,
WRITE_ROWS_EVENT = 30,
UPDATE_ROWS_EVENT = 31,
DELETE_ROWS_EVENT = 32,
GTID_LOG_EVENT= 33,
ANONYMOUS_GTID_LOG_EVENT= 34,
PREVIOUS_GTIDS_LOG_EVENT= 35,
ENUM_END_EVENT
/* end marker */
};
當然,內部已經有部分event被棄用了,我們不一一列舉,這里只簡單介紹幾個平時經常見到的:
QUERY_EVENT :用于具體的SQL文本。如果binlog_format=statement方式下,insert,update,delete等各種SQL都是以Query event記錄下來的。
WRITE_ROWS_EVENT,UPDATE_ROWS_EVENT,DELETE_ROWS_EVENT : 在binlog_format=row方式下,insert,update,delete操作的行信息分別以這三種event記錄下來。
GTID_LOG_EVENT:5.6的GTID模式下,每個事務的GTID序號被記錄到這種EVENT中。
PREVIOUS_GTIDS_LOG_EVENT :5.6的GTID模式下,這個event記錄了生成這個binlog之前,MySQL已經執行的所有事務的GTID集合
這里主要描述源碼中的函數調用關系
slave io線程對應的入口函數為sql/rpl_slave.cc:handle_slave_io()
該函數核心主要是做了以下三個事情:
safe_connect(thd, mysql, mi)
register_slave_on_master(mysql, mi, &suppress_warnings)
request_dump(thd, mysql, mi, &suppress_warnings)
event_len= read_event(mysql, mi, &suppress_warnings);
也就是說,它先以標準的連接方式連上master MySQL,然后把自己注冊到master上去,接著調用request_dump向master請求binlog數據,最后一個一個event讀取并存放到本地relay log中。
safe_connect
連接MySQL的標準方式,MySQL c的connector也是用這種方式連接MySQL server的。
register_slave_on_master
slave把自己的slave_id,IP,端口,用戶名提交給Master,用于注冊自己到Master上去。
request_dump
根據GTID來進行判斷,如果是GTID模式,那么把本地執行的GTID集合及其他相關信息傳給master;如果不是GTID模式,那么就把master log file和Pos傳給主庫。主庫如何根據這些信息來發送binlog的event,參考下節。
read_event
read_event調用了cli_safe_read(),cli_safe_read()調用了my_net_read(),等待主庫將binlog數據發過來
也就是說,read_event被動的從網絡中接受主庫發過來的信息。
MySQL處理各種命令的核心函數為:sql/sql_parse.cc:dispatch_command
該函數會根據用戶的請求來確定做什么事情,
COM_REGISTER_SLAVE則調用register_slave(thd, (uchar*)packet, packet_length)注冊slave
COM_BINLOG_DUMP_GTID 則調用com_binlog_dump_gtid(thd, packet, packet_length);
COM_BINLOG_DUMP 則調用com_binlog_dump(thd, packet, packet_length);
我們這里以com_binlog_dump為例介紹master怎么發送binlog event給slave的。
com_binlog_dump核心代碼為:
kill_zombie_dump_threads(&slave_uuid);
mysql_binlog_send(thd, thd->strdup(packet + 10), (my_off_t) pos, NULL)
kill_zombie_dump_threads()函數:如果新的server_id相同的slave注冊上來,master會移除跟該slave的server_id匹配的的binlog dump線程
com_binlog_dump()會調用mysql_binlog_send()來打開文件,將文件指針挪到指定位置,讀取文件,將一個個的event按照事件順序發給slave。
MySQL復制需要slave先注冊到Master,再向Master提交binlog和POS,請求發送binlog。Master接收到請求后,先做一系列驗證,打開本地binlog文件,按照內部event的順序,依序發給slave。
sql線程在5.6引入了db級別的并行,所以有兩個入口
1 2 | handle_slave_worker handle_slave_sql |
handle_slave_worker線程是主要干活的函數,handle_salve_sql函數作為協調器會啟動和分配worker線程。
handle_slave_sql函數主要調用了slave_worker_exec_job。
slave_worker_exec_job的主要功能:
job_item= pop_jobs_item(worker, job_item); ev= static_cast<Log_event*>(job_item->data);
error= ev->do_apply_event_worker(worker);
該函數做到事情其實就是 從handle_salve_sql()獲得具體的event(ev),然后調用ev->do_apply_event_worker(worker),利用c++的多態特性,調用真正的event的do_apply_event虛函數,以便將不同的event的操作在本地做一遍。
這里需要大家回顧一下event的概念了,event是binlog的最小單元,所有的event的父類是Log_event(抽象基類),它定義了一系列虛函數,其中就包括我們這里調用的函數:
這里舉一個insert語句對應的的Write_rows_log_event例子,簡單說明一下數據是怎么應用到本地MySQL的。
Write_rows_log_event,Update_rows_log_event和Delete_rows_log_event的do_apply_event都是調用的它的基類Rows_log_event的do_apply_event。
Rows_log_event的do_apply_event主要功能如下:
m_table= const_cast <relay_log_info* style=”-webkit-print-color-adjust: exact;”> (rli)->m_table_map.get_table(m_table_id);
error= (this->*do_apply_row_ptr)(rli);
get_table()先從table map中獲得對應的table的信息,然后調用do_apply_row_ptr函數指針指向的函數來將event對應操作應用到本地MySQL。
do_apply_row_ptr函數指針可能指向以下幾種不同的函數:
do_hash_scan_and_update
do_index_scan_and_update
do_table_scan_and_update
do_apply_row
Write_rows_log_event是insert,不用查找數據,所以它調用的是do_apply_row。
do_apply_row主要的功能就是調用了do_exec_row ….汗
do_exec_row是Write_rows_log_event自己實現的,它的主要功能是調用了 write_row ….汗
write_row也是Write_rows_log_event自己實現的,它的主要功能是:m_table->file->ha_start_bulk_insert(estimated_rows);也就是說,它直接把這一行數據交給了存儲引擎,讓存儲引擎把數據給插進去。
在sql/log_event.cc:log_event_print_value()函數中詳細描述了MySQL的各種數據類型的二進制表現形式,摘錄如下
這里有幾個比較有意思的地方:
MYSQL_TYPE_STRING 類型,它的length占用的字節數是不固定的。如果string長度不到大于255,則需要占用2個字節,所以,MySQL在定義String類型的字段時,255是一個坎,如果字段不可能超過255個字節,不建議定義長度的時候超過255,否則MySQL存儲數據時會白白浪費一個字節。
MYSQL_TYPE_DATETIME類型。它存儲的格式就是把年-月-日 時:分:秒按順序存儲下來的,比如:2015-10-10 22:45:55存儲下來就存儲為20151010224545。這種存儲格式比較浪費,所以字節數相比timestamp占用的也比較多。
關于“MySQL中binlog有什么用”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,使各位可以學到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。