分布式計算框架比較

目前市面上有很多大數(shù)據(jù)框架宗弯,如批處理框架Hadoop嘿棘,流處理框架Storm汤求,以及混合處理型框架Flink和Spark畅哑,本文將針對以上幾個主流框架進(jìn)行闡述比較肴楷。

批處理框架介紹

批處理在應(yīng)對大量持久數(shù)據(jù)方面的表現(xiàn)極為出色,因此經(jīng)常被用于對歷史數(shù)據(jù)進(jìn)行分析荠呐。

大量數(shù)據(jù)的處理需要付出大量時間赛蔫,因此批處理不適合對處理時間要求較高的場合。

Apache Hadoop

批處理模式
Hadoop的處理功能來自MapReduce引擎泥张,采用了hadoop分布式文件系統(tǒng)HDFS呵恢。可以在普通的PC集群上提供可靠的文件存儲媚创,通過數(shù)據(jù)塊進(jìn)行多個副本備份來解決服務(wù)器宕機或者硬盤損壞的問題渗钉。

MapReduce,把并發(fā)钞钙、分布式(如機器間通信)和故障恢復(fù)等計算細(xì)節(jié)隱藏起來鳄橘,在有足夠量計算機集群的前提下,一般每臺機器構(gòu)成一個Maper或者Reducer歇竟。
MapReduce的處理技術(shù)符合使用鍵值對的map挥唠、shuffle、reduce算法要求焕议。由Map和Reduce兩個部分組成一個job,再由job組成DAG弧关,其中把非常重要的Shuffle過程隱藏起來盅安。基本處理過程包括:

  • 從HDFS文件系統(tǒng)讀取數(shù)據(jù)集

  • 將數(shù)據(jù)集拆分成小塊并分配給所有可用節(jié)點

  • 針對每個節(jié)點上的數(shù)據(jù)子集進(jìn)行計算

  • 中間結(jié)果暫時保存在內(nèi)存中世囊,達(dá)到閾值會寫到磁盤上

  • 重新分配中間態(tài)結(jié)果并按照鍵進(jìn)行分組

  • 通過對每個節(jié)點計算的結(jié)果進(jìn)行匯總和組合對每個鍵的值進(jìn)行“Reducing”

  • 將計算而來的最終結(jié)果重新寫入 HDFS

map產(chǎn)生的中間結(jié)果暫時保存在內(nèi)存中别瞭,該緩沖區(qū)的默認(rèn)大小是100MB,可以通過參數(shù)io.sort.mb來調(diào)整其大小株憾。當(dāng)緩沖區(qū)中的數(shù)據(jù)使用率達(dá)到一定閥值后蝙寨,將環(huán)形緩沖區(qū)中的部分?jǐn)?shù)據(jù)寫到磁盤上晒衩,生成一個臨時的Linux本地數(shù)據(jù)的spill文件;然后在緩沖區(qū)的使用率再次達(dá)到閥值后墙歪,再次生成一個spill文件听系。直到數(shù)據(jù)處理完畢,在磁盤上會生成很多的臨時文件虹菲。

由于這種方法嚴(yán)重依賴持久存儲靠胜,每個任務(wù)需要多次執(zhí)行讀取和寫入操作,因此速度相對較慢毕源。但另一方面由于磁盤空間通常是服務(wù)器上最豐富的資源浪漠,這意味著MapReduce可以處理非常海量的數(shù)據(jù)集。同時也意味著相比其他類似技術(shù)霎褐,Hadoop的MapReduce通持吩福可以在廉價硬件上運行,因為該技術(shù)并不需要將一切都存儲在內(nèi)存中冻璃。MapReduce具備極高的縮放潛力响谓,生產(chǎn)環(huán)境中曾經(jīng)出現(xiàn)過包含數(shù)萬個節(jié)點的應(yīng)用。

Hadoop的局限性

  • 表層上只提供了Map和Reduce兩個操作俱饿,處理邏輯隱藏在代碼中歌粥,整體邏輯不夠清晰
  • 相對于Storm等流式框架,時延比較高拍埠,只適用于批數(shù)據(jù)處理失驶,難以處理實時數(shù)據(jù)

結(jié)論

Apache Hadoop及其MapReduce處理引擎提供了一套久經(jīng)考驗的批處理模型,最適合處理對時間要求不高的非常大規(guī)模數(shù)據(jù)集枣购。

流處理框架介紹

流處理系統(tǒng)會對隨時進(jìn)入系統(tǒng)的數(shù)據(jù)進(jìn)行計算嬉探。相比批處理模式,流處理方式無需針對整個數(shù)據(jù)集執(zhí)行操作棉圈,而是對通過系統(tǒng)傳輸?shù)拿總€數(shù)據(jù)項執(zhí)行操作涩堤。流處理主要針對副作用更少,更加功能性的處理(Functional processing)進(jìn)行優(yōu)化分瘾。

此類處理非常適合某些類型的工作負(fù)載胎围。有實時處理需求的任務(wù)很適合使用流處理模式。分析服務(wù)器或應(yīng)用程序錯誤日志德召,以及其他基于時間的衡量指標(biāo)是最適合的類型白魂,因為對這些領(lǐng)域的數(shù)據(jù)變化做出響應(yīng)對于業(yè)務(wù)職能來說是極為關(guān)鍵的。流處理很適合用來處理必須對變動或峰值做出響應(yīng)上岗,并且關(guān)注一段時間內(nèi)變化趨勢的數(shù)據(jù)福荸。

Apache Storm

流處理模式
Storm的流處理可對框架中名為Topology的DAG進(jìn)行編排。這些拓?fù)涿枋隽水?dāng)數(shù)據(jù)片段進(jìn)入系統(tǒng)后肴掷,需要對每個傳入的片段執(zhí)行的不同轉(zhuǎn)換或步驟敬锐。

拓?fù)浒?/p>

  • Stream:普通的數(shù)據(jù)流背传,這是一種會持續(xù)抵達(dá)系統(tǒng)的無邊界數(shù)據(jù)。

  • Spout:位于拓?fù)溥吘壍臄?shù)據(jù)流來源台夺,例如可以是API或查詢等径玖,從這里可以產(chǎn)生待處理的數(shù)據(jù)。

  • Bolt:Bolt代表需要消耗流數(shù)據(jù)谒养,對其應(yīng)用操作挺狰,并將結(jié)果以流的形式進(jìn)行輸出的處理步驟。Bolt需要與每個Spout建立連接买窟,隨后相互連接以組成所有必要的處理丰泊。在拓?fù)涞奈膊浚梢允褂米罱K的Bolt輸出作為相互連接的其他系統(tǒng)的輸入始绍。

默認(rèn)情況下Storm提供了“至少一次”的處理保證捏题,這意味著可以確保每條消息至少可以被處理一次抑片,但某些情況下如果遇到失敗可能會處理多次基括。Storm無法確比蓿可以按照特定順序處理消息。

總結(jié)

對于延遲需求很高的純粹的流處理工作負(fù)載吞杭,Storm可能是最適合的技術(shù)盏浇。該技術(shù)可以保證每條消息都被處理,可配合多種編程語言使用芽狗。由于Storm無法進(jìn)行批處理绢掰,如果需要這些能力可能還需要使用其他軟件。如果對嚴(yán)格的一次處理保證有比較高的要求童擎,此時可考慮使用Trident滴劲。不過這種情況下其他流處理框架也許更適合。

混合處理系統(tǒng)

Apache Flink

Apache Flink是一種可以處理批處理任務(wù)的流處理框架顾复。該技術(shù)可將批處理數(shù)據(jù)視作具備有限邊界的數(shù)據(jù)流班挖,借此將批處理任務(wù)作為流處理的子集加以處理。Flink是完全支持流處理芯砸,也就是說作為流處理看待時輸入數(shù)據(jù)流是無界的萧芙;批處理被作為一種特殊的流處理,只是它的輸入數(shù)據(jù)流被定義為有界的假丧。

整體組件棧

整體組件棧

流處理模型

Flink的流處理模型在處理傳入數(shù)據(jù)時會將每一項視作真正的數(shù)據(jù)流末购。Flink提供的DataStream API可用于處理無盡的數(shù)據(jù)流。Flink可配合使用的基本組件包括:

  • Stream是指在系統(tǒng)中流轉(zhuǎn)的的無邊界數(shù)據(jù)集

  • Operator是指針對數(shù)據(jù)流執(zhí)行操作以產(chǎn)生其他數(shù)據(jù)流的功能

  • Source 是指數(shù)據(jù)流進(jìn)入系統(tǒng)的入口點

  • Sink是指數(shù)據(jù)流離開Flink系統(tǒng)后進(jìn)入到的位置虎谢,槽可以是數(shù)據(jù)庫或到其他系統(tǒng)的連接器

Flink可以對批處理工作負(fù)載實現(xiàn)一定的優(yōu)化。例如由于批處理操作可通過持久存儲加以支持曹质,F(xiàn)link可以不對批處理工作負(fù)載創(chuàng)建快照婴噩。數(shù)據(jù)依然可以恢復(fù)擎场,但常規(guī)處理操作可以執(zhí)行得更快。

另一個優(yōu)化是對批處理任務(wù)進(jìn)行分解几莽,這樣即可在需要的時候調(diào)用不同階段和組件迅办。借此Flink可以與集群的其他用戶更好地共存。對任務(wù)提前進(jìn)行分析使得Flink可以查看需要執(zhí)行的所有操作章蚣、數(shù)據(jù)集的大小站欺,以及下游需要執(zhí)行的操作步驟,借此實現(xiàn)進(jìn)一步的優(yōu)化纤垂。

基本架構(gòu)

基本架構(gòu)

從上圖可以分析出Flink運行時的整體狀態(tài)矾策。 Flink的Driver程序會將代碼邏輯構(gòu)建成一個Program Dataflow(區(qū)分source,operator,sink等等),在通過Graph Builder構(gòu)建DAG的Dataflow graph, 構(gòu)建job,劃分出task 和subtask等等峭沦。 Client 將job 提交到JobManager. Client 通過Actor System和JobManager 進(jìn)行消息通訊贾虽,接收J(rèn)obManager返回的狀態(tài)更新和任務(wù)執(zhí)行統(tǒng)計結(jié)果。 JobMangaer 按照Dataflow的Task 和Subtask的劃分吼鱼,將任務(wù)調(diào)度分配到各個TaskManager中進(jìn)行執(zhí)行蓬豁。TaskManager會將內(nèi)存抽象成多個TaskSlot,用于執(zhí)行Task任務(wù)菇肃。JobManagers與TaskManagers之間的任務(wù)管理地粪,Checkpoints的觸發(fā),任務(wù)狀態(tài)琐谤,心跳等等消息處理都是通過ActorSystem蟆技。

優(yōu)勢和局限

  • Flink目前是處理框架領(lǐng)域一個獨特的技術(shù)。雖然Spark也可以執(zhí)行批處理和流處理笑跛,但Spark的流處理采取的微批架構(gòu)使其無法適用于很多用例付魔。Flink流處理為先的方法可提供低延遲,高吞吐率飞蹂,近乎逐項處理的能力几苍。

  • 在用戶工具方面,F(xiàn)link同樣提供了基于Web的調(diào)度視圖陈哑。對于分析類任務(wù)妻坝,F(xiàn)link提供了類似SQL的查詢,圖形化處理惊窖,以及機器學(xué)習(xí)庫刽宪,此外還支持內(nèi)存計算。

  • Flink能很好地與其他組件配合使用界酒。如果配合Hadoop使用圣拄,該技術(shù)可以很好地融入整個環(huán)境,在任何時候都只占用必要的資源毁欣。該技術(shù)可輕松地與YARN庇谆、HDFS和Kafka 集成岳掐。

總結(jié)

Flink提供了低延遲流處理,同時可支持傳統(tǒng)的批處理任務(wù)饭耳。Flink也許最適合有極高流處理需求串述,并有少量批處理任務(wù)的組織。該技術(shù)可兼容原生Storm和Hadoop程序寞肖,可在YARN管理的集群上運行纲酗,因此可以很方便地進(jìn)行評估。

Apache Spark

Apache Spark是一種包含流處理能力的下一代批處理框架新蟆。特色是提供了一個集群的分布式內(nèi)存抽象RDD(Resilient Distributed DataSet)觅赊,即彈性分布式數(shù)據(jù)集。Spark上有RDD的兩種操作栅葡,actor和traformation茉兰。transformation包括map、flatMap等操作欣簇,actor是返回結(jié)果规脸,如Reduce、count熊咽、collect等莫鸭。

批處理模式

與MapReduce不同,Spark的數(shù)據(jù)處理工作全部在內(nèi)存中進(jìn)行横殴,只在一開始將數(shù)據(jù)讀入內(nèi)存被因,以及將最終結(jié)果持久存儲時需要與存儲層交互。所有中間態(tài)的處理結(jié)果均存儲在內(nèi)存中衫仑。

Spark流結(jié)構(gòu)如下圖所示:

Spark流結(jié)構(gòu)

對比 Hadoop MapReduce 和 Spark 的 Shuffle 過程

如果熟悉 Hadoop MapReduce 中的 shuffle 過程梨与,可能會按照 MapReduce 的思路去想象 Spark 的 shuffle 過程。然而文狱,它們之間有一些區(qū)別和聯(lián)系粥鞋。

從 high-level 的角度來看,兩者并沒有大的差別瞄崇。 都是將 mapper(Spark 里是 ShuffleMapTask)的輸出進(jìn)行 partition呻粹,不同的 partition 送到不同的 reducer(Spark 里 reducer 可能是下一個 stage 里的 ShuffleMapTask,也可能是 ResultTask)苏研。Reducer 以內(nèi)存作緩沖區(qū)等浊,邊 shuffle 邊 aggregate 數(shù)據(jù),等到數(shù)據(jù) aggregate 好以后進(jìn)行 reduce() (Spark 里可能是后續(xù)的一系列操作)摹蘑。

從 low-level 的角度來看筹燕,兩者差別不小。 Hadoop MapReduce 是 sort-based,進(jìn)入 combine() 和 reduce() 的 records 必須先 sort庄萎。這樣的好處在于 combine/reduce() 可以處理大規(guī)模的數(shù)據(jù)踪少,因為其輸入數(shù)據(jù)可以通過外排得到(mapper 對每段數(shù)據(jù)先做排序,reducer 的 shuffle 對排好序的每段數(shù)據(jù)做歸并)糠涛。目前的 Spark 默認(rèn)選擇的是 hash-based,通常使用 HashMap 來對 shuffle 來的數(shù)據(jù)進(jìn)行 aggregate兼犯,不會對數(shù)據(jù)進(jìn)行提前排序忍捡。如果用戶需要經(jīng)過排序的數(shù)據(jù),那么需要自己調(diào)用類似 sortByKey() 的操作切黔;如果你是Spark 1.1的用戶砸脊,可以將spark.shuffle.manager設(shè)置為sort,則會對數(shù)據(jù)進(jìn)行排序纬霞。在Spark 1.2中凌埂,sort將作為默認(rèn)的Shuffle實現(xiàn)。

從實現(xiàn)角度來看诗芜,兩者也有不少差別瞳抓。 Hadoop MapReduce 將處理流程劃分出明顯的幾個階段:map(), spill, merge, shuffle, sort, reduce() 等。每個階段各司其職伏恐,可以按照過程式的編程思想來逐一實現(xiàn)每個階段的功能孩哑。在 Spark 中,沒有這樣功能明確的階段翠桦,只有不同的 stage 和一系列的 transformation()横蜒,所以 spill, merge, aggregate 等操作需要蘊含在 transformation() 中。

如果我們將 map 端劃分?jǐn)?shù)據(jù)销凑、持久化數(shù)據(jù)的過程稱為 shuffle write丛晌,而將 reducer 讀入數(shù)據(jù)、aggregate 數(shù)據(jù)的過程稱為 shuffle read斗幼。那么在 Spark 中澎蛛,問題就變?yōu)樵趺丛?job 的邏輯或者物理執(zhí)行圖中加入 shuffle write 和 shuffle read 的處理邏輯?以及兩個處理邏輯應(yīng)該怎么高效實現(xiàn)孟岛?

優(yōu)勢和局限

使用Spark而非Hadoop MapReduce的主要原因是速度瓶竭。在內(nèi)存計算策略和先進(jìn)的DAG調(diào)度等機制的幫助下,Spark可以用更快速度處理相同的數(shù)據(jù)集渠羞。

Spark的另一個重要優(yōu)勢在于多樣性斤贰。該產(chǎn)品可作為獨立集群部署,或與現(xiàn)有Hadoop集群集成次询。該產(chǎn)品可運行批處理和流處理荧恍,運行一個集群即可處理不同類型的任務(wù)。

為流處理系統(tǒng)采用批處理的方法,需要對進(jìn)入系統(tǒng)的數(shù)據(jù)進(jìn)行緩沖送巡。緩沖機制使得該技術(shù)可以處理非常大量的傳入數(shù)據(jù)摹菠,提高整體吞吐率,但等待緩沖區(qū)清空也會導(dǎo)致延遲增高骗爆。這意味著Spark Streaming可能不適合處理對延遲有較高要求的工作負(fù)載次氨。

Spark生態(tài)系統(tǒng)中還包括很多附加庫,介紹如下:

  • Spark Streaming:
    Spark Streaming基于微批量方式的計算和處理摘投,可以用于處理實時的流數(shù)據(jù)煮寡。它使用DStream,一個彈性分布式數(shù)據(jù)集(RDD)系列犀呼,來處理實時數(shù)據(jù)幸撕。

  • Spark SQL:
    Spark SQL可以通過JDBC API查詢Spark數(shù)據(jù)集,而且還可以用傳統(tǒng)的BI和可視化工具在Spark數(shù)據(jù)上執(zhí)行類似SQL的查詢外臂。用戶還可以用Spark SQL對不同格式的數(shù)據(jù)(如JSON等)執(zhí)行ETL坐儿,將其轉(zhuǎn)化,然后被給予特定的查詢宋光。

  • Spark MLlib:
    MLlib是一個可擴展的Spark機器學(xué)習(xí)庫貌矿,由通用的學(xué)習(xí)算法和工具組成,包括線性回歸跃须、聚類站叼、梯度下降等

  • Spark GraphX:
    GraphX是用于圖計算和并行圖計算的新的(alpha)Spark API。通過引入彈性分布式屬性圖(Resilient Distributed Property Graph)菇民,一種頂點和邊都帶有屬性的有向多重圖尽楔,擴展了Spark RDD。

總結(jié)

Spark是多樣化工作負(fù)載處理任務(wù)的最佳選擇第练。Spark批處理能力以更高內(nèi)存占用為代價提供了無與倫比的速度優(yōu)勢阔馋。對于重視吞吐率而非延遲的工作負(fù)載,則比較適合使用Spark Streaming作為流處理解決方案

總結(jié)

大數(shù)據(jù)系統(tǒng)可針對性地使用多種處理框架

對于僅需要批處理的工作負(fù)載娇掏,如果對時間不敏感呕寝,比其他解決方案實現(xiàn)成本更低的Hadoop將會是一個好選擇。數(shù)據(jù)量非常大的時候MapReduce要比Spark快婴梧。

對于僅需要流處理的工作負(fù)載下梢,Storm可支持更廣泛的語言并實現(xiàn)極低延遲的處理,但默認(rèn)配置可能產(chǎn)生重復(fù)結(jié)果并且無法保證順序塞蹭。

對于混合型工作負(fù)載孽江,Spark把streaming看成是更快的批處理,而Flink把批處理看成streaming的special case番电。Spark可提供高速批處理和微批處理模式的流處理岗屏。該技術(shù)的支持更完善辆琅,具備各種集成庫和工具,可實現(xiàn)靈活的集成这刷。Flink提供了真正的流處理并具備批處理能力婉烟,通過深度優(yōu)化可運行針對其他平臺編寫的任務(wù),提供低延遲的處理暇屋。

參考:

https://ci.apache.org/projects/flink/flink-docs-release-1.3/concepts/programming-model.html

http://codingxiaxw.cn/2016/12/10/61-spark-streaming

http://xuexi.edu#/88.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末似袁,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子率碾,更是在濱河造成了極大的恐慌叔营,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,639評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件所宰,死亡現(xiàn)場離奇詭異,居然都是意外死亡畜挥,警方通過查閱死者的電腦和手機仔粥,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,277評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蟹但,“玉大人躯泰,你說我怎么就攤上這事』牵” “怎么了麦向?”我有些...
    開封第一講書人閱讀 157,221評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長客叉。 經(jīng)常有香客問我诵竭,道長,這世上最難降的妖魔是什么兼搏? 我笑而不...
    開封第一講書人閱讀 56,474評論 1 283
  • 正文 為了忘掉前任卵慰,我火速辦了婚禮,結(jié)果婚禮上佛呻,老公的妹妹穿的比我還像新娘裳朋。我一直安慰自己,他們只是感情好吓著,可當(dāng)我...
    茶點故事閱讀 65,570評論 6 386
  • 文/花漫 我一把揭開白布鲤嫡。 她就那樣靜靜地躺著,像睡著了一般绑莺。 火紅的嫁衣襯著肌膚如雪暖眼。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,816評論 1 290
  • 那天紊撕,我揣著相機與錄音罢荡,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛区赵,可吹牛的內(nèi)容都是我干的惭缰。 我是一名探鬼主播,決...
    沈念sama閱讀 38,957評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼笼才,長吁一口氣:“原來是場噩夢啊……” “哼漱受!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起骡送,我...
    開封第一講書人閱讀 37,718評論 0 266
  • 序言:老撾萬榮一對情侶失蹤昂羡,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后摔踱,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體虐先,經(jīng)...
    沈念sama閱讀 44,176評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,511評論 2 327
  • 正文 我和宋清朗相戀三年派敷,在試婚紗的時候發(fā)現(xiàn)自己被綠了蛹批。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,646評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡篮愉,死狀恐怖腐芍,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情试躏,我是刑警寧澤猪勇,帶...
    沈念sama閱讀 34,322評論 4 330
  • 正文 年R本政府宣布,位于F島的核電站颠蕴,受9級特大地震影響泣刹,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜裁替,卻給世界環(huán)境...
    茶點故事閱讀 39,934評論 3 313
  • 文/蒙蒙 一项玛、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧弱判,春花似錦襟沮、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,755評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至遭商,卻和暖如春固灵,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背劫流。 一陣腳步聲響...
    開封第一講書人閱讀 31,987評論 1 266
  • 我被黑心中介騙來泰國打工巫玻, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留丛忆,地道東北人。 一個月前我還...
    沈念sama閱讀 46,358評論 2 360
  • 正文 我出身青樓仍秤,卻偏偏與公主長得像熄诡,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子诗力,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,514評論 2 348

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