七、MySQL備份恢復(fù)

圖片來自網(wǎng)絡(luò)

文/Bruce.Liu1

文章大綱

  1. 備份概念
    1.1. 備份目的
    1.2. 備份方式
    1.3. 備份類型
    1.4. 備份對象
    1.5. 備份策略
  2. mysqldump
    2.1. mysqldump原理
    2.2. 相關(guān)參數(shù)
    2.3. 最佳實踐
  3. Xtrabackup
    3.1. Xtrabackup原理
    3.2. 文件介紹
    3.3. 相關(guān)參數(shù)
    3.4. 最佳實踐
  4. mydumper
    4.1. mydumper原理
    4.2. 相關(guān)參數(shù)
    4.3. 最佳實踐

1.備份概念

為什么要備份?我們試著想一想, 在生產(chǎn)環(huán)境中什么最重要?如果我們服務(wù)器的硬件壞了可以維修或者換新, 軟件問題可以修復(fù)或重新安裝, 但是如果數(shù)據(jù)沒了呢?這可能是最恐怖的事情了吧,我感覺在生產(chǎn)環(huán)境中應(yīng)該沒有什么比數(shù)據(jù)跟更為重要. 那么我們該如何保證數(shù)據(jù)不丟失、或者丟失后可以快速恢復(fù)呢?只要看完這篇, 大家應(yīng)該就能對數(shù)據(jù)備份和恢復(fù)能有一定的了解。

當(dāng)年的911事件致使多少個金融公司遭受巨額損失,據(jù)初步估計,損失在100億美元以上。辦公室設(shè)在世貿(mào)大樓上的公司就更加倒霉,他們的業(yè)務(wù)幾近癱瘓,大量數(shù)據(jù)丟失,其中著名的公司有美洲銀行、朝日銀行、德國銀行、國際信托銀行、肯珀保險公司、馬什保險公司、帝國人壽保險公司、蓋伊·卡彭特保險公司、坎特·菲茲杰拉德投資公司、摩根斯坦利金融公司、美國商品期貨交易所。其中,摩根斯坦利損失最慘,因為它在世貿(mào)中心總共租用了29.8萬平米的辦公用地,公司很多職員連辦公地點都沒有。

更多的故障案例:
1. GitLab.com丟失6個小時數(shù)據(jù),操作員將被迫看“10小時的彩虹貓”,以示懲罰!
2. 攜程內(nèi)部數(shù)據(jù)嚴(yán)重丟失問題
3. 谷歌數(shù)據(jù)中心遭雷劈 部分?jǐn)?shù)據(jù)永久丟失
4. 9.11事件造成的建筑數(shù)據(jù)等財產(chǎn)直接損失達(dá)340億美元

1.1.備份目的

在生產(chǎn)環(huán)境中我們數(shù)據(jù)庫可能會遭遇各種各樣的不測從而導(dǎo)致數(shù)據(jù)丟失,數(shù)據(jù)備份就是針對以下幾種情況:

  • 硬件故障
  • 軟件故障
  • 自然災(zāi)害
  • 黑客攻擊
  • 誤操作 (占比最大)

總結(jié):針對以上各種災(zāi)難性的場景發(fā)生,一個良好的備份,能恢復(fù)至故障前一秒正常的運行狀態(tài)。

1.2.備份方式

備份方式

  • 冷備(cold backup):需要關(guān)mysql服務(wù),讀寫請求均不允許狀態(tài)下進(jìn)行;
    1.即:停止數(shù)據(jù)庫、將整個數(shù)據(jù)文件、日志文件、配置文件等拷貝至一個鏡像。

  • 熱備(hot backup):備份的同時,業(yè)務(wù)不受影響。
    1.邏輯備份
    a) mysqldump:官方自帶的邏輯備份工具
    b) mydumper:開源的多線程邏輯備份工具
    2.物理備份
    a) Enterprise Backup:官方企業(yè)級備份工具(收費產(chǎn)品)
    b) Xtrabackup tools:業(yè)界中最著名的開源備份工具,由Percona公司研發(fā)。

引擎支持是否備份方式

引擎 熱備 冷備
MyISAM ×
InnoDB
TokuDB

備份工具是否支持引擎

  1. 邏輯的備份工具一般來說都支持各種引擎(邏輯的導(dǎo)出和底層的Engine沒啥關(guān)系!!)
  2. 物理備份工具就有很大的局限性,著名的Xtrabackup也只是支持MyISAM、innodb引擎

1.3.備份類型

  • 完全備份:
    full backup,備份全部數(shù)據(jù)集。

  • 增量備份:
    incremental backup,上次完全備份或增量備份以來改變了的數(shù)據(jù),不能單獨使用,要借助完全備份,備份的頻率取決于數(shù)據(jù)的更新頻率。

  • 差異備份:
    differential backup,上次完全備份以來改變了的數(shù)據(jù)。

1.4. 備份對象

一般情況下, 我們需要備份的數(shù)據(jù)分為以下幾種

  • 全量數(shù)據(jù)
  • 二進(jìn)制日志, InnoDB事務(wù)日志
  • 代碼(存儲過程、存儲函數(shù)、觸發(fā)器、事件調(diào)度器)
  • 服務(wù)器配置文件

1.5.備份策略

在訂制一個備份策略之前,首先我們先要向架構(gòu)或業(yè)務(wù)部門了解清楚,我們的業(yè)務(wù)模型/場景類型/安全優(yōu)先級/以及對數(shù)據(jù)恢復(fù)的時間要求等因素, 在我遇到的很多中小型公司/甚至連一些互聯(lián)網(wǎng)金融機(jī)構(gòu)等對于數(shù)據(jù)安全級別很高的場景中,對數(shù)據(jù)庫備份策略也是一無所知,他們常見的做法幾乎都是由信息部門數(shù)據(jù)庫負(fù)責(zé)人或信息部技術(shù)意淫出來的。沒有人會徹徹底底的觀察場景/業(yè)務(wù)/以及安全級別等因素。

下面我們舉常見的幾種業(yè)務(wù)場景進(jìn)行分析:

  • SNS社交網(wǎng)絡(luò)服務(wù)類場景(Social Network Site)(國內(nèi)常見的SNS如:微博/人人網(wǎng)/豆瓣/論壇)
    a) 高并發(fā)
    b) 高可靠性99.999%
    c) 低數(shù)據(jù)一致性
    d) 數(shù)據(jù)恢復(fù)時間要求高

  • 傳統(tǒng)行業(yè)類業(yè)務(wù)場景(電力/物流/零售/服務(wù)/餐飲)
    a) 普遍低并發(fā)
    b) 高可靠性99.999%
    c) 高數(shù)據(jù)一致性
    d) 數(shù)據(jù)恢復(fù)時間一般

  • 傳統(tǒng)金融類場景(銀行/證券/股票)
    a) 普遍低并發(fā)
    b) 高可靠性99.999%
    c) 高數(shù)據(jù)一致性
    d) 數(shù)據(jù)恢復(fù)時間一般

  • 互聯(lián)網(wǎng)金融/支付類場景(微信/支付寶/P2P/電子商務(wù))
    a) 并發(fā)一般
    b) 高可靠性99.999%
    c) 高數(shù)據(jù)一致性
    d) 數(shù)據(jù)恢復(fù)時間高

以上任何一類業(yè)務(wù)場景中,對于可靠性都期望是99.999%,如果不知道什么是5個9,請自己默默的打開鏈接掃掃盲。但他們對于數(shù)據(jù)一致性要求卻有著重大的不同。那有的同學(xué)會說了,可靠性和數(shù)據(jù)一致性可不可以兼顧呢?我相信大家都知道魚和熊掌不可兼得的道理吧!

2.mysqldump

MySQL Client管理工具也叫:獨立的管理實用程序,程序本身不依賴于其他程序模塊。能夠獨立運行。這是MySQL的特性。

2.1.mysqldump原理

1.連接MySQL數(shù)據(jù)庫,設(shè)置基本session級環(huán)境變量
2.開啟快照級事務(wù)(加鎖)并獲取當(dāng)前的GTID
3.釋放鎖資源
4.create savepoint
5.獲取表結(jié)構(gòu)信息/設(shè)置字符集/備份數(shù)據(jù)
6.roll back savepoint
7.重復(fù)步驟5~6直至備份完成

savepoint原理

圖片來自原創(chuàng)

2.2.相關(guān)參數(shù)

--all-databases , -A 導(dǎo)出全部數(shù)據(jù)庫。
--all-tablespaces , -Y 導(dǎo)出全部表空間。
--no-tablespaces , -y 不導(dǎo)出任何表空間信息。
--add-drop-database 每個數(shù)據(jù)庫創(chuàng)建之前添加drop數(shù)據(jù)庫語句。
--add-drop-table 每個數(shù)據(jù)表創(chuàng)建之前添加drop數(shù)據(jù)表語句。(默認(rèn)為打開狀態(tài))
--add-locks 在每個表導(dǎo)出之前增加LOCK TABLES并且之后UNLOCK  TABLE。(默認(rèn)為打開狀態(tài))
--allow-keywords 允許創(chuàng)建是關(guān)鍵詞的列名字。這由表名前綴于每個列名做到。
--apply-slave-statements 在'CHANGE MASTER'前添加'STOP SLAVE',并且在導(dǎo)出的最后添加'START SLAVE'。
--character-sets-dir 字符集文件的目錄
--comments 附加注釋信息。默認(rèn)為打開,可以用--skip-comments取消
--compatible 導(dǎo)出的數(shù)據(jù)將和其它數(shù)據(jù)庫或舊版本的MySQL 相兼容。值可以為mysql323、mysql40、PG、oracle、mssql等,用逗號將它們隔開。它并不保證能完全兼容,而是盡量兼容。
--compact 導(dǎo)出更少的輸出信息(用于調(diào)試)。去掉注釋和頭尾等結(jié)構(gòu)。可以使用選項:--skip-add-drop-table  --skip-add-locks --skip-comments --skip-disable-keys
--complete-insert, -c 使用完整的insert語句(包含列名稱)。這么做能提高插入效率,但是可能會受到max_allowed_packet參數(shù)的影響而導(dǎo)致插入失敗。
--compress, -C 在客戶端和服務(wù)器之間啟用壓縮傳遞所有信息
--create-options, -a 在CREATE TABLE語句中包括所有MySQL特性選項。(默認(rèn)為打開狀態(tài))
--databases, -B 導(dǎo)出幾個數(shù)據(jù)庫。參數(shù)后面所有名字參量都被看作數(shù)據(jù)庫名。
--debug 輸出debug信息,用于調(diào)試。默認(rèn)值為:d:t:o,/tmp/mysqldump.trace
--debug-check 檢查內(nèi)存和打開文件使用說明并退出。
--debug-info 輸出調(diào)試信息并退出
--default-character-set 設(shè)置默認(rèn)字符集,默認(rèn)值為utf8
--delayed-insert 采用延時插入方式(INSERT DELAYED)導(dǎo)出數(shù)據(jù)
--delete-master-logs master 備份后刪除日志. 這個參數(shù)將自動激活--master-data。
--disable-keys 對于每個表,用/*!40000 ALTER TABLE tbl_name DISABLE KEYS */;和/*!40000 ALTER TABLE tbl_name ENABLE KEYS */;語句引用INSERT語句。該選項只適合MyISAM表,默認(rèn)為打開狀態(tài)。
--dump-slave 該選項將導(dǎo)致主的binlog位置和文件名追加到導(dǎo)出數(shù)據(jù)的文件中。設(shè)置為1時,將會以CHANGE MASTER命令輸出到數(shù)據(jù)文件;設(shè)置為2時,在命令前增加說明信息。該選項將會打開--lock-all-tables,除非--single-transaction被指定。該選項會自動關(guān)閉--lock-tables選項。默認(rèn)值為0。
--events, -E 導(dǎo)出事件。
--extended-insert,  -e 使用具有多個VALUES列的INSERT語法。這樣使導(dǎo)出文件更小,并加速導(dǎo)入時的速度。默認(rèn)為打開狀態(tài),使用--skip-extended-insert取消選項。
--fields-terminated-by 導(dǎo)出文件中忽略給定字段。與--tab選項一起使用,不能用于--databases和--all-databases選項
--fields-enclosed-by 輸出文件中的各個字段用給定字符包裹。與--tab選項一起使用,不能用于--databases和--all-databases選項
--fields-optionally-enclosed-by 輸出文件中的各個字段用給定字符選擇性包裹。與--tab選項一起使用,不能用于--databases和--all-databases選項
--fields-escaped-by 輸出文件中的各個字段忽略給定字符。與--tab選項一起使用,不能用于--databases和--all-databases選項
--flush-logs 開始導(dǎo)出之前刷新日志。
--flush-privileges 在導(dǎo)出mysql數(shù)據(jù)庫之后,發(fā)出一條FLUSH  PRIVILEGES 語句。為了正確恢復(fù),該選項應(yīng)該用于導(dǎo)出mysql數(shù)據(jù)庫和依賴mysql數(shù)據(jù)庫數(shù)據(jù)的任何時候。
--force ,-f 在導(dǎo)出過程中忽略出現(xiàn)的SQL錯誤。
--help 顯示幫助信息并退出。
--hex-blob 使用十六進(jìn)制格式導(dǎo)出二進(jìn)制字符串字段。如果有二進(jìn)制數(shù)據(jù)就必須使用該選項。影響到的字段類型有BINARY、VARBINARY、BLOB。
--host, -h 需要導(dǎo)出的主機(jī)信息
--ignore-table 不導(dǎo)出指定表。指定忽略多個表時,需要重復(fù)多次,每次一個表。每個表必須同時指定數(shù)據(jù)庫和表名。例如:--ignore-table=database.table1 --ignore-table=database.table2 ……
--include-master-host-port 在--dump-slave產(chǎn)生的'CHANGE  MASTER TO..'語句中增加'MASTER_HOST=<host>,MASTER_PORT=<port>'  
--insert-ignore 在插入行時使用INSERT IGNORE語句.
--lines-terminated-by 輸出文件的每行用給定字符串劃分。與--tab選項一起使用,不能用于--databases和--all-databases選項。
--lock-all-tables,  -x 提交請求鎖定所有數(shù)據(jù)庫中的所有表,以保證數(shù)據(jù)的一致性。這是一個全局讀鎖,并且自動關(guān)閉--single-transaction 和--lock-tables 選項。
--lock-tables,  -l 開始導(dǎo)出前,鎖定所有表。用READ  LOCAL鎖定表以允許MyISAM表并行插入。
--log-error 附加警告和錯誤信息到給定文件
--master-data 該選項將binlog的位置和文件名追加到輸出文件中。如果為1,將會輸出CHANGE MASTER 命令;如果為2,輸出的CHANGE  MASTER命令前添加注釋信息。該選項將打開--lock-all-tables 選項,除非--single-transaction也被指定(在這種情況下,全局讀鎖在開始導(dǎo)出時獲得很短的時間;其他內(nèi)容參考下面的--single-transaction選項)。該選項自動關(guān)閉--lock-tables選項。
--max_allowed_packet 服務(wù)器發(fā)送和接受的最大包長度。
--net_buffer_length TCP/IP和socket連接的緩存大小。
--no-autocommit 使用autocommit/commit 語句包裹表。
--no-create-db,  -n 只導(dǎo)出數(shù)據(jù),而不添加CREATE DATABASE 語句。
--no-create-info,  -t 只導(dǎo)出數(shù)據(jù),而不添加CREATE TABLE 語句。
--no-data, -d 不導(dǎo)出任何數(shù)據(jù),只導(dǎo)出數(shù)據(jù)庫表結(jié)構(gòu)。
--no-set-names,  -N 等同于--skip-set-charset
--opt 等同于--add-drop-table,  --add-locks, --create-options, --quick, --extended-insert, --lock-tables,  --set-charset, --disable-keys 該選項默認(rèn)開啟,  可以用--skip-opt禁用.
--order-by-primary 如果存在主鍵,或者第一個唯一鍵,對每個表的記錄進(jìn)行排序。
--password, -p 連接數(shù)據(jù)庫密碼
--pipe(windows系統(tǒng)可用) 使用命名管道連接mysql
--port, -P 連接數(shù)據(jù)庫端口號
--protocol 使用的連接協(xié)議,包括:tcp, socket, pipe, memory.
--quick, -q 不緩沖查詢,直接導(dǎo)出到標(biāo)準(zhǔn)輸出。默認(rèn)為打開狀態(tài),使用--skip-quick取消該選項。
--quote-names,-Q 使用(`)引起表和列名。默認(rèn)為打開狀態(tài),使用--skip-quote-names取消該選項。
--replace 使用REPLACE INTO 取代INSERT INTO.
--result-file,  -r 直接輸出到指定文件中。該選項應(yīng)該用在使用回車換行對(\\r\\n)換行的系統(tǒng)上(例如:DOS,Windows)。該選項確保只有一行被使用。
--routines, -R 導(dǎo)出存儲過程以及自定義函數(shù)。
--set-charset 添加'SET NAMES  default_character_set'到輸出文件。默認(rèn)為打開狀態(tài),使用--skip-set-charset關(guān)閉選項。
--single-transaction 該選項在導(dǎo)出數(shù)據(jù)之前提交一個BEGIN SQL語句,BEGIN 不會阻塞任何應(yīng)用程序且能保證導(dǎo)出時數(shù)據(jù)庫的一致性狀態(tài)。它只適用于多版本存儲引擎,僅InnoDB。本選項和--lock-tables 選項是互斥的,因為LOCK  TABLES 會使任何掛起的事務(wù)隱含提交。要想導(dǎo)出大表的話,應(yīng)結(jié)合使用--quick 選項。
--dump-date 將導(dǎo)出時間添加到輸出文件中。默認(rèn)為打開狀態(tài),使用--skip-dump-date關(guān)閉選項。
--skip-opt 禁用–opt選項.
--socket,-S 指定連接mysql的socket文件位置,默認(rèn)路徑/tmp/mysql.sock
--tab,-T 為每個表在給定路徑創(chuàng)建tab分割的文本文件。注意:僅僅用于mysqldump和mysqld服務(wù)器運行在相同機(jī)器上。
--tables ,定需要導(dǎo)出的表名,需要配合--databases (-B)參數(shù)一起使用
--triggers 導(dǎo)出觸發(fā)器。該選項默認(rèn)啟用,用--skip-triggers禁用它。
--tz-utc 在導(dǎo)出頂部設(shè)置時區(qū)TIME_ZONE='+00:00' ,以保證在不同時區(qū)導(dǎo)出的TIMESTAMP 數(shù)據(jù)或者數(shù)據(jù)被移動其他時區(qū)時的正確性。
--user, -u 指定連接的用戶名。
--verbose, --v 輸出多種平臺信息。
--version, -V 輸出mysqldump版本信息并退出
--where, -w 只轉(zhuǎn)儲給定的WHERE條件選擇的記錄。請注意如果條件包含命令解釋符專用空格或字符,一定要將條件引用起來。
--xml, -X 導(dǎo)出XML格式.
--plugin_dir 客戶端插件的目錄,用于兼容不同的插件版本。
--default_auth 客戶端插件默認(rèn)使用權(quán)限。

more info... ...

2.3.最佳實踐

導(dǎo)出表結(jié)構(gòu)

mysqldump --no-data --trigger=false mysql > mysql_01.sql

導(dǎo)出存儲過程

mysqldump -f -Rtdn --trigger=false mysql > mysql_02.sql

導(dǎo)出觸發(fā)器

mysqldump -f -tdn --trigger mysql > mysql_03.sql

導(dǎo)出事件

mysqldump -f -Etdn --trigger=false mysql > mysql_04.sql

導(dǎo)出數(shù)據(jù)

mysqldump -f --single-transaction --trigger=false -t mysql > mysql_05.sql

基于條件導(dǎo)出

mysqldump -t --single-transaction --where='cname="'jreey'"'  tydb tab01 > /tmp/tab01.sql

導(dǎo)出某張表

mysqldump -S /data1/db3316/my3316.sock -pxxxxx --default-character-set=utf8 --single-transaction --set-gtid-purged=off --databases intelligent_os --tables beacon_base_pos > /tmp/beacon_base_pos.sql

實例一:數(shù)據(jù)庫邏輯導(dǎo)出于恢復(fù)

備份一個數(shù)據(jù)庫

mysqldump -S /data1/db3307/my3307.sock --default-character-set=utf8 --master-data=2 --no-create-db --single-transaction --set-gtid-purged=off -q --extended-insert --databases zabbix > /data1/mysqlbackup/m3307-20170306-dump.sql

恢復(fù)

mysql -S /data1/db3307/my3307.sock -e "create database zabbix"
mysql -S /data1/db3307/my3307.sock < /data1/mysqlbackup/m3307-20170306-dump.sql

補(bǔ)充:導(dǎo)出導(dǎo)入平面文件”

select * INTO OUTFILE '/tmp/errorlog.txt' FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' LINES TERMINATED BY '\n' from error_log;
load data infile '/tmp/errorlog.txt' into table test.error_log FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' LINES TERMINATED BY '\n';

3.Xtrabackup

xtrabackup是Percona公司CTO Vadim參與開發(fā)的一款基于InnoDB的在線熱備工具,具有開源,免費,支持在線熱備,備份恢復(fù)速度快,占用磁盤空間小等特點,并且支持不同情況下的多種備份形式。(該產(chǎn)品的出現(xiàn)解決了業(yè)界內(nèi)MySQL社區(qū)版本中物理備份的空白)xtrabackup的官方下載地址為http://www.percona.com/software/percona-xtrabackup

Xtrabackup是由percona提供的mysql數(shù)據(jù)庫備份工具,據(jù)官方介紹,這也是世界上惟一一款開源的能夠?qū)nnodb和xtradb數(shù)據(jù)庫進(jìn)行熱備的工具。特點:

  • 備份過程快速、可靠;
  • 備份過程不會打斷正在執(zhí)行的事務(wù);
  • 能夠基于壓縮等功能節(jié)約磁盤空間和流量;
  • 自動實現(xiàn)備份檢驗;
  • 還原速度快;

xtrabackup包含兩個主要的工具,即xtrabackup和innobackupex:

  • xtrabackup只能備份innodb和xtradb兩種引擎的表,而不能備份myisam引擎的表;
  • innobackupex是一個封裝了xtrabackup的Perl腳本,支持同時備份innodb和myisam,但在對myisam備份時需要加一個全局的讀鎖。還有就是myisam不支持增量備份。

3.1.Xtrabackup原理

3.1.1.全備份|恢復(fù)原理
  • 備份原理
圖片來自網(wǎng)絡(luò)

1.備份開始前開啟一個后臺檢測進(jìn)程,實時檢測mysql redo的變化寫入到xtrabackup_logfile文件
2.拷貝innodb engine涉及的ibd ibdata1數(shù)據(jù)文件(拷貝的單位是page,而不是文件)
3.數(shù)據(jù)庫級只讀鎖(FLUSH TABLES WITH READ LOCK)
4.拷貝除innodb enging之外的數(shù)據(jù)文件(多數(shù)指MyIASM的表)
5.獲取當(dāng)前數(shù)據(jù)庫binary log position
6.釋放數(shù)據(jù)庫級只讀鎖(釋放全局級鎖)
7.等待redo變化寫入xtrabackup_logfile并關(guān)閉Xtrbackup進(jìn)程

建議: xtrabackup工具最好只備份innodb engine的表,因為這樣,就會節(jié)省掉步驟四的物理copy時間,從而大大減少,數(shù)據(jù)庫鎖的時間.

  • 恢復(fù)原理
圖片來自網(wǎng)絡(luò)

1.Xtrabackup內(nèi)嵌的innodb實例,回放xtrabackup_log日志至備份集
2.將提交的事務(wù)信息變更應(yīng)用到innodb數(shù)據(jù)/表空間,同時回滾未提交的事務(wù)(這一過程類似innodb的實例恢復(fù))。
3.根據(jù)配置文件(my.cnf)恢復(fù)數(shù)據(jù)文件、日志文件到指定路徑

3.1.2.增量備份|恢復(fù)原理
  • 備份原理

"增量"備份的過程主要是通過拷貝innodb中有變更的"頁"(這些變更的數(shù)據(jù)頁指的是"頁"的LSN大于xtrabackup_checkpoints中給定的LSN)。增量備份是基于全備的,第一次增備的數(shù)據(jù)必須要基于上一次的全備,之后的每次增備都是基于上一次的增備,最終達(dá)到一致性的增備。

圖片來自網(wǎng)絡(luò)

1.備份開始前開啟一個后臺檢測進(jìn)程,實時檢測mysql redo的變化寫入到xtrabackup_logfile文件
2.拷貝上次全備份以后LSN變化的數(shù)據(jù)
3.數(shù)據(jù)庫級只讀鎖(FLUSH TABLES WITH READ LOCK)
4.拷貝除innodb enging之外的數(shù)據(jù)文件(多數(shù)指MyIASM的表)
5.獲取當(dāng)前數(shù)據(jù)庫binary log position
6.釋放數(shù)據(jù)庫級只讀鎖(釋放全局級鎖)
7.等待redo變化寫入xtrabackup_logfile并關(guān)閉Xtrbackup進(jìn)程

注意:innobackupex增量備份過程中的"增量"處理,其實主要是相對innodb而言,對myisam和其他存儲引擎而言,它仍然是全拷貝(全備份)

  • 恢復(fù)原理
圖片來自網(wǎng)絡(luò)
圖片來自網(wǎng)絡(luò)

1.全備份以只"重做"的方式回放xtrabackup_log日志至備份集(為后面增量數(shù)據(jù)的合并做基礎(chǔ))
2.依次合并增量備份至完整備份集(此時的merge可以commit、rollback)
3.Xtrabackup內(nèi)嵌的innodb實例,回放xtrabackup_log日志至備份集
4.將提交的事務(wù)信息變更應(yīng)用到innodb數(shù)據(jù)/表空間,同時回滾未提交的事務(wù)(這一過程類似innodb的實例恢復(fù))。
5.根據(jù)配置文件(my.cnf)恢復(fù)數(shù)據(jù)文件、日志文件到指定路徑

和全備恢復(fù)類似,也需要兩步,一是數(shù)據(jù)文件的恢復(fù),如圖1,這里的數(shù)據(jù)來源由3部分組成:全備份,增量備份和xtrabackup log。圖2是對未提交事務(wù)的回滾

  • 如何選擇備份集
圖片來自原創(chuàng)

3.2.文件介紹

  • backup-my.cnf
    備份集的配置選項文件

  • xtrabackup_binlog_info
    當(dāng)前正在使用的二進(jìn)制日志文件及至備份的位置。

  • xtrabackup_binlog_pos_innodb
    包含二進(jìn)制日志文件及用于InnoDB或XtraDB表的二進(jìn)制日志文件的當(dāng)前position

  • xtrabackup_checkpoints
    備份類型(如完全或增量)、備份狀態(tài)(如是否已經(jīng)為prepared狀態(tài))和LSN(日志序列號)范圍信息;

  • xtrabackup_info
    備份集概要

  • xtrabackup_logfile
    備份過程中記錄redo變化的日志文件

3.3.相關(guān)參數(shù)

--defaults-file=# 該選項傳遞給xtrabackup子進(jìn)程,從指定文件讀取缺省選項
--apply-log 從備份恢復(fù)
--redo-only 選項用于準(zhǔn)備全庫備份和合并處最有一個備份外的所有增量備份。該選項強(qiáng)制跳過rollback階段,只進(jìn)行redo。這是有必要使用的,如果備份后,要使用增量改變的。
--copy-back 從備份目錄拷貝數(shù)據(jù)和索引文件到datadir目錄
--move-back 移動之前的所有備份從一個備份目錄到他們的原始位置
--incremental 建立一個增量備份,傳遞給xtrabackup的子進(jìn)程。該參數(shù)可以和參數(shù)--incremental-lsn or --incremental-basedir配合使用。
--incremental-basedir=DIRECTORY 指定一個包換全庫備份的目錄作為增量備份的基礎(chǔ)數(shù)據(jù)庫。
--incremental-dir=DIRECTORY 指定增量備份與全庫備份合并去建立一個新的全備份的目錄。
--remote-host=HOSTNAME 備份到遠(yuǎn)程主機(jī)上,使用ssh
--stream=[tar|cpio(notimplemented)] 指定備份標(biāo)準(zhǔn)輸出格式
--tmpdir=DIRECTORY 默認(rèn)與tmpdir相同。使用—remote-host或—stream參數(shù)后,傳輸日志文件將存放在臨時目錄下
--use-memory=MB 傳遞給xtrabackup子進(jìn)程。恢復(fù)使用內(nèi)存大小
--parallel=NUMBER-OF-THREADS 選項傳遞給xtrabackup子進(jìn)程,指定數(shù)據(jù)傳輸線程總數(shù)。默認(rèn)為1
--compress[=LEVEL] 選項傳遞給xtrabackup子進(jìn)程。壓縮級別在0-9.1快速壓縮,9最佳壓縮,0不壓縮。默認(rèn)為1.
--compress-threads[=NUMBER] 壓縮時的并行線程總數(shù),一般來說要和--parallel保持一致
--throttle=iOS 選項傳遞給xtrabackup子進(jìn)程,限制IO線程數(shù)量
--sleep=MS 選項傳遞給xtrabackup子進(jìn)程。每拷貝1MB數(shù)據(jù)暫停多少MS時間
--include=REGEXP 選項傳遞給xtrabackup子進(jìn)程。使用正則進(jìn)行匹配
--databases=LIST 指定備份數(shù)據(jù)庫
--tables-file=FILE 指定需要備份的表
--uncompress 選項傳遞給xtrabackup子進(jìn)程。對壓縮過的InnoDB數(shù)據(jù)文件不進(jìn)行壓縮
--export 僅使用于prepare選項。選項傳遞給xtrabackup子進(jìn)程。
--slave-info 備份復(fù)制從服務(wù)端,主從信息記錄在ibbackup_slave_info文件中
--no-timestamp 不在備份根目錄下創(chuàng)建以當(dāng)前時間戳為名稱的新的備份目錄
--ibbackup=IBBACKUP-BINARYibbackup 二進(jìn)制路徑
--no-lock 禁止表級鎖。全部是InnoDB引擎表和不關(guān)系二進(jìn)制日志位置下使用
--scpopt=SCP-OPTIONS 指定scp參數(shù)

3.4.最佳實踐

xtrabackup官方網(wǎng)站:https://www.percona.com/
xtrabackup下載站點:https://www.percona.com/downloads/XtraBackup/LATEST/

3.4.1.完全備份恢復(fù)
  • 備份數(shù)據(jù)庫
innobackupex --defaults-file=/etc/mysql/my10059.cnf -S /var/wd/db10059/my10059.sock -p 123 --use-memory=256M --no-timestamp /data1/mysqlbackup/xtra_full_135156_10059
  • 恢復(fù)數(shù)據(jù)庫
innobackupex --defaults-file=/data1/mysqlbackup/xtra_full_135156_10059/backup-my.cnf --apply-log /data1/mysqlbackup/xtra_full_135156_10059
innobackupex --defaults-file=/etc/mysql/my10059.cnf --move-back /data1/mysqlbackup/xtra_full_135156_10059
chown -R mysql:mysql /var/wd/db10059/
3.4.2.增量備份恢復(fù)
  • 備份數(shù)據(jù)庫
  1. 全備份
innobackupex --defaults-file=/etc/my.cnf -u root -S /data1/db3306/my3306.sock -p123 --no-timestamp /data1/xtra_full_168160_3306
  1. 增量備份
innobackupex --defaults-file=/etc/my.cnf -S /data1/db3306/my3306.sock -p 123 --no-timestamp --incremental /data1/xtra_incr_168160_3306 --incremental-basedir=/data1/xtra_full_168160_3306
  • 恢復(fù)數(shù)據(jù)庫
  1. 全備份只"重做"回放xtrabackup log
innobackupex --apply-log --redo-only /data1/xtra_full_168160_3306
  1. merge增量備份集(如果有多個,順序merge)
innobackupex --apply-log --redo-only xtra_full_168160_3306 --incremental-dir=xtra_incr_168160_3306
  1. 完整的回放xtrabackup log
innobackupex --defaults-file=/data1/xtra_full_168160_3306/backup-my.cnf  --apply-log /data1/xtra_incr_168160_3306
innobackupex --defaults-file=/etc/my.cnf --move-back xtra_full_168160_3306
  1. 通過binlog恢復(fù)誤刪除數(shù)據(jù)
mysqlbinlog --start-position=423234035  16703402-bin.000561 | mysql -S /data1/db3402/my3402.sock -pxxx
mysqlbinlog 16703402-bin.000562 16703402-bin.000563 16703402-bin.000564 16703402-bin.000565 16703402-bin.000566 | mysql -S /data1/db3402/my3402.sock -pxxx
mysqlbinlog 16703402-bin.000567 16703402-bin.000568 16703402-bin.000569 16703402-bin.000570 16703402-bin.000571 16703402-bin.000572 | mysql -S /data1/db3402/my3402.sock -pxxx
mysqlbinlog 16703402-bin.000573 16703402-bin.000574 16703402-bin.000575 16703402-bin.000576 16703402-bin.000577 | mysql -S /data1/db3402/my3402.sock -pxxx
mysqlbinlog --stop-position=657188280 16703402-bin.000578 | mysql -S /data1/db3402/my3402.sock -pxxxx
3.4.3.備份新特性
  • "流"方式壓縮備份
    Xtrabackup對備份的數(shù)據(jù)文件支持“流”功能,即可以將備份的數(shù)據(jù)通過STDOUT傳輸給tar程序進(jìn)行歸檔,而不是默認(rèn)的直接保存至某備份目錄中。要使用此功能,僅需要使用--stream選項即可。
innobackupex --defaults-file=/etc/mysql/my10059.cnf -p 123 --use-memory=256M --no-timestamp --stream=tar /data1/mysqlbackup/xtra_full_gzip135156_10059 | gzip  > /data1/mysqlbackup/xtra_full_gzip135156_10059.tar.gz
  • "innodb page"方式壓縮備份
innobackupex --defaults-file=/etc/mysql/my10059.cnf -S /var/wd/db10059/my10059.sock -p 123 --compress --use-memory=256M --no-timestamp /data1/mysqlbackup/xtra_full_135156_10059
  • 部分備份
innobackupex --defaults-file=/etc/mysql/my10059.cnf -S /var/wd/db10059/my10059.sock -p 123 --databases='sys performance_schema mysql custom_db' --use-memory=256M --no-timestamp /data1/mysqlbackup/xtra_full_135156_10059
  • 并行備份
innobackupex --defaults-file=/etc/mysql/my10059.cnf -S /var/wd/db10059/my10059.sock -p 123 --parallel=6 --use-memory=256M --no-timestamp /data1/mysqlbackup/xtra_full_135156_10059

4.mydumper

mydumper(&myloader)是用于對MySQL數(shù)據(jù)庫進(jìn)行多線程備份和恢復(fù)的開源 (GNU GPLv3)工具。開發(fā)人員主要來自MySQL、Facebook和SkySQL公司,目前由Percona公司開發(fā)和維護(hù),是 Percona Remote DBA 項目的重要組成部分,包含在Percona XtraDB Cluster中。mydumper的第一版0.1發(fā)布于2010.3.26,最新版本0.9.1發(fā)布于2015.11.06。

Mydumper主要特性:

  • 開源 (GNU GPLv3)
  • 輕量級C語言寫的
  • 快速的文件壓縮
  • 支持導(dǎo)出binlog
  • 執(zhí)行速度比mysqldump快10倍
  • 多線程恢復(fù)(適用于0.2.1以上版本)
  • 事務(wù)性和非事務(wù)性表一致的快照(適用于0.2.2以上版本)
  • 以守護(hù)進(jìn)程的工作方式,定時快照和連續(xù)二進(jìn)制日志(適用于0.5.0以上版本)

4.1.mydumper原理

mydumper作為一個實用工具,能夠良好支持多線程工作,可以并行的多線程的從表中讀入數(shù)據(jù)并同時寫到不同的文件里,這使得它在處理速度方面快于傳統(tǒng)的mysqldump N倍

圖片來自網(wǎng)絡(luò)

原理分析
mydumper的工作過程:

  • 主線程對備份實例加讀鎖,阻塞寫操作以建立一致性數(shù)據(jù)備份快照(FLUSH TABLES WITH READ LOCK)
  • 讀取當(dāng)前時間點的二進(jìn)制日志文件名和日志寫入的位置并記錄在metadata文件中,以供即使點恢復(fù)使用
  • 創(chuàng)建工作線程,初始化備份任務(wù)隊列,并向隊列中推送數(shù)據(jù)庫元數(shù)據(jù)(schema)、非InnoDB表和InnoDB表的備份任務(wù);
  • 工作線程負(fù)責(zé)將備份任務(wù)隊列中的任務(wù)按順序取出并完成備份(dump線程數(shù)可以指定,默認(rèn)是4)
  • 分別建立與備份實例連接,將session的事務(wù)級別設(shè)置為repeatable-read,用于實現(xiàn)可重復(fù)讀;
  • 在主線程仍持有全局讀鎖時開啟事務(wù)進(jìn)行快照讀,這樣保證了讀到的一致性數(shù)據(jù)與主線程相同,實現(xiàn)了備份數(shù)據(jù)的一致性;
  • 按序從備份任務(wù)隊列中取出備份任務(wù),工作線程先進(jìn)行MyISAM等非InnoDB表備份
  • 非事物引擎?zhèn)浞萃旰螅骶€程釋放全局只讀鎖(UNLOCK TABLES)
  • 完成InnoDB表備份,事務(wù)結(jié)束,關(guān)閉鏈接

表數(shù)據(jù)拆分方式如下所述:

  • mydumper優(yōu)先選擇主鍵索引的第一列作為chunk劃分字段
  • 若不存在主鍵索引,則選擇第一個唯一索引作為劃分依據(jù)
  • 若還不存在,則選擇區(qū)分度(Cardinality)最高的任意索引。
  • 如果還是無法滿足,則只能進(jìn)行表級的并行備份

范圍拆分方式:

  • 在確定了chunk劃分字段后,先獲取該字段的最大和最小值
  • 再通過執(zhí)行“explain select field from db.table”來估計該表的記錄數(shù)
  • 最后根據(jù)所設(shè)的每個任務(wù)(文件)記錄數(shù)來將該表劃分為多個chunk。

備份所生成的文件
目錄中包含一個metadata文件:

  • 記錄了備份數(shù)據(jù)庫在備份時間點的二進(jìn)制日志文件名,日志的寫入位置
  • 如果是在從庫進(jìn)行備份,還會記錄備份時同步至主庫的二進(jìn)制日志文件及寫入位置

每個表有兩個備份文件:

  • database.table-schema.sql 表結(jié)構(gòu)文件
  • database.table.sql 表數(shù)據(jù)文件
  • 如果對表文件分片,將生成多個備份數(shù)據(jù)文件,可以指定行數(shù)或指定大小分片

注意:mydumper導(dǎo)出時不寫binlog,復(fù)制環(huán)境中需要注意。

4.2.相關(guān)參數(shù)

  • mydumper參數(shù)介紹:
-B, --database 需要備份的庫
-T, --tables-list 需要備份的表,用,分隔
-o, --outputdir 輸出目錄 
-s, --statement-size Attempted size of INSERT statement in bytes, default 1000000
-r, --rows 試圖分裂成很多行塊表
-c, --compress 壓縮輸出文件
-e, --build-empty-files 即使表沒有數(shù)據(jù),還是產(chǎn)生一個空文件
-x, --regex 支持正則表達(dá)式
-i, --ignore-engines 忽略的存儲引擎,用,分隔
-m, --no-schemas 不導(dǎo)出表結(jié)構(gòu)
-k, --no-locks 不執(zhí)行臨時共享讀鎖 警告:這將導(dǎo)致不一致的備份
-l, --long-query-guard 長查詢,默認(rèn)60s
--kill-long-queries kill掉長時間執(zhí)行的查詢(instead of aborting)
-D, --daemon 啟用守護(hù)進(jìn)程模式
-I, --snapshot-interval dump快照間隔時間,默認(rèn)60s,需要在daemon模式下
-L, --logfile 日志文件
-h, --host
-u, --user
-p, --password
-P, --port
-S, --socket
-t, --threads 使用的線程數(shù),默認(rèn)4
-C, --compress-protocol 在mysql連接上使用壓縮
-V, --version
-v, --verbose 更多輸出, 0 = silent, 1 = errors, 2 = warnings, 3 = info, default 2
  • myloader參數(shù)介紹:
-d, --directory 導(dǎo)入備份目錄
-q, --queries-per-transaction 每次執(zhí)行的查詢數(shù)量, 默認(rèn)1000
-o, --overwrite-tables 如果表存在刪除表
-B, --database 需要還原的庫
-e, --enable-binlog 啟用二進(jìn)制恢復(fù)數(shù)據(jù)
-h, --host
-u, --user
-p, --password
-P, --port
-S, --socket
-t, --threads 使用的線程數(shù)量,默認(rèn)4
-C, --compress-protocol 連接上使用壓縮
-V, --version
-v, --verbose 更多輸出, 0 = silent, 1 = errors, 2 = warnings, 3 = info, default 2

4.3.最佳實踐

yum install gcc gcc-c++ make cmake glib2-devel zlib-devel pcre-devel openssl-devel mysql-devel
cd mydumper-0.9.1
cmake .
make
cp -p mydumper /usr/local/bin
cp -p myloader /usr/local/bin
ldd mydumper
  • 備份數(shù)據(jù)庫
mydumper -S /data1/db3307/my3307.sock -u root --tz-utc --threads 32 -o /data1/mysqlbackup/full_3307_mydumper
  • 恢復(fù)數(shù)據(jù)庫
myloader -S /data1/db3307/my3307.sock -u root --threads 32 -o -d /data1/mysqlbackup/full_3307_mydumper
  • 常見錯誤
** (mydumper:142452): WARNING **: Broken table detected, please review: wanda.view_s06_ffan_mem_reg_cnt_minute
** (mydumper:142452): WARNING **: Broken table detected, please review: wanda.view_s06_ffan_wifi_mobile_to_plaza_uniq_real_time
** (mydumper:142452): CRITICAL **: Could not read data from imc.MSG_BLACK_BATCH: Table definition has changed, please retry transaction
** (mydumper:142452): CRITICAL **: Error dumping table (scm_db.gerritapp_plan_jenkins) data: Table 'scm_db.gerritapp_plan_jenkins' doesn't exist
** (mydumper:142452): CRITICAL **: Error dumping schemas (wanda.view_s06_ffan_mem_reg_cnt_hour): SELECT command denied to user ''@'%' for column 'plaza_id' in table 's06_ffan_mem_reg_real_time'
** (mydumper:142452): CRITICAL **: Error dumping schemas (wanda.view_s06_ffan_mem_reg_info_uniq_real_time): SELECT command denied to user ''@'%' for column 'mobile' in table 's06_ffan_mem_reg_info_real_time'
** (myloader:1408769): CRITICAL **: Error restoring invoice.INVOICE_STOREINFO from file invoice.INVOICE_STOREINFO-schema.sql: Invalid default value for 'PAUSE_TIME'
** (myloader:1408769): CRITICAL **: Error restoring invoice.INVOICE_TASK from file invoice.INVOICE_TASK-schema.sql: Invalid default value for 'INVOICE_START_TIME'
** (myloader:1408769): CRITICAL **: Error restoring pubsub.logs from file pubsub.logs-schema.sql: Invalid default value for 'operatorTime'

出現(xiàn)問題的View

CREATE ALGORITHM=UNDEFINED DEFINER=`mycat`@`10.%` SQL SECURITY DEFINER VIEW `view_s06_ffan_mem_reg_cnt_hour` AS select `mycat`.`s06_ffan_mem_reg_real_time`.`plaza_id` AS `plaza_id`,date_format(`mycat`.`s06_ffan_mem_reg_real_time`.`create_time`,'%Y-%m-%d %H') AS `reg_time`,count(1) AS `total`,count((case when (`mycat`.`s06_ffan_mem_reg_real_time`.`channel` = 'app') then 1 end)) AS `app`,count((case when (`mycat`.`s06_ffan_mem_reg_real_time`.`channel` = 'web') then 1 end)) AS `web`,count((case when (`mycat`.`s06_ffan_mem_reg_real_time`.`channel` = 'html5') then 1 end)) AS `html5`,count((case when (`mycat`.`s06_ffan_mem_reg_real_time`.`channel` = 'wifi') then 1 end)) AS `wifi`,count((case when (`mycat`.`s06_ffan_mem_reg_real_time`.`channel` = 'card') then 1 end)) AS `card`,count((case when (`mycat`.`s06_ffan_mem_reg_real_time`.`channel` = 'sms') then 1 end)) AS `sms`,count((case when (`mycat`.`s06_ffan_mem_reg_real_time`.`channel` = 'thrid') then 1 end)) AS `thrid`,count((case when (`mycat`.`s06_ffan_mem_reg_real_time`.`channel` = 'offline') then 1 end)) AS `offline` from `s06_ffan_mem_reg_real_time` where (`mycat`.`s06_ffan_mem_reg_real_time`.`create_time` >= '2015-12-08') group by `mycat`.`s06_ffan_mem_reg_real_time`.`plaza_id`,`reg_time`;
  • 案例分享
    1.8T數(shù)據(jù)庫服務(wù)器,32核,希捷pci-E SSD卡
    導(dǎo)出時間25分鐘(意不意外、驚不驚喜、刺不刺激)
    導(dǎo)入時間5小時15分鐘

掃描下方二維碼關(guān)注本人微信號!歡迎大家交流學(xué)習(xí)!

Bruce.Liu










最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,363評論 6 532
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,497評論 3 416
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,305評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,962評論 1 311
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 71,727評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,193評論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,257評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,411評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,945評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 40,777評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,978評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,519評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,216評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,642評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,878評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,657評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 47,960評論 2 373

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