spark 內(nèi)存管理

內(nèi)容目錄

引言

?? ? ? Spark 從1.6x開始對JVM的內(nèi)存使用作出了一種全新的改變癞尚,Spark 1.6x以前是基于靜態(tài)固定的JVM內(nèi)存架構(gòu)和運行機(jī)制。如果你不知道Spark到底對JVM怎么使用憨颠,就無法完全掌握和控制數(shù)據(jù)的緩存空間烙心,所以理解Spark對JVM的內(nèi)存使用是至關(guān)重要的淫茵。很多人對于Spark的印象是:它是基于內(nèi)存的匙瘪,而且可以緩存很多數(shù)據(jù)丹喻,顯然Spark基于內(nèi)存的觀點是錯誤的碍论,Spark只是優(yōu)先充分地利用緩存鳍悠。如果你不知道Spark可以緩存多少數(shù)據(jù)藏研,就胡亂緩存數(shù)據(jù)的話概行,肯定會出問題。
?? ? ? 在數(shù)據(jù)規(guī)模已經(jīng)確定的情況下禽炬,你有多少Executor和每個Executor分配多少內(nèi)存(物理硬件資源確定的情況下)腹尖,你必須清楚知道你的內(nèi)存最多能緩存多少數(shù)據(jù)桐臊;在shuffle過程中又使用了多少比例的緩存断凶,這樣對于算法的編寫和業(yè)務(wù)的實現(xiàn)是至關(guān)重要的认烁。
?? ? ? 文章會介紹Spark 2.x版本的內(nèi)存使用比例,它被稱為:Spark Unified Memory介汹,這里的Unified是統(tǒng)一却嗡、聯(lián)合的意思,Spark沒有用Share這個詞嘹承,是因為A和B進(jìn)行Unified和A和B進(jìn)行Share是完全不同的概念窗价。Spark在運行過程中會出現(xiàn)不同類型的OOM,你必須搞清楚這個OOM背后是由于什么導(dǎo)致的叹卷。比如說我們使用算子mapPartition時候,一般會創(chuàng)建一些臨時對象或者中間數(shù)據(jù)骤竹,你這個時候使用的臨時對象和中間數(shù)據(jù)帝牡,是存儲在一個UserSpace里面的用戶操作空間,那你有沒有想過這個空間的大小會導(dǎo)致應(yīng)用程序出現(xiàn)OOM的情況蒙揣,在Spark 2.x 中的Broadcast的數(shù)據(jù)存儲在什么地方靶溜;ShuffleMapTask的數(shù)據(jù)又存儲在什么地方。文章會介紹 JVM 在 Spark 1.6.X 以前和 2.X 版本對 Java 堆的使用懒震,還會逐一解密上述幾個疑問罩息,也會簡單介紹 Spark 1.6.x 以前版本在 Spark On Yarn 上內(nèi)存的使用案例,希望這篇文章能為讀者帶出以下的啟發(fā):

  • 了解JVM內(nèi)存使用架構(gòu)
  • 了解JVM在Spark 1.6x以前和Spark 2.x中可以緩存多少數(shù)據(jù)
  • 了解Spark Unified Memory 的原理和機(jī)制還有它的三大核心空間的用途
  • 了解Shuffle在Spark 1.6x以前和Spark 2.x 中可以使用多少緩存
  • 了解Spark 1.6x以前on Yarn對內(nèi)存的使用
  • 了解Spark 1.6x以前和Spark 2.x的參數(shù)配置

<h2 id="1">JVM 內(nèi)存使用架構(gòu)剖析</h2>
????JVM的邏輯內(nèi)存模型如下:


圖片.png

???? 簡單介紹一下各個部分:

  • 本地方法棧
    ???? 本地方法棧(Native Method Stacks)與虛擬機(jī)棧所發(fā)揮的作用是非常相似的挎狸,其區(qū)別不過是虛擬機(jī)棧為虛擬機(jī)執(zhí)行Java 方法(也就是字節(jié)碼)服務(wù)扣汪,而本地方法棧則是為虛擬機(jī)使用到的Native 方法服務(wù)。
  • 程序計數(shù)器
    ???? 程序計數(shù)器(Program Counter Register)是一塊較小的內(nèi)存空間锨匆,它的作用可以看做是當(dāng)前線程所執(zhí)行的字節(jié)碼的行號指示器崭别。在虛擬機(jī)的概念模型里(僅是概念模型冬筒,各種虛擬機(jī)可能會通過一些更高效的方式去實現(xiàn)),字節(jié)碼解釋器工作時就是通過改變這個計數(shù)器的值來選取下一條需要執(zhí)行的字節(jié)碼指令茅主,分支舞痰、循環(huán)、跳轉(zhuǎn)诀姚、異常處理响牛、線程恢復(fù)等基礎(chǔ)功能都需要依賴這個計數(shù)器來完成。
  • Java 棧 (Stack)
    ???? Stack 區(qū)屬于線程私有赫段,高效的程序一般都是并發(fā)的呀打,每個線程都會包含一個 Stack 區(qū)域,Stack 區(qū)域中含有基本的數(shù)據(jù)類型以及對象的引用糯笙,其它線程均不能直接訪問該區(qū)域贬丛;Java 棧分為三大部份:基本數(shù)據(jù)類型區(qū)域、操作指令區(qū)域给涕、上下文等豺憔;
  • Java 堆 (Heap)
    ???? 存儲的全部都是 Object 對象實例,對象實例中一般都包含了其數(shù)據(jù)成員以及與該對象對應(yīng)類的信息够庙,它會指向類的引用一個恭应,不同線程肯定要操作這個對象;一個 JVM 實例在運行的時候只有一個 Heap 區(qū)域耘眨,而且該區(qū)域被所有的線程共享昼榛;補(bǔ)充說明:垃圾回收是回收堆 (heap) 中內(nèi)容,堆上才有我們的對象剔难。
  • 方法區(qū)
    ???? 又名靜態(tài)成員區(qū)域褒纲,包含整個程序的 class、static 成員等钥飞,類本身的字節(jié)碼是靜態(tài)的;它會被所有的線程共享和是全區(qū)級別的衫嵌。

???? ==從 Spark 的角度來談代碼的運行和數(shù)據(jù)的處理读宙,主要是談 Java 堆 (Heap) 空間的運用。==

<h2 id="2">Spark 1.6.x以前版本內(nèi)存管理</h2>

????下面兩個圖是Spark 1.6x以前版本對Java的堆(heap)的使用情況楔绞,左側(cè)是Storage對內(nèi)存的使用结闸,右側(cè)是Shuffle對內(nèi)存的使用,這種方式叫做:StaticMemoryManagement酒朵,數(shù)據(jù)處理以及類的實體對象都放在JVM堆(heap)中桦锄。


圖片.png

????JVM Heap默認(rèn)情況下是512M,這是取決于spark.executor.memory的參數(shù)蔫耽,在回答Spark JVM到底可以緩存多少數(shù)據(jù)之前结耀,先了解一下JVM Heap在Spark中是如何分配內(nèi)存比例的留夜。無論你定義了Spark.executor.memory的內(nèi)存空間有多大,Spark必然會定義一個安全空間图甜,在默認(rèn)的情況下只會使用JVM Heap的90%作為安全空間碍粥,在單個Executor的角度來說就是Heap size * 90%。

場景一:假設(shè)說在一個Executor黑毅,它可用的JVM Heap是10g嚼摩,實際上Spark只能用90%,這個safe memory的的比例是由 ==spark.storage.safetyFraction== 控制的矿瘦。(如果你單個的Executor的內(nèi)存非常大枕面,可以考慮提高這個比例),在safe memory中也會劃分為三個不同空間:Storage memory缚去,Unroll memory潮秘、Shuffle memory。

  • Safe memory
    ????計算公式是:==spark.executor.memory * spark.storage.safetyFraction== 病游。也就是Heap Size的90%唇跨。在場景一種的案例是10*0.9=9g
  • Storage memory
    ????計算公式是參考==StaticMemoryManager==類中的getMaxStorageMemory方法。如下圖:
    圖片.png

也就是 Heap Size x 90% x 60%衬衬;Heap Size x 54%买猖,在場景一的例子中是 10 x 0.9 x 0.6 = 5.4G;一個應(yīng)用程序可以緩存多少數(shù)據(jù)是由 ==spark.storage.safetyFraction== 和 ==spark.storage.memoryFraction== 這兩個參數(shù)共同決定的滋尉。

  • Unroll memory
    ????計算公式是參考==StaticMemoryManager==類中的maxUnrollMemory方法玉控。如下圖:
    圖片.png

也就是 Heap Size x 90% x 60% x 20%;Heap Size x 10.8%狮惜,在場景一的例子中是 10 x 0.9 x 0.6 x 0.2 = 1.8G高诺,你可能把序例化后的數(shù)據(jù)放在內(nèi)存中,當(dāng)你使用數(shù)據(jù)時碾篡,你需要把序例化的數(shù)據(jù)進(jìn)行反序例化虱而。
????對 cache 緩存數(shù)據(jù)的影響是由于 Unroll 是一個優(yōu)先級較高的操作,進(jìn)行 Unroll 操作的時候會占用 cache 的空間开泽,而且又可以擠掉緩存在內(nèi)存中的數(shù)據(jù) (如果該數(shù)據(jù)的緩存級別是 MEMORY_ONLY 的話牡拇,否則該數(shù)據(jù)會丟失)。

  • Shuffle memory
    ????計算公式是參考==StaticMemoryManager==類中的getMaxExecutionMemory方法穆律。如下圖:
    圖片.png

????在 Shuffle 空間中也會有一個默認(rèn) 80% 的安全空間比例惠呼,所以應(yīng)該是 Heap Size x 20% x 80%;Heap Size x 16%峦耘,在場景一的例子中是 10 x 0.2 x 0.8 = 1.6G剔蹋。
????從內(nèi)存的角度講,你需要從遠(yuǎn)程抓取數(shù)據(jù)辅髓,抓取數(shù)據(jù)是一個 Shuffle 的過程泣崩,比如說你需要對數(shù)據(jù)進(jìn)行排序少梁,顯現(xiàn)在這個過程中需要內(nèi)存空間。

<h2 id="3">Spark on Yarn 計算內(nèi)存使用案例</h2>
????這是一張 Spark 運行在 Yarn 上的架構(gòu)圖律想,它有 Driver 和 Executor 部份猎莲,在 Driver 部份有一個內(nèi)存控制參數(shù),Spark 1.6.x 以前是 spark.driver.memory技即,在實際生產(chǎn)環(huán)境下建義配置成 2G著洼。如果 Driver 比較繁忙或者是經(jīng)常把某些數(shù)據(jù)收集到 Driver 上的話,建義把這個參數(shù)調(diào)大一點而叼。

????圖的左邊是 Executor 部份身笤,它是被 Yarn 管理的,每臺機(jī)制上都有一個 Node Manager葵陵;Node Manager 是被 Resources Manager 管理的液荸,Resources Manager 的工作主要是管理全區(qū)級別的計算資源,計算資源核心就是內(nèi)存和 CPU脱篙,每臺機(jī)器上都有一個 Node Manager 來管理當(dāng)前內(nèi)存和 CPU 等資源娇钱。Yarn 一般跟 Hadoop 藕合,它底層會有 HDFS Node Manager绊困,主要是負(fù)責(zé)管理當(dāng)前機(jī)器進(jìn)程上的數(shù)據(jù)并且與HDFS Name Node 進(jìn)行通信文搂。


圖片.png

????在每個節(jié)點上至少有兩個進(jìn)程,一個是 HDFS Data Node秤朗,負(fù)責(zé)管理磁盤上的數(shù)據(jù)煤蹭,另外一個是 Yarn Node Manager,負(fù)責(zé)管理執(zhí)行進(jìn)程取视,在這兩個 Node 的下面有兩個 Executors稽物,每個 Executor 里面運行的都是 Tasks怨酝。從 Yarn 的角度來講售淡,會配置每個 Executor 所占用的空間揍堕,以防止資源競爭芹血,Yarn 里有一個叫 Node Memory Pool 的概念,可以配置 64G 或者是 128G,Node Memory Pool 是當(dāng)前節(jié)點上總共能夠使用的內(nèi)存大小。

????圖中這兩個 Executors 在兩個不同的進(jìn)程中 (JVM#1 和 JVM#2)夫啊,里面的 Task 是并行運行的,Task 是運行在線程中,但你可以配置 Task 使用線程的數(shù)量,e.g. 2條線程或者是4條線程,但默認(rèn)情況下都是1條線程去處理一個Task,你也可以用 spark.executor.cores 去配置可用的 Core 以及 spark.executor.memory 去配置可用的 RAM 的大小。

在 Yarn 上啟動 Spark Application 的時候可以通過以下參數(shù)來調(diào)優(yōu):

  • num-executor 或者 spark.executor.instances 來指定運行時所需要的 Executor 的個數(shù);
  • executor-memory 或者 spark.executor.memory 來指定每個 Executor 在運行時所需要的內(nèi)存空間;
  • executor-cores 或者是 spark.executor.cores 來指定每個 Executor 在運行時所需要的 Cores 的個數(shù)容握;
  • driver-memory 或者是 spark.driver.memory 來指定 Driver 內(nèi)存的大刑铬恕;
  • spark.task.cpus 來指定每個 Task 運行時所需要的 Cores 的個數(shù)稽寒;

????場景一:例如 Yarn 集群上有 32 個 Node 來運行的 Node Manager,每個 Node 的內(nèi)存是 64G蚓土,每個 Node 的 Cores 是 32 Cores宏侍。
????假如說每個 Node 我們要分配兩個 Executors,那么可以把每個 Executor 分配 28G蜀漆,Cores 分配為 12 個 Cores负芋,每個 Spark Task 在運行的時候只需要一個 Core 就行啦,那么我們 32 個 Nodes 同時可以運行: 32 個 Node x 2 個 Executors x (12 個 Cores / 1) = 768 個 Task Slots,也就是說這個集群可以并行運行 768 個 Task旧蛾,如果 Job 超過了 Task 可以并行運行的數(shù)量 (e.g. 768) 則需要排隊。
????那么這個集群娜浼蓿可以緩存多少數(shù)據(jù)呢锨天?從理論上:32 個 Node x 2 個 Executors x 28g x 90% 安全空間 x 60%緩存空間 = 967.68G,這個緩存數(shù)量對于普通的 Spark Job 而言是完全夠用的剃毒,而實際上在運行中可能只能緩存 900G 的數(shù)據(jù)病袄,900G 的數(shù)據(jù)從磁盤儲存的角度數(shù)據(jù)有多大呢?還是 900G 嗎赘阀?不是的益缠,數(shù)據(jù)一般都會膨脹好幾倍,這是和壓縮基公、序列化和反序列化框架有關(guān)幅慌,所以在磁盤上可能也就 300G 的樣子的數(shù)據(jù)。

<h2 id="4">Spark Unified Memory 的運行原理和機(jī)制(spark 1.6.x以后的內(nèi)存管理器)</h2>
????下圖是一種叫做聯(lián)合內(nèi)存(Spark Unified Memory)轰豆,數(shù)據(jù)緩存和數(shù)據(jù)執(zhí)行直接的內(nèi)存可以相互移動胰伍,這是一種更加彈性的方式。下圖顯示的是Spark 2.0.0 版本起JVM Heap的使用情況酸休。


圖片.png

==(1.6.x 到2.0.0之間的版本Spark Memory 占比是75%骂租,User Memory 是25%)==

新型 JVM Heap 分成三個部份:Reserved Memory、User Memory 和 Spark Memory斑司。

  • Reserved Memory
    ????默認(rèn)都是300M,這個數(shù)字一般都是固定不變渗饮,在系統(tǒng)運行時候jvm heap 的大小至少為Heap Reserved Memory x 1.5。e.g. 300MB x 1.5 = 450MB 的 JVM配置宿刮。一般本地開發(fā)例如說在 Windows 系統(tǒng)上互站,建義系統(tǒng)至少 2G 的大小。
    ????UnifiedMemoryManager.scala 中 UnifiedMemoryManager 伴生對象里的 RESERVED_SYSTEM_MEMORY_BYTES 參數(shù)糙置。如圖:

    圖片.png

  • User Memory
    ????Spark程序中產(chǎn)生的臨時數(shù)據(jù)或者是自己維護(hù)的一些數(shù)據(jù)結(jié)構(gòu)需要給予一定的存儲空間云茸,你可以認(rèn)為這是程序運行時用戶可以主導(dǎo)的空間,叫做用戶空間谤饭。它占用的空間是 (Java Heap - Reserved Memory) x 40% (默認(rèn)是25%标捺,可以有參數(shù)供調(diào)優(yōu)),這樣設(shè)計可以讓用戶操作時所需要的空間與系統(tǒng)框架運行時所需要的空間分離開揉抵。假設(shè) Executor 有 4G 的大小亡容,那么在默認(rèn)情況下 User Memory 大小是:(4G - 300MB) x 40% = 1519MB,也就是說一個 Stage 內(nèi)部展開后 Task 的算子在運行時最大的大小不能夠超過 1519MB冤今。例如工程師使用 mapPartition 等闺兢,一個 Task 內(nèi)部所有算子使用的數(shù)據(jù)空間的大小如果大于 1519MB 的話,那么就會出現(xiàn) OOM。
    ???? 思考題:有 100個 Executors 每個 4G 大小屋谭,現(xiàn)在要處理 100G 的數(shù)據(jù)脚囊,假設(shè)這 100G 分配給 100個 Executors,每個 Executor 分配 2G 的數(shù)據(jù)桐磁,這 2G 的數(shù)據(jù)遠(yuǎn)遠(yuǎn)少于 4G Executor 內(nèi)存的大小悔耘,為什么還會出現(xiàn) OOM 的情況呢?
    ???? ==那是因為在你的代碼中(e.g.你寫的應(yīng)用程序算子)超過用戶空間的限制 (e.g. 949MB)我擂,而不是 RDD 本身的數(shù)據(jù)超過了限制衬以。==

  • Spark Memory
    ????SparkMemory的計算公式:參考UnifiedMemoryManager.scala 中 UnifiedMemoryManager 伴生對象里的 getMaxMemory 方法

    圖片.png

由兩部分構(gòu)成,分別是Storage Memory和Execution Memory校摩。

  • Storage Memeory
    ???? 相當(dāng)于舊版本的 Storage 空間看峻,在舊版本中 Storage 占了 54% 的 Heap 空間,這個空間會負(fù)責(zé)存儲 Persist衙吩、Unroll 以及 Broadcast 的數(shù)據(jù)互妓。假設(shè) Executor 有 4G 的大小,那么 Storage 空間是:(4G - 300MB) x 75% x 50% = 1423.5MB 的空間分井,也就是說如果你的內(nèi)存夠大的話车猬,你可以擴(kuò)播足夠大的變量,擴(kuò)播對于性能提升是一件很重要的事情尺锚,因為它所有的線程都是共享的珠闰。從算子運行的角度來講,Spark 會傾向于數(shù)據(jù)直接從 Storgae Memeory 中抓取過來瘫辩,這也就所謂的內(nèi)存計算伏嗜。
  • Execution Memeory
    ???? 相當(dāng)于舊版本的 Shuffle 空間,這個空間會負(fù)責(zé)存儲 ShuffleMapTask 的數(shù)據(jù)伐厌。比如說從上一個 Stage 抓取數(shù)據(jù)和一些聚合的操作承绸、等等。在舊版本中 Shuffle 占了 16% 的 Heap 空間挣轨。Execution 如果空間不足的情況下军熏,除了選擇向 Storage Memory 借空間以外,也可以把一部份數(shù)據(jù) Spill 到磁盤上卷扮,但很多時候基于性能調(diào)優(yōu)方面的考慮都不想把數(shù)據(jù) Spill 到磁盤上荡澎。思考題:你覺得是 Storgae 空間或者是 Execution 空間比較重要呢?

現(xiàn)在 Storage 和 Execution (Shuffle) 采用了 Unified 的方式共同使用了 (Heap Size - 300MB) x 60%晤锹,默認(rèn)情況下 Storage 和 Execution 各占該空間的 50%摩幔。
下圖是 UnifiedMemoryManager.scala 中 UnifiedMemoryManager 伴生對象里的 apply 方法

圖片.png

????定義:所謂 Unified 的意思是 Storgae 和 Execution 在適當(dāng)時候可以借用彼此的 Memory,需要注意的是鞭铆,當(dāng) Execution 空間不足而且 Storage 空間也不足的情況下或衡,Storage 空間如果曾經(jīng)使用了超過 Unified 默認(rèn)的 50% 空間的話則超過部份會被強(qiáng)制 drop 掉一部份數(shù)據(jù)來解決 Execution 空間不足的問題 (注意:drop 后數(shù)據(jù)會不會丟失主要是看你在程序設(shè)置的 storage_level 來決定你是 Drop 到那里,可能 Drop 到磁盤上),這是因為執(zhí)行(Execution) 比緩存 (Storage) 是更重要的事情封断。

但是也有它的基本條件限制斯辰,Execution 向 Storage 借空間有兩種情況:具體代碼實現(xiàn)可以參考源碼補(bǔ)充 : Spark 2.1.X 中 Unified 和 Static MemoryManager

下圖是 Execution 向 Storage 借空間的第一種情況


圖片.png

第一種情況:Storage 曾經(jīng)向 Execution 借了空間,它緩存的數(shù)據(jù)可能是非常的多坡疼,然后 Execution 又不需要那么大的空間 (默認(rèn)情況下各占 50%)椒涯,假設(shè)現(xiàn)在 Storage 占了 80%,Execution 占了 20%回梧,然后 Execution 說自己空間不足,Execution 會向內(nèi)存管理器發(fā)信號把 Storgae 曾經(jīng)占用的超過 50%數(shù)據(jù)的那部份強(qiáng)制擠掉祖搓,在這個例子中擠掉了 30%狱意;

下圖是 Execution 向 Storage 借空間的第二種情況


圖片.png

第二種情況:Execution 可以向 Storage Memory 借空間,在 Storage Memory 不足 50% 的情況下拯欧,Storgae Memory 會很樂意地把剩馀空間借給 Execution详囤。相反當(dāng) Execution 有剩馀空間的時候,Storgae 也可以找 Execution 借空間镐作。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末藏姐,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子该贾,更是在濱河造成了極大的恐慌羔杨,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,858評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件杨蛋,死亡現(xiàn)場離奇詭異兜材,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)逞力,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評論 3 395
  • 文/潘曉璐 我一進(jìn)店門曙寡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人寇荧,你說我怎么就攤上這事举庶。” “怎么了揩抡?”我有些...
    開封第一講書人閱讀 165,282評論 0 356
  • 文/不壞的土叔 我叫張陵户侥,是天一觀的道長。 經(jīng)常有香客問我捅膘,道長添祸,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,842評論 1 295
  • 正文 為了忘掉前任寻仗,我火速辦了婚禮刃泌,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己耙替,他們只是感情好亚侠,可當(dāng)我...
    茶點故事閱讀 67,857評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著俗扇,像睡著了一般硝烂。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上铜幽,一...
    開封第一講書人閱讀 51,679評論 1 305
  • 那天滞谢,我揣著相機(jī)與錄音,去河邊找鬼除抛。 笑死狮杨,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的到忽。 我是一名探鬼主播橄教,決...
    沈念sama閱讀 40,406評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼喘漏!你這毒婦竟也來了护蝶?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,311評論 0 276
  • 序言:老撾萬榮一對情侶失蹤翩迈,失蹤者是張志新(化名)和其女友劉穎持灰,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體帽馋,經(jīng)...
    沈念sama閱讀 45,767評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡搅方,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了绽族。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片姨涡。...
    茶點故事閱讀 40,090評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖吧慢,靈堂內(nèi)的尸體忽然破棺而出涛漂,到底是詐尸還是另有隱情,我是刑警寧澤检诗,帶...
    沈念sama閱讀 35,785評論 5 346
  • 正文 年R本政府宣布匈仗,位于F島的核電站,受9級特大地震影響逢慌,放射性物質(zhì)發(fā)生泄漏悠轩。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,420評論 3 331
  • 文/蒙蒙 一攻泼、第九天 我趴在偏房一處隱蔽的房頂上張望火架。 院中可真熱鬧鉴象,春花似錦、人聲如沸何鸡。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽骡男。三九已至淆游,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間隔盛,已是汗流浹背犹菱。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留吮炕,地道東北人已亥。 一個月前我還...
    沈念sama閱讀 48,298評論 3 372
  • 正文 我出身青樓,卻偏偏與公主長得像来屠,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子震鹉,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,033評論 2 355

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