微服務(wù)實(shí)戰(zhàn)(二):構(gòu)建微服務(wù):使用API Gateway

構(gòu)建微服務(wù):使用API Gateway


當(dāng)你決定將應(yīng)用作為一組微服務(wù)時(shí)薪者,需要決定應(yīng)用客戶端如何與微服務(wù)交互。在單體式程序中窖杀,通常只有一組冗余的或者負(fù)載均衡的服務(wù)提供點(diǎn)角骤。在微服務(wù)架構(gòu)中投蝉,每一個(gè)微服務(wù)暴露一組細(xì)粒度的服務(wù)提供點(diǎn)养葵。在本篇文章中,我們來看它如何影響客戶端到服務(wù)端通信瘩缆,同時(shí)提出一種API Gateway的方法关拒。

介紹

假定你正在為在線購物應(yīng)用開發(fā)一個(gè)原生手機(jī)客戶端。你需要實(shí)現(xiàn)一個(gè)產(chǎn)品最終頁來展示商品信息咳榜。

例如夏醉,下面的圖展示了你在亞馬遜Android客戶端上滑動(dòng)產(chǎn)品最終頁時(shí)看到的信息。

雖然這是一個(gè)智能手機(jī)應(yīng)用涌韩,這個(gè)產(chǎn)品最終頁展示了非常多的信息畔柔。例如,不僅這里有產(chǎn)品基本信息(名字臣樱、描述和價(jià)格)靶擦,還有以下內(nèi)容:

購物車中的物品數(shù)

下單歷史

用戶評(píng)論

低庫存警告

快遞選項(xiàng)

各式各樣的推薦,包括經(jīng)常跟這個(gè)物品一起被購買的產(chǎn)品雇毫、購買該物品的其他顧客購買的產(chǎn)品以及購買該產(chǎn)品的顧客還瀏覽了哪些產(chǎn)品玄捕。

可選的購物選項(xiàng)

當(dāng)采用一個(gè)單體式應(yīng)用架構(gòu),一個(gè)移動(dòng)客戶端將會(huì)通過一個(gè)REST請(qǐng)求(GET api.company.com/productdetails/productId)來獲取這些數(shù)據(jù)棚放。一個(gè)負(fù)載均衡將請(qǐng)求分發(fā)到多個(gè)應(yīng)用實(shí)例之一枚粘。應(yīng)用將查詢各種數(shù)據(jù)庫并返回請(qǐng)求給客戶端。

相對(duì)的飘蚯,若是采用微服務(wù)架構(gòu)馍迄,最終頁上的數(shù)據(jù)會(huì)分布在不同的微服務(wù)上。下面列舉了可能與產(chǎn)品最終頁數(shù)據(jù)有關(guān)的一些微服務(wù):

購物車服務(wù) -- 購物車中的物品數(shù)

下單服務(wù) -- 下單歷史

分類服務(wù) -- 基本產(chǎn)品信息局骤,如名字攀圈、圖片和價(jià)格

評(píng)論服務(wù) -- 用戶評(píng)論

庫存服務(wù) -- 低庫存警告

快遞服務(wù) -- 快遞選項(xiàng)、截止時(shí)間峦甩、來自不同快遞API的成本計(jì)算

推薦服務(wù) -- 推薦產(chǎn)品

我們需要決定移動(dòng)客戶端如何訪問這些服務(wù)赘来。請(qǐng)看下面這幾種方式

客戶端到微服務(wù)直接通信

理論上說,一個(gè)客戶端可以直接給多個(gè)微服務(wù)中的任何一個(gè)發(fā)起請(qǐng)求凯傲。每一個(gè)微服務(wù)都會(huì)有一個(gè)對(duì)外服務(wù)端犬辰。這個(gè)URL可能會(huì)映射到微服務(wù)的負(fù)載均衡上,它再轉(zhuǎn)發(fā)請(qǐng)求到具體節(jié)點(diǎn)上冰单。為了搜索產(chǎn)品細(xì)節(jié)忧风,移動(dòng)端需要向上述微服務(wù)逐個(gè)發(fā)請(qǐng)求。

不幸的是球凰,這個(gè)方案有很多困難和限制狮腿。其中一個(gè)問題是客戶端的需求量與每個(gè)微服務(wù)暴露的細(xì)粒度API數(shù)量的不匹配腿宰。如圖中,客戶端需要7次單獨(dú)請(qǐng)求缘厢。在更復(fù)雜的場景中吃度,可能會(huì)需要更多次請(qǐng)求。例如贴硫,亞馬遜的產(chǎn)品最終頁要請(qǐng)求數(shù)百個(gè)微服務(wù)椿每。雖然一個(gè)客戶端可以通過LAN發(fā)起很多個(gè)請(qǐng)求,但是在公網(wǎng)上這樣會(huì)很沒有效率英遭,這個(gè)問題在移動(dòng)互聯(lián)網(wǎng)上尤為突出间护。這個(gè)方案同時(shí)會(huì)導(dǎo)致客戶端代碼非常復(fù)雜。

另一個(gè)存在的問題是客戶端直接請(qǐng)求微服務(wù)的協(xié)議可能并不是web友好型挖诸。一個(gè)服務(wù)可能是用Thrift的RPC協(xié)議汁尺,而另一個(gè)服務(wù)可能是用AMQP消息協(xié)議。它們都不是瀏覽或防火墻友好的多律,并且最好是內(nèi)部使用痴突。應(yīng)用應(yīng)該在防火墻外采用類似HTTP或者WEBSocket協(xié)議。

這個(gè)方案的另一個(gè)缺點(diǎn)是它很難重構(gòu)微服務(wù)狼荞。隨著時(shí)間的推移辽装,我們可能需要改變系統(tǒng)微服務(wù)目前的切分方案。例如相味,我們可能需要將兩個(gè)服務(wù)合并或者將一個(gè)服務(wù)拆分為多個(gè)拾积。但是,如果客戶端直接與微服務(wù)交互丰涉,那么這種重構(gòu)就很難實(shí)施殷勘。

由于上述三種問題的原因,客戶端直接與服務(wù)器端通信的方式很少在實(shí)際中使用昔搂。

采用一個(gè)API Gateway

通常來說,一個(gè)更好的解決辦法是采用API Gateway的方式输拇。API Gateway是一個(gè)服務(wù)器摘符,也可以說是進(jìn)入系統(tǒng)的唯一節(jié)點(diǎn)。這跟面向?qū)ο笤O(shè)計(jì)模式中的Facet模式很像策吠。API Gateway封裝內(nèi)部系統(tǒng)的架構(gòu)逛裤,并且提供API給各個(gè)客戶端。它還可能有其他功能猴抹,如授權(quán)带族、監(jiān)控、負(fù)載均衡蟀给、緩存蝙砌、請(qǐng)求分片和管理阳堕、靜態(tài)響應(yīng)處理等。下圖展示了一個(gè)適應(yīng)當(dāng)前架構(gòu)的API Gateway择克。

API Gateway負(fù)責(zé)請(qǐng)求轉(zhuǎn)發(fā)恬总、合成和協(xié)議轉(zhuǎn)換。所有來自客戶端的請(qǐng)求都要先經(jīng)過API Gateway肚邢,然后路由這些請(qǐng)求到對(duì)應(yīng)的微服務(wù)壹堰。API Gateway將經(jīng)常通過調(diào)用多個(gè)微服務(wù)來處理一個(gè)請(qǐng)求以及聚合多個(gè)服務(wù)的結(jié)果。它可以在web協(xié)議與內(nèi)部使用的非Web友好型協(xié)議間進(jìn)行轉(zhuǎn)換骡湖,如HTTP協(xié)議贱纠、WebSocket協(xié)議。

API Gateway可以提供給客戶端一個(gè)定制化的API响蕴。它暴露一個(gè)粗粒度API給移動(dòng)客戶端谆焊。以產(chǎn)品最終頁這個(gè)使用場景為例。API Gateway提供一個(gè)服務(wù)提供點(diǎn)(/productdetails?productid=xxx)使得移動(dòng)客戶端可以在一個(gè)請(qǐng)求中檢索到產(chǎn)品最終頁的全部數(shù)據(jù)换途。API Gateway通過調(diào)用多個(gè)服務(wù)來處理這一個(gè)請(qǐng)求并返回結(jié)果懊渡,涉及產(chǎn)品信息、推薦军拟、評(píng)論等剃执。

一個(gè)很好的API Gateway例子是Netfix API Gateway。Netflix流服務(wù)提供數(shù)百個(gè)不同的微服務(wù)懈息,包括電視肾档、機(jī)頂盒、智能手機(jī)辫继、游戲系統(tǒng)怒见、平板電腦等。起初姑宽,Netflix視圖提供一個(gè)適用全場景的API遣耍。但是,他們發(fā)現(xiàn)這種形式不好用炮车,因?yàn)樯婕暗礁魇礁鳂拥脑O(shè)備以及它們獨(dú)特的需求《姹洌現(xiàn)在,他們采用一個(gè)API Gateway來提供容錯(cuò)性高的API瘦穆,針對(duì)不同類型設(shè)備有相應(yīng)代碼纪隙。事實(shí)上,一個(gè)適配器處理一個(gè)請(qǐng)求平均要調(diào)用6到8個(gè)后端服務(wù)扛或。Netflix API Gateway每天處理數(shù)十億的請(qǐng)求绵咱。

API Gateway的優(yōu)點(diǎn)和缺點(diǎn)

如你所料,采用API Gateway也是優(yōu)缺點(diǎn)并存的熙兔。API Gateway的一個(gè)最大好處是封裝應(yīng)用內(nèi)部結(jié)構(gòu)悲伶。相比起來調(diào)用指定的服務(wù)艾恼,客戶端直接跟gatway交互更簡單點(diǎn)。API Gateway提供給每一個(gè)客戶端一個(gè)特定API拢切,這樣減少了客戶端與服務(wù)器端的通信次數(shù)蒂萎,也簡化了客戶端代碼。

API Gateway也有一些缺點(diǎn)淮椰。它是一個(gè)高可用的組件五慈,必須要開發(fā)、部署和管理主穗。還有一個(gè)問題泻拦,它可能成為開發(fā)的一個(gè)瓶頸。開發(fā)者必須更新API Gateway來提供新服務(wù)提供點(diǎn)來支持新暴露的微服務(wù)忽媒。更新API Gateway時(shí)必須越輕量級(jí)越好争拐。否則,開發(fā)者將因?yàn)楦翯ateway而排隊(duì)列晦雨。但是架曹,除了這些缺點(diǎn),對(duì)于大部分的應(yīng)用闹瞧,采用API Gateway的方式都是有效的绑雄。

實(shí)現(xiàn)一個(gè)API Gateway

既然我們已經(jīng)知道了采用API Gateway的動(dòng)機(jī)和優(yōu)缺點(diǎn),下面來看在設(shè)計(jì)它時(shí)需要考慮哪些事情奥邮。

性能和可擴(kuò)展性

只有少數(shù)公司需要處理像Netflix那樣的規(guī)模万牺,每天需要處理數(shù)十億的請(qǐng)求。但是洽腺,對(duì)于大多數(shù)應(yīng)用脚粟,API Gateway的性能和可擴(kuò)展性也是非常重要的。因此蘸朋,創(chuàng)建一個(gè)支持同步核无、非阻塞I/O的API Gateway是有意義的。已經(jīng)有不同的技術(shù)可以用來實(shí)現(xiàn)一個(gè)可擴(kuò)展的API Gateway藕坯。在JVM上团南,采用基于NIO技術(shù)的框架,如Netty堕担,Vertx,Spring Reactor或者JBoss Undertow曲聂。Node.js是一個(gè)非JVM的流行平臺(tái)霹购,它是一個(gè)在Chrome的JavaScript引擎基礎(chǔ)上建立的平臺(tái)。一個(gè)可選的方案是NGINX Plus朋腋。NGINX Plus提供一個(gè)成熟的齐疙、可擴(kuò)展的膜楷、高性能web服務(wù)器和反向代理,它們均容易部署贞奋、配置和二次開發(fā)赌厅。NGINX Plus可以管理授權(quán)、權(quán)限控制轿塔、負(fù)載均衡特愿、緩存并提供應(yīng)用健康檢查和監(jiān)控。

采用反應(yīng)性編程模型

對(duì)于有些請(qǐng)求勾缭,API Gateway可以通過直接路由請(qǐng)求到對(duì)應(yīng)的后端服務(wù)上的方式來處理揍障。對(duì)于另外一些請(qǐng)求,它需要調(diào)用多個(gè)后端服務(wù)并合并結(jié)果來處理俩由。對(duì)于一些請(qǐng)求毒嫡,例如產(chǎn)品最終頁面請(qǐng)求,發(fā)給后端服務(wù)的請(qǐng)求是相互獨(dú)立的幻梯。為了最小化響應(yīng)時(shí)間兜畸,API Gateway應(yīng)該并發(fā)的處理相互獨(dú)立的請(qǐng)求。但是碘梢,有時(shí)候請(qǐng)求之間是有依賴的咬摇。API Gateway可能需要先通過授權(quán)服務(wù)來驗(yàn)證請(qǐng)求,然后在路由到后端服務(wù)痘系。類似的菲嘴,為了獲得客戶的產(chǎn)品愿望清單,需要先獲取該用戶的資料汰翠,然后返回清單上產(chǎn)品的信息龄坪。這樣的一個(gè)API 組件是Netflix Video Grid。

利用傳統(tǒng)的同步回調(diào)方法來實(shí)現(xiàn)API合并的代碼會(huì)使得你進(jìn)入回調(diào)函數(shù)的噩夢(mèng)中复唤。這種代碼將非常難度且難以維護(hù)健田。一個(gè)優(yōu)雅的解決方案是采用反應(yīng)性編程模式來實(shí)現(xiàn)。類似的反應(yīng)抽象實(shí)現(xiàn)有Scala的Future佛纫,Java8的CompletableFuture和JavaScript的Promise妓局。基于微軟.Net平臺(tái)的有Reactive Extensions(Rx)呈宇。Netflix為JVM環(huán)境創(chuàng)建了RxJava來使用他們的API Gateway好爬。同樣地,JavaScript平臺(tái)有RxJS甥啄,可以在瀏覽器和Node.js平臺(tái)上運(yùn)行存炮。采用反應(yīng)編程方法可以幫助快速實(shí)現(xiàn)一個(gè)高效的API Gateway代碼。

服務(wù)調(diào)用

一個(gè)基于微服務(wù)的應(yīng)用是一個(gè)分布式系統(tǒng),并且必須采用線程間通信的機(jī)制穆桂。有兩種線程間通信的方法宫盔。一種是采用同步機(jī)制,基于消息的方法享完。這類的實(shí)現(xiàn)方法有JMS和AMQP灼芭。另外的,例如Zeromq屬于服務(wù)間直接通信般又。還有一種線程間通信采用異步機(jī)制彼绷,例如Thrift和HTTP。事實(shí)上一個(gè)系統(tǒng)會(huì)同時(shí)采用同步和異步兩種機(jī)制倒源。由于它的實(shí)現(xiàn)方式有很多種苛预,因此API Gateway就需要支持多種通信方式。

服務(wù)發(fā)現(xiàn)

API Gateway需要知道每一個(gè)微服務(wù)的IP和端口笋熬。在傳統(tǒng)應(yīng)用中热某,你可能會(huì)硬編碼這些地址,但是在現(xiàn)在云基礎(chǔ)的微服務(wù)應(yīng)用中胳螟,這將是個(gè)簡單的問題昔馋。基礎(chǔ)服務(wù)通常會(huì)采用靜態(tài)地址糖耸,可以采用操作系統(tǒng)環(huán)境變量來指定秘遏。但是,探測(cè)應(yīng)用服務(wù)的地址就沒那么容易了嘉竟。應(yīng)用服務(wù)通常動(dòng)態(tài)分配地址和端口邦危。同樣的,由于擴(kuò)展或者升級(jí)舍扰,服務(wù)的實(shí)例也會(huì)動(dòng)態(tài)的改變倦蚪。因此,API Gateway需要采用系統(tǒng)的服務(wù)發(fā)現(xiàn)機(jī)制边苹,要么采用服務(wù)端發(fā)現(xiàn)陵且,要么是客戶端發(fā)現(xiàn)。后續(xù)的一篇文章將會(huì)更詳細(xì)的介紹這部分个束。如果采用客戶端發(fā)現(xiàn)服務(wù)慕购,API Gateway必須要去查詢服務(wù)注冊(cè)處,也就是微服務(wù)實(shí)例地址的數(shù)據(jù)庫茬底。

處理部分失敗

在實(shí)現(xiàn)API Gateway過程中沪悲,另外一個(gè)需要考慮的問題就是部分失敗。這個(gè)問題發(fā)生在分布式系統(tǒng)中當(dāng)一個(gè)服務(wù)調(diào)用另外一個(gè)服務(wù)超時(shí)或者不可用的情況阱表。API Gateway不應(yīng)該被阻斷并處于無限期等待下游服務(wù)的狀態(tài)殿如。但是昌妹,如何處理這種失敗依賴于特定的場景和具體服務(wù)。例如握截,如果是在產(chǎn)品詳情頁的推薦服務(wù)模塊無響應(yīng),那么API Gateway應(yīng)該返回剩下的其他信息給用戶烂叔,因?yàn)檫@些信息也是有用的谨胞。推薦部分可以返回空,也可以返回固定的頂部10個(gè)給用戶蒜鸡。但是胯努,如果是產(chǎn)品信息服務(wù)無響應(yīng),那么API Gateway就應(yīng)該給客戶端返回一個(gè)錯(cuò)誤逢防。

在緩存有效的時(shí)候叶沛,API Gateway應(yīng)該能夠返回緩存。例如忘朝,由于產(chǎn)品價(jià)格變化并不頻繁灰署,API Gateway在價(jià)格服務(wù)不可用時(shí)應(yīng)該返回緩存中的數(shù)值。這類數(shù)據(jù)可以由API Gateway自身來緩存局嘁,也可以由Redis或Memcached這類外部緩存實(shí)現(xiàn)溉箕。通過返回緩存數(shù)據(jù)或者默認(rèn)數(shù)據(jù),API Gateway來確保系統(tǒng)錯(cuò)誤不影響到用戶體驗(yàn)悦昵。

Netflix Hystrix對(duì)于實(shí)現(xiàn)遠(yuǎn)程服務(wù)調(diào)用代碼來說是一個(gè)非常好用的庫肴茄。Hystrix記錄那些超過預(yù)設(shè)定的極限值的調(diào)用。它實(shí)現(xiàn)了circuit break模式但指,使得可以將客戶端從無響應(yīng)服務(wù)的無盡等待中停止寡痰。如果一個(gè)服務(wù)的錯(cuò)誤率超過預(yù)設(shè)值,Hystrix將中斷服務(wù)棋凳,并且在一段時(shí)間內(nèi)所有請(qǐng)求立刻失效拦坠。Hystrix可以為請(qǐng)求失敗定義一個(gè)fallback操作,例如讀取緩存或者返回默認(rèn)值贫橙。如果你在用JVM贪婉,就應(yīng)該考慮使用Hystrix。如果你采用的非JVM環(huán)境卢肃,那么應(yīng)該考慮采用類似功能的庫疲迂。

總結(jié)

對(duì)于大多數(shù)微服務(wù)基礎(chǔ)的應(yīng)用,實(shí)現(xiàn)一個(gè)API Gateway都是有意義的莫湘,它就像是進(jìn)入系統(tǒng)的一個(gè)服務(wù)提供點(diǎn)尤蒿。API Gateway負(fù)責(zé)請(qǐng)求轉(zhuǎn)發(fā)、請(qǐng)求合成和協(xié)議轉(zhuǎn)換幅垮。它提供給應(yīng)用客戶端一個(gè)自定義的API腰池。API Gateway可以通過返回緩存或者默認(rèn)值的方式來掩蓋后端服務(wù)的錯(cuò)誤。在本系列的下一篇文章中,我們將討論服務(wù)間的通信問題示弓。

DockOne.io

DockOne讳侨,新圈子,新思路奏属,新視野跨跨。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市囱皿,隨后出現(xiàn)的幾起案子勇婴,更是在濱河造成了極大的恐慌,老刑警劉巖嘱腥,帶你破解...
    沈念sama閱讀 212,029評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件耕渴,死亡現(xiàn)場離奇詭異,居然都是意外死亡齿兔,警方通過查閱死者的電腦和手機(jī)橱脸,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,395評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來分苇,“玉大人慰技,你說我怎么就攤上這事∽檠猓” “怎么了吻商?”我有些...
    開封第一講書人閱讀 157,570評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長糟红。 經(jīng)常有香客問我艾帐,道長,這世上最難降的妖魔是什么盆偿? 我笑而不...
    開封第一講書人閱讀 56,535評(píng)論 1 284
  • 正文 為了忘掉前任柒爸,我火速辦了婚禮,結(jié)果婚禮上事扭,老公的妹妹穿的比我還像新娘捎稚。我一直安慰自己,他們只是感情好求橄,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,650評(píng)論 6 386
  • 文/花漫 我一把揭開白布今野。 她就那樣靜靜地躺著,像睡著了一般罐农。 火紅的嫁衣襯著肌膚如雪条霜。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,850評(píng)論 1 290
  • 那天涵亏,我揣著相機(jī)與錄音宰睡,去河邊找鬼蒲凶。 笑死,一個(gè)胖子當(dāng)著我的面吹牛拆内,可吹牛的內(nèi)容都是我干的旋圆。 我是一名探鬼主播,決...
    沈念sama閱讀 39,006評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼麸恍,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼臂聋!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起或南,我...
    開封第一講書人閱讀 37,747評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎艾君,沒想到半個(gè)月后采够,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,207評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡冰垄,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,536評(píng)論 2 327
  • 正文 我和宋清朗相戀三年蹬癌,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片虹茶。...
    茶點(diǎn)故事閱讀 38,683評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡逝薪,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出蝴罪,到底是詐尸還是另有隱情董济,我是刑警寧澤,帶...
    沈念sama閱讀 34,342評(píng)論 4 330
  • 正文 年R本政府宣布要门,位于F島的核電站虏肾,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏欢搜。R本人自食惡果不足惜封豪,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,964評(píng)論 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望炒瘟。 院中可真熱鬧吹埠,春花似錦、人聲如沸疮装。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,772評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽廓推。三九已至胯杭,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間受啥,已是汗流浹背做个。 一陣腳步聲響...
    開封第一講書人閱讀 32,004評(píng)論 1 266
  • 我被黑心中介騙來泰國打工鸽心, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人居暖。 一個(gè)月前我還...
    沈念sama閱讀 46,401評(píng)論 2 360
  • 正文 我出身青樓顽频,卻偏偏與公主長得像,于是被迫代替她去往敵國和親太闺。 傳聞我的和親對(duì)象是個(gè)殘疾皇子糯景,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,566評(píng)論 2 349

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