mysql binlog解析概要

來源:互聯網
上載者:User

標籤:

1,dump協議:

根據資料庫的ip+port建立socket,如果建立成功,說明連結建立成功,接下來是使用dump協議訂閱binlog

連結建立成功之後,服務端會主動向用戶端發送如下問候資訊greeting(可以理解為經java轉換後,是一個java對象),

在下面的代碼中可以看到greeting中的資訊:

this.context.setServerStatus(greeting.getServerStatus());//
this.context.setServerVersion(greeting.getServerVersion().toString());
this.context.setServerCollation(greeting.getServerCollation());
this.context.setServerCapabilities(greeting.getServerCapabilities());
this.context.setThreadId(greeting.getThreadId());
this.context.setProtocolVersion(greeting.getProtocolVersion());
this.context.setScramble(greeting.getScramble1().toString() + greeting.getScramble2().toString());

然後如下:
將ctx=this.context;
final XSerializer s = new XSerializer(64);
s.writeInt(buildClientCapabilities(), 4);
s.writeInt(this.maximumPacketLength, 4);
s.writeInt(this.clientCollation > 0 ? this.clientCollation : ctx.getServerCollation(), 1);
s.writeBytes((byte)0, 23); // Fixed, all 0
s.writeNullTerminatedString(StringColumn.valueOf(this.user.getBytes(this.encoding)));
s.writeInt(20, 1); // the length of the SHA1 encrypted password
s.writeBytes(MySQLUtils.password41OrLater(this.password.getBytes(this.encoding), ctx.getScramble().getBytes(this.encoding)));
if(this.initialSchema != null) s.writeNullTerminatedString(StringColumn.valueOf(this.initialSchema.getBytes(this.encoding)));

//transport可以理解為是一個socket的封裝後的東西
final RawPacket request = new RawPacket();
request.setSequence(1);
request.setPacketBody(s.toByteArray());
request.setLength(request.getPacketBody().length);
transport.getOutputStream().writePacket(request);
transport.getOutputStream().flush();

然後可以在下面的代碼中得到mysql的相應:
final Packet response = transport.getInputStream().readPacket();
if(response.getPacketBody()[0] == ErrorPacket.PACKET_MARKER) {
final ErrorPacket error = ErrorPacket.valueOf(response);
LOGGER.info("login failed, user: {}, error: {}", this.user, error);
throw new TransportException(error);
} else if(response.getPacketBody()[0] == OKPacket.PACKET_MARKER) {
final OKPacket ok = OKPacket.valueOf(response);
LOGGER.info("login successfully, user: {}, detail: {}", this.user, ok);
} else {
LOGGER.warn("login failed, unknown packet: ", response);
throw new RuntimeException("assertion failed, invalid packet: " + response);
}

2,dump報文格式:

下方表格來自mysql官網連結:http://dev.mysql.com/doc/internals/en/mysql-packet.html

Type Name Description
int<3> payload_length Length of the payload. The number of bytes in the packet beyond the initial 4 bytes that make up the packet header.
int<1> sequence_id Sequence ID
string<var> payload [len=payload_length] payload of the packet
報文對超大packet的支援方式如下:

當一個packet過大 (超過1<<24-1byte ~= 16 MB) 時, 傳輸需要對packet進行切割, 參看這裡

注意, 在A上產生binlog時, 是可以容納大於16MB的packet的, 也就是原binlog裡存在超大的event, 需要在傳輸時加以限制

切割packet沒什麼特別之處, 僅需要注意包格式, 一個20MB的event的傳輸packet格式舉例為 (此處用16MB便於描述, 應為1<<24-1byte):

    packet 1        4位元組 packet header        1位元組 值為[00], 是binlog event的特徵標誌        16MB-1位元組 為第一段資料            packet 2        4位元組 packet header        20MB-16MB+1位元組 為第二段資料

需要注意的是之後的packet時不帶有[00]特徵位的. 而包的大小計算範圍為除去前4位元組的全部位元組

上面的講解對應的代碼為:

// Parse packet
final int packetLength = is.readInt(3);
final int packetSequence = is.readInt(1);//超大資料包切割後的順序
is.setReadLimit(packetLength); // Ensure the packet boundary

//
final int packetMarker = is.readInt(1);//特徵位
if(packetMarker != OKPacket.PACKET_MARKER) { // 0x00
if((byte)packetMarker == ErrorPacket.PACKET_MARKER) {
final ErrorPacket packet = ErrorPacket.valueOf(packetLength, packetSequence, packetMarker, is);
throw new RuntimeException(packet.toString());
} else if((byte)packetMarker == EOFPacket.PACKET_MARKER) {
final EOFPacket packet = EOFPacket.valueOf(packetLength, packetSequence, packetMarker, is);
throw new RuntimeException(packet.toString());
} else {
throw new RuntimeException("assertion failed, invalid packet marker: " + packetMarker);
}
}

 接下來直接解析mysql binlog即可,header擷取如下:

// Parse the event header
final BinlogEventV4HeaderImpl header = new BinlogEventV4HeaderImpl();
header.setTimestamp(is.readLong(4) * 1000L);//timestamp
header.setEventType(is.readInt(1));//type_code
header.setServerId(is.readLong(4));//server_id
header.setEventLength(is.readInt(4));//event_length
header.setNextPosition(is.readLong(4));//next_position
header.setFlags(is.readInt(2));//flags
header.setBinlogFileName(this.binlogFileName);
header.setTimestampOfReceipt(System.currentTimeMillis());

body的解析不同事件格式不一樣,類似header那樣取值



註:代碼來自開源項目open replicator

mysql binlog解析概要

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.