xxl-job分布式任務(wù)調(diào)度框架體驗

一捻撑、xxl-job是什么

xxl-job是一個分布式任務(wù)調(diào)度平臺,其核心特點就是簡單缤底、能快速上手顾患、輕量級、易擴展个唧。在如今的分布式場景中取董,已經(jīng)成為主流的任務(wù)調(diào)度框架企量。

二、xxl-job快速上手體驗

2.1 環(huán)境配置

該步驟在官方中文文檔上都有詳細介紹,略過~

2.2 配置和部署調(diào)度中心

按照文檔將xxl-job-admin打包部署到對應(yīng)的服務(wù)器上即可奥洼。

2.3 配置和部署執(zhí)行器

這里就以github來下來的項目中的xxl-job-executor-sample-springboot為例進行演示蝶怔。該項目需要包含如下三個要素才能正常注冊到調(diào)度中心:

  1. 引入核心依賴包

    <!-- xxl-job-core -->
    <dependency>
        <groupId>com.xuxueli</groupId>
        <artifactId>xxl-job-core</artifactId>
        <version>${project.parent.version}</version>
    </dependency>
    
  2. 修改執(zhí)行器配置

    # web port
    server.port=8081
    # log config
    logging.config=classpath:logback.xml
    # [選填]調(diào)度中心地址:如調(diào)度中心集群部署存在多個地址則用逗號分隔俗壹。執(zhí)行器將會使用該地址進行"執(zhí)行器心跳注冊"和"任務(wù)結(jié)果回調(diào)"恰梢;為空則關(guān)閉自動注冊;
    xxl.job.admin.addresses=http://x.x.x.x:8080/xxl-job-admin/
    # [選填]執(zhí)行器通訊TOKEN:非空時啟用画恰;
    xxl.job.accessToken=
    # [選填]執(zhí)行器AppName:執(zhí)行器心跳注冊分組依據(jù)彭谁;為空則關(guān)閉自動注冊
    xxl.job.executor.appname=zx-executor
    # [選填]執(zhí)行器注冊:優(yōu)先使用該配置作為注冊地址,為空時使用內(nèi)嵌服務(wù) ”IP:PORT“ 作為注冊地址允扇。從而更靈活的支持容器類型執(zhí)行器動態(tài)IP和動態(tài)映射端口問題缠局。
    xxl.job.executor.address=
    # [選填]執(zhí)行器IP:默認為空表示自動獲取IP,多網(wǎng)卡時可手動設(shè)置指定IP考润,該IP不會綁定Host僅作為通訊實用狭园;地址信息用于 "執(zhí)行器注冊" 和 "調(diào)度中心請求并觸發(fā)任務(wù)";
    xxl.job.executor.ip=
    # [選填]執(zhí)行器端口號:小于等于0則自動獲群巍唱矛;默認端口為9999,單機部署多個執(zhí)行器時井辜,注意要配置不同執(zhí)行器端口绎谦;
    xxl.job.executor.port=9998
    # [選填]執(zhí)行器運行日志文件存儲磁盤路徑:需要對該路徑擁有讀寫權(quán)限;為空則使用默認路徑粥脚;
    xxl.job.executor.logpath=/data/applogs/xxl-job/jobhandler
    # [選填]執(zhí)行器日志文件保存天數(shù):過期日志自動清理, 限制值大于等于3時生效; 否則, 如-1, 關(guān)閉自動清理功能窃肠;
    xxl.job.executor.logretentiondays=30
    
  3. 注冊執(zhí)行器組件

    參考XxlJobConfig.java中的代碼,將如上配置文件中的內(nèi)容注冊到Spring的Bean中刷允。

最后將該項目打包部署到對應(yīng)的服務(wù)器上即可冤留。

2.4 調(diào)度中心執(zhí)行器配置

默認情況下碧囊,我們?nèi)缟系?code>zx-executor并不會自動注冊并展示在調(diào)度中心admin控制臺的“執(zhí)行器管理”里面,需要我們手動創(chuàng)建一下:

新建執(zhí)行器

如果此時執(zhí)行器不在線的話纤怒,OnLine機器地址就展示無糯而,如果在線的話就能展示具體的執(zhí)行器IP地址了。因為我們是自動注冊泊窘,所以執(zhí)行器和調(diào)度中心之間會有心跳熄驼,按照官方文檔的描述,默認是30秒州既,如果持續(xù)90秒沒有收到執(zhí)行器的心跳谜洽,調(diào)度中心就會將該執(zhí)行器移除。當然吴叶,如果執(zhí)行器是主動注銷的,會立即上報給調(diào)度中心序臂。

2.5 調(diào)度中心任務(wù)配置

默認情況下蚌卤,我們在執(zhí)行器中聲明和定義的任務(wù)也不會自動注冊和展示到調(diào)度中心admin控制臺的“任務(wù)管理”里面,需要我們手動創(chuàng)建一下奥秆。

新建任務(wù)

具體的參數(shù)信息可以查看官方文檔逊彭,有比較詳細的描述和說明。在創(chuàng)建完畢后构订,該任務(wù)是處于STOP狀態(tài)侮叮,需要將其改為”啟動狀態(tài)“,才會按照設(shè)置的調(diào)度信息進行任務(wù)的調(diào)度悼瘾。

三囊榜、特性介紹

  1. 簡單:支持通過Web頁面對任務(wù)進行CRUD操作,可以簡單上手亥宿;

  2. 動態(tài):支持動態(tài)修改任務(wù)狀態(tài)卸勺,切換啟動和停止,還可以終止正在運行中的任務(wù)烫扼,即時生效曙求;

  3. 調(diào)度中心HA:調(diào)度中心支持集群部署,多個調(diào)度中心連接同一個數(shù)據(jù)庫即可映企,靠DB鎖來實現(xiàn)調(diào)度的一致性悟狱;

  4. 執(zhí)行器HA:同一個執(zhí)行器支持集群部署,保持各自設(shè)置的appname相同即可堰氓,支持分片執(zhí)行挤渐;

  5. 注冊中心:執(zhí)行器會周期性地自動注冊任務(wù),調(diào)度中心則會自動發(fā)現(xiàn)任務(wù)并按照設(shè)定的調(diào)度參數(shù)執(zhí)行豆赏,同時挣菲,也支持手動錄入執(zhí)行器地址富稻;

    執(zhí)行器的自動注冊不是指執(zhí)行器會自動出現(xiàn)在“執(zhí)行器管理”的列表里面,相反執(zhí)行器需要管理員自己手動創(chuàng)建白胀,自動注冊指的是執(zhí)行器里面Online機器地址會自動注冊椭赋。

    如果我們在創(chuàng)建執(zhí)行器的時候沒有選擇“自動注冊”,而是選擇手動錄入機器地址或杠,那么就不會有心跳自動檢測哪怔,即是執(zhí)行器關(guān)閉或者有新的執(zhí)行器注冊上來都不會自動注冊,更新到Online機器地址中向抢;

    同樣的认境,執(zhí)行器里面的任務(wù)也是需要管理員手動創(chuàng)建的,并非可以自動展示在執(zhí)行器的任務(wù)列表里面挟鸠。其實這也是為了安全考慮叉信,只有管理員手動確認新建的任務(wù)才能得到執(zhí)行。

  6. 彈性擴縮容:一旦有新的執(zhí)行器上線或者下線艘希,下次調(diào)度將會重新分配任務(wù)硼身;

  7. 觸發(fā)策略:提供豐富的任務(wù)觸發(fā)策略,包括Cron觸發(fā)覆享、固定間隔觸發(fā)佳遂、固定延時觸發(fā)、API事件觸發(fā)撒顿、人工觸發(fā)、父子任務(wù)觸發(fā)吩屹;

  8. 調(diào)度過期策略:調(diào)度中心錯過調(diào)度時間的補償處理策略祟峦,包括忽略宅楞、立即補償觸發(fā)一次等袱吆;

  9. 阻塞處理策略:調(diào)度過于密集執(zhí)行器來不及處理時的策略绞绒,包括:

    1. 單機串行:調(diào)度請求進入單機執(zhí)行器后蓬衡,無論執(zhí)行器當前是否忙碌彤枢,調(diào)度請求進入FIFO隊列缴啡,等待穿行執(zhí)行业栅;
    2. 丟棄后續(xù)調(diào)度:調(diào)度請求進入單機執(zhí)行器后谬晕,發(fā)現(xiàn)執(zhí)行器正在工作攒钳,那么本次請求會被丟棄標記為調(diào)度失敳怀拧;
    3. 覆蓋之前調(diào)度:調(diào)度請求進入單機執(zhí)行器后,發(fā)現(xiàn)執(zhí)行器正在工作揩页,那么會終止正在執(zhí)行的任務(wù)烹俗,清空隊列幢妄,馬上運行當前請求的任務(wù);
  10. 任務(wù)超時控制:支持自定義任務(wù)超時時間乎赴,任務(wù)運行超時就會主動中斷任務(wù)榕吼;

  11. 任務(wù)失敗重試:支持自定義任務(wù)失敗重試次數(shù)羹蚣,當任務(wù)失敗時將會按照預(yù)設(shè)的失敗重試次數(shù)主動進行重試顽素;其中分片任務(wù)支持分片粒度的失敗重試;

  12. 任務(wù)失敗告警:默認提供郵件方式失敗告警胁出,同時預(yù)留擴展接口输莺,可方便的擴展短信裸诽、釘釘?shù)雀婢绞剑?/p>

  13. 路由策略:執(zhí)行器集群部署時提供豐富的路由策略丈冬,包括:第一個、最后一個往弓、輪詢函似、隨機撇寞、一致性HASH蔑担、最不經(jīng)常使用啤握、最近最久未使用排抬、故障轉(zhuǎn)移三妈、忙碌轉(zhuǎn)移等畴蒲;這是明顯由于Quartz的特性;

  14. 分片廣播任務(wù):執(zhí)行器集群部署時掩宜,任務(wù)路由策略選擇”分片廣播”情況下牺汤,一次任務(wù)調(diào)度將會廣播觸發(fā)集群中所有執(zhí)行器執(zhí)行一次任務(wù)浩嫌,可根據(jù)分片參數(shù)開發(fā)分片任務(wù);

    分片任務(wù)的好處就是可以把一個n個相同的任務(wù)分給同一個執(zhí)行器中的不同單機執(zhí)行追迟,從而提升并發(fā)度敦间,提高任務(wù)的執(zhí)行效率廓块。我們將springboot示例項目在項目里面復(fù)制一份带猴,修改端口號并改為maven子項目后啟動懈万,從而就得到一個執(zhí)行器集群。

    然后在管理端新建一個分片廣播任務(wù):

    新建一個分片廣播任務(wù)

    然后我們手動執(zhí)行一次后嫡秕,會發(fā)現(xiàn)該執(zhí)行器集群中的兩臺單機都執(zhí)行了一次shardingJobHandler任務(wù):

    分片廣播任務(wù)的執(zhí)行結(jié)果

    它們對應(yīng)的執(zhí)行日志如下:

    2023-01-20 14:16:57 [com.xxl.job.executor.service.jobhandler.SampleXxlJob#shardingJobHandler]-[59]-[xxl-job, JobThread-44-1674195417203] 分片參數(shù):當前分片序號 = 0, 總分片數(shù) = 2
    2023-01-20 14:16:57 [com.xxl.job.executor.service.jobhandler.SampleXxlJob#shardingJobHandler]-[64]-[xxl-job, JobThread-44-1674195417203] 第 0 片, 命中分片開始處理
    2023-01-20 14:16:57 [com.xxl.job.executor.service.jobhandler.SampleXxlJob#shardingJobHandler]-[66]-[xxl-job, JobThread-44-1674195417203] 第 1 片, 忽略
    2023-01-20 14:16:57 [com.xxl.job.executor.service.jobhandler.SampleXxlJob#shardingJobHandler]-[59]-[xxl-job, JobThread-44-1674195417341] 分片參數(shù):當前分片序號 = 1, 總分片數(shù) = 2
    2023-01-20 14:16:57 [com.xxl.job.executor.service.jobhandler.SampleXxlJob#shardingJobHandler]-[66]-[xxl-job, JobThread-44-1674195417341] 第 0 片, 忽略
    2023-01-20 14:16:57 [com.xxl.job.executor.service.jobhandler.SampleXxlJob#shardingJobHandler]-[64]-[xxl-job, JobThread-44-1674195417341] 第 1 片, 命中分片開始處理

分片任務(wù)還有另外一種形式驾凶,就是在管理端創(chuàng)建多個配置相同的任務(wù)调违,路由策略都是第一個空閑的執(zhí)行器執(zhí)行技肩,然后JobHandler都設(shè)置成為一樣的虚婿,只是執(zhí)行參數(shù)設(shè)置為不同的參數(shù)段然痊,從而使得各個單機執(zhí)行器按照自己的參數(shù)段各自執(zhí)行各自的任務(wù)。

  1. 動態(tài)分片:分片廣播任務(wù)以執(zhí)行器為維度進行分片锹引,支持動態(tài)擴容執(zhí)行器集群從而動態(tài)增加分片數(shù)量嫌变,協(xié)同進行業(yè)務(wù)處理初澎;在進行大數(shù)據(jù)量業(yè)務(wù)操作時可顯著提升任務(wù)處理能力和速度碑宴;

  2. 故障轉(zhuǎn)移:任務(wù)路由策略選擇”故障轉(zhuǎn)移”情況下桑谍,如果執(zhí)行器集群中某一臺機器故障贞间,將會自動Failover切換到一臺正常的執(zhí)行器發(fā)送調(diào)度請求增热;

  3. 任務(wù)進度監(jiān)控:支持實時監(jiān)控任務(wù)進度;

  4. Rolling實時日志:支持在線查看調(diào)度結(jié)果峻仇,并且支持以Rolling方式實時查看執(zhí)行器輸出的完整的執(zhí)行日志;

  5. GLUE:提供Web IDE人断,支持在線開發(fā)任務(wù)邏輯代碼吭从,動態(tài)發(fā)布,實時編譯生效恶迈,省略部署上線的過程涩金。支持30個版本的歷史版本回溯;--待實驗

  6. 腳本任務(wù):支持以GLUE模式開發(fā)和運行腳本任務(wù),包括Shell鸭廷、Python枣抱、NodeJS、PHP辆床、PowerShell等類型腳本佳晶;--待實驗

  7. 命令行任務(wù):原生提供通用命令行任務(wù)Handler(Bean任務(wù),”CommandJobHandler”)讼载;業(yè)務(wù)方只需要提供命令行即可轿秧;--待實驗

  8. 任務(wù)依賴:支持配置子任務(wù)依賴驱还,當父任務(wù)執(zhí)行結(jié)束且執(zhí)行成功后將會主動觸發(fā)一次子任務(wù)的執(zhí)行, 多個子任務(wù)用逗號分隔萎战;--待實驗

  9. 一致性:“調(diào)度中心”通過DB鎖保證集群分布式調(diào)度的一致性, 一次任務(wù)調(diào)度只會觸發(fā)一次執(zhí)行;

  10. 自定義任務(wù)參數(shù):支持在線配置調(diào)度任務(wù)入?yún)ⅲ磿r生效;--待實驗

  11. 調(diào)度線程池:調(diào)度系統(tǒng)多線程觸發(fā)調(diào)度運行锰悼,確保調(diào)度精確執(zhí)行,不被堵塞;

  12. 數(shù)據(jù)加密:調(diào)度中心和執(zhí)行器之間的通訊進行數(shù)據(jù)加密抒痒,提升調(diào)度信息安全性彩届;

  13. 郵件報警:任務(wù)失敗時支持郵件報警寨辩,支持配置多郵件地址群發(fā)報警郵件停巷;

  14. 推送maven中央倉庫: 將會把最新穩(wěn)定版推送到maven中央倉庫, 方便用戶接入和使用;

  15. 運行報表:支持實時查看運行數(shù)據(jù)庆揪,如任務(wù)數(shù)量吝羞、調(diào)度次數(shù)恨溜、執(zhí)行器數(shù)量等项戴;以及調(diào)度報表,如調(diào)度日期分布圖,調(diào)度成功分布圖等敬扛;

  16. 全異步:任務(wù)調(diào)度流程全異步化設(shè)計實現(xiàn)急侥,如異步調(diào)度铝宵、異步運行横朋、異步回調(diào)等耐版,有效對密集調(diào)度進行流量削峰祠够,理論上支持任意時長任務(wù)的運行落君;

  17. 跨語言:調(diào)度中心與執(zhí)行器提供語言無關(guān)的 RESTful API 服務(wù),第三方任意語言可據(jù)此對接調(diào)度中心或者實現(xiàn)執(zhí)行器知残。除此之外比庄,還提供了 “多任務(wù)模式”和“httpJobHandler”等其他跨語言方案;

  18. 國際化:調(diào)度中心支持國際化設(shè)置扒最,提供中文、英文兩種可選語言八匠,默認為中文柜蜈;

  19. 容器化:提供官方docker鏡像贯要,并實時更新推送dockerhub,進一步實現(xiàn)產(chǎn)品開箱即用椭住;

  20. 線程池隔離:調(diào)度線程池進行隔離拆分崇渗,慢任務(wù)自動降級進入”Slow”線程池,避免耗盡調(diào)度線程京郑,提高系統(tǒng)穩(wěn)定性宅广;

  21. 用戶管理:支持在線管理系統(tǒng)用戶,存在管理員些举、普通用戶兩種角色跟狱;

  22. 權(quán)限控制:執(zhí)行器維度進行權(quán)限控制,管理員擁有全量權(quán)限户魏,普通用戶需要分配執(zhí)行器權(quán)限后才允許相關(guān)操作驶臊;

四、架構(gòu)分析

xxl-job架構(gòu)圖

分為調(diào)度中心和執(zhí)行器兩種角色:

  • 調(diào)度中心被抽象為一個只負責(zé)調(diào)度的平臺叼丑,其本身不承擔(dān)任何任務(wù)相關(guān)的業(yè)務(wù)邏輯关翎,只負責(zé)發(fā)起調(diào)度請求;
  • 執(zhí)行器是具體執(zhí)行業(yè)務(wù)邏輯任務(wù)的承擔(dān)者鸠信;

這兩種角色都可以HA纵寝,集群方式部署,如此調(diào)度和任務(wù)兩部分就可以解耦星立,提高了系統(tǒng)的整體穩(wěn)定性和可擴展性爽茴。

五葬凳、和Quartz的區(qū)別

同樣是集群環(huán)境下,Quartz具有如下的缺點:

  • Quartz只能通過API的方式操作任務(wù)室奏,不夠人性化沮明;而xxl-job則還可以提供管理端界面操作的形式,使用上更方便窍奋;
  • Quartz會把調(diào)度邏輯和業(yè)務(wù)邏輯放在一個項目中,且業(yè)務(wù)任務(wù)信息會持久化到底層數(shù)據(jù)庫表中酱畅,對業(yè)務(wù)系統(tǒng)的侵入性較強琳袄;反觀xxl-job,調(diào)度邏輯和任務(wù)信息都注冊到調(diào)度中心纺酸,和業(yè)務(wù)邏輯及其底層的數(shù)據(jù)表沒有關(guān)系窖逗;
  • 調(diào)度邏輯和業(yè)務(wù)任務(wù)耦合在同一個項目中,這將導(dǎo)致一個問題餐蔬,在調(diào)度任務(wù)數(shù)量逐漸增多碎紊,同時調(diào)度任務(wù)邏輯逐漸加重的情況下,此時調(diào)度系統(tǒng)的性能將大大受限于業(yè)務(wù)樊诺;
  • quartz底層以“搶占式”獲取DB鎖并由搶占成功節(jié)點負責(zé)運行任務(wù)仗考,會導(dǎo)致節(jié)點負載懸殊非常大;而XXL-JOB通過執(zhí)行器實現(xiàn)“協(xié)同分配式”運行任務(wù)词爬,充分發(fā)揮集群優(yōu)勢秃嗜,負載各節(jié)點均衡。

當然也有相同點顿膨,就是集群模式下锅锨,xxl-job和Quartz為了實現(xiàn)一致性,即一個任務(wù)調(diào)度只會被觸發(fā)一次恋沃,都是采用DB鎖的方式實現(xiàn)的必搞。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市囊咏,隨后出現(xiàn)的幾起案子恕洲,更是在濱河造成了極大的恐慌,老刑警劉巖匆笤,帶你破解...
    沈念sama閱讀 219,188評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件研侣,死亡現(xiàn)場離奇詭異,居然都是意外死亡炮捧,警方通過查閱死者的電腦和手機庶诡,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來咆课,“玉大人末誓,你說我怎么就攤上這事扯俱。” “怎么了喇澡?”我有些...
    開封第一講書人閱讀 165,562評論 0 356
  • 文/不壞的土叔 我叫張陵迅栅,是天一觀的道長。 經(jīng)常有香客問我晴玖,道長读存,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,893評論 1 295
  • 正文 為了忘掉前任呕屎,我火速辦了婚禮让簿,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘秀睛。我一直安慰自己尔当,他們只是感情好,可當我...
    茶點故事閱讀 67,917評論 6 392
  • 文/花漫 我一把揭開白布蹂安。 她就那樣靜靜地躺著椭迎,像睡著了一般。 火紅的嫁衣襯著肌膚如雪田盈。 梳的紋絲不亂的頭發(fā)上畜号,一...
    開封第一講書人閱讀 51,708評論 1 305
  • 那天,我揣著相機與錄音允瞧,去河邊找鬼弄兜。 笑死,一個胖子當著我的面吹牛瓷式,可吹牛的內(nèi)容都是我干的替饿。 我是一名探鬼主播,決...
    沈念sama閱讀 40,430評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼贸典,長吁一口氣:“原來是場噩夢啊……” “哼视卢!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起廊驼,我...
    開封第一講書人閱讀 39,342評論 0 276
  • 序言:老撾萬榮一對情侶失蹤据过,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后妒挎,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體绳锅,經(jīng)...
    沈念sama閱讀 45,801評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,976評論 3 337
  • 正文 我和宋清朗相戀三年酝掩,在試婚紗的時候發(fā)現(xiàn)自己被綠了鳞芙。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,115評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖原朝,靈堂內(nèi)的尸體忽然破棺而出驯嘱,到底是詐尸還是另有隱情,我是刑警寧澤喳坠,帶...
    沈念sama閱讀 35,804評論 5 346
  • 正文 年R本政府宣布鞠评,位于F島的核電站,受9級特大地震影響壕鹉,放射性物質(zhì)發(fā)生泄漏剃幌。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,458評論 3 331
  • 文/蒙蒙 一晾浴、第九天 我趴在偏房一處隱蔽的房頂上張望锥忿。 院中可真熱鬧,春花似錦怠肋、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,008評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至础芍,卻和暖如春杈抢,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背仑性。 一陣腳步聲響...
    開封第一講書人閱讀 33,135評論 1 272
  • 我被黑心中介騙來泰國打工惶楼, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人诊杆。 一個月前我還...
    沈念sama閱讀 48,365評論 3 373
  • 正文 我出身青樓歼捐,卻偏偏與公主長得像,于是被迫代替她去往敵國和親晨汹。 傳聞我的和親對象是個殘疾皇子豹储,可洞房花燭夜當晚...
    茶點故事閱讀 45,055評論 2 355

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