初探 MySQL 的 Binlog

原文地址:https://xcoder.in/2015/08/10/mysql-binlog-try/

花瓣網(wǎng)的搜索架構(gòu)需要重構(gòu)围小,尤其是在索引建立或者更新層面躯枢。

目前的一個(gè)架構(gòu)導(dǎo)致的結(jié)果就是時(shí)間越久歉井,數(shù)據(jù)本體與搜索引擎索引中的數(shù)據(jù)越不同步,相差甚大。

新的一個(gè)架構(gòu)打算從 MySQL 的 Binlog 中讀取數(shù)據(jù)更新、刪除驼壶、新增等歷史記錄,并把相應(yīng)信息提取出來(lái)丟到隊(duì)列中慢慢去同步矗烛。

所以我就在這里小小去了解一下 Binlog。

準(zhǔn)備工作

什么是 Binlog

MySQL Server 有四種類(lèi)型的日志——Error Log箩溃、General Query Log瞭吃、Binary Log 和 Slow Query Log。

第一個(gè)是錯(cuò)誤日志涣旨,記錄 mysqld 的一些錯(cuò)誤歪架。第二個(gè)是一般查詢(xún)?nèi)罩荆涗?mysqld 正在做的事情霹陡,比如客戶(hù)端的連接和斷開(kāi)和蚪、來(lái)自客戶(hù)端每條 Sql Statement 記錄信息;如果你想準(zhǔn)確知道客戶(hù)端到底傳了什么瞎 [嗶嗶] 玩意兒給服務(wù)端烹棉,這個(gè)日志就非常管用了攒霹,不過(guò)它非常影響性能。第四個(gè)是慢查詢(xún)?nèi)罩窘矗涗浺恍┎樵?xún)比較慢的 SQL 語(yǔ)句——這種日志非常常用催束,主要是給開(kāi)發(fā)者調(diào)優(yōu)用的。

剩下的第三種就是 Binlog 了伏社,包含了一些事件抠刺,這些事件描述了數(shù)據(jù)庫(kù)的改動(dòng)塔淤,如建表、數(shù)據(jù)改動(dòng)等速妖,也包括一些潛在改動(dòng)高蜂,比如 DELETE FROM ran WHERE bing = luan,然而一條數(shù)據(jù)都沒(méi)被刪掉的這種情況罕容。除非使用 Row-based logging备恤,否則會(huì)包含所有改動(dòng)數(shù)據(jù)的 SQL Statement。

那么 Binlog 就有了兩個(gè)重要的用途——復(fù)制和恢復(fù)杀赢。比如主從表的復(fù)制烘跺,和備份恢復(fù)什么的。

啟用 Binlog

通常情況 MySQL 是默認(rèn)關(guān)閉 Binlog 的脂崔,所以你得配置一下以啟用它滤淳。

啟用的過(guò)程就是修改配置文件 my.cnf 了。

至于 my.cnf 位置請(qǐng)自行尋找砌左。例如通過(guò) OSX 的 brew 安裝的 mysql 默認(rèn)配置目錄通常在

/usr/local/Cellar/mysql/$VERSION/support-files/my-default.cnf

這個(gè)時(shí)候需要將它拷貝到 /etc/my.cnf 下面脖咐。

詳見(jiàn) <StackOverflow - MySQL 'my.cnf' location?>。

緊接著配置 log-binlog-bin-index 的值汇歹,如果沒(méi)有則自行加上去屁擅。

log-bin=master-bin
log-bin-index=master-bin.index

這里的 log-bin 是指以后生成各 Binlog 文件的前綴,比如上述使用 master-bin产弹,那么文件就將會(huì)是 master-bin.000001派歌、master-bin.000002 等。而這里的 log-bin-index 則指 binlog index 文件的名稱(chēng)痰哨,這里我們?cè)O(shè)置為 master-bin.index胶果。

如果上述工作做完之后重啟 MySQL 服務(wù),你可以進(jìn)入你的 MySQL CLI 驗(yàn)證一下是否真的啟用了斤斧。

$ mysql -u $USERNAME ...

然后在終端里面輸入下面一句 SQL 語(yǔ)句:

SHOW VARIABLES LIKE '%log_bin%';

如果結(jié)果里面出來(lái)這樣類(lèi)似的話(huà)就表示成功了:

+---------------------------------+---------------------------------------+
| Variable_name                   | Value                                 |
+---------------------------------+---------------------------------------+
| log_bin                         | ON                                    |
| log_bin_basename                | /usr/local/var/mysql/master-bin       |
| log_bin_index                   | /usr/local/var/mysql/master-bin.index |
| log_bin_trust_function_creators | OFF                                   |
| log_bin_use_v1_row_events       | OFF                                   |
| sql_log_bin                     | ON                                    |
+---------------------------------+---------------------------------------+
6 rows in set (0.00 sec)

更多的一些相關(guān)配置可以參考這篇《MySQL 的 binary log 初探》早抠。

隨便玩玩

然后你就可以隨便去執(zhí)行一些數(shù)據(jù)變動(dòng)的 SQL 語(yǔ)句了。當(dāng)你執(zhí)行了一堆語(yǔ)句之后就可以看到你的 Binlog 里面有內(nèi)容了撬讽。

如上表所示蕊连,log_bin_basename 的值是 /usr/local/var/mysql/master-bin 就是 Binlog 的基礎(chǔ)文件名了。

那我們進(jìn)去看游昼,比如我的這邊就有這么幾個(gè)文件:

Binlog 文件
Binlog 文件

很容易發(fā)現(xiàn)甘苍,里面有 master-bin.indexmaster-bin.000001 兩個(gè)文件,這兩個(gè)文件在上文中有提到過(guò)了烘豌。

我們打開(kāi)那個(gè) master-bin.index 文件羊赵,會(huì)發(fā)現(xiàn)這個(gè)索引文件就是一個(gè)普通的文本文件,然后列舉了各 binlog 的文件名。而 master-bin.000001 文件就是一堆亂碼了——畢竟人家是二進(jìn)制文件昧捷。

結(jié)構(gòu)解析

索引文件

索引文件就是上文中的 master-bin.index 文件闲昭,是一個(gè)普通的文本文件,以換行為間隔靡挥,一行一個(gè)文件名序矩。比如它可能是:

master-bin.000001
master-bin.000002
master-bin.000003

然后對(duì)應(yīng)的每行文件就是一個(gè) Binlog 實(shí)體文件了。

Binlog 文件

Binlog 的文件結(jié)構(gòu)大致由如下幾個(gè)方面組成跋破。

文件頭

文件頭由一個(gè)四字節(jié) Magic Number簸淀,其值為 1852400382,在內(nèi)存中就是 "\xfe\x62\x69\x6e"毒返,參考 MySQL 源碼的 log_event.h租幕,也就是 '\0xfe' 'b' 'i' 'n'

與平常二進(jìn)制一樣拧簸,通常都有一個(gè) Magic Number 進(jìn)行文件識(shí)別劲绪,如果 Magic Number 不吻合上述的值那么這個(gè)文件就不是一個(gè)正常的 Binlog。

事件

在文件頭之后盆赤,跟隨的是一個(gè)一個(gè)事件依次排列贾富。每個(gè)事件都由一個(gè)事件頭和事件體組成。

事件頭里面的內(nèi)容包含了這個(gè)事件的類(lèi)型(如新增牺六、刪除等)颤枪、事件執(zhí)行時(shí)間以及是哪個(gè)服務(wù)器執(zhí)行的事件等信息。

第一個(gè)事件是一個(gè)事件描述符淑际,描述了這個(gè) Binlog 文件格式的版本畏纲。接下去的一堆事件將會(huì)按照第一個(gè)事件描述符所描述的結(jié)構(gòu)版本進(jìn)行解讀。最后一個(gè)事件是一個(gè)銜接事件春缕,指定了下一個(gè) Binlog 文件名——有點(diǎn)類(lèi)似于鏈表里面的 next 指針盗胀。

根據(jù)《[High-Level Binary Log Structure and Contents](High-Level Binary Log Structure and Contents)》所述,不同版本的 Binlog 格式不一定一樣淡溯,所以也沒(méi)有一個(gè)定性读整。在我寫(xiě)這篇文章的時(shí)候簿训,目前有三種版本的格式咱娶。

  • v1,用于 MySQL 3.2.3
  • v3强品,用于 MySQL 4.0.2 以及 4.1.0
  • v4膘侮,用于 MySQL 5.0 以及更高版本

實(shí)際上還有一個(gè) v2 版本,不過(guò)只在早期 4.0.x 的 MySQL 版本中使用過(guò)的榛,但是 v2 已經(jīng)過(guò)于陳舊并且不再被 MySQL 官方支持了琼了。

通常我們現(xiàn)在用的 MySQL 都是在 5.0 以上的了,所以就略過(guò) v1 ~ v3 版本的 Binlog,如果需要了解 v1 ~ v3 版本的 Binlog 可以自行前往上述的《High-level...》文章查看雕薪。

事件頭

一個(gè)事件頭有 19 字節(jié)昧诱,依次排列為四字節(jié)的時(shí)間戳、一字節(jié)的當(dāng)前事件類(lèi)型所袁、四字節(jié)的服務(wù)端 ID盏档、四字節(jié)的當(dāng)前事件長(zhǎng)度描述、四字節(jié)的下個(gè)事件位置(方便跳轉(zhuǎn))以及兩字節(jié)的標(biāo)識(shí)燥爷。

用 ASCII Diagram 表示如下:

+---------+---------+---------+------------+-------------+-------+
|timestamp|type code|server_id|event_length|next_position|flags  |
|4 bytes  |1 byte   |4 bytes  |4 bytes     |4 bytes      |2 bytes|
+---------+---------+---------+------------+-------------+-------+

也可以字節(jié)編造一個(gè)結(jié)構(gòu)體來(lái)解讀這個(gè)頭:

struct BinlogEventHeader
{
    int   timestamp;
    char  type_code;
    int   server_id;
    int   event_length;
    int   next_position;
    char  flags[2];
};

如果你要直接用這個(gè)結(jié)構(gòu)體來(lái)讀取數(shù)據(jù)的話(huà)蜈亩,需要加點(diǎn)手腳。

因?yàn)槟J(rèn)情況下 GCC 或者 G++ 編譯器會(huì)對(duì)結(jié)構(gòu)體進(jìn)行字節(jié)對(duì)齊前翎,這樣讀進(jìn)來(lái)的數(shù)據(jù)就不對(duì)了稚配,因?yàn)?Binlog 并不是對(duì)齊的。為了統(tǒng)一我們需要取消這個(gè)結(jié)構(gòu)體的字節(jié)對(duì)齊港华,一個(gè)方法是使用 #pragma pack(n)道川,一個(gè)方法是使用 __attribute__((__packed__)),還有一種情況是在編譯器編譯的時(shí)候強(qiáng)制把所有的結(jié)構(gòu)體對(duì)其取消苹丸,即在編譯的時(shí)候使用 fpack-struct 參數(shù)愤惰,如:

$ g++ temp.cpp -o a -fpack-struct=1


  根據(jù)上述的結(jié)構(gòu)我們可以明確得到各變量在結(jié)構(gòu)體里面的偏移量,所以在 MySQL 源碼里面([libbinlogevents/include/binlog_event.h](https://github.com/mysql/mysql-server/blob/5.7/libbinlogevents/include/binlog_event.h#L353))有下面幾個(gè)常量以快速標(biāo)記偏移:

```c
#define EVENT_TYPE_OFFSET    4
#define SERVER_ID_OFFSET     5
#define EVENT_LEN_OFFSET     9
#define LOG_POS_OFFSET       13
#define FLAGS_OFFSET         17

而具體有哪些事件則在 libbinlogevents/include/binlog_event.h#L245 里面被定義赘理。如有個(gè) FORMAT_DESCRIPTION_EVENT 事件的 type_code 是 15宦言、UPDATE_ROWS_EVENTtype_code 是 31。

還有那個(gè) next_position商模,在 v4 版本中代表從 Binlog 一開(kāi)始到下一個(gè)事件開(kāi)始的偏移量奠旺,比如到第一個(gè)事件的 next_position 就是 4,因?yàn)槲募^有一個(gè)字節(jié)的長(zhǎng)度施流。然后接下去對(duì)于事件 n 和事件 n + 1 來(lái)說(shuō)响疚,他們有這樣的關(guān)系:

next_position(n + 1) = next_position(n) + event_length(n)

關(guān)于 flags 暫時(shí)不需要了解太多,如果真的想了解的話(huà)可以看看 MySQL 的相關(guān)官方文檔瞪醋。

事件體

事實(shí)上在 Binlog 事件中應(yīng)該是有三個(gè)部分組成忿晕,headerpost-headerpayload银受,不過(guò)通常情況下我們把 post-headerpayload 都?xì)w結(jié)為事件體践盼,實(shí)際上這個(gè) post-header 里面放的是一些定長(zhǎng)的數(shù)據(jù),只不過(guò)有時(shí)候我們不需要特別地關(guān)心宾巍。想要深入了解可以去查看 MySQL 的官方文檔咕幻。

所以實(shí)際上一個(gè)真正的事件體由兩部分組成,用 ASCII Diagram 表示就像這樣:

+=====================================+
| event  | fixed part (post-header)   |
| data   +----------------------------+
|        | variable part (payload)    |
+=====================================+

而這個(gè) post-header 對(duì)于不同類(lèi)型的事件來(lái)說(shuō)長(zhǎng)度是不一樣的顶霞,同種類(lèi)型來(lái)說(shuō)是一樣的肄程,而這個(gè)長(zhǎng)度的預(yù)先規(guī)定將會(huì)在一個(gè)“格式描述事件”中定好。

格式描述事件

在上文我們有提到過(guò),在 Magic Number 之后跟著的是一個(gè)格式描述事件(Format Description Event)蓝厌,其實(shí)這只是在 v4 版本中的稱(chēng)呼玄叠,在以前的版本里面叫起始事件(Start Event)。

在 v4 版本中這個(gè)事件的結(jié)構(gòu)如下面的 ASCII Diagram 所示拓提。

+=====================================+
| event  | timestamp         0 : 4    |
| header +----------------------------+
|        | type_code         4 : 1    | = FORMAT_DESCRIPTION_EVENT = 15
|        +----------------------------+
|        | server_id         5 : 4    |
|        +----------------------------+
|        | event_length      9 : 4    | >= 91
|        +----------------------------+
|        | next_position    13 : 4    |
|        +----------------------------+
|        | flags            17 : 2    |
+=====================================+
| event  | binlog_version   19 : 2    | = 4
| data   +----------------------------+
|        | server_version   21 : 50   |
|        +----------------------------+
|        | create_timestamp 71 : 4    |
|        +----------------------------+
|        | header_length    75 : 1    |
|        +----------------------------+
|        | post-header      76 : n    | = array of n bytes, one byte per event
|        | lengths for all            |   type that the server knows about
|        | event types                |
+=====================================+

這個(gè)事件的 type_code 是 15诸典,然后 event_length 是大于等于 91 的值的,這個(gè)主要取決于所有事件類(lèi)型數(shù)崎苗。

因?yàn)閺牡?76 字節(jié)開(kāi)始后面的二進(jìn)制就代表一個(gè)字節(jié)類(lèi)型的數(shù)組了狐粱,一個(gè)字節(jié)代表一個(gè)事件類(lèi)型的 post-header 長(zhǎng)度,即每個(gè)事件類(lèi)型固定數(shù)據(jù)的長(zhǎng)度胆数。

那么按照上述的一些線(xiàn)索來(lái)看肌蜻,我們能非常快地寫(xiě)出一個(gè)簡(jiǎn)單的解讀 Binlog 格式描述事件的代碼必尼。

如上文所述蒋搜,如果需要正常解讀 Binlog 文件的話(huà),下面的代碼編譯時(shí)候需要加上 -fpack-struct=1 這個(gè)參數(shù)判莉。

#include <cstdio>
#include <cstdlib>

struct BinlogEventHeader
{
    int  timestamp;
    unsigned char type_code;
    int  server_id;
    int  event_length;
    int  next_position;
    short flags;
};

int main()
{
    FILE* fp = fopen("/usr/local/var/mysql/master-bin.000001", "rb");
    int magic_number;
    fread(&magic_number, 4, 1, fp);

    printf("%d - %s\n", magic_number, (char*)(&magic_number));

    struct BinlogEventHeader format_description_event_header;
    fread(&format_description_event_header, 19, 1, fp);

    printf("BinlogEventHeader\n{\n");
    printf("    timestamp: %d\n", format_description_event_header.timestamp);
    printf("    type_code: %d\n", format_description_event_header.type_code);
    printf("    server_id: %d\n", format_description_event_header.server_id);
    printf("    event_length: %d\n", format_description_event_header.event_length);
    printf("    next_position: %d\n", format_description_event_header.next_position);
    printf("    flags[]: %d\n}\n", format_description_event_header.flags);

    short binlog_version;
    fread(&binlog_version, 2, 1, fp);
    printf("binlog_version: %d\n", binlog_version);

    char server_version[51];
    fread(server_version, 50, 1, fp);
    server_version[50] = '\0';
    printf("server_version: %s\n", server_version);
    
    int create_timestamp;
    fread(&create_timestamp, 4, 1, fp);
    printf("create_timestamp: %d\n", create_timestamp);

    char header_length;
    fread(&header_length, 1, 1, fp);
    printf("header_length: %d\n", header_length);

    int type_count = format_description_event_header.event_length - 76;
    unsigned char post_header_length[type_count];
    fread(post_header_length, 1, type_count, fp);
    for(int i = 0; i < type_count; i++) 
    {
        printf("  - type %d: %d\n", i + 1, post_header_length[i]);
    }

    return 0;
}

這個(gè)時(shí)候你得到的結(jié)果有可能就是這樣的了:

1852400382 - ?binpz?
BinlogEventHeader
{
    timestamp: 1439186734
    type_code: 15
    server_id: 1
    event_length: 116
    next_position: 120
    flags[]: 1
}
binlog_version: 4
server_version: 5.6.24-log
create_timestamp: 1439186734
header_length: 19
  - type 1: 56
  - type 2: 13
  - type 3: 0
  - type 4: 8
  - type 5: 0
  - type 6: 18
  - ...

一共會(huì)輸出 40 種類(lèi)型(從 1 到 40)有决,如官方文檔所說(shuō)皿渗,這個(gè)數(shù)組從 START_EVENT_V3 事件開(kāi)始(type_code 是 1)。

跳轉(zhuǎn)事件

跳轉(zhuǎn)事件即 ROTATE_EVENT,其 type_code 是 4痒芝,其 post-header 長(zhǎng)度為 8侠驯。

當(dāng)一個(gè) Binlog 文件大小已經(jīng)差不多要分割了兄纺,它就會(huì)在末尾被寫(xiě)入一個(gè) ROTATE_EVENT——用于指出這個(gè) Binlog 的下一個(gè)文件着降。

它的 post-header 是 8 字節(jié)的一個(gè)東西,內(nèi)容通常就是一個(gè)整數(shù) 4泳炉,用于表示下一個(gè) Binlog 文件中的第一個(gè)事件起始偏移量憾筏。我們從上文就能得出在一般情況下這個(gè)數(shù)字只可能是四,就偏移了一個(gè)魔法數(shù)字花鹅。當(dāng)然我們講的是在 v4 這個(gè) Binlog 版本下的情況氧腰。

然后在 payload 位置是一個(gè)字符串,即下一個(gè) Binlog 文件的文件名刨肃。

各種不同的事件體

由于篇幅原因這里就不詳細(xì)舉例其它普通的不同事件體了古拴,具體的詳解在 MySQL 文檔中一樣有介紹,用到什么類(lèi)型的事件體就可以自己去查詢(xún)之景。

小結(jié)

本文大概介紹了 Binlog 的一些情況斤富,以及 Binlog 的內(nèi)部二進(jìn)制解析結(jié)構(gòu)膏潮。方便大家造輪子用——不然老用別人的輪子锻狗,只知其然而不知其所以然多沒(méi)勁。

好了要下班了,就寫(xiě)到這里過(guò)吧轻纪。

參考

  1. MySQL's binary log 結(jié)構(gòu)簡(jiǎn)介油额,目測(cè)原文在 TaobaoDBA(已無(wú)法訪問(wèn))
  2. MySQL Binlog 的介紹
  3. MySQL 的 binary log 初探
  4. High-Level Binary Log Structure and Contents and related official documents
  5. #pragma pack vs -fpack-struct for Intel C
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市刻帚,隨后出現(xiàn)的幾起案子潦嘶,更是在濱河造成了極大的恐慌,老刑警劉巖崇众,帶你破解...
    沈念sama閱讀 221,820評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件掂僵,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡顷歌,警方通過(guò)查閱死者的電腦和手機(jī)锰蓬,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,648評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)眯漩,“玉大人芹扭,你說(shuō)我怎么就攤上這事∩舛叮” “怎么了舱卡?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,324評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)队萤。 經(jīng)常有香客問(wèn)我轮锥,道長(zhǎng),這世上最難降的妖魔是什么要尔? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,714評(píng)論 1 297
  • 正文 為了忘掉前任交胚,我火速辦了婚禮,結(jié)果婚禮上盈电,老公的妹妹穿的比我還像新娘蝴簇。我一直安慰自己,他們只是感情好匆帚,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,724評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布熬词。 她就那樣靜靜地躺著,像睡著了一般吸重。 火紅的嫁衣襯著肌膚如雪互拾。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 52,328評(píng)論 1 310
  • 那天嚎幸,我揣著相機(jī)與錄音颜矿,去河邊找鬼。 笑死嫉晶,一個(gè)胖子當(dāng)著我的面吹牛骑疆,可吹牛的內(nèi)容都是我干的田篇。 我是一名探鬼主播,決...
    沈念sama閱讀 40,897評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼箍铭,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼泊柬!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起诈火,我...
    開(kāi)封第一講書(shū)人閱讀 39,804評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤兽赁,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后冷守,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體刀崖,經(jīng)...
    沈念sama閱讀 46,345評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,431評(píng)論 3 340
  • 正文 我和宋清朗相戀三年拍摇,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了蒲跨。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,561評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡授翻,死狀恐怖或悲,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情堪唐,我是刑警寧澤巡语,帶...
    沈念sama閱讀 36,238評(píng)論 5 350
  • 正文 年R本政府宣布,位于F島的核電站淮菠,受9級(jí)特大地震影響男公,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜合陵,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,928評(píng)論 3 334
  • 文/蒙蒙 一枢赔、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧拥知,春花似錦踏拜、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,417評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至襟齿,卻和暖如春姻锁,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背猜欺。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,528評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工位隶, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人开皿。 一個(gè)月前我還...
    沈念sama閱讀 48,983評(píng)論 3 376
  • 正文 我出身青樓涧黄,卻偏偏與公主長(zhǎng)得像篮昧,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子弓熏,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,573評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容