帶你了解分布式系統(tǒng)的數(shù)據(jù)一致性問題

老劉是一名即將找工作的研二學生,寫博客一方面是復習總結大數(shù)據(jù)開發(fā)的知識點,一方面是希望能夠幫助和自己一樣自學編程的伙伴。由于老劉是自學大數(shù)據(jù)開發(fā),博客中肯定會存在一些不足,還希望大家能夠批評指正,讓我們一起進步!

今天給各位小伙伴聊聊分布式系統(tǒng)的數(shù)據(jù)一致性問題,這個一定要從服務器架構部署的發(fā)展歷程講起!文章篇幅較長,請大家耐心觀看,精彩千萬不要錯過!

1. 背景

1.1. 集中式服務

首先要講的是集中式服務,那集中式是什么?就是事情都由一臺服務器搞定。

而集中式系統(tǒng)就是由一臺或多臺主計算機組成中心節(jié)點,數(shù)據(jù)集中存儲于這個中心節(jié)點中,并且整個系統(tǒng)的所有業(yè)務都在這個中心節(jié)點上,系統(tǒng)所有的功能都由它做。

也就是說,在集中式系統(tǒng)中,每個客戶端僅僅負責數(shù)據(jù)的輸入和輸出,而數(shù)據(jù)的存儲與控制處理完全交給主機完成。

那集中式服務優(yōu)點:

1、結構簡單 2、部署簡單 3、項目架構簡單

但是它的缺點也是非常明顯:

1、大型主機的研發(fā)和維護成本非常高

2、大型主機非常昂貴

3、存在單點故障問題,主機一掛,所有服務終止

4、大型主機的性能擴展受限于摩爾定律

什么是摩爾定律?

摩爾定律是由英特爾(Intel)創(chuàng)始人之一戈登·摩爾(Gordon Moore)提出來的。其內容為:當價格不變時,集成電路上可容納的元器件的數(shù)目,約每隔18-24個月便會增加一倍,性能也將提升一倍。換言之,每一美元所能買到的電腦性能,將每隔18-24個月翻一倍以上。摘自:百度百科

摩爾定律告訴我們:縱向擴展理論上是受限的,所以只能考慮橫向擴展,而且從理論上說,橫向擴展理論上是不受限的!

那既然縱向擴展受限,我們就去嘗試橫向擴展,就有了分布式!

1.2. 分布式服務

分布式意味著可以采用更多的普通計算機(相對于昂貴的大型機)組成分布式集群對外提供服務。計算機越多,CPU、內存、存儲資源等也就越多,能夠處理的并發(fā)訪問量也就越大。

例如一個由分布式系統(tǒng)實現(xiàn)的電子商城,在功能上可能被拆分成多個應用,分別提供不同的功能,組成一個分布式系統(tǒng)對外提供服務。

所以,分布式系統(tǒng)中的計算機在空間上是幾乎沒有限制的,這些計算機可能被放在不同的機柜上,也可能被部署在不同的機房中,還可能在不同的城市中。

和集中式系統(tǒng)相比,分布式系統(tǒng)的性價比更高、處理能力更強、可靠性更高、也有很好的擴展性。

但是,分布式解決了網站的高并發(fā)問題的同時也帶來了一些其他問題。

首先,分布式的必要條件就是網絡,這可能對性能甚至服務能力造成一定的影響。其次,一個集群中的服務器數(shù)量越多,服務器宕機的概率也就越大。另外,由于服務在集群中分布式部署,用戶的請求只會落到其中一臺機器上,所以,一旦處理不好就很容易產生數(shù)據(jù)一致性問題。

1.3. 分布式存在的異常

1、通信異常:網絡不可用(消息延遲或者丟失),會導致分布式系統(tǒng)內部無法順利進行網絡通信,所以可能造成多個節(jié)點數(shù)據(jù)丟失和狀態(tài)不一致,還有可能造成數(shù)據(jù)亂序。

2、網絡分區(qū):網絡不連通,但各個子網絡的內部網絡是正常的,從而導致整個系統(tǒng)的網絡環(huán)境被切分成若干個孤立的區(qū)域,分布式系統(tǒng)就出現(xiàn)了局部小集群造成的數(shù)據(jù)不一致。

3、節(jié)點故障:服務器節(jié)點出現(xiàn)的宕機的現(xiàn)象。

4、存儲數(shù)據(jù)丟失:對于有狀態(tài)節(jié)點來說,數(shù)據(jù)丟失意味著狀態(tài)丟失,通常只能從其他節(jié)點讀取、恢復存儲的狀態(tài)。解決方案:利用多副本機制。

1.4. 衡量分布式系統(tǒng)的性能指標

1、性能:這是一個非常讓人頭疼的問題,追求高吞吐的系統(tǒng),往往很難做到低延遲;系統(tǒng)平均響應時間較長時,也很難提高QPS。

系統(tǒng)的吞吐能力,指系統(tǒng)在某一時間可以處理的數(shù)據(jù)總量,通常可以用系統(tǒng)每秒處理的總數(shù)據(jù)量來衡量;

系統(tǒng)的響應延遲,指系統(tǒng)完成某一功能需要使用的時間;

系統(tǒng)的并發(fā)能力,指系統(tǒng)可以同時完成某一功能的能力,通常也用QPS來衡量。

2、可用性:系統(tǒng)的可用性(availability)指系統(tǒng)在面對各種異常時可以正確提供服務的能力。可用性是分布式的重要指標,衡量了系統(tǒng)的魯棒性,是系統(tǒng)容錯能力的體現(xiàn)。

3、可擴展性:系統(tǒng)的可擴展性(scalability)指分布式系統(tǒng)通過擴展集群機器規(guī)模提高系統(tǒng)性能(吞吐、延遲、并發(fā))、存儲容量、計算能力的特性。

4、一致性:分布式系統(tǒng)為了提高可用性,總是不可避免地使用副本的機制,從而引發(fā)副本一致性的問題。

例如,就是一份數(shù)據(jù)存在分布式系統(tǒng),存在多個不同的節(jié)點當中存著相同的數(shù)據(jù)。如果多個不同的節(jié)點存的數(shù)據(jù)不一樣,多個客戶端去訪問的時候就會存在這種情況,第1個客戶端去訪問的結果為A,第2個客戶端訪問的結果為B,兩個客戶端訪問得到不同的結果,那就是一致性做的不好。

說了這么多,我們如果設計一個優(yōu)秀的分布式系統(tǒng),它應該具有這些特點:吞吐高、響應延遲低、并發(fā)強、可用性很高、可擴展性很強、一致性很好。但并不是每個特點都能滿足,有幾個特點是相互矛盾的,需要我們想辦法克服!

而在分布式場景中真正復雜的是數(shù)據(jù)一致性的問題!

1.5. 一致性理解

一致性也分很多種,這里說說老劉了解的三個。

強一致性:寫操作完成之后,讀操作一定能讀到最新數(shù)據(jù)。通俗地講就是客戶端只要把結果寫進去了,什么時候訪問都能拿到最新的數(shù)據(jù)。但是在分布式場景中很難實現(xiàn),后續(xù)的Paxos 算法,Quorum 機制,ZAB 協(xié)議等能實現(xiàn)!

弱一致性:不保證拿到最新的數(shù)據(jù),也有可能拿到舊的數(shù)據(jù)。

最終一致性:不考慮中間的任何狀態(tài),只保證經過一段時間之后,最終系統(tǒng)內數(shù)據(jù)正確。在高并發(fā)場景中,它也是使用最廣的一致性模型。

1.6. 分布式一致性的作用

說了那么多分布式一致性的內容,那它的作用是什么呢?

1、為了提高系統(tǒng)的可用性,一般都會使用多副本機制,多副本就會有分布式一致性的問題,它就是為了提高系統(tǒng)的可用性,防止單點節(jié)點故障引起的系統(tǒng)不可用。

2、提高系統(tǒng)的整體性能,數(shù)據(jù)分布在集群中多個節(jié)點上,它們都能為用戶提供服務。

老劉說了這么多,大家有沒有猜到想引出什么內容呢?

上述那么多內容只為引出分布式系統(tǒng)的數(shù)據(jù)一致性問題!我們用來解決分布式系統(tǒng)的數(shù)據(jù)一致性問題的方案有如下:

分布式事務+事務

分布式一致性算法

Quorum機制

CAP和BASE理論

2. 分布式事務

分布式系統(tǒng)中,每個節(jié)點都能知道自己的事務操作是否成功,但是沒法知道系統(tǒng)中的其他節(jié)點的事務是否成功。這就有可能會造成分布式系統(tǒng)中的各節(jié)點的狀態(tài)出現(xiàn)不一致。因此當一個事務需要跨越服務器節(jié)點,并且要保證事務的ACID特性時,就必須引入一個協(xié)調者的角色。那么其他的各個進行事務操作的節(jié)點就都叫做參與者。

現(xiàn)實生活中有兩種典型的分布式事務的提交模式:2PC和3PC。

2.1. 2PC提交過程

直接上圖:

我讓A去做一件事,讓B去做另外一件事,并且這兩件事在一個分布式事務中要保證同時成功或失敗。那如何做到數(shù)據(jù)一致呢?

2PC分兩個階段:

第一階段:執(zhí)行事務,但不提交。

第二階段:當協(xié)調者收到第一階段中所有事務參與者的正反饋時(事務都執(zhí)行成功了),

就去發(fā)命令讓所有參與者提交事務。

2.2. 2PC的問題

看了2PC的兩個提交階段和圖,有經驗的人一眼就會看出里面存在的問題。

1 阻塞問題

協(xié)調者發(fā)送命令給參與者,由于是網路發(fā)送命令,就會存在不同參與者收到的命令有先后、有延遲。例如參與者A很快就收到了,參與者B網絡有問題,過了很久才收到命令。參與者A很快處理完發(fā)送反饋,而參與者B就很久之后才發(fā)送反饋,導致協(xié)調者等待時間特別長。

這就是一個非常典型的阻塞問題,非常浪費資源,影響性能!

2 沒有容錯機制,存在單點故障問題

事務協(xié)調者是整個分布式事務的核心,一旦協(xié)調者出現(xiàn)故障,看看上面那張圖,就會知道參與者就收不到commit/rollback的通知,從而導致參與者節(jié)點一直處于事務無法完成的中間狀態(tài)。

3 數(shù)據(jù)不一致

在第二階段,如果發(fā)生局部網絡問題,一個參與者收到提交的命令,另一個參與者沒有收到提交的命令,就會造成節(jié)點間數(shù)據(jù)不一致。

2.3. 3PC

3PC就是三階段提交的意思,它是2階段提交的改進版,把二階段提交協(xié)議的 "提交事務請求" 一分為二,形成了cancommit,precommit,docommit 三個階段。

除了在 2PC 的基礎上增加了CanCommit階段,還引入了超時機制。一旦事務參與者在指定時間內沒有收到協(xié)調者的 commit/rollback 指令,就會自動本地 commit,這樣可以解決協(xié)調者單點故障的問題。

2.4. 執(zhí)行過程解析

第一階段:CanCommit階段

在第一階段準備的時候,先問一下各個參與者是否可以進行事務操作以及超時機制,參與者在一定時間沒收到協(xié)調者的指令會自動提交。

第二階段:PreCommit階段

1、如果每個參與者返回的都是同意,協(xié)調者則向所有參與者發(fā)送預提交請求,并進入預提交階段;

2、參與者收到預提交請求后,執(zhí)行事務操作。

3、參與者執(zhí)行完本地事務之后,會向協(xié)調者發(fā)出Ack表示已準備好提交,并等待協(xié)調者下一步指令。

4、如果協(xié)調者收到預提交響應為拒絕或者超時,則執(zhí)行中斷事務操作,通知各參與者中斷事務。

5、參與者收到中斷事務或者等待超時,都會主動中斷事務/直接提交

第三階段:doCommit階段

1、協(xié)調者收到所有參與 的Ack,則從預提交入提交段,并向各參與者發(fā)送提交請求。

2、參與者收到提交請求,正式提交事務(commit),并向協(xié)調者反饋提交結果Y/N。

3、協(xié)調者收到所有反饋消息,完成分布式事務。

4、如果協(xié)調者超時沒有收到反饋,則發(fā)送中斷事務指令。

5、參與者收到中斷事務指令后,利用事務日志進行rollback。

6、參與者反饋回滾結果,協(xié)調者接收反饋結果或者超時,完成中斷事務。

2.5. 3PC的問題

3PC也可能出現(xiàn)數(shù)據(jù)不一致,第三階段讓所有參與者回滾事務,但有一個參與者在規(guī)定的時間內沒有收到,它會默認進行提交操作,就會出現(xiàn)數(shù)據(jù)不一致。由于網絡問題,第二階段到第三階段之間特別容易出現(xiàn)數(shù)據(jù)不一致問題。

3. 分布式一致性算法

在2PC和3PC的原理上,優(yōu)秀的開發(fā)者們實現(xiàn)了分布式一致性算法,這里老劉先大致講講Poxos算法和ZAB協(xié)議的相關概念。如果想詳細了解Paxos算法和ZAB協(xié)議,等老劉找完工作后,專門寫一篇Zookeeper源碼文章。

3.1. Paxos算法

Paxos 算法使用一個希臘故事來描述,在 Paxos 中,存在三種角色,分別為

1、Proposer(提議者,用來發(fā)出提案proposal),

2、Acceptor(接受者,可以接受或拒絕提案),

3、Learner(學習者,學習被選定的提案,當提案被超過半數(shù)的Acceptor接受后為被批準)。

映射到 zookeeper 集群:

leader:發(fā)起提案? 主席(單點故障的解決辦法是leader選舉機制)

follower:參與投票? 人大代表

observer:被動接受? 全國所有人

以及有一個特別出名的機制:議會制

保證超過半數(shù)達成一致性即可的協(xié)議

總結下Paxos算法,它就是所有事務請求必須由一個全局唯一的服務器來協(xié)調處理,這樣的服務器被稱為 leader 服務器,而余下的其他服務器則成為 follower 服務器。

leader 服務器負責將一個客戶端事務請求轉換成一個事務proposal,并將該 proposal 分發(fā)給集群中所有的follower 服務器。之后 leader 服務器需要等待所有follower 服務器的反饋,一旦超過半數(shù)的 follower 服務器進行了正確的反饋后,那么 leader 就會再次向所有的 follower 服務器分發(fā) commit 消息,要求其將前一個 proposal 進行提交。

3.2. ZAB協(xié)議

ZooKeeper的底層工作機制,就是依靠 ZAB 實現(xiàn)的。它實現(xiàn)了崩潰回復和消息廣播兩個主要功能。

ZAB協(xié)議保證數(shù)據(jù)一致性的兩個重要特點就是:

1、ZAB協(xié)議需要確保那些已經在 leader 服務器上提交的事務最終被所有服務器都提交。

2、ZAB協(xié)議需要確保丟棄那些只在 leader 服務器上被提出的事務。

為了解決單點故障,有l(wèi)eader選舉算法。在leader選舉中,如果讓 leader 選舉算法能夠保證新選舉出來的 leader 服務器擁有集群中所有機器最高事務編號(ZXID)的事務proposal,那么就可以保證這個新選舉出來的 leader 一定具有所有已經提交的提案。

因為事務的每次執(zhí)行都會有一個編號,最高事務編號代表著最新的事務,即最新的數(shù)據(jù)。 根據(jù)上述ZAB協(xié)議內容,ZooKeeper實現(xiàn)了分布式系統(tǒng)數(shù)據(jù)的一致性!

4. 鴿巢原理

簡單描述:若有n個籠子和n+1只鴿子,所有的鴿子都被關在鴿籠里,那么至少有一個籠子有至少2只鴿子 。

5. Quorum NWR機制

Quorum NWR:Quorum 機制是分布式場景中常用的,用來保證數(shù)據(jù)安全,并且在分布式環(huán)境中實現(xiàn)最終一致性的投票算法。這種算法的主要原理來源于鴿巢原理。它最大的優(yōu)勢,既能實現(xiàn)強一致性,而且還能自定義一致性級別!

N:總節(jié)點數(shù)

W:總寫入成功數(shù)

R:總讀取數(shù)

當W+R>N時,一定能保證讀到最新的數(shù)據(jù),即強一致性! 為什么這樣說?

如上圖,有4個箱子,3個箱子里面有東西,那如何保證一定能拿到有數(shù)據(jù)的箱子?最起碼拿2個箱子就能拿到有東西的箱子!

就是利用這種原理,只要保證(W + R > N)就一定能讀取到最新的數(shù)據(jù),數(shù)據(jù)一致性級別完全可以根據(jù)讀寫副本數(shù)的約束來達到強一致性!

那現(xiàn)在分以下三種情況討論:前提是N已經確定不改了!

W = 1, R = N,Write Once Read All

在分布式環(huán)境中,寫一份,相當于只有只有一個箱子有東西,那么如果要讀取到最新數(shù)據(jù),即拿到有東西的箱子,就必須要讀取所有節(jié)點,然后取最新版本的值了。寫操作高效,但是讀操作效率低。一致性高,但分區(qū)容錯性差,可用性低。

W = N,R = 1, Read Only Write All

在分布式環(huán)境中,所有節(jié)點都同步完畢,才能讀取,所以只要讀取任意一個節(jié)點就可以讀取到最新數(shù)據(jù)。讀操作高效,但是寫操作效率低。分區(qū)容錯性好,一致性差,實現(xiàn)難度更高,可用性高 。

W = Q, R = Q where Q = N/2 + 1

可以簡單理解為寫超過一半節(jié)點,那么讀也超過一半節(jié)點,取得讀寫性能平衡。一般應用適用,讀寫性能之間取得平衡。如 N=3, W=2, R=2,分區(qū)容錯性,可用性,一致性取得一個平衡。

ZooKeeper就是這么干的!采用了第三種情況!

6. CAP理論

根據(jù)上述說的,做到強一致性了,就難做到高可用,兩者是非常矛盾的。所以CAP理論就告訴我們,一個分布式系統(tǒng)不可能同時滿足C,A,P三個需求。

C:Consistency,強一致性

分布式環(huán)境中多個數(shù)據(jù)副本保持一致

A:Availability,高可用性

系統(tǒng)提供的服務必須一直處于可用,對于用戶的每一個操作請求總是能在有限時間內返回結果

P:Partiton Tolerance 分區(qū)容錯性

分布式系統(tǒng)在遇到任何網絡分區(qū)故障時,仍然需要能夠保證對外提供滿足一致性和可用性的服務

既然一個分布式系統(tǒng)不能同時滿足C,A,P三個需求,那么如何選擇?

CAP只能3選2,因為在分布式系統(tǒng)中,容錯性P肯定是必須有的,所以這時候無非就兩種情況,網絡問題導致要么錯誤返回,要么阻塞等待,前者犧牲了一致性,后者犧牲了可用性。

對于單機軟件,因為不同考慮P,所以肯定是CA型,比如MySQL。

對于分布式軟件,因為一定會考慮P,所以又不能兼顧A和C的情況下,只能在A和C做權衡,比如HBase、Redis等。做到服務基本可用,并且數(shù)據(jù)最終一致性即可。 所以,就產生了BASE理論。

7. BASE理論

多數(shù)情況下,其實我們也并非一定要求強一致性,部分業(yè)務可以容忍一定程度的延遲一致,所以為了兼顧效率,發(fā)展出來了最終一致性理論 BASE,它的核心思想是:即使無法做到強一致性,但每個應用都可以根據(jù)自身業(yè)務特點,采用適當?shù)姆绞絹硎瓜到y(tǒng)達到最終一致性。

一句話就是做事別走極端,BASE 是對 CAP 理論中的 C 和 A 進行權衡得到的結果。

BASE理論做到的不是強一致,而是最終一致;不是高可用,而是基本可用。

Basically Available(基本可用):基本可用是指分布式系統(tǒng)在出現(xiàn)故障的時候,允許損失部分可用性,保證核心可用。 例如:淘寶雙11,為保護系統(tǒng)穩(wěn)定性,正常下單,其他邊緣服務可暫時不可用。

Eventually Consistent(最終一致):最終一致性是指系統(tǒng)中的所有數(shù)據(jù)副本經過一定時間后,最終能夠達到一致的狀態(tài)。

以后開發(fā)分布式系統(tǒng),就可以根據(jù)業(yè)務來決定到底追求高可用還是追求強一致性!

8. 總結

好啦,分布式系統(tǒng)的數(shù)據(jù)一致性問題大致聊得差不多了,老劉主要給大家講了講分布式系統(tǒng)一致性的背景以及實現(xiàn)。盡管當前水平可能不及各位大佬,但老劉還是希望能夠變得更加優(yōu)秀,能夠幫助更多自學編程的伙伴。

如果有相關問題,請聯(lián)系公眾號:努力的老劉,和老劉進行愉快的交流,如果覺得幫到了您,不妨點贊關注支持一波!

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

推薦閱讀更多精彩內容