使用Spring Cloud和Docker的微服務(wù)架構(gòu)

本文通過使用Spring Boot,Spring Cloud和Docker構(gòu)建的概念驗證應(yīng)用程序的示例,為了解常見的微服務(wù)架構(gòu)模式提供了一個起點廊遍。另外小編從事在線教育多年,將自己的資料整合建了一個QQ群曼氛,對于有興趣一起交流學(xué)習(xí)java的可以加群:732976516,里面有大神會給予解答令野,也會有許多的資源可以供大家學(xué)習(xí)分享舀患,歡迎大家前來一起學(xué)習(xí)進步!

該代碼可在Github上獲得气破,圖像可在Docker Hub上獲得聊浅。只需一個命令即可啟動整個系統(tǒng)。

作為這個系統(tǒng)的基礎(chǔ),我選擇了一個舊項目低匙,其后端曾經(jīng)是一個整體旷痕。該應(yīng)用程序提供了一種處理個人財務(wù),組織收入和支出顽冶,管理儲蓄欺抗,分析統(tǒng)計數(shù)據(jù)和創(chuàng)建簡單預(yù)測的方法。

功能服務(wù)

整體應(yīng)用程序被分解為三個核心微服務(wù)强重。所有這些都是可獨立部署的應(yīng)用程序佩迟,圍繞某些業(yè)務(wù)功能組織。

帳戶服務(wù)

包含一般用戶輸入邏輯和驗證:收入/費用項目竿屹,節(jié)省和帳戶設(shè)置。

方法路徑描述用戶通過身份驗證可從UI獲得得到/賬戶/ {帳戶}獲取指定的帳戶數(shù)據(jù)

得到/帳號/電流獲取當(dāng)前帳戶數(shù)據(jù)××得到/帳號/演示獲取模擬賬戶數(shù)據(jù)(預(yù)先填寫的收入/費用項目等)

×放/帳號/電流保存當(dāng)前帳戶數(shù)據(jù)××POST/帳號/注冊新帳戶

×

統(tǒng)計服務(wù)

對主要統(tǒng)計參數(shù)執(zhí)行計算并捕獲每個帳戶的時間序列灸姊。數(shù)據(jù)點包含標(biāo)準(zhǔn)化為基本貨幣和時間段的值拱燃。此數(shù)據(jù)可用于跟蹤帳戶生命周期中的現(xiàn)金流動態(tài)。

方法路徑描述用戶通過身份驗證可從UI獲得得到/統(tǒng)計/ {}帳戶獲取指定的帳戶統(tǒng)計信

得到/統(tǒng)計/電流獲取當(dāng)前帳戶統(tǒng)計信息××得到/統(tǒng)計/演示獲取模擬賬戶統(tǒng)計信息

×放/統(tǒng)計/ {}帳戶為指定的帳戶創(chuàng)建或更新時間序列數(shù)據(jù)點

通知服務(wù)

存儲用戶的聯(lián)系信息和通知設(shè)置(如提醒和備份頻率)力惯。計劃工作人員從其他服務(wù)收集所需信息碗誉,并向訂閱客戶發(fā)送電子郵件。

方法路徑描述用戶通過身份驗證可從UI獲得得到/通知/設(shè)置/電流獲取當(dāng)前帳戶通知設(shè)置××放/通知/設(shè)置/電流保存當(dāng)前帳戶通知設(shè)置××

筆記

每個微服務(wù)都有自己的數(shù)據(jù)庫父晶,因此無法繞過API并直接訪問持久性數(shù)據(jù)哮缺。

對于這個項目,我使用MongoDB作為每個服務(wù)的主數(shù)據(jù)庫甲喝。擁有多語言持久性體系結(jié)構(gòu)(以便選擇最適合服務(wù)要求的數(shù)據(jù)庫類型)也是有意義的尝苇。

服務(wù)到服務(wù)通信非常簡單:微服務(wù)僅使用同步REST API進行通信。現(xiàn)實世界系統(tǒng)中的常見做法是使用交互方式的組合埠胖。例如糠溜,執(zhí)行同步GET請求以檢索數(shù)據(jù)并通過Message代理使用異步方法進行創(chuàng)建/更新操作,以便解耦服務(wù)和緩沖消息直撤。然而非竿,這給我們帶來了? 最終的一致性? 世界。

基建服務(wù)

分布式系統(tǒng)中有許多常見模式谋竖,可以幫助我們使所描述的核心服務(wù)工作红柱。 Spring云? 提供了強大的工具,可以增強Spring Boot應(yīng)用程序的行為以實現(xiàn)這些模式蓖乘。我會簡要介紹一下锤悄。

配置服務(wù)

Spring Cloud Config? 是分布式系統(tǒng)的水平可擴展集中配置服務(wù)。它使用可插入的存儲庫層嘉抒,目前支持本地存儲铁蹈,Git和Subversion。

在這個項目中,我使用? native profile握牧,它只是從本地類路徑加載配置文件容诬。您可以shared在Config服務(wù)資源中查看? 目錄? 。現(xiàn)在沿腰,當(dāng)Notification-service請求它的配置時览徒,使用shared/notification-service.yml 和? 配置服務(wù)響應(yīng)? shared/application.yml (在所有客戶端應(yīng)用程序之間共享)。

客戶端使用

只需構(gòu)建具有spring-cloud-starter-config 依賴關(guān)系的Spring Boot應(yīng)用程序? 颂龙,自動配置將完成剩下的工作习蓬。

現(xiàn)在,您的應(yīng)用程序中不需要任何嵌入屬性措嵌。只需提供? bootstrap.yml 應(yīng)用程序名稱和配置服務(wù)URL:

spring:

? application:

? ? name: notification-service

? cloud:

? ? config:

? ? ? uri: http://config:8888

? ? ? fail-fast: true

使用Spring Cloud Config躲叼,您可以動態(tài)更改應(yīng)用程序配置

例如,? EmailService bean? 使用注釋? @RefreshScope企巢。這意味著您可以更改電子郵件文本和主題行枫慷,而無需重建和重新啟動Notification Service應(yīng)用程序。

首先浪规,在Config服務(wù)器中更改所需的屬性或听。然后,對Notification服務(wù)執(zhí)行刷新請求: curl -H "Authorization: Bearer #token#" -XPOST http://127.0.0.1:8000/notifications/refresh

您還可以使用? webhooks自動執(zhí)行此過程笋婿。

筆記

但動態(tài)刷新有一些限制誉裆。 @RefreshScope 不適用于? @Configuration 類,不能影響? @Scheduled 方法缸濒。

fail-fast property表示如果Spring Boot應(yīng)用程序無法連接到Config Service足丢,則會立即失敗啟動。當(dāng)你一起啟動所有應(yīng)用程序時庇配,這非常有用? 霎桅。

下面有重要的安全說明。

驗證服務(wù)

授權(quán)職責(zé)被完全提取到單獨的服務(wù)器讨永,該服務(wù)器 為后端資源服務(wù)授予? OAuth2令牌滔驶。Auth Server用于用戶授權(quán)以及周邊內(nèi)部的安全機器到機器通信。

在這個項目中卿闹,我使用? Password credentials 授權(quán)類型進行用戶授權(quán)(因為它僅由本機應(yīng)用程序UI使用)揭糕,并? Client Credentials 用作微服務(wù)授權(quán)的授權(quán)類型。

Spring Cloud Security提供方便的注釋和自動配置锻霎,使服務(wù)器和客戶端都能輕松實現(xiàn)著角。您可以在文檔中了解有關(guān)它的更多信息,? 并檢查Auth Server代碼中的配置詳細(xì)信息? 旋恼。

從客戶端來看吏口,一切都與傳統(tǒng)的基于會話的授權(quán)完全相同。您可以Principal 從請求中檢索? 對象,使用基于表達式的訪問控制和@PreAuthorize 注釋檢查用戶角色和其他內(nèi)容? 产徊。

PiggyMetrics中的每個客戶端(帳戶服務(wù)昂勒,統(tǒng)計服務(wù),通知服務(wù)和瀏覽器)都有一個范圍:? server用于后端服務(wù)舟铜,以及? ui - 用于瀏覽器戈盈。因此,我們還可以保護控制器免受外部訪問谆刨,例如:

@PreAuthorize("#oauth2.hasScope('server')")

@RequestMapping(value = "accounts/{name}", method = RequestMethod.GET)

public List<DataPoint> getStatisticsByAccountName(@PathVariable String name) {

? ? return statisticsService.findByAccountName(name);

}

API網(wǎng)關(guān)

如您所見塘娶,有三種核心服務(wù),它們向客戶端公開外部API痊夭。在現(xiàn)實世界的系統(tǒng)中刁岸,這個數(shù)字可以非常快速地增長以及整個系統(tǒng)的復(fù)雜性她我。實際上虹曙,渲染一個復(fù)雜的網(wǎng)頁可能涉及數(shù)百種服務(wù)

理論上鸦难,客戶端可以直接向每個微服務(wù)發(fā)出請求。但顯然這個選項存在挑戰(zhàn)和局限员淫,例如必須知道所有端點地址合蔽,分別對每個信息的和平執(zhí)行http請求,在客戶端合并結(jié)果介返。另一個問題是非網(wǎng)絡(luò)友好協(xié)議拴事,可能會在后端使用。

通常圣蝎,更好的方法是使用API??網(wǎng)關(guān)刃宵。它是系統(tǒng)的單一入口點,用于通過將請求路由到適當(dāng)?shù)暮蠖朔?wù)或通過調(diào)用多個后端服務(wù)并聚合結(jié)果來處理請求? 徘公。此外牲证,它還可用于身份驗證,洞察关面,壓力和金絲雀測試坦袍,服務(wù)遷移,靜態(tài)響應(yīng)處理等太,主動流量管理捂齐。

Netflix開源了? 這樣的優(yōu)質(zhì)服務(wù),現(xiàn)在使用Spring Cloud缩抡,我們可以通過一個@EnableZuulProxy注釋啟用它? 奠宜。在這個項目中,我使用Zuul存儲靜態(tài)內(nèi)容(UI應(yīng)用程序)并將請求路由到適當(dāng)?shù)奈⒎?wù)。以下是Notification服務(wù)的簡單基于前綴的路由配置:

zuul:

? routes:

? ? notification-service:

? ? ? ? path: /notifications/**

? ? ? ? serviceId: notification-service

? ? ? ? stripPrefix: false

這意味著所有以請求開頭的請求? /notifications 都將路由到Notification服務(wù)压真。您可以看到娩嚼,沒有硬編碼的地址。Zuul使用? 服務(wù)發(fā)現(xiàn)? 機制來定位Notification服務(wù)實例以及? Circuit Breaker和Load Balancer榴都,如下所述待锈。

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

另一種眾所周知的架構(gòu)模式是服務(wù)發(fā)現(xiàn)。它允許自動檢測服務(wù)實例的網(wǎng)絡(luò)位置嘴高,這些服務(wù)實例可能由于自動擴展竿音,故障和升級而動態(tài)分配地址。

服務(wù)發(fā)現(xiàn)的關(guān)鍵部分是注冊表拴驮。我在這個項目中使用了Netflix Eureka春瞬。當(dāng)客戶端負(fù)責(zé)確定可用服務(wù)實例的位置(使用注冊服務(wù)器)并在它們之間加載平衡請求時,Eureka是客戶端發(fā)現(xiàn)模式的一個很好的例子套啤。

使用Spring Boot宽气,您可以輕松地使用spring-cloud-starter-eureka-server 依賴項,? @EnableEurekaServer 注釋和簡單配置屬性構(gòu)建Eureka Registry? 潜沦。

通過@EnableDiscoveryClient 注釋和? bootstrap.yml 應(yīng)用程序名稱啟用客戶端支持? :

spring:

? application:

? ? name: notification-service

現(xiàn)在萄涯,在應(yīng)用程序啟動時,它將向Eureka Server注冊并提供元數(shù)據(jù)唆鸡,例如主機和端口涝影,運行狀況指示器URL,主頁等.Eureka從屬于服務(wù)的每個實例接收心跳消息争占。如果心跳故障超過可配置的時間表燃逻,則實例將從注冊表中刪除。

此外臂痕,Eureka提供了一個簡單的界面伯襟,您可以在其中跟蹤正在運行的服務(wù)和可用實例的數(shù)量: http://localhost:8761

負(fù)載均衡器,斷路器和Http客戶端

Netflix OSS提供了另一套很棒的工具握童。

Ribbon是一個客戶端負(fù)載均衡器姆怪,可以讓您對HTTP和TCP客戶端的行為進行大量控制。與傳統(tǒng)的負(fù)載均衡器相比澡绩,每次線上調(diào)用都不需要額外的跳 - 您可以直接聯(lián)系所需的服務(wù)片效。

開箱即用,它本身與Spring Cloud和Service Discovery集成英古。 Eureka Client? 提供可用服務(wù)器的動態(tài)列表淀衣,因此Ribbon可以在它們之間取得平衡。

豪豬

Hystrix是Circuit Breaker模式的實現(xiàn)? 召调,它可以控制通過網(wǎng)絡(luò)訪問的依賴關(guān)系的延遲和故障膨桥。主要思想是在具有大量微服務(wù)的分布式環(huán)境中停止級聯(lián)故障蛮浑。這有助于快速失敗并盡快恢復(fù) - 自我修復(fù)的容錯系統(tǒng)的重要方面。

除了斷路器控制之外只嚣,您還可以使用Hystrix添加一個回退方法沮稚,以便在主命令失敗時獲取默認(rèn)值。

此外册舞,Hystrix會為每個命令生成執(zhí)行結(jié)果和延遲的指標(biāo)蕴掏,我們可以使用它來? 監(jiān)控系統(tǒng)行為

假裝

Feign是一個聲明式HTTP客戶端调鲸,可與Ribbon和Hystrix無縫集成盛杰。實際上,通過一個? spring-cloud-starter-feign 依賴關(guān)系和? @EnableFeignClients 注釋藐石,您可以擁有一整套負(fù)載均衡器即供,斷路器和HTTP客戶端,并具有合理的即用型默認(rèn)配置于微。

以下是帳戶服務(wù)的示例:

@FeignClient(name = "statistics-service")

public interface StatisticsServiceClient {

? ? @RequestMapping(method = RequestMethod.PUT, value = "/statistics/{accountName}", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)

? ? void updateStatistics(@PathVariable("accountName") String accountName, Account account);

}

你需要的一切只是一個界面

您可以@RequestMapping 在Spring MVC控制器和Feign方法之間共享

以上示例指定了所需的服務(wù)ID -? statistics-service感謝Eureka的自動發(fā)現(xiàn)(但顯然您可以訪問具有特定URL的任何資源)

監(jiān)控儀表板

在此項目配置中逗嫡,每個帶有Hystrix的微服務(wù)都會通過Spring Cloud Bus(使用AMQP代理)將指標(biāo)推送到Turbine。Monitoring項目只是一個帶有Turbine? 和? Hystrix Dashboard的小型Spring啟動應(yīng)用程序? 株依。

讓我們看看我們在負(fù)載下的系統(tǒng)行為:帳戶服務(wù)調(diào)用統(tǒng)計服務(wù)驱证,它響應(yīng)模擬延遲變化。響應(yīng)超時閾值設(shè)置為1秒恋腕。

0 ms delay500 ms delay800 ms delay1100 ms delay表現(xiàn)良好的系統(tǒng)抹锄。吞吐量約為22個請求/秒。統(tǒng)計服務(wù)中的活動線程數(shù)量很少吗坚。中位服務(wù)時間約為50毫秒祈远。

活動線程數(shù)正在增長呆万。我們可以看到紫色線程池拒絕的數(shù)量商源,因此大約有30-40%的錯誤,但電路仍然關(guān)閉谋减。

半開狀態(tài):失敗命令的比例超過50%牡彻,斷路器啟動。睡眠窗口的時間量后出爹,下一個請求通過庄吼。

100%的請求失敗。電路現(xiàn)在永久開放严就。睡眠時間后重試不會再次關(guān)閉電路总寻,因為單個請求太慢。

日志分析

在嘗試識別分布式環(huán)境中的問題時梢为,集中日志記錄非常有用渐行。Elasticsearch轰坊,Logstash和Kibana堆棧使您可以輕松搜索和分析日志,利用率和網(wǎng)絡(luò)活動數(shù)據(jù)祟印。我的其他項目中描述隨時可用的Docker配置? 肴沫。

安全

高級安全配置超出了此概念驗證項目的范圍。要更真實地模擬真實系統(tǒng)蕴忆,請考慮使用https和JCE密鑰庫來加密微服務(wù)密碼和配置服務(wù)器屬性內(nèi)容( 有關(guān)詳細(xì)信息颤芬,請參閱? 文檔)。

基建自動化

與部署整體應(yīng)用程序相比套鹅,部署微服務(wù)具有相互依賴性站蝠,這是一個復(fù)雜得多的過程。擁有完全自動化的基礎(chǔ)架構(gòu)非常重要芋哭。我們可以通過持續(xù)交付方法獲得以下好處:

隨時發(fā)布軟件的能力沉衣。

任何構(gòu)建都可能最終成為一個版本。

構(gòu)建工件一次减牺,根據(jù)需要進行部署豌习。

這是一個簡單的Continuous Delivery工作流程,在此項目中實施:

在此? 配置中拔疚,Travis CI為每個成功的Git推送構(gòu)建標(biāo)記圖像肥隆。因此latest ,Docker Hub上的每個微服務(wù)始終都有一個? 映像? 稚失,舊映像使用Git commit hash進行標(biāo)記栋艳。如果需要,可以輕松部署其中任何一個并快速回滾句各。

如何運行所有的東西吸占?

這真的很容易,我建議你試試凿宾。請記住矾屯,您將啟動8個Spring Boot應(yīng)用程序,4個MongoDB實例和RabbitMq初厚。確保您4 Gb 的計算機上有? 可用的RAM件蚕。您始終可以通過網(wǎng)關(guān),注冊表产禾,配置排作,身份驗證服務(wù)和帳戶服務(wù)運行重要服務(wù)。

在你開始之前

安裝Docker和Docker Compose亚情。

出口環(huán)境變量:? CONFIG_SERVICE_PASSWORD妄痪,? NOTIFICATION_SERVICE_PASSWORD,? STATISTICS_SERVICE_PASSWORD楞件,? ACCOUNT_SERVICE_PASSWORD衫生, MONGODB_PASSWORD

生產(chǎn)模式

在此模式下僧著,所有最新圖像都將從Docker Hub中提取。只需復(fù)制? docker-compose.yml 并點擊即可? docker-compose up -d障簿。

發(fā)展模式

如果您想自己構(gòu)建映像(例如盹愚,代碼中有一些更改),則必須使用Maven克隆所有存儲庫并構(gòu)建工件站故。然后皆怕,跑 docker-compose -f docker-compose.yml -f docker-compose.dev.yml up -d

docker-compose.dev.yml 繼承? docker-compose.yml 了在本地構(gòu)建映像的額外可能性,并公開所有容器端口以便于開發(fā)西篓。

重要的終點

localhost:80 - 網(wǎng)關(guān)

localhost:8761 - Eureka Dashboard

localhost:9000 - Hystrix儀表板

localhost:8989 - 渦輪流(Hystrix儀表板的來源)

localhost:15672 - RabbitMq管理

筆記

所有Spring Boot應(yīng)用程序都需要運行? Config Server? 才能啟動愈腾。但是我們可以同時啟動所有容器,因為? fail-fast Spring Boot屬性和? restart: always docker-compose選項岂津。這意味著所有相關(guān)容器都將嘗試重新啟動虱黄,直到Config Server啟動并運行。

此外吮成,Service Discovery機制在所有應(yīng)用程序啟動后需要一些時間橱乱。在實例,Eureka服務(wù)器和客戶端在其本地緩存中都具有相同的元數(shù)據(jù)之前粱甫,客戶端無法發(fā)現(xiàn)任何服務(wù)泳叠,因此可能需要3次聽覺。默認(rèn)聽覺時間為30秒茶宵。

另外本人從事在線教育多年危纫,將自己的資料整合建了一個公眾號,對于有興趣一起交流學(xué)習(xí)java的初學(xué)者可以搜索:程序員文明乌庶,里面有大神會給予解答种蝶,也會有許多的資源可以供大家學(xué)習(xí)分享,歡迎大家前來一起學(xué)習(xí)進步瞒大!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末螃征,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子糠赦,更是在濱河造成了極大的恐慌会傲,老刑警劉巖锅棕,帶你破解...
    沈念sama閱讀 217,509評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件拙泽,死亡現(xiàn)場離奇詭異,居然都是意外死亡裸燎,警方通過查閱死者的電腦和手機顾瞻,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評論 3 394
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來德绿,“玉大人荷荤,你說我怎么就攤上這事退渗。” “怎么了蕴纳?”我有些...
    開封第一講書人閱讀 163,875評論 0 354
  • 文/不壞的土叔 我叫張陵会油,是天一觀的道長。 經(jīng)常有香客問我古毛,道長翻翩,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,441評論 1 293
  • 正文 為了忘掉前任稻薇,我火速辦了婚禮嫂冻,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘塞椎。我一直安慰自己桨仿,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,488評論 6 392
  • 文/花漫 我一把揭開白布案狠。 她就那樣靜靜地躺著服傍,像睡著了一般。 火紅的嫁衣襯著肌膚如雪骂铁。 梳的紋絲不亂的頭發(fā)上伴嗡,一...
    開封第一講書人閱讀 51,365評論 1 302
  • 那天,我揣著相機與錄音从铲,去河邊找鬼瘪校。 笑死,一個胖子當(dāng)著我的面吹牛名段,可吹牛的內(nèi)容都是我干的阱扬。 我是一名探鬼主播,決...
    沈念sama閱讀 40,190評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼伸辟,長吁一口氣:“原來是場噩夢啊……” “哼麻惶!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起信夫,我...
    開封第一講書人閱讀 39,062評論 0 276
  • 序言:老撾萬榮一對情侶失蹤窃蹋,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后静稻,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體警没,經(jīng)...
    沈念sama閱讀 45,500評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,706評論 3 335
  • 正文 我和宋清朗相戀三年振湾,在試婚紗的時候發(fā)現(xiàn)自己被綠了杀迹。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,834評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡押搪,死狀恐怖树酪,靈堂內(nèi)的尸體忽然破棺而出浅碾,到底是詐尸還是另有隱情,我是刑警寧澤续语,帶...
    沈念sama閱讀 35,559評論 5 345
  • 正文 年R本政府宣布垂谢,位于F島的核電站,受9級特大地震影響疮茄,放射性物質(zhì)發(fā)生泄漏埂陆。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,167評論 3 328
  • 文/蒙蒙 一娃豹、第九天 我趴在偏房一處隱蔽的房頂上張望焚虱。 院中可真熱鬧,春花似錦懂版、人聲如沸鹃栽。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽民鼓。三九已至,卻和暖如春蓬抄,著一層夾襖步出監(jiān)牢的瞬間丰嘉,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評論 1 269
  • 我被黑心中介騙來泰國打工嚷缭, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留饮亏,地道東北人。 一個月前我還...
    沈念sama閱讀 47,958評論 2 370
  • 正文 我出身青樓阅爽,卻偏偏與公主長得像路幸,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子付翁,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,779評論 2 354

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