【Java應(yīng)用服務(wù)體系】「序章入門」全方位盤點(diǎn)和總結(jié)調(diào)優(yōu)技術(shù)專題指南

專題?標(biāo)

本系列專題的目標(biāo)是希望可以幫助讀者們系統(tǒng)和全訪問掌握應(yīng)?系統(tǒng)調(diào)優(yōu)的思路與方案以及相關(guān)的調(diào)優(yōu)工具的使用忌傻,雖然未必會(huì)覆蓋目前的所有的問題場(chǎng)景,但是還是提供了較為豐富的案例和調(diào)優(yōu)理論份乒,會(huì)幫助大家打開思維去?撐系統(tǒng)服務(wù)體系優(yōu)化能力盐茎。

適合人員

Java相關(guān)的開發(fā)人員袭蝗、系統(tǒng)架構(gòu)師、數(shù)據(jù)庫DB人員以及運(yùn)維人員等斋攀。

什么是調(diào)優(yōu)

調(diào)優(yōu)手段就是讓計(jì)算機(jī)的硬件或軟件在正常地?作基礎(chǔ)上,非常出色的發(fā)揮其應(yīng)有的性能梧田,并且將所承擔(dān)的負(fù)擔(dān)降低到最低的技術(shù)手段淳蔼。在Java應(yīng)用服務(wù)體系中有大致可以分為5個(gè)維度的調(diào)優(yōu)方向。

調(diào)優(yōu)技術(shù)的五個(gè)維度

  • 應(yīng)??身的調(diào)優(yōu)
  • 運(yùn)?環(huán)境的調(diào)優(yōu)(JVM的調(diào)優(yōu))
  • 存儲(chǔ)上的調(diào)優(yōu)(數(shù)據(jù)庫的調(diào)優(yōu))
  • 操作系統(tǒng)的調(diào)優(yōu)
  • 架構(gòu)上的調(diào)優(yōu)

如下圖所示裁眯。

image

一般從上到下系統(tǒng)優(yōu)化的層面成本越來越高鹉梨,而從下到上系統(tǒng)優(yōu)化層面的成本越來月底,而且難度也適當(dāng)下降未状,建議自下而上的去進(jìn)行調(diào)優(yōu)規(guī)劃俯画。

調(diào)優(yōu)技術(shù)的四條準(zhǔn)則

借助監(jiān)控預(yù)防問題、發(fā)現(xiàn)問題司草,監(jiān)控 + 告警

采用監(jiān)控和預(yù)防的手段去實(shí)現(xiàn)提前發(fā)現(xiàn)問題:zabbix艰垂、promethus等等

借助?具定位問題

問題排查工具使用機(jī)制

定期復(fù)盤,防?同類問題再現(xiàn)

定期進(jìn)行排查和復(fù)盤相關(guān)的代碼問題埋虹,加深我們對(duì)問題的印象以及防止問題再次發(fā)生

定好規(guī)范猜憎,?定程度上規(guī)避問題

制定標(biāo)準(zhǔn)規(guī)范,約束問題的發(fā)生搔课。

調(diào)優(yōu)的原則

有問題胰柑,解決問題。not broken, don't fix.

應(yīng)?調(diào)優(yōu)

應(yīng)?調(diào)優(yōu)-?具篇

  • ?具旨在幫助我們快速找到應(yīng)?的性能瓶頸爬泥。

  • ?志分析?具?較與分析

  • ELK柬讨、GrayLog、SLSLog...

  • ELK搭建與使?

  • 現(xiàn)場(chǎng)演示

  • 調(diào)?鏈跟蹤?具與對(duì)?

  • Skywalking袍啡、Sleuth + Zipkin踩官、Jaeger...

  • Skywalking快速發(fā)現(xiàn)性能瓶頸

應(yīng)?調(diào)優(yōu)常?技巧-池化技術(shù)-對(duì)象池

通過復(fù)?對(duì)象,減少對(duì)象創(chuàng)建境输、垃圾回收的開銷

適?場(chǎng)景

維護(hù)?些很?蔗牡、創(chuàng)建很慢的對(duì)象,提升性能
缺點(diǎn):有學(xué)習(xí)成本嗅剖、增加了代碼的復(fù)雜度

對(duì)象池框架

Apache Commons-Pool2
Commons-Pool2詳解

兩?類對(duì)象池:ObjectPool & KeyedObjectPool

ObjectPool

實(shí)現(xiàn)類如下辩越,其中,最重要信粮、功能最強(qiáng)黔攒、使?最?泛的GenericObjectPool,這個(gè)對(duì)象池?常的強(qiáng)?,它?較的通?亏钩,?且封裝得也?常完備莲绰。

  • BaseObjectPool:抽象類,?來擴(kuò)展??的對(duì)象池
  • ErodingObjectPool:“腐蝕”對(duì)象池姑丑,代理?個(gè)對(duì)象池蛤签,并基于factor參數(shù),為其添加“腐蝕”?為栅哀。歸還的對(duì)象被腐蝕后震肮,將會(huì)丟棄,?不是添加到空閑容量中留拾。
  • GenericObjectPool:?個(gè)可配置的通?對(duì)象池實(shí)現(xiàn)戳晌。
  • ProxiedObjectPool:代理?個(gè)其他的對(duì)象池,并基于動(dòng)態(tài)代理(?持JDK代理和CGLib代理)痴柔,返回?個(gè)代理后的對(duì)象沦偎。該對(duì)象池主要?來增強(qiáng)對(duì)池化對(duì)象的控制,?如防?在歸還該對(duì)象后咳蔚,還繼續(xù)使?該對(duì)象等豪嚎。
  • SoftReferenceObjectPool:基于軟引?的對(duì)象池
  • SynchronizedObjectPool:代理?個(gè)其他對(duì)象池,并為其提供線程安全的能?谈火。
核?API如下
  • borrowObject() 從對(duì)象池中借對(duì)象
  • returnObject() 將對(duì)象歸還到對(duì)象池
  • invalidateObject() 失效?個(gè)對(duì)象
  • addObject() 增加?個(gè)空閑對(duì)象侈询,該?法適?于使?空閑對(duì)象預(yù)加載對(duì)象池
  • clear() 清空空閑的所有對(duì)象,并釋放相關(guān)資源
  • close() 關(guān)閉對(duì)象池糯耍,并釋放相關(guān)資源
  • getNumIdle() 獲得空閑的對(duì)象數(shù)量
  • getNumActive() 獲得被借出對(duì)象數(shù)量
KeyedObjectPool

這種對(duì)象池和ObjectPool的區(qū)別在于扔字,它是通過key找對(duì)象的,從設(shè)計(jì)上來看和ObjectPool沒什么區(qū)別温技。實(shí)現(xiàn)類如下革为,使?最?的是GenericKeyedObjectPool。

  • ErodingKeyedObjectPool 類似ErodingObjectPool
  • GenericKeyedObjectPool 類似GenericObjectPool
  • ProxiedKeyedObjectPool 類似ProxiedObjectPool
  • SynchronizedKeyedObjectPool 類似SynchronizedObjectPool
使?
new GenericObjectPool(PooledObjectFactory<T> factory)
new GenericObjectPool(PooledObjectFactory<T> factory, GenericObjectPoolConfig<T> config)
new GenericObjectPool(PooledObjectFactory<T> factory, GenericObjectPoolConfig<T> config, AbandonedConfig abando
nedConfig)

最重要的參數(shù)是PooledObjectFactory舵鳞,?般來說篷角,??是需要我們??根據(jù)業(yè)務(wù)需求去實(shí)現(xiàn)的。它是?來創(chuàng)建對(duì)象的系任,這其實(shí)就是設(shè)計(jì)模式??的??模式。

?前PooledObjectFactory有兩個(gè)實(shí)現(xiàn)類虐块。

  • BasePooledObjectFactory:抽象類俩滥,?于擴(kuò)展??的PooledObjectFactory
  • PoolUtils.SynchronizedPooledObjectFactory:內(nèi)部類,代理?個(gè)其他的PooledObjectFactory贺奠,實(shí)現(xiàn)線程同步霜旧,? PoolUtils.synchronizedPooledFactory() 創(chuàng)建

Factory核??法:

  • makeObject 創(chuàng)建?個(gè)對(duì)象實(shí)例,并將其包裝成?個(gè)PooledObject
  • destroyObject 銷毀對(duì)象
  • validateObject 校驗(yàn)對(duì)象,確保對(duì)象池返回的對(duì)象是OK的
  • activateObject 重新初始化對(duì)象
  • passivateObject 取消初始化對(duì)象挂据。GenericObjectPool的addIdleObject以清、returnObject、evict調(diào)?該?法崎逃。

Commons-Pool2總體分析

  • ObjectPool:對(duì)象池掷倔,最核?:GenericObjectPool、 GenericKeyedObjectPool个绍。
  • Factory:創(chuàng)建&管理PooledObject勒葱,?般要??擴(kuò)展
  • PooledObject:包裝原有的對(duì)象,從?讓對(duì)象池管理巴柿,?般?DefaultPooledObject即可
Factory示例
class MyPooledObjectFactory implements PooledObjectFactory<Model> { 
   public static final Logger LOGGER = LoggerFactory.getLogger(MyPooledObjectFactory.class); 
   @Override
   public PooledObject<Model> makeObject() throws Exception {
      DefaultPooledObject<Model> object = new DefaultPooledObject<>(new Model(1, "S")); 
      LOGGER.info("makeObject..state = {}", object.getState());
      return object; 
   }
  @Override
  public void destroyObject(PooledObject p) throws Exception{
      LOGGER.info("destroyObject..state = {}", object.getState());
   }
  @Override
  public boolean validateObject(PooledObject p) {
      LOGGER.info("validateObject..state = {}", object.getState());
      return true;
   }
  @Override
  public void activateObject(PooledObject p) throws Exception{
    LOGGER.info("activateObject..state = {}", p.getState());
   }
@Override
  public void passivateObject(PooledObject p) {
      LOGGER.info("passivateObject..state = {}", object.getState());
      return true;
   }

所有操作面向的都是PooledObject這個(gè)參數(shù)凛虽,makeObject返回的是PooledObject,其他API為什么操作的也是 PooledObject广恢,?不是直接操作我們創(chuàng)建的對(duì)象呢凯旋?

這其實(shí)也是commons-pool設(shè)計(jì)巧妙之處。Pooledobject可以對(duì)原始對(duì)象進(jìn)?包裝钉迷,從?被對(duì)象池管理至非。?前 pooledobject有兩個(gè)實(shí)現(xiàn)類:

  • DefaultPooledObject:包裝原始對(duì)象,實(shí)現(xiàn)監(jiān)控(例如創(chuàng)建時(shí)間篷牌、使?時(shí)間等)睡蟋、狀態(tài)跟蹤等
  • PooledSoftReference:封裝了DefaultPooledObject,?來和SoftReferenceObjectPool配合使?枷颊。
DefaultPooledObject定義了對(duì)象的若?種狀態(tài)
  • IDLE 對(duì)象在隊(duì)列中戳杀,并空閑。
  • ALLOCATED 使?中(即出借中)
  • EVICTION 對(duì)象當(dāng)在隊(duì)列中夭苗,正在進(jìn)?驅(qū)逐測(cè)試
  • EVICTION_RETURN_TO_HEAD 對(duì)象驅(qū)逐測(cè)試通過后信卡,放回到隊(duì)列頭部
  • VALIDATION 對(duì)象當(dāng)前在隊(duì)列中,空閑校驗(yàn)中
  • VALIDATION_PREALLOCATED 對(duì)象當(dāng)前不在隊(duì)列中题造,出借前校驗(yàn)中 VALIDATION_RETURN_TO_HEAD 對(duì)象當(dāng)前不在隊(duì)列中傍菇,校驗(yàn)通過后放回頭部 INVALID 對(duì)象失效,驅(qū)逐測(cè)試失敗界赔、校驗(yàn)失敗丢习、對(duì)象銷毀,都會(huì)將對(duì)象置為 INVALID淮悼。
  • ABANDONED 放逐中咐低,如果對(duì)象上次使?時(shí)間超過removeAbandonedTimeout的配置,則將其標(biāo)記為ABANDONED袜腥。標(biāo)記為ABANDONED的對(duì)象即將變成 INVALID见擦。
  • RETURNING 對(duì)象歸還池中。

JVM調(diào)優(yōu)

本系列專題將針對(duì)于Oracle Java HotSpot虛擬機(jī)為為開發(fā)者們提供不同的Java Heap內(nèi)存空間的較為深入的分析介紹。對(duì)于任何接觸的開發(fā)者都是非常重要的理論依據(jù)鲤屡。頻繁遇到的內(nèi)存問題损痰,提供生產(chǎn)環(huán)境的優(yōu)化調(diào)整。那么適當(dāng)?shù)膶?shí)戰(zhàn)層級(jí)的Java虛擬機(jī)的內(nèi)存空間分析能力是至關(guān)重要的酒来。

前提概述

  • Java虛擬機(jī)是你的Java程序運(yùn)行的基礎(chǔ)卢未,它為你提供動(dòng)態(tài)的分配內(nèi)存服務(wù)、垃圾收集役首、線程調(diào)度和切換尝丐、IO處理和本機(jī)操作等
  • Java堆空間是運(yùn)行時(shí)Java程序的內(nèi)存“容器”,它提供給您的Java應(yīng)用程序所需的適當(dāng)內(nèi)存空間(Java堆衡奥、本機(jī)堆)爹袁,并由JVM本身去管理。

JVM HotSpot內(nèi)存被劃分2類和5空間:

  • Heap堆內(nèi)存空間:屬于線程共享區(qū)域矮固,也是我們JVM的內(nèi)存管理范疇的最大的一部分運(yùn)行時(shí)內(nèi)存區(qū)域失息。
  • 方法區(qū)(永久代/元空間):屬于線程共享區(qū)域,往往我們會(huì)忽略了這個(gè)區(qū)域的內(nèi)存回收能力档址。
  • 本地堆 (C-Heap):本地方法的調(diào)用棧盹兢。
  • 虛擬機(jī)棧:Java方法的調(diào)用棧。
image

Heap堆內(nèi)存空間

JVM的堆空間的變化在<18的版本之內(nèi)守伸,主要有一個(gè)分水嶺绎秒,主要集中在8之前和8之后。

JDK8之前的對(duì)空間

JDK8之前的Heap空間如下圖所示:

image

JDK8之后的Heap空間如下圖所示:

image

主要時(shí)針對(duì)于方法區(qū)的實(shí)現(xiàn)機(jī)制:永久代 -> 元空間結(jié)構(gòu)模型尼摹,接下來我們看看元數(shù)據(jù)空間在方法區(qū)中的分布結(jié)構(gòu)模型见芹。

后續(xù)版本中的-元空間和方法去的內(nèi)存才能出分配關(guān)系
image

可以看到JDK8之后,方法去的實(shí)現(xiàn)有元空間和一部分堆內(nèi)存組成蠢涝。之前主要只有單純的永久代去實(shí)現(xiàn)的玄呛。

常量池

常量池主要有靜態(tài)常量池和運(yùn)行時(shí)常量池組成。

  • 類信息
    • 類的版本
    • 字段描述信息
    • 方法描述信息
    • 接口和父類等描述信息
    • class文件常量池(靜態(tài)常量池)
靜態(tài)常量池和二,也叫class?件常量池徘铝,主要存放:
  • 字?量:例如?本字符串、 final修飾的常量惯吕。
  • 符號(hào)引?:例如類和接?的全限定名惕它、字段的名稱和描述符、?法的名稱和描述符废登。
運(yùn)?時(shí)常量池

當(dāng)類加載到內(nèi)存中后怠缸,JVM就會(huì)將靜態(tài)常量池中的內(nèi)容存放到運(yùn)?時(shí)的常量池中;運(yùn)?時(shí)常量池??存儲(chǔ)的主要是編譯期間?成的字?量钳宪、符號(hào)引?等等。如下圖對(duì)應(yīng)的字符串常量在字符串常量池中的存儲(chǔ)模式。

image
字符串常量池

字符串常量池吏颖,也可以理解成運(yùn)?時(shí)常量池分出來的?部分搔体,類加載到內(nèi)存的時(shí)候,字符串半醉,會(huì)存到字符串常量池??疚俱。

image
對(duì)象和類在內(nèi)存分布

針對(duì)于代碼的執(zhí)行和存儲(chǔ)在JVM的分布,主要集中在椝醵啵空間和堆空間呆奕、方法區(qū)。它們各個(gè)的職能不同衬吆,對(duì)應(yīng)的能力也是不同的梁钾。我們針對(duì)于一段代碼塊進(jìn)行分析和介紹

虛擬機(jī)棧的基本結(jié)構(gòu)模型
image
代碼在堆棧中的存儲(chǔ)結(jié)構(gòu)信息
image

內(nèi)存泄漏怎么排查[java內(nèi)存溢出排查]

top 等查看系統(tǒng)內(nèi)存概況

top:顯示所有進(jìn)程運(yùn)行情況,按M鍵按照內(nèi)存大小排序逊抡。

使用格式

top [-] [d] [p] [q] [c] [C] [S] [s] [n]

參數(shù)說明

  • d:指定每?jī)纱纹聊恍畔⑺⑿轮g的時(shí)間間隔姆泻,當(dāng)然用戶可以使用s交互命令來改變之
  • p:通過指定監(jiān)控進(jìn)程ID來僅僅監(jiān)控某個(gè)進(jìn)程的狀態(tài)冒嫡。
  • q:該選項(xiàng)將使top沒有任何延遲的進(jìn)行刷新拇勃。如果調(diào)用程序有超級(jí)用戶權(quán)限,那么top將以盡可能高的優(yōu)先級(jí)運(yùn)行孝凌。
  • S:指定累計(jì)模式方咆。
  • s:使top命令在安全模式中運(yùn)行。這將去除交互命令所帶來的潛在危險(xiǎn)蟀架。
  • i:使top不顯示任何閑置或者僵死進(jìn)程瓣赂。
  • c:顯示整個(gè)命令行而不只是顯示命令名。

命令說明

  • jmx 快速發(fā)現(xiàn)jvm中的內(nèi)存異常項(xiàng)

【實(shí)戰(zhàn)階段】JVM排查問題優(yōu)化參數(shù)

jps [-q] [-mlvV] [<hostid>]

參數(shù)如下:

  • -q 只顯示進(jìn)程號(hào)
  • -m 顯示傳遞給main?法的參數(shù)
  • -l 顯示應(yīng)?main class的完整包名應(yīng)?的jar?件完整路徑名
  • -v 顯示傳遞給JVM的參數(shù)
  • -V 禁?輸出類名辜窑、JAR?件名和傳遞給main?法的參數(shù)钩述,僅顯示本地JVM標(biāo)識(shí)符的列表

hostid的參數(shù)格式

  • hostid:想要查看的主機(jī)的標(biāo)識(shí)符,格式為: [protocol:][[//]hostname][:port][/servername] 穆碎,其中:
  • protocol:通信協(xié)議牙勘,默認(rèn)rmi
  • hostname:?標(biāo)主機(jī)的主機(jī)名或IP地址
  • port:通信端?,對(duì)于默認(rèn) rmi 協(xié)議所禀,該參數(shù)?來指定 rmiregistry 遠(yuǎn)程主機(jī)上的端?號(hào)方面。如省略該參數(shù),并且該
  • protocol指示rmi色徘,則使?默認(rèn)使?1099端?恭金。
  • servicename:服務(wù)名稱,取值取決于實(shí)現(xiàn)?式褂策,對(duì)于rmi協(xié)議横腿,此參數(shù)代表遠(yuǎn)程主機(jī)上RMI遠(yuǎn)程對(duì)象的名稱

今天就寫到這里颓屑,未完待續(xù),等待下一部分的內(nèi)容耿焊。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末揪惦,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子罗侯,更是在濱河造成了極大的恐慌器腋,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,332評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件钩杰,死亡現(xiàn)場(chǎng)離奇詭異纫塌,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)讲弄,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,508評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門措左,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人垂睬,你說我怎么就攤上這事媳荒。” “怎么了驹饺?”我有些...
    開封第一講書人閱讀 157,812評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵钳枕,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我赏壹,道長(zhǎng)鱼炒,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,607評(píng)論 1 284
  • 正文 為了忘掉前任蝌借,我火速辦了婚禮昔瞧,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘菩佑。我一直安慰自己自晰,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,728評(píng)論 6 386
  • 文/花漫 我一把揭開白布稍坯。 她就那樣靜靜地躺著酬荞,像睡著了一般。 火紅的嫁衣襯著肌膚如雪瞧哟。 梳的紋絲不亂的頭發(fā)上混巧,一...
    開封第一講書人閱讀 49,919評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音勤揩,去河邊找鬼咧党。 笑死,一個(gè)胖子當(dāng)著我的面吹牛陨亡,可吹牛的內(nèi)容都是我干的傍衡。 我是一名探鬼主播深员,決...
    沈念sama閱讀 39,071評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼蛙埂!你這毒婦竟也來了辨液?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,802評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤箱残,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后止吁,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體被辑,經(jīng)...
    沈念sama閱讀 44,256評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,576評(píng)論 2 327
  • 正文 我和宋清朗相戀三年敬惦,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了盼理。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,712評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡俄删,死狀恐怖宏怔,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情畴椰,我是刑警寧澤臊诊,帶...
    沈念sama閱讀 34,389評(píng)論 4 332
  • 正文 年R本政府宣布,位于F島的核電站斜脂,受9級(jí)特大地震影響抓艳,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜帚戳,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,032評(píng)論 3 316
  • 文/蒙蒙 一玷或、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧片任,春花似錦偏友、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至犁钟,卻和暖如春棱诱,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背涝动。 一陣腳步聲響...
    開封第一講書人閱讀 32,026評(píng)論 1 266
  • 我被黑心中介騙來泰國(guó)打工迈勋, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人醋粟。 一個(gè)月前我還...
    沈念sama閱讀 46,473評(píng)論 2 360
  • 正文 我出身青樓靡菇,卻偏偏與公主長(zhǎng)得像重归,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子厦凤,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,606評(píng)論 2 350

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