聊聊MySQL、HBase、ES的特點和區別

很少寫技術博客,一是覺得自己技術有限,怕誤人子弟;二是文筆較差,比較排斥寫作之類的工作。話說不鍛煉,哪會有進步呢,因為陌生而抵觸,往往會陷入惡性循環,生活中其他事又何嘗不是這樣呢(突然就感慨人生了...)。明日復明日,明日何其多,時間不等人,有想法就要立馬行動。有句話說的好:種一棵樹最好的時間是十年前,其次是現在……共勉

互聯網時代各種存儲框架層出不窮,眼花繚亂,比如傳統的關系型數據庫:Oracle、MySQL;新興的NoSQL:HBase、Cassandra、Redis;全文檢索框架:ES、Solr等。如何為自己的業務選取合適的存儲方案,相信大家都思考過這個問題,本文簡單聊聊我對Mysql、HBase、ES的理解,希望能和大家一起探討進步,有不對的地方還請指出。

MySQL:關系型數據庫,主要面向OLTP,支持事務,支持二級索引,支持sql,支持主從、Group Replication架構模型(本文全部以Innodb為例,不涉及別的存儲引擎)。

HBase:基于HDFS,支持海量數據讀寫(尤其是寫),支持上億行、上百萬列的,面向列的分布式NoSql數據庫。天然分布式,主從架構,不支持事務,不支持二級索引,不支持sql。

ElasticSearch:ES是一款分布式的全文檢索框架,底層基于Lucene實現,雖然ES也提供存儲,檢索功能,但我一直不認為ES是一款數據庫,但是隨著ES功能越來越強大,與數據庫的界限也越來越模糊。天然分布式,p2p架構,不支持事務,采用倒排索引提供全文檢索。

下面分別從數據存儲方式、讀寫方式、索引、分布式等方面對它們進行對比。

參考鏈接:

ES:http://www.lxweimin.com/p/e8ee319a238d

HBase:http://www.cnblogs.com/songlee/p/5738027.html


---------------------------------------------------我是分割線---------------------------------------------------------


數據存儲方式


MySQL采用行存儲,HBase是面向列的NoSql數據庫,這篇文章很好的解釋了行、列存儲的區別,至于ES,呃~我也說不清楚它是什么存儲方式,暫且叫它索引存儲吧。

栗子

假設有這樣一張人員信息表:

MySQL中要提前定義表結構,也就是說表共有多少列(屬性)需要提前定義好,并且同時需要定義好每個列所占用的存儲空間。數據以行為單位組織在一起的,假如某一行的某一列沒有數據,也需要占用存儲空間。

HBase則是以列為單位存儲數據,每一列就是一個key-value,HBase的表列(屬性)不用提前定義,而且列可以動態擴展,比如人員信息表中需要添加一個新的“address”字段,MySQL需要提前alter表,HBase的話直接插入即可。

ES比較靈活,索引中的field類型可以提前定義(定義mapping),也可以不定義,如果不定義,會有一個默認類型,不過出于可控性考慮,關鍵字段最好提前定義好。(Solr中必須提前定義好schema.xml文件)

上圖簡單的展示了數據在MySQL和HBase中存儲差異(和真實的情況還有差距),可以看到即使第二條記錄的sex字段為空,MySQL依然會為該字段保留空間,因為后續有可能會有update語句來更新該記錄,補上sex內容。而HBase則是把每一列都看做是一條記錄,row+列名作為key,data作為value,依次存放。假如某一行的某一個列沒有數據,則直接跳過該列。對于稀疏矩陣的大表,HBase能節省空間。

看到這里,大家是否會有一個疑問:使用HBase存儲時,假如此時需要添加第二行的sex內容,如何實現呢,數據是否連續?后面介紹讀寫流程會解釋。

不一樣的ES

說完MySQL、HBase,這里要重點說一下ES,ES的存儲方式和上面兩個都不一樣,MySQL和HBase是將數據按不同的方式進行存儲,好歹它們存的還是數據,而ES則存的是倒排索引。我們先來了解一下什么是倒排索引,以及為什么需要倒排索引(Inverted Index):

我們肯定都會這樣的經歷:偶然看到一段很好的文字,但是卻不知道出處,這時候去圖書館,一個一個翻找,無疑是大海撈針,這個時候腫么辦呢,于是便有了全文檢索這項技術,而它最核心的就是倒排索引。假如有如下文檔:

我們想要知道有哪些文檔含有you這個關鍵字,首先可以創建一個倒排索引,格式如下:

我們把前面的部分叫做dictionary(字典),里面的每個單詞叫做term,后面的文檔列表叫做psoting-list,list中記錄了所有含有該term的文檔id,兩個組合起來就是一個完成的倒排索引(Inverted Index)。能夠看出,假如需要查找含有“you”的文檔時,根據dictionary然后找到對應的posting-list即可。

而全文檢索中,創建Inverted Index是最關鍵也是最耗時的過程,而且真正的Inverted Index結構也遠比圖中展示的復雜,不僅需要對文檔進行分詞(ES里中文可以自定義分詞器),還要計算TF-IDF,方便評分排序(當查找you時,評分決定哪個doc顯示在前面,也就是所謂的搜索排名),壓縮等操作。每接收一個document,ES就會將其信息更新在倒排索引中。

從這里我們就可以看出ES和MySQL、HBase的存儲還是有很大的區別。而且ES不僅包含倒排索引,默認同時還會把文檔doc存儲起來,所以當我們使用ES時,也能拿到完整的文檔信息,所以某種程度上,感覺就像在使用數據庫一樣,但是也可以配置不存儲文檔信息,這時只能根據查詢條件得到文檔id,并不能拿到完整的文檔內容。

總結:MySQL行存儲的方式比較適合OLTP業務。列存儲的方式比較適合OLAP業務,而HBase采用了列族的方式平衡了OLTP和OLAP,支持水平擴展,如果數據量比較大、對性能要求沒有那么高、并且對事務沒有要求的話,HBase也是個不錯的考慮。ES默認對所有字段都建了索引,所以比較適合復雜的檢索或全文檢索。


---------------------------------------------------我是分割線---------------------------------------------------------


讀寫方式


存儲方式和讀寫方式很大程度上決定了系統的吞吐,本節主要介紹MySQL、HBase、ES各自是如何讀寫數據的。

Mysql


先說說MySQL,MySQL的Innodb中的數據是按主鍵的順序依次存放,主鍵即為聚簇索引(對聚簇索引和非聚簇索引不了解同學可以看看這篇文章),索引采用B+樹結構進行組織。

從圖中可以看出,數據是按聚簇索引順序依次存放,假設下面一些場景:

1.查詢

Innodb中主鍵即為聚簇索引,假如根據主鍵查詢,聚簇索引的葉子節點存放就是真正的數據,可以直接查到相應的記錄。

假如是二級索引查詢,那么需要先通過二級索引找到該記錄的主鍵,然后根據主鍵通過聚簇索引找到對應的記錄,這里多了一個索引查找的過程。

2.插入

順序插入:因為Innodb的數據是按聚簇索引的順序依次存放的,如果是根據主鍵索引的順序插入,即插入的數據的主鍵是連續的,因為是順序io,所以插入效率會較高。

隨機插入:假如每次插入的數據主鍵是不連續的,MySQL需要取出每條記錄對應的物理block,會引起大量的隨機io,隨機io操作和順序io的性能差距很大,尤其是機械盤。

(Kafka官網提到一個機械盤的順序寫能達到600M/s,而隨機寫可能只有100k/s。As a result the performance of linear writes on aJBODconfiguration with six 7200rpm SATA RAID-5 array is about 600MB/sec but the performance of random writes is only about 100k/sec—a difference of over 6000X.這也是為什么HBase、ES將所有的insert、update、delete操作都統一看成順序寫操作,避免隨機io)

note:這也是為什么MySQL的主鍵通常定義為自增id,不涉及業務邏輯,這樣新數據插入時能保證是順序io。另外MySQL為了提高隨機io的性能,提供了insert buffer的功能。

3.更新 & 刪除

update和delete如果不是順序的話,也會包含大量的隨機io,當然MySQL都針對隨機io都進行了一些優化,盡量減少隨機io帶來的性能損失。

HBase


HBase不支持二級索引,它只有一個主鍵索引,采用LSM樹(LSM可以參考這篇博客)。

HBase是一個分布式系統,這點跟MySQL不同,它的數據是分散不同的server上,每個table由一個或多個region組成,region分散在集群中的server上,一個server可以負責多個region。

這里有一點需要特別注意:table中各個region的存放數據的rowkey(主鍵)范圍是不會重疊的,可以認為region上數據基于rowkey全局有序,每個region負責它自己的那一部分的數據。

1.查詢

假如我們要查詢rowkey=150的這條記錄,首先從zk中獲取hbase:meta表(存放region和key的對應關系的元數據表)的位置,通過查詢meta表得知rowkey=150的數據在哪個server的哪個region上。

2.插入

上圖粗略的展示了HBase的region的結構,region不單單是一個文件,它是由一個memstore和多個storeFile組成(storeFile上的上限可以配置)。插入數據時首先將數據寫入memstore,當memstore大小達到一定閾值,將memstore flush到硬盤,變成一個新的storeFile。flush的時候會對memstore中的數據進行排序,壓縮等操作。可以看到單個storeFile中的數據是有序的,但是region中的storeFile間的數據不是全局有序的。

這樣有的好處就是:不管主鍵是否連續,所有的插入一律變成順序寫,大大提高了寫入性能。

看到這里大家可能會有一個疑問:這種寫入方式導致了一條記錄如果不是一次性插入,很可能分散在不同的storeFile中,那在該region上面查詢一條記錄時,怎么知道去找哪個storeFile呢?答案就是:全部查詢。HBase會采用多路歸并的方式,對該region上的所有storeFile進行查詢,直到找到符合條件的記錄。所以HBase的擁有很好的寫入性能,但是讀性能較差。

當然HBase也做了很多優化,比如每個storeFile都有自己的index、用于過濾的bloom filter、compaction:按可配置的方式將多個storeFile合并成一個,減少檢索時打開的文件數。

3.更新 & 刪除

HBase將更新和刪除也全部看做插入操作,用timestamp和delete marker來區分該記錄是否是最新記錄、是否需要刪除。也正是因為這樣,除了查詢,其他的操作統一轉換成了順序寫,保證了HBase高效的寫性能。

ES


ES的也是一個分布式系統,與ES類似的還有一個叫Solr的項目,都是基于Lucene的全文檢索分布式框架,有興趣的可以去Lucene官網了解,這里就不做對比了。

上如展示了ES和傳統數據庫的概念對比。下面的介紹中,統一使用index對應DB中table,doc對應table中的記錄,field對應row中的一列。

ES集群由一個或多個node組成,一個node即為一個ES服務進程。一個index由多個分片shard組成,shard分散在各個node上面,每個shard都采用Lucene來創建倒排索引,維護各自的索引數據。

圖中的一個小方框即為一個shard,出于容災考慮,每個shard都會有多副本,副本個數可以配置,默認為2,綠色的即為primary shard,灰色的即為replica shard。

1.插入

先來說說寫入吧,由于有多個shard,請求過來時,如何判斷寫入到哪個shard呢,ES中每個doc都會有一個唯一id,默認會對id取hash值,根據shard的個數mode到對應的shard上,默認情況下shard中的數據id不是全局有序的,這點和Mysql、HBase有很大區別。

ES的寫入和HBase有些類似,也是將所有的寫操作變成順序寫,也是先將數據寫入內存,然后一段時間后會將內存數據flush到磁盤,磁盤的索引文件會定時進行merge,保證索引文件不會過多而影響檢索性能。

另外提一點,數據存入ES后并不是立馬就能檢索到,這點跟MySQL和HBase,或者說跟數據庫系統是完全不一樣的。主要是因為由于Inverted Index結構的復雜,需要一個專門的indexReader來查詢數據,但是indexReader是以snapshot的方式打開的索引,也就是說indexReader看不到之后的新數據。所以ES提供了一個refresh功能,refresh會重新打開indexReader,使其能夠讀到最新的數據。默認refresh的間隔是1s,所以ES自稱是近實時檢索功能。

說到順序寫,這時候大家可能會想:那ES的寫入速度和HBase差不多嘍?那,其實不是的,不止不如而且差的還不是一點點,因為ES多了兩個最關鍵的步驟:build index和refresh index!這兩個過程是很耗時的: build index時需要分詞、計算權重等復雜的操作(對inverted index創建,檢索感興趣的,可以參考《信息檢索導論》)。而refresh會重新打開index,這兩個過程加起來導致ES接收文檔的速率并不高(可以通過bulk方式來加快數據導入)。但也正是因為這些過程才使ES有強大的檢索功能。(雖然我insert慢,但是我花樣多呀^ ^)

2.讀取

每個node都可以接收讀request,然后該node會把request分發到含有該index的shard的節點上,對應的節點會查詢、并計算出符合條件的文檔,排序后結果匯聚到分發request的node(所以查詢請求默認會輪循的將發送到各個節點上,防止請求全部打到一個節點),由該node將數據返回給client。(ES也支持指定shard查詢,默認是根據文檔id進行路由,相當于主鍵查詢,但是假如不能確定數據在哪個shard上時,還是需要查詢所有shard)

這里要強調一下,由于ES支持全文檢索,根據Inverted Index的特性,大部分情況下,一個關鍵字對應了很多的doc,如果全部返回,數據量較大,會對集群造成較大壓力,所以ES默認只返回權重最高的前20條記錄(可配置),也可以通過scroll功能獲取全部數據。類似的場景跟我們平時使用baidu、google是一樣的,我們使用搜索引擎時,往往是希望得到關聯性最強的top N文檔,并不關心全部文檔有多少個,這也是為什么要計算權重的原因。

現在的ES的功能越來越豐富,不僅僅包含全文檢索的功能,而且還有統計分析等功能,說它是全文檢索框架吧,它比全文檢索功能要豐富,說它是數據庫吧,但是它不支持事務,只能說現在各個框架之間的界限越來越模糊了。

3.更新 &刪除

ES的更新和刪除和HBase類似,也是全部看做是插入操作,通過timestamp和delete marker來區分。

又到了問題環節 :D :既然這種將更新刪除統一變成順序寫的方式能夠提高寫性能,那它難道沒有什么壞處嗎?

答案是肯定有的呀,這種方式能夠有效的提升寫性能,但是存在一個很大的問題就是后臺經常會需要merge,而merge是一個非常耗資源的過程,對于某些穩定性要求較高的業務來說,這是不能接受的,但是不merge的話,又會降低查詢性能(過多的小文件影響查詢性能)。目前通用的做法是盡量選擇業務低峰期進行merge操作。


---------------------------------------------------我是分割線---------------------------------------------------------


容災


數據庫系統,數據的完整性和一致性是非常重要的問題,數據庫進程掛了,可以恢復,但是數據丟了,就再也找不回來了。下面說說各個系統的容災方式。

MySQL


單節點:

現在的數據庫普遍采用write ahead log策略來避免數據丟失,wal機制簡單的解釋就是:在提交CUD操作,數據寫入內存的同時,也要寫一份到log文件中,而且要保證log數據落盤成功后才能向client返回操作成功,假如此時數據庫宕機,已經提交到內存的數據還沒來得及刷回磁盤,重啟數據庫后可以通過回放log文件來恢復內存中的數據。

問題又來了:寫log的話,對性能影響會不會很大?其實多少還是有點影響的,不過log文件是順序寫入,相對來說為了保證數據完整性,這點性能損失還是可以接受的。

單機情況下,MySQL的innodb通過redo log和checkpoint機制來保證數據的完整性。因為怕log越寫越大,占用過多磁盤,而且當log特別大的時候,恢復起來也比較耗時。而checkpoint的出現就是為了解決這些問題。

checkpoint機制保證了之前的log數據一定已經刷回磁盤,當數據庫宕機時,只需要將checkpoint之后的log回放即可,數據庫會定時做checkpoint,這樣就保證了數據庫恢復的效率。

但是考慮到如果硬件故障時機器無法啟動,或者磁盤故障時數據無法恢復,checkpoint+redo log方案也就不起作用了,為了防止這種故障,MySQL還提供了master-slave和group replication 集群級別的容災方案。?

Master-Slave架構主要思路是:master負責業務的讀寫請求,然后通過binlog復制到slave節點,這樣如果主庫因為不可抗拒因素無法恢復時,從庫可以提供服務,這里我們用了“復制“這個詞,而不是”同步“,因為基于binlog復制的方案并不能做到主從數據強一致,這種主從同步方式會導致主庫掛掉之后從庫有可能丟失少量的數據。

正是因為主從架構存在數據不一致的問題,所以MySQL5.7出現了Mysql Group Replication方案,mgr采用paxos協議實現了數據節點的強同步,保證了所有節點都可以寫數據,并且所有節點讀到的也是最新的數據。(原諒本人水平有限,說不清楚主從架構為什么會丟數據,也講不清楚mgr是怎么實現的,但是這里強烈推薦一本前司同事的書:《MySQL運維內參》,里面詳細解釋了Master-Slave和Group Replication 的架構,是深入理解Mysql的不二之選,據說本書的出現拉低了DBA的門檻,沒有任何打廣告的嫌疑^ ^)

HBase:


HBase的容災和MySQL的單機容災有些類似,但具體實現上還是很有自己的特點。在介紹HBase容災前,我們先來了解一下HBase和HDFS的關系:HBase中的數據都是存放在HDFS上,可以簡單理解HBase分為兩層:一層為NoSql service(即提供分布式檢索服務),一層是分布式文件系統(數據真正存放的位置,目前采用HDFS)。HBase中region分布在不同的regionserver上,client端通過meta表來定位數據在在哪個regionserver的region上,然后獲取數據,但是數據有可能并不一定在該regionserver本地保存,每個region都知道自己對應的數據在HDFS的哪些數據塊上,最后通過訪問HDFS來獲取數據,尤其當HBase和HDFS部署在不同的集群上時,數據的讀寫完全是通過RPC來實現,為了減少RPC的開銷,保證服務穩定,往往會將HBase和HDFS部署在同一個集群。同理,當一個regionserver掛了,region可以快速切換到別的regionserver上,因為只涉及到回放Log,并不會移動已經落盤的數據,而且HBase也會控制log的大小,來減少恢復時間

HBase也是采用寫log的方式防止數據丟失,數據寫內存的同時,同時也會寫入HLog,HLog也是存儲在HDFS上,寫入HLog后才會認為數據寫成功,某個regionserver掛掉之后,master將故障機器上的regions調度到別的regionserver上,regionserver通過回放HLog來恢復region的數據,恢復成功后,region重新上線,由于log是直接寫在HDFS上,所以不用擔心單個節點掛掉log數據丟失的問題。

這里引出一個問題:回放HLog的時候,正在被恢復的region會短時間不可用,直到HLog回放成功。HBase1.0版本中加入了region replicas功能,也就是提供一個slave region,當主region掛掉的時候,依然可以通過slave replicas來讀數據,但是slave不提供write,而且slave replicas和primary region并不是強同步的,并不一定總能讀到最新的數據,所以開啟該功能時,也要考慮自己業務是否必須要求強一致。

HBase也提供了cluster replication,目的是為了做機房級的容災,boss說現在cluster replication功能還有些bug,目前也在積極優化改進,相信以后會cluster replication會越來越完善。

ES:


ES的容災也是采用寫log的方式,與HBase不同的是,ES的節點保存各自的log,這點跟MySQL類似,log是存放在本地的,這也就存在和MySQL一樣的問題,假如機器宕機或硬盤故障,log數據也會丟失,所以index每個shard也有主備,默認配置是一個primary shard,一個replica shard,當然也可以配置多個replica。

默認情況下:primary shard首先接收client端發送過來的數據,然后將數據同步到replica shard中,當replica shard也寫入成功后,才會告知client數據已正確寫入,這樣就防止數據還沒寫入replica shard時,primary掛掉導致的數據丟失。

又到了提問環節,如果有一個replica節點出了問題,比如網絡故障無法寫入,那豈不是數據一直寫入不成功了?所以ES的master維護了一個in-sync set,里面保存了目前存活、且與primary同步的replica集合,只要set中的replica同步完成即認為數據寫入成功。考慮到一種情況:所有的replica因為網絡故障都下線了,in-sync set此時為空,數據只在primary中保留一份,很有可能因primary故障而導致丟數據,所以ES新增了wait_for_active_shards參數,只有當存活的replica數大于該參數時,才能正常寫入,若不滿足,則停止寫服務。

(這是5.X版本的實現,由于ES版本更新過快,這和2.X之前的版本有些差異,5.X中in-sync set的方式和Kafka的容災模式非常類似,但和Kafka有一點區別:ES的primary負責寫服務,但是primary和replica都可以提供讀服務,而Kafka只有primary partition提供讀寫服務,replica只是同步primary上的數據,并不提供讀。具體為什么Kafka不用replica提供讀服務,大家可以思考一下哈。而ES 2.X之前版本的容災更像ZK,采用quorum的方式,如果不對請指正)

使用場景


說了這么多,其實還是希望對MySQL,HBase,ES各自的實現做下對比,方便我們根據業務特點選擇最合適的存儲、檢索方案。下面說一下筆者在工作中使用的經驗:

MySQL在三款中最為成熟,而且支持事務,支持二級索引,容災備份方案也最為成熟,所以線上核心業務Mysql是不二之選(當然如果不差錢,Oracle也挺不錯,而且出問題自己解決不了的話,打電話就可以了,手動斜眼)。

HBase因為其強大的寫入能力和水平擴展能力,比較適合存儲日志,用戶行為等數據量比較大的數據,這種數據一般不涉及事務級別的讀寫,對二級索引的需求也不是很高。而且HBase的主鍵不像Mysql,往往是涉及到業務邏輯的,如果查詢條件單一的話,可以把直接把需要查詢的字段作為主鍵的一部分,類似MySQL的聯合索引,來提供檢索功能。

ES現在不僅提供全文檢索,還提供統計功能,并且提供的Restful接口非常好用,配上Kibana還可以進行圖形化展示,第三方插件也很豐富。雖然ES可以水平擴展,但是考慮到ES的大部分檢索都會檢索該index的所有shard,如果單個index數據過大,性能多少也會受到影響,所以單個index的大小最好控制在一定的范圍,比如存儲用戶行為日志的index,可以每隔一段時間歸一次檔,創建新的index,做到冷熱分離。而且ES也可以作為MySQL或HBase的索引來使用,雖然Mysql也有索引功能,但是過多的索引往往會拖累MySQL的性能,并且線上MySQL數據庫一般也不允許執行統計類的sql,這時可以用ES輔助實現統計,HBase因為只有主鍵檢索,所以更需要二級索引的功能。

舉一個筆者前司組合使用的場景:trace系統的log數據以HBase作為主要存儲,同時最近三個月的數據也在ES里面保留一份,ES主要用來完成各種復雜檢索、統計。但數據同步需要業務自己實現,當然trace業務對一致性要求不那么高,也可以忽略這個問題。

tip:將數據庫的數據向ES中同步的時候,因為網絡延遲等問題,到達的順序可能會亂序,這時老數據有可能會覆蓋新的數據,ES提供了一個version功能,可以將數據的timestamp作為version值,防止舊version的數據覆蓋新version的數據。

展望

傳統的關系型數據庫有著強大的事物處理能力,滿足了大部分線上業務需求,但是水平擴展性一直是一個頭疼的問題,NoSql數據庫雖然解決了水平擴展問題,但是功能太單一,現在越來越多的公司開始著手研究新一代NewSQL數據庫,結合了關系型數據庫的優點外還擁有水平擴展能力,比如淘寶的Oceanbase,PingCAP的TiDB,國外的CockroachDB,讓我們做好擁抱NewSQL的準備吧。

下一篇聊一聊實時計算^ ^。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,606評論 6 533
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,582評論 3 418
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,540評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,028評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,801評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,223評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,294評論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,442評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,976評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,800評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,996評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,543評論 5 360
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,233評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,662評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,926評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,702評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,991評論 2 374

推薦閱讀更多精彩內容