七牛李道兵:高可用可伸縮架構(gòu)實(shí)用經(jīng)驗(yàn)談


移動(dòng)互聯(lián)網(wǎng)、云計(jì)算和大數(shù)據(jù)的成熟和發(fā)展,讓更多的好想法得以在很短的時(shí)間內(nèi)實(shí)現(xiàn)為產(chǎn)品碱呼。此時(shí),如果用戶需求抓得準(zhǔn)宗侦,用戶數(shù)量將很可能獲得爆發(fā)式增長(zhǎng)愚臀,而不需要像以往一樣需要精心運(yùn)營(yíng)幾年的時(shí)間。然而用戶數(shù)量的快速增長(zhǎng)(尤其是短時(shí)間內(nèi)的爆發(fā)式增長(zhǎng))凝垛,通常會(huì)讓?xiě)?yīng)用開(kāi)發(fā)者有些吃不消懊悯,不得不面臨一些嚴(yán)峻的技術(shù)挑戰(zhàn):如何避免因?yàn)閱闻_(tái)機(jī)器當(dāng)機(jī)導(dǎo)致服務(wù)不可用蜓谋;如何避免在服務(wù)容量不足時(shí),用戶體驗(yàn)下降炭分,等等桃焕。在系統(tǒng)構(gòu)建之初就采用高可用和可伸縮架構(gòu),將能有效避免這些問(wèn)題捧毛。

如何構(gòu)建高可用和可伸縮架構(gòu)呢观堂?七牛云存儲(chǔ)首席架構(gòu)師李道兵在3月22的「開(kāi)發(fā)者最佳實(shí)踐日」第十期沙龍活動(dòng)上給出了自己的想法。他結(jié)合自己多年的實(shí)踐經(jīng)驗(yàn)呀忧,針對(duì)一些不太復(fù)雜的業(yè)務(wù)場(chǎng)景师痕,從入口層、業(yè)務(wù)層而账、緩存層和數(shù)據(jù)庫(kù)層四個(gè)層面細(xì)致講述了如何構(gòu)建高可用和可伸縮系統(tǒng)胰坟。希望大家讀完這篇文章,能覺(jué)得高可用和可伸縮不是一個(gè)高不可攀的東西泞辐,投入不高的成本就能在項(xiàng)目早期把高可用和可伸縮納入架構(gòu)設(shè)計(jì)之中笔横。

如何實(shí)現(xiàn)高可用

入口層

入口層,通常指Nginx和Apache等層面的東西咐吼,負(fù)責(zé)應(yīng)用(不管是Web應(yīng)用還是移動(dòng)應(yīng)用)的服務(wù)入口吹缔。我們通常會(huì)將服務(wù)定位在一個(gè)IP,如果這個(gè)IP對(duì)應(yīng)的服務(wù)器當(dāng)機(jī)了锯茄,那么用戶的訪問(wèn)肯定會(huì)中斷厢塘。此時(shí),可以用keepalived來(lái)實(shí)現(xiàn)入口層的高可用肌幽。例如晚碾,機(jī)器A的IP是1.2.3.4,機(jī)器B的IP是1.2.3.5,那么再申請(qǐng)一個(gè)IP 1.2.3.6(稱為?跳IP),平時(shí)綁定在機(jī)器A上,如果A當(dāng)機(jī)牍颈,IP會(huì)自動(dòng)綁定在機(jī)器B上迄薄;如果B當(dāng)機(jī),IP會(huì)自動(dòng)綁定在機(jī)器A上煮岁。對(duì)于這種形式讥蔽,我們將DNS綁定到心跳IP上,即可實(shí)現(xiàn)入口層的高可用画机。

但這個(gè)方案有一點(diǎn)小問(wèn)題冶伞。第一,它的切換可能會(huì)有一到兩秒的中斷步氏,也就是說(shuō)响禽,如果不是要求到非常嚴(yán)格的毫秒級(jí)就不會(huì)有問(wèn)題。第二,對(duì)入口的機(jī)器會(huì)有些浪費(fèi)芋类,因?yàn)橘I了兩臺(tái)機(jī)器的入口隆嗅,可能就只有一臺(tái)機(jī)器用上。對(duì)一些長(zhǎng)連接的應(yīng)用可能會(huì)導(dǎo)致服務(wù)中斷侯繁,這時(shí)候就需要客戶端做配合做一些重新創(chuàng)建連接的工作胖喳。簡(jiǎn)單來(lái)說(shuō),對(duì)于比較普通的業(yè)務(wù)來(lái)說(shuō)贮竟,這個(gè)方案就能解決一部分問(wèn)題丽焊。

這里要注意,keepalived在使用上會(huì)有一些限制咕别。

l兩臺(tái)機(jī)器必須在同一個(gè)網(wǎng)段技健,不是在同一個(gè)網(wǎng)段,沒(méi)有辦法實(shí)現(xiàn)互相搶IP惰拱。

l內(nèi)網(wǎng)服務(wù)也可以做心跳雌贱,但需要注意的是,以前為了安全我們會(huì)把內(nèi)網(wǎng)服務(wù)綁定在內(nèi)網(wǎng)IP上弓颈,避免出現(xiàn)安全問(wèn)題帽芽。但為了使用keepalived删掀,必須監(jiān)聽(tīng)在所有IP上(如果監(jiān)聽(tīng)在心跳IP上翔冀,那么機(jī)器沒(méi)有持有該IP時(shí),服務(wù)無(wú)法啟動(dòng))披泪,簡(jiǎn)單的方案是啟用iptables,避免內(nèi)網(wǎng)服務(wù)被外網(wǎng)訪問(wèn)纤子。

l服務(wù)器利用率下降,這時(shí)可以考慮做混合部署來(lái)改善這一點(diǎn)款票。

比較常見(jiàn)的一個(gè)錯(cuò)誤是控硼,如果有兩臺(tái)機(jī)器,兩個(gè)公網(wǎng)IP艾少,DNS上把域名同時(shí)定位到兩個(gè)IP卡乾,就覺(jué)得已經(jīng)做了高可用了。這完全不是高可用缚够,因?yàn)槿绻慌_(tái)機(jī)器當(dāng)機(jī),那么就有一半左右的用戶無(wú)法訪問(wèn)幔妨。

除了keepalive,lvs也能用來(lái)解決入口層的高可用問(wèn)題谍椅。不過(guò)误堡,與keepalived相比,lvs會(huì)更復(fù)雜一些雏吭,門檻也會(huì)高一些锁施。

業(yè)務(wù)層

業(yè)務(wù)層通常是由PHP、Java、Python悉抵、Go等寫(xiě)的邏輯代碼構(gòu)成的肩狂,需要依賴于后臺(tái)數(shù)據(jù)庫(kù)及一些緩存層面的東西。如何實(shí)現(xiàn)業(yè)務(wù)層的高可用呢姥饰?最核心的就是婚温,業(yè)務(wù)層不要有狀態(tài),將狀態(tài)分散到緩存層和數(shù)據(jù)庫(kù)。目前大家通常喜歡將以下幾種數(shù)據(jù)放入業(yè)務(wù)層媳否。

第一個(gè)是session栅螟,即用戶登錄相關(guān)的數(shù)據(jù),但好的做法是將session放在數(shù)據(jù)庫(kù)里篱竭,或者一個(gè)比較穩(wěn)定的緩存系統(tǒng)中力图。

第二個(gè)是緩存,在訪問(wèn)數(shù)據(jù)庫(kù)時(shí)掺逼,如果一個(gè)查詢很慢吃媒,就希望將這些結(jié)果暫時(shí)放到進(jìn)程里,下次再做查詢時(shí)就不用再訪問(wèn)數(shù)據(jù)庫(kù)了吕喘。這種做法帶來(lái)的問(wèn)題是赘那,當(dāng)業(yè)務(wù)層服務(wù)器不只一臺(tái)時(shí),數(shù)據(jù)很難做到一致氯质,從緩存拿到的數(shù)據(jù)就可能是錯(cuò)誤的募舟。。

一個(gè)簡(jiǎn)單的原則就是業(yè)務(wù)層不要有狀態(tài)闻察。在業(yè)務(wù)層沒(méi)有狀態(tài)時(shí)拱礁,一臺(tái)業(yè)務(wù)層服務(wù)器當(dāng)?shù)袅酥螅琋ginx/Apache會(huì)自動(dòng)將所有的請(qǐng)求打到另外一臺(tái)業(yè)務(wù)層的服務(wù)器上辕漂。由于沒(méi)有狀態(tài)呢灶,兩臺(tái)服務(wù)器沒(méi)有任何差異,所以用戶完全感受不到钉嘹。如果把session放在業(yè)務(wù)層里面的話鸯乃,那么面臨的問(wèn)題是,這個(gè)用戶以前是登錄在一臺(tái)機(jī)器上的跋涣,這個(gè)進(jìn)程死掉后缨睡,用戶就會(huì)被登出了。

友情提醒:有一段時(shí)間比較流行cookie session仆潮,就是將session中的數(shù)據(jù)加密之后放在客戶的cookie里宏蛉,然后下發(fā)到客戶端,這樣也能做到與服務(wù)端完全無(wú)狀態(tài)性置。但這里面有很多坑拾并,如果能繞過(guò)這些坑就可以這樣使用。第一個(gè)坑是怎么保證加密的密鑰不泄露,一旦泄露就意味著攻擊者可以偽造任何人的身份嗅义。第二個(gè)坑是重放攻擊屏歹,如何避免別人通過(guò)保存cookie去不停地嘗試的驗(yàn)證碼,當(dāng)然也還有其他一些攻擊手段之碗。如果沒(méi)有好辦法解決這兩方面的問(wèn)題蝙眶,那么cookie session盡量慎用。最好是將session放在一個(gè)性能比較好的數(shù)據(jù)庫(kù)中褪那。如果數(shù)據(jù)庫(kù)性能不行幽纷,那么將session放在緩存中也比放在cookie里要好一點(diǎn)。

緩存層

非常簡(jiǎn)單的架構(gòu)里是沒(méi)有緩存這個(gè)概念的博敬。但在訪問(wèn)量上來(lái)之后友浸,MySQL之類的數(shù)據(jù)庫(kù)扛不住了,比如在SATA盤里跑MySQL偏窝,QPS到達(dá)200收恢、300甚至500時(shí),MySQL的性能會(huì)大幅下降祭往,這時(shí)就可以考慮用緩存層來(lái)?yè)踝〗^大部分服務(wù)請(qǐng)求伦意,提升系統(tǒng)整體的容量。

緩存層做高可用一個(gè)簡(jiǎn)單的方法就是硼补,將緩存層分得細(xì)一點(diǎn)兒驮肉。比如說(shuō),緩存層就一臺(tái)機(jī)器的話括勺,那么這臺(tái)機(jī)器當(dāng)了以后缆八,所有應(yīng)用層的壓力就會(huì)往數(shù)據(jù)庫(kù)里壓,數(shù)據(jù)庫(kù)扛不住的話疾捍,整個(gè)網(wǎng)站(或應(yīng)用)就會(huì)隨之當(dāng)?shù)簟6绻彺鎸臃衷谒呐_(tái)機(jī)器上的話栏妖,每臺(tái)只有四分之一乱豆,這臺(tái)機(jī)器當(dāng)?shù)袅艘院螅仓挥锌傇L問(wèn)量的四分之一會(huì)壓在數(shù)據(jù)庫(kù)上面吊趾,數(shù)據(jù)庫(kù)能扛住的話宛裕,網(wǎng)站就能很穩(wěn)定地等到緩存層重新起來(lái)。在實(shí)踐中论泛,四分之一顯然是不夠的揩尸,我們會(huì)將它分得更細(xì),以保證單臺(tái)緩存當(dāng)機(jī)后數(shù)據(jù)庫(kù)還能撐得住即可屁奏。在中小規(guī)模下岩榆,緩存層和業(yè)務(wù)層可以混合部署,這樣可以節(jié)省機(jī)器。

數(shù)據(jù)庫(kù)層

在數(shù)據(jù)庫(kù)層面實(shí)現(xiàn)高可用,通常是在軟件層面來(lái)做勇边。例如犹撒,MySQL有主從模式(Master-Slave),還有主主模式(Master-Master)都能滿足需求粒褒。MongoDB也有ReplicaSet的概念,基本都能滿足大家的需求识颊。

總之,要想實(shí)現(xiàn)高可用奕坟,需要做到這幾點(diǎn):入口層做心跳祥款,業(yè)務(wù)層服務(wù)器無(wú)狀態(tài),緩存層減小粒度月杉,數(shù)據(jù)庫(kù)做一個(gè)主從模式镰踏。對(duì)于這種模式來(lái)講,我們做的高可用不需要太多服務(wù)器沙合,這些東西都可以同時(shí)部署在兩臺(tái)服務(wù)器上奠伪。這時(shí),兩臺(tái)服務(wù)器就能滿足早期的高可用需求了首懈。任何一臺(tái)服務(wù)器當(dāng)機(jī)用戶完全無(wú)感知绊率。

如何實(shí)現(xiàn)可伸縮

入口層

在入口層實(shí)現(xiàn)伸縮性,可以通過(guò)直接水平擴(kuò)機(jī)器究履,然后DNS加IP來(lái)實(shí)現(xiàn)滤否。但需要注意,盡管一個(gè)域名解析到幾十個(gè)IP沒(méi)有問(wèn)題,但是很多瀏覽器客戶端只會(huì)使用前幾個(gè)IP,部分域名供應(yīng)商對(duì)此有優(yōu)化(如每次返回的IP順序隨機(jī)),但這個(gè)優(yōu)化效果不穩(wěn)定最仑。

推薦的做法是使用少量的Nginx機(jī)器作為入口,業(yè)務(wù)服務(wù)器隱藏在內(nèi)網(wǎng)(HTTP類型的業(yè)務(wù)這種方式居多)藐俺。另外,也可以把所有IP下發(fā)到客戶端,然后在客戶端做一些調(diào)度(特別是非HTTP型的業(yè)務(wù),如游戲泥彤、直播)欲芹。

業(yè)務(wù)層

業(yè)務(wù)層的伸縮性如何實(shí)現(xiàn)?與做高可用時(shí)的解決方案一樣,要實(shí)現(xiàn)業(yè)務(wù)層的伸縮性,保證無(wú)狀態(tài)是很好的手段吟吝。此外菱父,加機(jī)器繼續(xù)水平部署即可。

緩存層

比較麻煩的是緩存層的伸縮性剑逃,最簡(jiǎn)單粗暴的方式是什么呢浙宜?趁著半夜量比較低的時(shí)候,把整個(gè)緩存層全部下線蛹磺,然后上線新的緩存層粟瞬。新的緩存層啟動(dòng)起來(lái)之后,再等這些緩存慢慢預(yù)熱萤捆。當(dāng)然這里一個(gè)要求裙品,你的數(shù)據(jù)庫(kù)能抗住低估期的請(qǐng)求量俗批。如果扛不住呢?取決于緩存類型清酥,下面我們先可以將緩存的類型區(qū)分一下扶镀。

l強(qiáng)一致性緩存:無(wú)法接受從緩存拿到錯(cuò)誤的數(shù)據(jù)(比如用戶余額,或者會(huì)被下游繼續(xù)緩存這種情形)

l弱一致性緩存:能接受在一段時(shí)間內(nèi)從緩存拿到錯(cuò)誤的數(shù)據(jù)(比如微博的轉(zhuǎn)發(fā)數(shù))焰轻。

l不變型緩存:緩存key對(duì)應(yīng)的value不會(huì)變更(比如從SHA1推出來(lái)的密碼,或者其他復(fù)雜公式的計(jì)算結(jié)果)臭觉。

那什么緩存類型伸縮性比較好呢?弱一致性和不變型緩存的擴(kuò)容很方便,用一致性Hash即可辱志;強(qiáng)一致性情況稍微復(fù)雜一些蝠筑,稍后再講。使用一致性Hash揩懒,而不用簡(jiǎn)單Hash的原因是緩存的失效率什乙。如果緩存從9臺(tái)擴(kuò)容到10臺(tái),簡(jiǎn)單Hash情況下90%的緩存會(huì)馬上失效,而如果使用一致性Hash情況,只有10%的緩存會(huì)失效。

那么已球,強(qiáng)一致性緩存會(huì)有什么問(wèn)題臣镣?第一個(gè)問(wèn)題是,緩存客戶端的配置更新時(shí)間會(huì)有微小的差異,在這個(gè)時(shí)間窗內(nèi)有可能會(huì)拿到過(guò)期的數(shù)據(jù)智亮。第二個(gè)問(wèn)題是忆某,如果擴(kuò)容之后再裁撤節(jié)點(diǎn),會(huì)拿到臟數(shù)據(jù)。比如a這個(gè)key之前在機(jī)器1阔蛉,擴(kuò)容后在機(jī)器2弃舒,數(shù)據(jù)更新了,但裁撤節(jié)點(diǎn)后key回到機(jī)器1状原,這時(shí)候就會(huì)拿到臟數(shù)據(jù)聋呢。

要解決問(wèn)題2比較簡(jiǎn)單,要么保持永不減少節(jié)點(diǎn),要么節(jié)點(diǎn)調(diào)整間隔大于數(shù)據(jù)的有效時(shí)間颠区。問(wèn)題1可以用如下的步驟來(lái)解決:

1.兩套hash配置都更新到客戶端削锰,但仍然使用舊配置;

2.逐個(gè)客戶端改為只有兩套hash結(jié)果一致的情況下會(huì)使用緩存瓦呼,其余情況從數(shù)據(jù)庫(kù)讀喂窟,但寫(xiě)入緩存;

3.逐個(gè)客戶端通知使用新配置央串。

Memcache設(shè)計(jì)得比較早,導(dǎo)致在伸縮性高可用方面的考慮得不太周到碗啄。Redis在這方面有不少改進(jìn)质和,特別是@ngaut團(tuán)隊(duì)基于redis開(kāi)發(fā)了codis這個(gè)軟件,一次性地解決了緩存層的絕大部分問(wèn)題稚字。推薦大家考察一下饲宿。

數(shù)據(jù)庫(kù)

在數(shù)據(jù)庫(kù)層面實(shí)現(xiàn)伸縮厦酬,方法很多,文檔也很多瘫想,此處不做過(guò)多贅述仗阅。大致方法為:水平拆分、垂直拆分和定期滾動(dòng)国夜。

總之减噪,我們可以在入口層、業(yè)務(wù)層面车吹、緩存層和數(shù)據(jù)庫(kù)層四個(gè)層面筹裕,使用剛才介紹的方法和技術(shù)實(shí)現(xiàn)系統(tǒng)高可用和可伸縮性。具體為:在入口層用心跳來(lái)做到高可用窄驹,用平行部署來(lái)伸縮朝卒;在業(yè)務(wù)層做到服務(wù)無(wú)狀態(tài);在緩存層乐埠,可以減小一些粒度抗斤,以方便實(shí)現(xiàn)高可用,使用一致性Hash將有助于實(shí)現(xiàn)緩存層的伸縮性丈咐;數(shù)據(jù)庫(kù)層的主從模式能解決高可用問(wèn)題瑞眼,拆分和滾動(dòng)能解決可伸縮問(wèn)題。

本文中分享的這些技巧和方法扯罐,主要想幫助不太復(fù)雜的業(yè)務(wù)場(chǎng)景或者中小型應(yīng)用快速搭建起高可用可伸縮的系統(tǒng)负拟。關(guān)于如何構(gòu)建高可用和可伸縮系統(tǒng)還有很多更為細(xì)節(jié)的點(diǎn)和實(shí)踐經(jīng)驗(yàn)值得探討,望以后能與大家做更充分的交流

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末歹河,一起剝皮案震驚了整個(gè)濱河市掩浙,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌秸歧,老刑警劉巖厨姚,帶你破解...
    沈念sama閱讀 217,907評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異键菱,居然都是意外死亡谬墙,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,987評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門经备,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)拭抬,“玉大人,你說(shuō)我怎么就攤上這事侵蒙≡旎ⅲ” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,298評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵纷闺,是天一觀的道長(zhǎng)算凿。 經(jīng)常有香客問(wèn)我份蝴,道長(zhǎng),這世上最難降的妖魔是什么氓轰? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,586評(píng)論 1 293
  • 正文 為了忘掉前任婚夫,我火速辦了婚禮,結(jié)果婚禮上署鸡,老公的妹妹穿的比我還像新娘案糙。我一直安慰自己,他們只是感情好储玫,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,633評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布侍筛。 她就那樣靜靜地躺著,像睡著了一般撒穷。 火紅的嫁衣襯著肌膚如雪匣椰。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,488評(píng)論 1 302
  • 那天端礼,我揣著相機(jī)與錄音禽笑,去河邊找鬼。 笑死蛤奥,一個(gè)胖子當(dāng)著我的面吹牛佳镜,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播凡桥,決...
    沈念sama閱讀 40,275評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼蟀伸,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了缅刽?” 一聲冷哼從身側(cè)響起啊掏,我...
    開(kāi)封第一講書(shū)人閱讀 39,176評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎衰猛,沒(méi)想到半個(gè)月后迟蜜,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,619評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡啡省,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,819評(píng)論 3 336
  • 正文 我和宋清朗相戀三年娜睛,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片卦睹。...
    茶點(diǎn)故事閱讀 39,932評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡畦戒,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出结序,到底是詐尸還是另有隱情兢交,我是刑警寧澤,帶...
    沈念sama閱讀 35,655評(píng)論 5 346
  • 正文 年R本政府宣布笼痹,位于F島的核電站配喳,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏凳干。R本人自食惡果不足惜晴裹,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,265評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望救赐。 院中可真熱鬧涧团,春花似錦、人聲如沸经磅。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,871評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)预厌。三九已至阿迈,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間轧叽,已是汗流浹背苗沧。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,994評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留炭晒,地道東北人待逞。 一個(gè)月前我還...
    沈念sama閱讀 48,095評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像网严,于是被迫代替她去往敵國(guó)和親识樱。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,884評(píng)論 2 354

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