京東架構(gòu)師:日均 5 億查詢量的ElasticSearch架構(gòu)如何設(shè)計(jì)刨裆?

作者:張sir
來源:京東技術(shù)(id:jingdongjishu)

背景

京東到家訂單中心系統(tǒng)業(yè)務(wù)中澈圈,無論是外部商家的訂單生產(chǎn),或是內(nèi)部上下游系統(tǒng)的依賴帆啃,訂單查詢的調(diào)用量都非常大瞬女,造成了訂單數(shù)據(jù)讀多寫少的情況。

京東到家的訂單數(shù)據(jù)存儲(chǔ)在Mysql中努潘,但顯然只通過DB來支撐大量的查詢是不可取的诽偷,同時(shí)對(duì)于一些復(fù)雜的查詢,Mysql支持得不夠友好疯坤,所以訂單中心系統(tǒng)使用了Elasticsearch來承載訂單查詢的主要壓力报慕。

image

Elasticsearch 做為一款功能強(qiáng)大的分布式搜索引擎,支持近實(shí)時(shí)的存儲(chǔ)压怠、搜索數(shù)據(jù)卖子,在京東到家訂單系統(tǒng)中發(fā)揮著巨大作用,目前訂單中心ES集群存儲(chǔ)數(shù)據(jù)量達(dá)到10億個(gè)文檔刑峡,日均查詢量達(dá)到5億洋闽。

隨著京東到家近幾年業(yè)務(wù)的快速發(fā)展,訂單中心ES架設(shè)方案也不斷演進(jìn)突梦,發(fā)展至今ES集群架設(shè)是一套實(shí)時(shí)互備方案诫舅,很好的保障了ES集群讀寫的穩(wěn)定性,下面就給大家介紹一下這個(gè)歷程以及遇到的一些坑宫患。

ES集群架設(shè)演進(jìn)歷程

1刊懈、初始階段

訂單中心ES初始階段好如一張白紙,架設(shè)方案基本沒有娃闲,很多配置都是保持集群默認(rèn)配置虚汛。整個(gè)集群部署在集團(tuán)的彈性云上,ES集群的節(jié)點(diǎn)以及機(jī)器部署都比較混亂皇帮。同時(shí)按照集群維度來看卷哩,一個(gè)ES集群會(huì)有單點(diǎn)問題,顯然對(duì)于訂單中心業(yè)務(wù)來說也是不被允許的属拾。

2将谊、集群隔離階段

和很多業(yè)務(wù)一樣,ES集群采用的混布的方式渐白。但由于訂單中心ES存儲(chǔ)的是線上訂單數(shù)據(jù)尊浓,偶爾會(huì)發(fā)生混布集群搶占系統(tǒng)大量資源,導(dǎo)致整個(gè)訂單中心ES服務(wù)異常的情況纯衍。

顯然任何影響到訂單查詢穩(wěn)定性都是無法容忍的栋齿,所以針對(duì)于這個(gè)情況,先是對(duì)訂單中心ES所在的彈性云,遷出那些系統(tǒng)資源搶占很高的集群節(jié)點(diǎn)瓦堵,ES集群狀況稍有好轉(zhuǎn)基协。但隨著集群數(shù)據(jù)不斷增加,彈性云配置已經(jīng)不太能滿足ES集群谷丸,且為了完全的物理隔離堡掏,最終干脆將訂單中心ES集群部署到高配置的物理機(jī)上应结,ES集群性能又得到提升刨疼。

3、節(jié)點(diǎn)副本調(diào)優(yōu)階段

ES的性能跟硬件資源有很大關(guān)系鹅龄,當(dāng)ES集群?jiǎn)为?dú)部署到物理機(jī)器上時(shí)揩慕,集群內(nèi)部的節(jié)點(diǎn)并不是獨(dú)占整臺(tái)物理機(jī)資源,在集群運(yùn)行的時(shí)候同一物理機(jī)上的節(jié)點(diǎn)仍會(huì)出現(xiàn)資源搶占的問題扮休。所以在這種情況下迎卤,為了讓ES單個(gè)節(jié)點(diǎn)能夠使用最大程度的機(jī)器資源,采用每個(gè)ES節(jié)點(diǎn)部署在單獨(dú)一臺(tái)物理機(jī)上方式玷坠。

但緊接著蜗搔,問題又來了,如果單個(gè)節(jié)點(diǎn)出現(xiàn)瓶頸了呢八堡?我們應(yīng)該怎么再優(yōu)化呢樟凄?ES查詢的原理,當(dāng)請(qǐng)求打到某號(hào)分片的時(shí)候兄渺,如果沒有指定分片類型(preference參數(shù))查詢缝龄,請(qǐng)求會(huì)負(fù)載到對(duì)應(yīng)分片號(hào)的各個(gè)節(jié)點(diǎn)上。而集群默認(rèn)副本配置是一主一副挂谍,針對(duì)于此叔壤,我們想到了擴(kuò)容副本的方式,由默認(rèn)的一主一副變?yōu)橐恢鞫笨谛穑瑫r(shí)增加相應(yīng)物理機(jī)炼绘。

image

如上圖,訂單中心ES集群架設(shè)示意圖妄田。整個(gè)架設(shè)方式通過VIP來負(fù)載均衡外部請(qǐng)求饭望,第一層gateway節(jié)點(diǎn)實(shí)質(zhì)為ES中client node,相當(dāng)于一個(gè)智能負(fù)載均衡器形庭,充當(dāng)著分發(fā)請(qǐng)求的角色铅辞。第二層為data node,負(fù)責(zé)存儲(chǔ)數(shù)據(jù)以及執(zhí)行數(shù)據(jù)的相關(guān)操作萨醒。

整個(gè)集群有一套主分片斟珊,二套副分片(一主二副),從網(wǎng)關(guān)節(jié)點(diǎn)轉(zhuǎn)發(fā)過來的請(qǐng)求,會(huì)在打到數(shù)據(jù)節(jié)點(diǎn)之前通過輪詢的方式進(jìn)行均衡囤踩。集群增加一套副本并擴(kuò)容機(jī)器的方式旨椒,增加了集群吞吐量,從而提升了整個(gè)集群查詢性能堵漱。

image

當(dāng)然分片數(shù)量和分片副本數(shù)量并不是越多越好综慎,在此階段中,對(duì)選擇適當(dāng)?shù)姆制瑪?shù)量做了近一步探索勤庐。分片數(shù)可以理解為Mysql中的分庫(kù)分表示惊,而當(dāng)前訂單中心ES查詢主要分為兩類:?jiǎn)蜪D查詢以及分頁(yè)查詢。

分片數(shù)越大愉镰,集群橫向擴(kuò)容規(guī)模也更大米罚,根據(jù)分片路由的單ID查詢吞吐量也能大大提升,但對(duì)于聚合的分頁(yè)查詢性能則將降低丈探。分片數(shù)越小录择,集群橫向擴(kuò)容規(guī)模更小,單ID的查詢性能也將下降碗降,但對(duì)于分頁(yè)查詢隘竭,性能將會(huì)得到提升。

所以如何均衡分片數(shù)量和現(xiàn)有查詢業(yè)務(wù)讼渊,我們做了很多次調(diào)整壓測(cè)动看,最終選擇了集群性能較好的分片數(shù)。

4精偿、主從集群調(diào)整階段

到此弧圆,訂單中心的ES集群已經(jīng)初具規(guī)模,但由于訂單中心業(yè)務(wù)時(shí)效性要求高笔咽,對(duì)于ES查詢穩(wěn)定性要求也高搔预,如果集群中有節(jié)點(diǎn)發(fā)生異常,查詢服務(wù)會(huì)受到影響叶组,從而影響到整個(gè)訂單生產(chǎn)流程拯田。顯而易見這種異常情況是致命,所以為了應(yīng)對(duì)這種情況甩十,我們初步設(shè)想是增加一個(gè)備用集群船庇,當(dāng)主集群發(fā)生異常時(shí),可以實(shí)時(shí)的將查詢流量降級(jí)到備用集群侣监。

那備用集群應(yīng)該怎么來搭鸭轮?主備之間數(shù)據(jù)如何同步?備用集群應(yīng)該存儲(chǔ)什么樣的數(shù)據(jù)橄霉?考慮到ES集群暫時(shí)沒有很好的主備方案窃爷,同時(shí)為了更好的控制ES數(shù)據(jù)寫入,我們采用業(yè)務(wù)雙寫的方式來搭設(shè)主備集群。

每次業(yè)務(wù)操作需要寫入ES數(shù)據(jù)時(shí)按厘,同步的寫入主集群數(shù)據(jù)医吊,然后異步的寫入備集群數(shù)據(jù)。同時(shí)由于大部分ES查詢的流量都來源于近幾天的訂單逮京,且訂單中心數(shù)據(jù)庫(kù)數(shù)據(jù)已有一套歸檔機(jī)制卿堂,將指定天數(shù)之前已經(jīng)關(guān)閉的訂單轉(zhuǎn)移到歷史訂單庫(kù)。

所以歸檔機(jī)制中增加刪除備集群文檔的邏輯懒棉,讓新搭建的備集群存儲(chǔ)的訂單數(shù)據(jù)與訂單中心線上數(shù)據(jù)庫(kù)中的數(shù)據(jù)量保持一致草描。同時(shí)使用ZK在查詢服務(wù)中做了流量控制開關(guān),保證查詢流量能夠?qū)崟r(shí)的降級(jí)到備集群漓藕。在此陶珠,訂單中心主從集群完成挟裂,ES查詢服務(wù)穩(wěn)定性大大提升享钞。

image
image

5、現(xiàn)今:實(shí)時(shí)互備雙集群階段

期間由于主集群ES版本是較低的1.7诀蓉,而現(xiàn)今ES穩(wěn)定版本都以及迭代到6.x栗竖,新版本的ES不僅性能方面優(yōu)化很大,更提供了一些新的好用的功能渠啤,所以我們對(duì)主集群進(jìn)行了一次版本升級(jí)狐肢,直接從原來的1.7升級(jí)到6.x版本。集群升級(jí)的過程繁瑣而漫長(zhǎng)沥曹,不但需要保證線上業(yè)務(wù)無任何影響份名,平滑無感知升級(jí),同時(shí)由于ES集群暫不支持從1.7到6.x跨越多個(gè)版本的數(shù)據(jù)遷移妓美,所以需要通過重建索引的方式來升級(jí)主集群僵腺,具體升級(jí)過程就不在此贅述了。

主集群升級(jí)的時(shí)候必不可免的會(huì)發(fā)生不可用的情況壶栋,但對(duì)于訂單中心ES查詢服務(wù)辰如,這種情況是不允許的。所以在升級(jí)的階段中贵试,備集群暫時(shí)頂上充當(dāng)主集群琉兜,來支撐所有的線上ES查詢,保證升級(jí)過程不影響正常線上服務(wù)毙玻。同時(shí)針對(duì)于線上業(yè)務(wù)豌蟋,我們對(duì)兩個(gè)集群做了重新的規(guī)劃定義,承擔(dān)的線上查詢流量也做了重新的劃分桑滩。

備集群存儲(chǔ)的是線上近幾天的熱點(diǎn)數(shù)據(jù)梧疲,數(shù)據(jù)規(guī)模遠(yuǎn)小于主集群,大約是主集群文檔數(shù)的十分之一左右。集群數(shù)據(jù)量小往声,在相同的集群部署規(guī)模下擂找,備集群的性能要優(yōu)于主集群。然而在線上真實(shí)場(chǎng)景中浩销,線上大部分查詢流量也來源于熱點(diǎn)數(shù)據(jù)贯涎,所以用備集群來承載這些熱點(diǎn)數(shù)據(jù)的查詢,而備集群也慢慢演變成一個(gè)熱數(shù)據(jù)集群慢洋。

之前的主集群存儲(chǔ)的是全量數(shù)據(jù)塘雳,用該集群來支撐剩余較小部分的查詢流量,這部分查詢主要是需要搜索全量訂單的特殊場(chǎng)景查詢以及訂單中心系統(tǒng)內(nèi)部查詢等普筹,而主集群也慢慢演變成一個(gè)冷數(shù)據(jù)集群败明。

同時(shí)備集群增加一鍵降級(jí)到主集群的功能,兩個(gè)集群地位同等重要太防,但都可以各自降級(jí)到另一個(gè)集群妻顶。雙寫策略也優(yōu)化為:假設(shè)有A B集群,正常同步方式寫主(A集群)異步方式寫備(B集群)蜒车。A集群發(fā)生異常時(shí)讳嘱,同步寫B(tài)集群(主),異步寫A集群(備)酿愧。

ES訂單數(shù)據(jù)的同步方案

Mysql數(shù)據(jù)同步到ES中沥潭,大致總結(jié)可以分為兩種方案:

方案1:監(jiān)聽mysql的binlog,分析binlog將數(shù)據(jù)同步到ES集群中

優(yōu)點(diǎn):業(yè)務(wù)與ES數(shù)據(jù)耦合度低嬉挡,業(yè)務(wù)邏輯中不需要關(guān)心ES數(shù)據(jù)的寫入钝鸽。

缺點(diǎn):binglog模式只能使用ROW模式,且引入了新的同步服務(wù)庞钢,增加了開發(fā)量以及維護(hù)成本拔恰,也增大了ES同步的風(fēng)險(xiǎn)。

方案2:直接通過ES API將數(shù)據(jù)寫入到ES集群中

優(yōu)點(diǎn):簡(jiǎn)潔明了焊夸,能夠靈活的控制數(shù)據(jù)的寫入

缺點(diǎn):與業(yè)務(wù)耦合嚴(yán)重仁连,強(qiáng)依賴于業(yè)務(wù)系統(tǒng)的寫入方式

考慮到訂單系統(tǒng)ES服務(wù)的業(yè)務(wù)特殊性,對(duì)于訂單數(shù)據(jù)的實(shí)時(shí)性較高阱穗,顯然監(jiān)聽binlog的方式相當(dāng)于異步同步饭冬,有可能會(huì)產(chǎn)生較大的延時(shí)性。且方案1實(shí)質(zhì)上跟方案2類似揪阶,但又引入了新的系統(tǒng)昌抠,維護(hù)成本也增高。

所以訂單中心ES采用了直接通過ES API寫入訂單數(shù)據(jù)的方式鲁僚,該方式簡(jiǎn)潔靈活炊苫,能夠很好的滿足訂單中心數(shù)據(jù)同步到ES的需求裁厅。

由于ES訂單數(shù)據(jù)的同步采用的是在業(yè)務(wù)中寫入的方式,當(dāng)新建或更新文檔發(fā)生異常時(shí)侨艾,如果重試勢(shì)必會(huì)影響業(yè)務(wù)正常操作的響應(yīng)時(shí)間执虹。

所以每次業(yè)務(wù)操作只更新一次ES,如果發(fā)生錯(cuò)誤或者異常唠梨,在數(shù)據(jù)庫(kù)中插入一條補(bǔ)救任務(wù)袋励,有worker任務(wù)會(huì)實(shí)時(shí)的掃這些數(shù)據(jù),以數(shù)據(jù)庫(kù)訂單數(shù)據(jù)為基準(zhǔn)來再次更新ES數(shù)據(jù)当叭。通過此種補(bǔ)償機(jī)制茬故,來保證ES數(shù)據(jù)與數(shù)據(jù)庫(kù)訂單數(shù)據(jù)的最終一致性。

遇到的一些坑

1蚁鳖、實(shí)時(shí)性要求高的查詢走db

對(duì)于ES寫入機(jī)制的有了解的可能會(huì)知道磺芭,新增的文檔會(huì)被收集到indexing buffer,然后寫入到文件系統(tǒng)緩存中醉箕,到了文件系統(tǒng)緩存中就可以像其他的文件一樣被索引到钾腺。

然而默認(rèn)情況文檔從index buffer到文件系統(tǒng)緩存(即refresh操作)是每秒分片自動(dòng)刷新,所以這就是我們說ES是近實(shí)時(shí)搜索而非實(shí)時(shí)的原因:文檔的變化并不是立即對(duì)搜索可見琅攘,但會(huì)在一秒之內(nèi)變?yōu)榭梢姟?/p>

當(dāng)前訂單系統(tǒng)ES采用的是默認(rèn)refresh配置垮庐,故對(duì)于那些訂單數(shù)據(jù)實(shí)時(shí)性比較高的業(yè)務(wù)松邪,直接走數(shù)據(jù)庫(kù)查詢坞琴,保證數(shù)據(jù)的準(zhǔn)確性。

image

2逗抑、避免深分頁(yè)查詢

ES集群的分頁(yè)查詢支持from和size參數(shù)剧辐,查詢的時(shí)候每個(gè)分片必須構(gòu)造一個(gè)長(zhǎng)度為from+size的優(yōu)先隊(duì)列,然后回傳到網(wǎng)關(guān)節(jié)點(diǎn)邮府,網(wǎng)關(guān)節(jié)點(diǎn)再對(duì)這些優(yōu)先隊(duì)列進(jìn)行排序找到正確的size個(gè)文檔荧关。

假設(shè)在一個(gè)有6個(gè)主分片的索引中,from為10000褂傀,size為10忍啤,每個(gè)分片必須產(chǎn)生10010個(gè)結(jié)果,在網(wǎng)關(guān)節(jié)點(diǎn)中匯聚合并60060個(gè)結(jié)果仙辟,最終找到符合要求的10個(gè)文檔同波。由此可見,當(dāng)from足夠大的時(shí)候叠国,就算不發(fā)生OOM未檩,也會(huì)影響到CPU和帶寬等,從而影響到整個(gè)集群的性能粟焊。所以應(yīng)該避免深分頁(yè)查詢冤狡,盡量不去使用孙蒙。

3、FieldData與Doc Values

Fielddata:線上查詢出現(xiàn)偶爾超時(shí)的情況悲雳,通過調(diào)試查詢語(yǔ)句挎峦,定位到是跟排序有關(guān)系。排序在es 1.x版本使用的是fielddata 結(jié)構(gòu)合瓢,fielddata占用的是jvm heap內(nèi)存浑测,jvm內(nèi)存是有限,對(duì)于fielddata cache會(huì)設(shè)定一個(gè)閾值歪玲。

如果空間不足時(shí)迁央,使用最久未使用(LRU)算法移除fielddata,同時(shí)加載新的fielddata cache滥崩,加載的過程需要消耗系統(tǒng)資源岖圈,且耗時(shí)很大。所以導(dǎo)致這個(gè)查詢的響應(yīng)時(shí)間暴漲钙皮,甚至影響整個(gè)集群的性能蜂科。針對(duì)于這種問題,解決的方式是采用doc values短条。

Doc Values:Doc Values是一種列式的數(shù)據(jù)存儲(chǔ)結(jié)構(gòu)导匣,跟fieldata很類似,但其存儲(chǔ)位置是在Lucene文件中茸时,即不會(huì)占用JVM heap贡定。隨著ES版本的迭代,doc values比fielddata更加穩(wěn)定可都,doc values在2.x起為默認(rèn)設(shè)置缓待。

總結(jié)

架構(gòu)的快速迭代源于業(yè)務(wù)的快速發(fā)展,正是由于近幾年到家業(yè)務(wù)的高速發(fā)展渠牲,訂單中心的架構(gòu)也不斷優(yōu)化升級(jí)旋炒。而架構(gòu)方案沒有最好的,只有最合適的签杈,相信再過幾年瘫镇,訂單中心的架構(gòu)又將是另一個(gè)面貌,但吞吐量更大答姥,性能更好铣除,穩(wěn)定性更強(qiáng),將是訂單中心系統(tǒng)永遠(yuǎn)的追求踢涌。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末通孽,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子睁壁,更是在濱河造成了極大的恐慌背苦,老刑警劉巖互捌,帶你破解...
    沈念sama閱讀 212,718評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異行剂,居然都是意外死亡秕噪,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,683評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門厚宰,熙熙樓的掌柜王于貴愁眉苦臉地迎上來腌巾,“玉大人,你說我怎么就攤上這事铲觉〕候” “怎么了?”我有些...
    開封第一講書人閱讀 158,207評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵撵幽,是天一觀的道長(zhǎng)灯荧。 經(jīng)常有香客問我,道長(zhǎng)盐杂,這世上最難降的妖魔是什么逗载? 我笑而不...
    開封第一講書人閱讀 56,755評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮链烈,結(jié)果婚禮上厉斟,老公的妹妹穿的比我還像新娘。我一直安慰自己强衡,他們只是感情好擦秽,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,862評(píng)論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著食侮,像睡著了一般号涯。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上锯七,一...
    開封第一講書人閱讀 50,050評(píng)論 1 291
  • 那天,我揣著相機(jī)與錄音誉己,去河邊找鬼眉尸。 笑死,一個(gè)胖子當(dāng)著我的面吹牛巨双,可吹牛的內(nèi)容都是我干的噪猾。 我是一名探鬼主播,決...
    沈念sama閱讀 39,136評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼筑累,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼袱蜡!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起慢宗,我...
    開封第一講書人閱讀 37,882評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤坪蚁,失蹤者是張志新(化名)和其女友劉穎奔穿,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體敏晤,經(jīng)...
    沈念sama閱讀 44,330評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡贱田,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,651評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了嘴脾。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片男摧。...
    茶點(diǎn)故事閱讀 38,789評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖译打,靈堂內(nèi)的尸體忽然破棺而出耗拓,到底是詐尸還是另有隱情,我是刑警寧澤奏司,帶...
    沈念sama閱讀 34,477評(píng)論 4 333
  • 正文 年R本政府宣布帆离,位于F島的核電站,受9級(jí)特大地震影響结澄,放射性物質(zhì)發(fā)生泄漏哥谷。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,135評(píng)論 3 317
  • 文/蒙蒙 一麻献、第九天 我趴在偏房一處隱蔽的房頂上張望们妥。 院中可真熱鬧,春花似錦勉吻、人聲如沸监婶。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,864評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)惑惶。三九已至,卻和暖如春短纵,著一層夾襖步出監(jiān)牢的瞬間带污,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,099評(píng)論 1 267
  • 我被黑心中介騙來泰國(guó)打工香到, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留鱼冀,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,598評(píng)論 2 362
  • 正文 我出身青樓悠就,卻偏偏與公主長(zhǎng)得像千绪,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子梗脾,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,697評(píng)論 2 351

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