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

數(shù)據(jù)序列化

內(nèi)存調(diào)整

內(nèi)存管理概述

確定內(nèi)存消耗

調(diào)整數(shù)據(jù)結(jié)構(gòu)

序列化RDD存儲

垃圾收集調(diào)整

其他考慮因素

并行程度

減少任務(wù)的內(nèi)存使用情況

廣播大變量

數(shù)據(jù)位置

概要

由于大多數(shù)Spark計算的內(nèi)存特性粤策,Spark程序可能會受到群集中任何資源的瓶頸:CPU樟澜,網(wǎng)絡(luò)帶寬或內(nèi)存。大多數(shù)情況下叮盘,如果數(shù)據(jù)適合內(nèi)存秩贰,瓶頸就是網(wǎng)絡(luò)帶寬,但有時候柔吼,您還需要進行一些調(diào)整毒费,例如以序列化形式存儲RDD,以減少內(nèi)存使用愈魏。本指南將介紹兩個主要主題:數(shù)據(jù)序列化觅玻,這對于良好的網(wǎng)絡(luò)性能至關(guān)重要艇棕,還可以減少內(nèi)存使用和內(nèi)存調(diào)整。我們還草擬了幾個較小的主題串塑。

數(shù)據(jù)序列化

序列化在任何分布式應(yīng)用程序的性能中起著重要作用沼琉。將對象序列化或消耗大量字節(jié)的速度慢的格式將大大減慢計算速度。通常桩匪,這將是您應(yīng)該優(yōu)化Spark應(yīng)用程序的第一件事打瘪。Spark旨在在便利性(允許您使用操作中的任何Java類型)和性能之間取得平衡。它提供了兩個序列化庫:

Java序列化:默認情況下傻昙,Spark使用JavaObjectOutputStream框架序列化對象闺骚,并且可以與您創(chuàng)建的任何實現(xiàn)的類一起使用java.io.Serializable。您還可以通過擴展來更緊密地控制序列化的性能java.io.Externalizable妆档。Java序列化是靈活的僻爽,但通常很慢,并導(dǎo)致許多類的大型序列化格式贾惦。

Kryo序列化:Spark還可以使用Kryo庫(版本2)更快地序列化對象胸梆。Kryo比Java序列化(通常高達10倍)明顯更快,更緊湊须板,但不支持所有Serializable類型碰镜,并且需要您提前注冊您將在程序中使用的類以獲得最佳性能。

您可以通過使用SparkConf初始化作業(yè)?并調(diào)用來切換到使用Kryoconf.set("spark.serializer", "org.apache.spark.serializer.KryoSerializer")习瑰。此設(shè)置配置序列化程序绪颖,不僅用于在工作節(jié)點之間混洗數(shù)據(jù),還用于將RDD序列化到磁盤甜奄。Kryo不是默認值的唯一原因是因為自定義注冊要求柠横,但我們建議在任何網(wǎng)絡(luò)密集型應(yīng)用程序中嘗試它。從Spark 2.0.0開始课兄,我們在使用簡單類型牍氛,簡單類型數(shù)組或字符串類型對RDD進行混洗時,內(nèi)部使用Kryo序列化程序第喳。

Spark自動包含Kryo序列化程序糜俗,用于來自Twitter chill庫的AllScalaRegistrar中涵蓋的許多常用核心Scala類。

要使用Kryo注冊自己的自定義類曲饱,請使用該registerKryoClasses方法。

valconf=newSparkConf().setMaster(...).setAppName(...)conf.registerKryoClasses(Array(classOf[MyClass1],classOf[MyClass2]))valsc=newSparkContext(conf)

所述KRYO文檔描述了更先進的注冊選項珠月,如添加自定義序列的代碼扩淀。

如果對象很大,則可能還需要增加spark.kryoserializer.buffer配置啤挎。此值必須足夠大才能容納要序列化的最大對象驻谆。

最后卵凑,如果你沒有注冊你的自定義類,Kryo仍然會工作胜臊,但它必須存儲每個對象的完整類名勺卢,這是浪費。

內(nèi)存調(diào)整

有三個方面的考慮在調(diào)整內(nèi)存使用:該的存儲你的對象所使用的(你可能希望你的整個數(shù)據(jù)集象对,以適應(yīng)在內(nèi)存中)黑忱,則成本訪問這些對象,并且開銷垃圾收集(如果你有高成交對象的條款)勒魔。

默認情況下甫煞,Java對象訪問速度很快,但與其字段中的“原始”數(shù)據(jù)相比冠绢,可以輕松占用2-5倍的空間抚吠。這是由于以下幾個原因:

每個不同的Java對象都有一個“對象頭”,大約16個字節(jié)弟胀,并包含諸如指向其類的指針之類的信息楷力。對于包含非常少數(shù)據(jù)的對象(比如一個Int字段),這可能比數(shù)據(jù)大孵户。

JavaString在原始字符串?dāng)?shù)據(jù)上有大約40字節(jié)的開銷(因為它們將它存儲在Chars?的數(shù)組中并保留額外的數(shù)據(jù)弥雹,例如長度),并且由于UTF-16的內(nèi)部使用而將每個字符存儲為兩個字節(jié)String編碼延届。因此剪勿,10個字符的字符串很容易消耗60個字節(jié)。

公共集合類方庭,例如HashMap和LinkedList厕吉,使用鏈接數(shù)據(jù)結(jié)構(gòu),其中每個條目都有一個“包裝”對象(例如Map.Entry)械念。此對象不僅具有標題头朱,還具有指向列表中下一個對象的指針(通常為8個字節(jié))。

原始類型的集合通常將它們存儲為“盒裝”對象龄减,例如java.lang.Integer项钮。

本節(jié)將首先概述Spark中的內(nèi)存管理,然后討論用戶可以采取的具體策略希停,以便在他/她的應(yīng)用程序中更有效地使用內(nèi)存烁巫。特別是,我們將描述如何確定對象的內(nèi)存使用情況宠能,以及如何通過更改數(shù)據(jù)結(jié)構(gòu)或以序列化格式存儲數(shù)據(jù)來改進它亚隙。然后我們將介紹調(diào)整Spark的緩存大小和Java垃圾收集器。

內(nèi)存管理概述

Spark中的內(nèi)存使用大致屬于以下兩種類別之一:執(zhí)行和存儲违崇。執(zhí)行內(nèi)存是指用于在隨機阿弃,連接诊霹,排序和聚合中進行計算的內(nèi)存,而存儲內(nèi)存是指用于在集群中緩存和傳播內(nèi)部數(shù)據(jù)的內(nèi)存渣淳。在Spark中脾还,執(zhí)行和存儲共享一個統(tǒng)一的區(qū)域(M)。當(dāng)沒有使用執(zhí)行內(nèi)存時入愧,存儲可以獲取所有可用內(nèi)存鄙漏,反之亦然。如有必要砂客,執(zhí)行可以驅(qū)逐存儲泥张,但僅限于總存儲內(nèi)存使用量低于某個閾值(R)。換句話說鞠值,R描述了M高速緩存塊從未被驅(qū)逐的子區(qū)域媚创。由于實施的復(fù)雜性,存儲可能不會驅(qū)逐執(zhí)行彤恶。

該設(shè)計確保了幾種理想的特性钞钙。首先,不使用緩存的應(yīng)用程序可以使用整個空間執(zhí)行声离,從而避免不必要的磁盤溢出芒炼。其次,使用緩存的應(yīng)用程序可以保留最小的存儲空間(R)术徊,其中數(shù)據(jù)塊不受驅(qū)逐本刽。最后,這種方法為各種工作負載提供了合理的開箱即用性能赠涮,而無需用戶內(nèi)部劃分內(nèi)存的專業(yè)知識子寓。

雖然有兩種相關(guān)配置,但典型用戶不需要調(diào)整它們笋除,因為默認值適用于大多數(shù)工作負載:

spark.memory.fraction表示大小M為(JVM堆空間 - 300MB)的一小部分(默認值為0.6)斜友。其余的空間(40%)保留用于用戶數(shù)據(jù)結(jié)構(gòu),Spark中的內(nèi)部元數(shù)據(jù)垃它,以及在稀疏和異常大的記錄的情況下防止OOM錯誤鲜屏。

spark.memory.storageFraction將大小表示R為M(默認值0.5)的一小部分。R是M緩存塊不受執(zhí)行驅(qū)逐的存儲空間国拇。

spark.memory.fraction應(yīng)該設(shè)置值洛史,以便在JVM的舊版或“終身”代中舒適地適應(yīng)這個堆空間量。有關(guān)詳細信息贝奇,請參閱下面的高級GC調(diào)整討論虹菲。

確定內(nèi)存消耗

確定數(shù)據(jù)集所需內(nèi)存消耗量的最佳方法是創(chuàng)建RDD,將其放入緩存中掉瞳,然后查看Web UI中的“存儲”頁面毕源。該頁面將告訴您RDD占用多少內(nèi)存。

為了估計特定對象的內(nèi)存消耗陕习,使用SizeEstimator的estimate方法這是用于與不同的數(shù)據(jù)布局試驗修剪內(nèi)存使用情況霎褐,以及確定的空間的廣播變量將占據(jù)每個執(zhí)行器堆的量是有用的。

調(diào)整數(shù)據(jù)結(jié)構(gòu)

減少內(nèi)存消耗的第一種方法是避免增加開銷的Java功能该镣,例如基于指針的數(shù)據(jù)結(jié)構(gòu)和包裝器對象冻璃。做這件事有很多種方法:

設(shè)計您的數(shù)據(jù)結(jié)構(gòu)以優(yōu)先選擇對象數(shù)組和基本類型,而不是標準的Java或Scala集合類(例如HashMap)损合。該fastutil庫提供方便的集合類基本類型是與Java標準庫兼容省艳。

盡可能避免使用包含大量小對象和指針的嵌套結(jié)構(gòu)。

考慮使用數(shù)字ID或枚舉對象而不是鍵的字符串嫁审。

如果RAM少于32 GB跋炕,請設(shè)置JVM標志-XX:+UseCompressedOops以使指針為四個字節(jié)而不是八個字節(jié)。您可以添加這些選項spark-env.sh律适。

序列化RDD存儲

盡管進行了這種調(diào)整辐烂,但是當(dāng)對象仍然太大而無法有效存儲時,減少內(nèi)存使用的一種更簡單的方法是使用RDD持久性API中的序列化StorageLevels以序列化形式存儲它們捂贿,例如纠修。然后,Spark將每個RDD分區(qū)存儲為一個大字節(jié)數(shù)組厂僧。由于必須動態(tài)地反序列化每個對象扣草,因此以序列化形式存儲數(shù)據(jù)的唯一缺點是訪問時間較慢。如果您希望以序列化形式緩存數(shù)據(jù)颜屠,我們強烈建議使用Kryo辰妙,因為它導(dǎo)致比Java序列化(當(dāng)然比原始Java對象)小得多的尺寸。MEMORY_ONLY_SER

垃圾收集調(diào)整

當(dāng)您根據(jù)程序存儲的RDD進行大量“流失”時汽纤,JVM垃圾回收可能會出現(xiàn)問題上岗。(在讀取RDD一次然后在其上運行許多操作的程序中通常不會出現(xiàn)問題。)當(dāng)Java需要逐出舊對象以便為新對象騰出空間時蕴坪,它需要遍歷所有Java對象并查找未使用的肴掷。這里要記住的要點是垃圾收集的成本與Java對象的數(shù)量成正比,因此使用具有較少對象的數(shù)據(jù)結(jié)構(gòu)(例如背传,Ints而不是a?的數(shù)組LinkedList)大大降低了這種成本呆瞻。更好的方法是以序列化形式保存對象,如上所述:現(xiàn)在只有一個每個RDD分區(qū)的對象(一個字節(jié)數(shù)組)径玖。在嘗試其他技術(shù)之前痴脾,首先要嘗試GC是一個問題是使用序列化緩存

由于任務(wù)的工作內(nèi)存(運行任務(wù)所需的空間量)與節(jié)點上緩存的RDD之間的干擾梳星,GC也可能是一個問題赞赖。我們將討論如何控制分配給RDD緩存的空間以緩解這種情況滚朵。

測量GC的影響

GC調(diào)優(yōu)的第一步是收集有關(guān)垃圾收集發(fā)生頻率和GC使用時間的統(tǒng)計信息。這可以通過添加-verbose:gc -XX:+PrintGCDetails -XX:+PrintGCTimeStampsJava選項來完成前域。(有關(guān)將Java選項傳遞給Spark作業(yè)的信息辕近,請參閱配置指南。)下次運行Spark作業(yè)時匿垄,每次發(fā)生垃圾收集時移宅,您都會看到工作日志中打印的消息。請注意椿疗,這些日志將位于群集的工作節(jié)點上(stdout位于其工作目錄中的文件中)漏峰,而不是位于驅(qū)動程序上。

高級GC調(diào)整

為了進一步調(diào)整垃圾收集届榄,我們首先需要了解JVM中有關(guān)內(nèi)存管理的一些基本信息:

Java堆空間分為Young和Old兩個區(qū)域浅乔。Young代表意味著持有短命的物體,而老一代則用于生命周期較長的物體痒蓬。

Young代進一步分為三個區(qū)域[Eden童擎,Survivor1,Survivor2]攻晒。

垃圾收集過程的簡化描述:當(dāng)Eden已滿時顾复,在Eden上運行次要GC,并將從Eden和Survivor1中存活的對象復(fù)制到Survivor2鲁捏。幸存者地區(qū)被交換芯砸。如果對象足夠大或Survivor2已滿,則將其移至Old给梅。最后假丧,當(dāng)Old接近滿時,將調(diào)用完整的GC动羽。

Spark中GC調(diào)整的目標是確保只有長壽命的RDD存儲在Old代中包帚,并且Young代的大小足以存儲短期對象。這將有助于避免完整的GC收集在任務(wù)執(zhí)行期間創(chuàng)建的臨時對象运吓】拾睿可能有用的一些步驟是:

通過收集GC統(tǒng)計數(shù)據(jù)來檢查是否有太多垃圾收集。如果在任務(wù)完成之前多次調(diào)用完整的GC拘哨,則意味著沒有足夠的內(nèi)存可用于執(zhí)行任務(wù)谋梭。

如果有太多次要集合但沒有很多主要的GC,那么為Eden分配更多內(nèi)存將會有所幫助倦青。您可以將Eden的大小設(shè)置為高估每個任務(wù)所需的內(nèi)存量瓮床。如果確定Eden的大小E,則可以使用該選項設(shè)置Young代的大小-Xmn=4/3*E。(按比例增加4/3也是為了解釋幸存者地區(qū)使用的空間隘庄。)

在打印的GC統(tǒng)計信息中踢步,如果OldGen接近滿,則通過降低來減少用于緩存的內(nèi)存量spark.memory.fraction;?緩存更少的對象比減慢任務(wù)執(zhí)行速度更好峭沦〖炙洌或者逃糟,考慮減小Young代的尺寸吼鱼。-Xmn如果您按上述設(shè)置,這意味著降低绰咽。如果沒有菇肃,請嘗試更改JVMNewRatio參數(shù)的值。許多JVM將此默認為2取募,這意味著舊一代占據(jù)堆的2/3琐谤。它應(yīng)該足夠大,使得該分數(shù)超過spark.memory.fraction玩敏。

嘗試使用G1GC垃圾收集器-XX:+UseG1GC斗忌。在垃圾收集成為瓶頸的某些情況下,它可以提高性能旺聚。請注意织阳,大執(zhí)行人堆大小,可能重要的是增加了G1區(qū)域大小與-XX:G1HeapRegionSize

例如砰粹,如果您的任務(wù)是從HDFS讀取數(shù)據(jù)唧躲,則可以使用從HDFS讀取的數(shù)據(jù)塊的大小來估計任務(wù)使用的內(nèi)存量。請注意碱璃,解壓縮塊的大小通常是塊大小的2或3倍弄痹。因此,如果我們希望有3或4個任務(wù)的工作空間嵌器,并且HDFS塊大小為128 MB肛真,我們可以估計Eden的大小4*3*128MB。

監(jiān)視垃圾收集所用頻率和時間如何隨新設(shè)置而變化爽航。

我們的經(jīng)驗表明蚓让,GC調(diào)整的效果取決于您的應(yīng)用程序和可用內(nèi)存量。有更多的微調(diào)選項在線描述岳掐,但在較高的水平凭疮,管理完整的GC如何經(jīng)常發(fā)生可以減少開銷幫助。

可以通過設(shè)置spark.executor.extraJavaOptions作業(yè)的配置來指定執(zhí)行程序的GC調(diào)整標志串述。

其他考慮因素

并行程度

除非您為每個操作設(shè)置足夠高的并行度执解,否則將無法充分利用群集。Spark根據(jù)其大小自動設(shè)置要在每個文件上運行的“map”任務(wù)的數(shù)量(盡管可以通過可選參數(shù)來控制它SparkContext.textFile等),并且對于分布式“reduce”操作衰腌,例如groupByKey和reduceByKey新蟆,它使用最大的父級RDD的分區(qū)數(shù)量。您可以將并行級別作為第二個參數(shù)傳遞(請參閱spark.PairRDDFunctions文檔)右蕊,或者設(shè)置config屬性spark.default.parallelism以更改默認值琼稻。通常,我們建議群集中每個CPU核心有2-3個任務(wù)饶囚。

減少任務(wù)的內(nèi)存使用情況

有時候帕翻,你會得到一個OutOfMemoryError,不是因為你的RDD不適合內(nèi)存萝风,而是因為你的一個任務(wù)的工作集嘀掸,比如其中一個reduce任務(wù)groupByKey,太大了规惰。斯巴克的整理操作(sortByKey睬塌,groupByKey,reduceByKey歇万,join揩晴,等)建立每個任務(wù)中的哈希表來進行分組,而這往往是大的贪磺。這里最簡單的解決方法是增加并行度硫兰,以便每個任務(wù)的輸入集更小。Spark可以有效地支持短至200毫秒的任務(wù)缘挽,因為它可以在多個任務(wù)中重用一個執(zhí)行程序JVM瞄崇,并且它具有較低的任務(wù)啟動成本,因此您可以安全地將并行度提高到超過群集中的核心數(shù)壕曼。

廣播大變量

使用?可用的廣播功能SparkContext可以大大減少每個序列化任務(wù)的大小苏研,以及通過群集啟動作業(yè)的成本。如果您的任務(wù)使用其中的驅(qū)動程序中的任何大對象(例如靜態(tài)查找表)腮郊,請考慮將其轉(zhuǎn)換為廣播變量摹蘑。Spark打印主服務(wù)器上每個任務(wù)的序列化大小,因此您可以查看它以確定您的任務(wù)是否過大;?一般來說轧飞,大于約20 KB的任務(wù)可能值得優(yōu)化衅鹿。

數(shù)據(jù)位置

數(shù)據(jù)位置可能會對Spark作業(yè)的性能產(chǎn)生重大影響。如果數(shù)據(jù)和在其上運行的代碼在一起过咬,那么計算往往很快大渤。但是如果代碼和數(shù)據(jù)是分開的,那么必須移動到另一個掸绞。通常泵三,將序列化代碼從一個地方運送到另一個地方比一塊數(shù)據(jù)更快,因為代碼大小比數(shù)據(jù)小得多。Spark圍繞數(shù)據(jù)局部性的一般原則構(gòu)建其調(diào)度烫幕。

數(shù)據(jù)位置是數(shù)據(jù)與處理它的代碼的接近程度俺抽。根據(jù)數(shù)據(jù)的當(dāng)前位置,有多個級別的位置较曼。從最近到最遠的順序:

PROCESS_LOCAL數(shù)據(jù)與正在運行的代碼位于同一JVM中磷斧。這是最好的地方

NODE_LOCAL數(shù)據(jù)在同一節(jié)點上。示例可能位于同一節(jié)點上的HDFS中捷犹,也可能位于同一節(jié)點上的另一個執(zhí)行程序中弛饭。這比PROCESS_LOCAL因為數(shù)據(jù)必須在進程之間傳輸要慢一些

NO_PREF可以從任何地方快速訪問數(shù)據(jù),并且沒有位置偏好

RACK_LOCAL數(shù)據(jù)位于同一機架的服務(wù)器上伏恐。數(shù)據(jù)位于同一機架上的不同服務(wù)器上孩哑,因此需要通過網(wǎng)絡(luò)發(fā)送,通常通過單個交換機

ANY數(shù)據(jù)在網(wǎng)絡(luò)上的其他位置翠桦,而不在同一個機架中

Spark更喜歡在最佳位置級別安排所有任務(wù),但這并非總是可行胳蛮。在任何空閑執(zhí)行程序上沒有未處理數(shù)據(jù)的情況下销凑,Spark會切換到較低的位置級別。有兩種選擇:a)等待繁忙的CPU釋放以啟動同一服務(wù)器上的數(shù)據(jù)任務(wù)仅炊,或b)立即在需要移動數(shù)據(jù)的較遠位置啟動新任務(wù)斗幼。

Spark通常會做的是等待繁忙的CPU釋放的希望。一旦超時到期抚垄,它就開始將數(shù)據(jù)從遠處移動到空閑CPU蜕窿。每個級別之間的回退等待超時可以單獨配置,也可以在一個參數(shù)中一起配置;?有關(guān)詳細信息呆馁,請參閱配置頁面spark.locality上的?參數(shù)桐经。如果您的任務(wù)很長并且看不到位置,則應(yīng)該增加這些設(shè)置浙滤,但默認情況通常很有效阴挣。

概要

這是一個簡短的指南,指出在調(diào)優(yōu)Spark應(yīng)用程序時應(yīng)該了解的主要問題 - 最重要的是纺腊,數(shù)據(jù)序列化和內(nèi)存調(diào)整畔咧。對于大多數(shù)程序,切換到Kryo序列化并以序列化形式保存數(shù)據(jù)將解決最常見的性能問題揖膜。請隨時在Spark郵件列表中詢問有關(guān)其他調(diào)優(yōu)最佳做法的信息誓沸。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市壹粟,隨后出現(xiàn)的幾起案子拜隧,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,544評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件虹蓄,死亡現(xiàn)場離奇詭異犀呼,居然都是意外死亡,警方通過查閱死者的電腦和手機薇组,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評論 3 392
  • 文/潘曉璐 我一進店門外臂,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人律胀,你說我怎么就攤上這事宋光。” “怎么了炭菌?”我有些...
    開封第一講書人閱讀 162,764評論 0 353
  • 文/不壞的土叔 我叫張陵罪佳,是天一觀的道長。 經(jīng)常有香客問我黑低,道長赘艳,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,193評論 1 292
  • 正文 為了忘掉前任克握,我火速辦了婚禮蕾管,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘菩暗。我一直安慰自己掰曾,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,216評論 6 388
  • 文/花漫 我一把揭開白布停团。 她就那樣靜靜地躺著旷坦,像睡著了一般。 火紅的嫁衣襯著肌膚如雪佑稠。 梳的紋絲不亂的頭發(fā)上秒梅,一...
    開封第一講書人閱讀 51,182評論 1 299
  • 那天,我揣著相機與錄音讶坯,去河邊找鬼番电。 笑死,一個胖子當(dāng)著我的面吹牛辆琅,可吹牛的內(nèi)容都是我干的漱办。 我是一名探鬼主播,決...
    沈念sama閱讀 40,063評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼婉烟,長吁一口氣:“原來是場噩夢啊……” “哼娩井!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起似袁,我...
    開封第一講書人閱讀 38,917評論 0 274
  • 序言:老撾萬榮一對情侶失蹤洞辣,失蹤者是張志新(化名)和其女友劉穎咐刨,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體扬霜,經(jīng)...
    沈念sama閱讀 45,329評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡定鸟,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,543評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了著瓶。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片联予。...
    茶點故事閱讀 39,722評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖材原,靈堂內(nèi)的尸體忽然破棺而出沸久,到底是詐尸還是另有隱情,我是刑警寧澤余蟹,帶...
    沈念sama閱讀 35,425評論 5 343
  • 正文 年R本政府宣布卷胯,位于F島的核電站,受9級特大地震影響威酒,放射性物質(zhì)發(fā)生泄漏窑睁。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,019評論 3 326
  • 文/蒙蒙 一兼搏、第九天 我趴在偏房一處隱蔽的房頂上張望卵慰。 院中可真熱鬧,春花似錦佛呻、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至兄淫,卻和暖如春哈误,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背惕耕。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評論 1 269
  • 我被黑心中介騙來泰國打工纺裁, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人司澎。 一個月前我還...
    沈念sama閱讀 47,729評論 2 368
  • 正文 我出身青樓欺缘,卻偏偏與公主長得像,于是被迫代替她去往敵國和親挤安。 傳聞我的和親對象是個殘疾皇子谚殊,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,614評論 2 353

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