超越批處理的世界——流式計算(1)

超越批處理的世界——流式計算(1)

本文來自我的個人博客 https://www.zhangshenghai.com/posts/58781/

作者:Tyler Akidau

譯者:shenghaishxt

原文:https://www.oreilly.com/ideas/the-world-beyond-batch-streaming-101

如今天通,流式數(shù)據(jù)處理在大數(shù)據(jù)中十分重要熄驼,這里有幾個原因像寒,如下:

  • 商業(yè)競爭渴望更加及時的數(shù)據(jù),而使用流計算能夠有效地實現(xiàn)低延遲瓜贾。
  • 大量的诺祸、無限的數(shù)據(jù)集在現(xiàn)代商業(yè)領(lǐng)域變得越來越常見,如果我們使用專門設(shè)計用來處理這些無限數(shù)據(jù)的系統(tǒng)筷笨,那么這樣的處理會變得更加輕松。
  • 在數(shù)據(jù)到達(dá)前對其進(jìn)行流式處理能夠?qū)崿F(xiàn)負(fù)載均衡实束,實現(xiàn)更好的一致性以及可預(yù)測的資源消耗奥秆。

盡管這樣的商業(yè)驅(qū)動使得人們對于流式計算的興趣大大增加,但是相對于已經(jīng)在這個領(lǐng)域取得了許多令人激動的咸灿、積極的發(fā)展的批處理來說构订,流式計算仍然表現(xiàn)的不成熟。

對于一個在谷歌的大規(guī)模流式計算系統(tǒng)工作了超過五年的員工來說(曾經(jīng)開發(fā)過MillWheel和Cloud Dataflow)避矢,我非常開心能夠見證如今流式計算的熱潮悼瘾。我也對幫助人們理解關(guān)于流計算系統(tǒng)的方方面面以及如何最好地使用它感興趣,尤其是在現(xiàn)有的批處理系統(tǒng)和流處理系統(tǒng)大多存在語義上的鴻溝的情況下审胸。因此亥宿,O’Reilly的編輯邀請我寫篇稿子談?wù)勎矣?015年在Strata+Hadoop World倫敦大會上的演講《對批處理說再見》的一些看法。由于我有相當(dāng)多的內(nèi)容需要敘述砂沛,因此我把它們分成兩個部分:

  1. 流式計算(1):在深入討論關(guān)于時間域和高層次數(shù)據(jù)處理(包括批處理和流處理)的細(xì)節(jié)之前烫扼,第一篇文章將會涉及一些基本的背景信息并且說清楚一些基礎(chǔ)的術(shù)語。
  2. 數(shù)據(jù)流模型:第二篇文章主要包括云數(shù)據(jù)流模型使用的關(guān)于統(tǒng)一批處理和流式計算模型的速覽碍庵,我們通過各種實際例子來進(jìn)行解讀映企。之后,我會將現(xiàn)有地批處理系統(tǒng)和流處理系統(tǒng)進(jìn)行一個簡潔的語義比較静浴。

背景

在開始介紹前堰氓,我將會介紹一些重要的背景信息,這將會幫助我們理解剩余一些我們還未討論的背景知識苹享。我們將會分成三個不同的部分來討論:

  • 術(shù)語:為了能夠精確地談?wù)搹?fù)雜的術(shù)語双絮,我們需要對術(shù)語進(jìn)行精確地定義。對于一些如今已經(jīng)被濫用了的術(shù)語,在談?wù)摰綍r我也會精確地定義它們囤攀。
  • 功能:我會對流式系統(tǒng)的一些經(jīng)常性的缺點(diǎn)進(jìn)行評論软免。我也會提出數(shù)據(jù)處理系統(tǒng)的建造者們需要的思維框架,從而解決現(xiàn)代數(shù)據(jù)消費(fèi)者不斷增長的需求焚挠。
  • 時間域:我將會介紹兩個與數(shù)據(jù)處理相關(guān)的關(guān)于時間的主要概念或杠,解釋它們是如何聯(lián)系,并且指出關(guān)于這兩個時間域帶來的難題宣蔚。

術(shù)語

在進(jìn)一步深入之前,我希望先解決一個問題:什么是流計算认境?如今我們使用“流計算”這個術(shù)語來表示著各種各樣的事情(簡單來說胚委,在某種程度上我在很隨意地使用它),這會導(dǎo)致我們對于流計算的誤解叉信,或者是我們不知道流計算到底能夠做些什么亩冬。因此,我寧愿先定義好“流計算”硼身。

問題的關(guān)鍵是硅急,許多術(shù)語應(yīng)該被描述為它們本該成為的樣子(例如,無限數(shù)據(jù)處理佳遂,近似結(jié)果营袜,等等),但卻被描述成它們過去所被描述成的樣子(例如丑罪,通過流計算執(zhí)行的引擎)荚板。缺乏在術(shù)語上的精確定義模糊了流計算真實的意義,在某些情況下吩屹,流計算系統(tǒng)本身還帶有某種暗示跪另,暗示著這種系統(tǒng)的能力被限制,常被冠以“流”的特征煤搜,例如近似或推測結(jié)果免绿。鑒于設(shè)計良好的流計算系統(tǒng)與現(xiàn)有的批處理系統(tǒng)相比,同樣擁有產(chǎn)生正確性擦盾、一致性和可重復(fù)性結(jié)果的能力嘲驾,我更喜歡把“流計算”這個術(shù)語定義為一個非常明確的意義:一種設(shè)計時考慮了無限數(shù)據(jù)集的數(shù)據(jù)處理引擎。僅此而已厌衙。(為了實現(xiàn)完整性距淫,值得強(qiáng)調(diào)的是這個定義包含了真正的流計算和微批處理的實現(xiàn)。)

至于關(guān)于流計算的其他一般的用途婶希,這兒有一些我經(jīng)常聽到且每一個都有著更加具有精確性和描述性的術(shù)語榕暇,作為同一個社區(qū),我建議我們應(yīng)該采用這些術(shù)語。

  1. 無限數(shù)據(jù):一種持續(xù)增長的彤枢、實際上是無限的一種數(shù)據(jù)集狰晚。它們經(jīng)常被稱為“流數(shù)據(jù)”。然而在應(yīng)用于數(shù)據(jù)集的時候缴啡,流處理或批處理這樣的術(shù)語是有問題的壁晒,如上所說,這就暗示著用某一種類型的執(zhí)行引擎來處理那些數(shù)據(jù)业栅。這兩種類型的數(shù)據(jù)集之間的關(guān)鍵區(qū)別實際上是它們的有限性秒咐,所以最好用術(shù)語來描述它們從而研究這種區(qū)別。因此碘裕,我更喜歡把“流式”數(shù)據(jù)集稱為無限數(shù)據(jù)集携取,并且把“批次”數(shù)據(jù)集稱為有限數(shù)據(jù)集。
  2. 無限數(shù)據(jù)處理:一種不斷向前發(fā)展著的數(shù)據(jù)處理模式帮孔,應(yīng)用于前面所提及的無限數(shù)據(jù)雷滋。盡管我個人喜歡用“流”這個術(shù)語來描述這種類型的數(shù)據(jù),但是在本文再次使用它意味著使用流式處理引擎文兢,這是十分具有誤導(dǎo)性的晤斩。自從批處理系統(tǒng)被構(gòu)思出來以后,批處理引擎的循環(huán)處理就用于處理無限數(shù)據(jù)(相反姆坚,設(shè)計良好的流式系統(tǒng)比批處理系統(tǒng)更有能力處理有限數(shù)據(jù))澳泵。所以為了使文章更加清晰,我簡單將其稱為無限數(shù)據(jù)處理兼呵。
  3. 低延遲烹俗、近似和/或推測結(jié)果:這種類型的結(jié)果經(jīng)常與流式引擎聯(lián)系在一起。在傳統(tǒng)上萍程,批處理系統(tǒng)并不是設(shè)計來實現(xiàn)低延遲幢妄、近似和/或推測結(jié)果的,但這并不是說它不可以茫负。當(dāng)然蕉鸳,批處理引擎更有能力得到近似結(jié)果。因此忍法,在討論了上列術(shù)語之后潮尝,再來描述這些結(jié)果是什么(低延遲、近似和/或推測)饿序,而不是通過歷史表現(xiàn)(流式引擎)來描述勉失。

在這之后,無論我在哪里用到“流計算”這個術(shù)語原探,你都能夠理解為這是一種設(shè)計用來處理無限數(shù)據(jù)集的一種執(zhí)行引擎乱凿,僅此而已顽素。當(dāng)我使用上述的任何術(shù)語時,我將會明確其是無限數(shù)據(jù)徒蟆、無限數(shù)據(jù)處理還是低延遲胁出、近似和/或推測結(jié)果。在云數(shù)據(jù)流中段审,這些是我們已經(jīng)采用的術(shù)語全蝶,我鼓勵大家使用相同的術(shù)語。

關(guān)于流式計算極其夸張的限制

下一步寺枉,讓我們討論流式系統(tǒng)可以做什么以及不可以做什么抑淫,重點(diǎn)是可以做什么。我希望實現(xiàn)的其中一件最重要的事情是討論一個設(shè)計良好的流式系統(tǒng)能夠做什么事情姥闪。流式系統(tǒng)長期被認(rèn)為是給市場提供低延遲丈冬、近似和/或推測結(jié)果,常常與批處理系統(tǒng)結(jié)合從而提供最終正確的結(jié)果甘畅。例如:Lambda架構(gòu)。

對那些不熟悉Lambda架構(gòu)的讀者來說往弓,其基本思想是在運(yùn)行流處理系統(tǒng)的同時運(yùn)行批處理系統(tǒng)疏唾,兩者都執(zhí)行本質(zhì)上一樣的計算。流處理系統(tǒng)提供低延遲函似、不精確的結(jié)果(要么是因為使用了近似算法槐脏,要么是因為流處理系統(tǒng)本身就不提供正確性),一段時間后批處理系統(tǒng)計算完成并且提供正確的輸出撇寞。Lambda架構(gòu)最初由推特的Nathan Marz提出顿天,他是Storm的創(chuàng)始人,這種方法最后取得了很大的成功蔑担,事實上牌废,這在當(dāng)時的確是非常好的主意。不過啤握,流處理系統(tǒng)在正確性方面有些令人失望鸟缕,而批處理系統(tǒng)又是那樣固有的不靈活,所以Lambda就給我們一套現(xiàn)成的方案解決這個問題排抬。不幸的是懂从,維護(hù)這個系統(tǒng)比較麻煩,你需要構(gòu)建蹲蒲、規(guī)定和維護(hù)兩套獨(dú)立的管道番甩,然后以某種方式融合這兩個管道的最終結(jié)果。

當(dāng)我在一個強(qiáng)一致的流引擎中工作了幾年之后届搁,我也發(fā)現(xiàn)整個Lambda架構(gòu)是有些問題的缘薛。不出所料窍育,當(dāng)Jay Krep的《質(zhì)問Lambda架構(gòu)》未出版前,我就是它的狂熱粉絲掩宜。下面是反對雙模式處理系統(tǒng)的必要性的陳述理由之一蔫骂。克雷普通過使用可重用系統(tǒng)牺汤,例如Kafka作為流計算的連接點(diǎn)來處理重復(fù)性問題辽旋。這意味著使用一個設(shè)計良好的系統(tǒng)來運(yùn)行管道,處理Lambda的任務(wù)檐迟。我不認(rèn)為這個概念本身需要一個名字补胚,但是我原則上完全支持這個主意。

實話說追迟,我希望更進(jìn)一步溶其。我認(rèn)為設(shè)計良好的流式系統(tǒng)實際上提供一種嚴(yán)格的超集給批處理。模數(shù)也許是個效率增量敦间,像今天這樣存在著的批處理系統(tǒng)不再必要瓶逃。Flink的員工基于這種想法建造了一個完全使用流計算的系統(tǒng),甚至同時支持批處理模式廓块。我愛它厢绝。

必然的結(jié)果是廣泛成熟的流式系統(tǒng)結(jié)合了具有魯棒性的框架能夠應(yīng)用于無限數(shù)據(jù),同時带猴,允許Lambda架構(gòu)回到屬于它的大數(shù)據(jù)歷史進(jìn)程中昔汉。我相信這個時刻會成為現(xiàn)實,我們只需要做到這兩件事拴清,就可以在批處理擅長的領(lǐng)域打敗批處理:

正確性——這使流處理引擎和批處理引擎能夠等同

本質(zhì)上靶病,正確性最終歸結(jié)于一致的存儲。流式計算系統(tǒng)需要一種檢查長久一致性的方法(Kreps曾在他的文章——《為什么本地狀態(tài)是流式處理的基礎(chǔ)》中談到過這個問題)口予,由于機(jī)器故障仍然存在娄周,這個系統(tǒng)必須被設(shè)計得足夠好來保持一致性。幾年前沪停,當(dāng)Spark流計算第一次出現(xiàn)在公眾大數(shù)據(jù)領(lǐng)域中昆咽,它就像一座燈塔照亮了黑暗的流世界。幸運(yùn)的是牙甫,從那以后情況改善了很多掷酗。但是仍然有許多流式系統(tǒng)在沒有強(qiáng)一致性的情況下繼續(xù)嘗試取得成功。我完全無法相信“至多一次處理”這樣的處理方式依然存在窟哺。

再次重申泻轰,以下原因十分重要:“只處理一次”這個標(biāo)準(zhǔn)需要強(qiáng)一致性,這是正確性的要求且轨,對于有機(jī)會超越批處理系統(tǒng)的流式系統(tǒng)來說浮声,這也是必須的虚婿。除非你真正不在意你的結(jié)果的正確性,否則我還是建議你避開任何不能提供強(qiáng)一致性的流式系統(tǒng)泳挥。如果批處理系統(tǒng)有能力計算出正確的結(jié)果然痊,那么它也不會要求你提前檢查和確認(rèn),別把時間浪費(fèi)在那些達(dá)不到這種能力的流式系統(tǒng)上屉符。

如果你對于在流式系統(tǒng)中如何獲取強(qiáng)一致性有疑問剧浸,我建議你查閱MillWheel和Spark Streaming里的相關(guān)論文。它們都花費(fèi)了大量的篇幅講解一致性矗钟∷粝悖考慮到關(guān)于這個主題的信息也有大量的文獻(xiàn)供參考,在下面的篇幅中我就不會再討論它了吨艇。

時間推理工具——這使流處理引擎超越批處理引擎

優(yōu)秀的時間推理工具對于無限躬它、存在事件時間偏差的無序數(shù)據(jù)是重要的。越來越多的現(xiàn)代數(shù)據(jù)集顯示出這樣的特征东涡,而現(xiàn)在的批處理系統(tǒng)(也包括大部分的流系統(tǒng))缺乏必要的工具來解決這些特性帶來的問題冯吓。我將會使用余下的篇幅以及下一章的大部分來重點(diǎn)介紹這個問題。

在開始之前疮跑,我們將會理解關(guān)于時間域的一些基本概念组贺,之后我們將會深入理解無限、存在事件時間偏差的無序數(shù)據(jù)的概念祸挪。我將會花費(fèi)本章剩余的篇幅來介紹批處理系統(tǒng)和流處理系統(tǒng)處理數(shù)據(jù)的一般方法。

事件時間和處理時間

對無限數(shù)據(jù)處理過程的進(jìn)行強(qiáng)有力的說明需要對于時間域的清晰的理解贞间。在任何數(shù)據(jù)處理系統(tǒng)中贿条,我們主要關(guān)心以下兩種時間域:

  • 事件時間,即事件實際發(fā)生的時間增热。
  • 處理時間整以,即系統(tǒng)中觀察事件發(fā)生的時間。

不是所有的場景都需要關(guān)注事件時間(如果你不需要事件時間的話峻仇,那你的工作就輕松多了)公黑,但是大部分場景都是需要的。讓我們舉一些例子吧摄咆,比如說在一段時間內(nèi)描述用戶的行為凡蚜,大多付費(fèi)應(yīng)用或者是許多類型的異常檢測。

在理想的世界里吭从,事件時間和處理時間永遠(yuǎn)是相等的朝蜘,當(dāng)事件發(fā)生的時候它就立即被處理了。然而事實并不是這么簡單的涩金,事件時間與處理時間的偏差不只是非零的谱醇,而常常是與輸入源暇仲、執(zhí)行引擎和硬件有關(guān)的一個可變化方程。以下因素能夠影響偏差:

  • 共享資源的限制副渴,例如網(wǎng)絡(luò)擁塞奈附、網(wǎng)絡(luò)分區(qū)或者是非專用環(huán)境下的共享CPU。
  • 軟件原因煮剧,例如分布式系統(tǒng)邏輯和爭用等斥滤。
  • 數(shù)據(jù)本身的特征,例如密鑰分配轿秧、吞吐率變化或無序變化(例如中跌,乘客在飛機(jī)落地后才把手機(jī)由飛行模式調(diào)為正常模式)。

所以菇篡,如果你在任何真實世界系統(tǒng)中繪制關(guān)于事件時間和處理時間的處理過程圖漩符,你通常會得到如同圖1中紅線一樣的內(nèi)容。

image

<center>圖1:時間域?qū)?yīng)的描述圖驱还。X軸代表系統(tǒng)中事件時間的完整性嗜暴,即事件發(fā)生在某一刻之前所發(fā)生的所有事件。Y軸代表處理時間的過程议蟆,即數(shù)據(jù)處理系統(tǒng)中處理數(shù)據(jù)時系統(tǒng)的時間闷沥。</center>

圖中斜率為1的黑線代表理想狀態(tài)下處理時間和事件時間是相等的,而紅線代表著真實情況咐容。在這個例子的初始階段舆逃,處理時間在系統(tǒng)中有一定的延遲,隨后在中期趨向于理想狀態(tài)戳粒,而在最后階段又出現(xiàn)了一些延遲路狮。理想線與紅線的水平距離即為處理時間和事件時間之間的偏差。本質(zhì)上蔚约,這種偏差就是由處理管道所引入的延遲奄妨。

事件時間和處理時間之間的描述圖并不是靜態(tài)的,這意味著當(dāng)在管道中觀察它們時苹祟,如果你關(guān)心事件時間(如事件實際上發(fā)生的時間)的話砸抛,那么你就不能只分析管道中觀察到的數(shù)據(jù),即處理時間树枫。不幸的是直焙,這現(xiàn)有大多數(shù)無限數(shù)據(jù)處理系統(tǒng)分析數(shù)據(jù)的方法(即大多數(shù)無限數(shù)據(jù)處理系統(tǒng)都按照處理時間來設(shè)計)。為了解決無限數(shù)據(jù)集無窮的特性砂轻,這些系統(tǒng)常常提供一種窗口來將輸入數(shù)據(jù)分塊箕般。我們將會在下面深度討論如何進(jìn)行分塊,但本質(zhì)上來說舔清,它們都是將一大塊數(shù)據(jù)集按照時間分成有限的塊丝里。

如果你在意正確性和數(shù)據(jù)中的事件時間曲初,那么你不能用處理時間來定義那些數(shù)據(jù)邊界(即處理時間窗口),但是仍然有許多現(xiàn)有的系統(tǒng)這樣做杯聚。在處理時間和事件時間不存在一致性關(guān)聯(lián)的情況下臼婆,有些按照事件時間分塊的數(shù)據(jù)可能會被分到錯誤的處理時間窗口下(由分布式系統(tǒng)內(nèi)在的延遲,或是許多在線/離線的數(shù)據(jù)源類型的延遲引起)幌绍,在處理時間窗口下颁褂,正確性無法保證。我會在下面一篇文章中舉大量例子傀广,從而更加詳細(xì)地講解這個問題颁独。

不幸的是,當(dāng)使用事件窗口分塊時伪冰,得出的圖片似乎也不太樂觀誓酒。在無限數(shù)據(jù)的環(huán)境下,無序和變化的偏差為事件時間窗口引入了完整性問題:在處理時間和事件時間之間缺少可預(yù)測的映射贮聂,在給定處理時間X的情況下靠柑,你如何決定是否已經(jīng)觀察到了所有的數(shù)據(jù)?對于大多數(shù)真實數(shù)據(jù)源來說吓懈,你沒有辦法歼冰。如今使用中的大多數(shù)數(shù)據(jù)處理系統(tǒng)都依賴于某種完整性的概念,但是在應(yīng)用于無限數(shù)據(jù)集的時這樣的缺點(diǎn)是十分嚴(yán)重的耻警。

我的建議是不再嘗試將無限數(shù)據(jù)分成有限次的最終具有完整性的數(shù)據(jù)隔嫡,而是應(yīng)該設(shè)計一種能夠允許我們處理不確定的復(fù)雜數(shù)據(jù)的工具。當(dāng)新數(shù)據(jù)到來時甘穿,老數(shù)據(jù)將會被撤銷或更新腮恩,而且我們建造的任何系統(tǒng)都應(yīng)該有能力解決這些情況,不斷將完整性概念進(jìn)行方便的優(yōu)化扒磁,而不是語義上的需要庆揪。

在我們深入討論如何使用Cloud Dataflow中的Dataflow Model建造這樣的系統(tǒng)之前式曲,讓我們先了解一個更有用的背景概念:常用的數(shù)據(jù)處理模式妨托。

數(shù)據(jù)處理模式

目前為止,我們已經(jīng)擁有了足夠的背景吝羞,足以讓我們開始關(guān)注于如今有限數(shù)據(jù)處理和無限數(shù)據(jù)處理的常見的核心模型兰伤。我們將會在這兩種引擎(流計算和批處理)的情況下,著重討論這兩種處理模式钧排,我把微批處理模式與流處理歸為一類敦腔。因為在這個層面上它們之間的差異并不是十分重要。

有限數(shù)據(jù)

處理有限數(shù)據(jù)是十分直接的恨溜,并且對于每個人來說都很熟悉符衔。在下圖中找前,我們首先從左邊的非結(jié)構(gòu)化的數(shù)據(jù)著手。我們通過一些數(shù)據(jù)處理引擎來處理它(典型的是批處理判族,不過設(shè)計優(yōu)秀的流處理也可以完成得同樣好躺盛,例如MapReduce),然后得到右邊新的有著完好結(jié)構(gòu)化的數(shù)據(jù)以及其內(nèi)在的價值形帮。

image

<center>圖2:使用經(jīng)典批處理引擎處理有限數(shù)據(jù)槽惫。左側(cè)的有限非結(jié)構(gòu)化數(shù)據(jù)在經(jīng)過數(shù)據(jù)處理引擎后,得到右側(cè)對應(yīng)的結(jié)構(gòu)化數(shù)據(jù)辩撑。</center>

當(dāng)然界斜,當(dāng)你使用這個模型來進(jìn)行計算的時候,當(dāng)中會有無數(shù)種變化合冀,但是總體來說這個模型是十分簡單的各薇。更有趣的是處理無限數(shù)據(jù)集的任務(wù)。現(xiàn)在讓我們看看處理無限數(shù)據(jù)集的各種典型方式水慨。我們從使用傳統(tǒng)的批處理引擎的方法開始得糜,最后以專門為無限數(shù)據(jù)集設(shè)計的系統(tǒng)所使用的方法結(jié)束,如流引擎或微批處理引擎晰洒。

無限數(shù)據(jù)——批處理

盡管批處理引擎并不是為無限數(shù)據(jù)量身定做的朝抖,但是自從批處理系統(tǒng)被構(gòu)思出來時,批處理系統(tǒng)就一直用于處理無限數(shù)據(jù)集谍珊。我們可以想象治宣,這樣的方法將無限數(shù)據(jù)切分成一系列的有限數(shù)據(jù)集,以便其方便為批處理引擎處理砌滞。

固定窗口

最常見的處理無限數(shù)據(jù)集的方法多次重復(fù)將輸入數(shù)據(jù)分割成一個個固定的窗口侮邀,然后將每一個窗口作為一個獨(dú)立的、有限的數(shù)據(jù)源進(jìn)行處理贝润。特別是對于像日志這樣的輸入數(shù)據(jù)源绊茧,在這里事件能被記錄到文件系統(tǒng)中的層級中,日志的名字就對應(yīng)了它的窗口打掘。其實在數(shù)據(jù)建立之前华畏,系統(tǒng)實際上就已經(jīng)基于事件時間把數(shù)據(jù)記錄到對應(yīng)的時間窗口中。

實際上尊蚁,大多數(shù)系統(tǒng)仍然需要解決完整性問題:倘若由于網(wǎng)絡(luò)的故障導(dǎo)致你的事件被延遲了怎么辦亡笑?倘若你的事件在處理之前都要被傳送到一個通用的地點(diǎn)怎么辦?倘若你的事件是來自移動設(shè)備怎么辦横朋?這些情況都意味著我們需要用一些特別的方法處理它們(例如延遲處理事件直到你確認(rèn)所有的事件都已經(jīng)到達(dá)仑乌,或者當(dāng)數(shù)據(jù)遲到時就在給定的窗口內(nèi)對所有數(shù)據(jù)進(jìn)行再次處理)。

image

<center>圖3:使用經(jīng)典批處理引擎通過固定窗口處理無限數(shù)據(jù)。一個無限數(shù)據(jù)集被分為有限的晰甚、窗口固定的有限數(shù)據(jù)集衙传,然后通過經(jīng)典的批處理引擎來對其進(jìn)行連續(xù)處理。</center>

會話單元

如果你要用批處理引擎將無線數(shù)據(jù)劃分為更加復(fù)雜的窗口(如會話單元)厕九,以上方法會失效粪牲。會話單元通常被定義為活動(例如特定的用戶)的周期,以一段不活躍的時間來作為結(jié)束的標(biāo)志止剖。當(dāng)使用經(jīng)典的批處理引擎來計算會話單元時腺阳,你常常會看到會話單元被分到不同的批次中,如下圖紅色的標(biāo)注所示穿香。這些裂縫的數(shù)量可以通過增加批次的大小來減少亭引,但這樣做的話會增大延遲。另一個選擇是增加額外的邏輯來拼接上一批的會話單元皮获,但是這樣會大大增加復(fù)雜度焙蚓。

image

<center>圖4:使用經(jīng)典批處理引擎通過固定窗口處理無限數(shù)據(jù)。一個無界的數(shù)據(jù)集被收集到有限的固定大小的有界數(shù)據(jù)窗口中洒宝,然后通過連續(xù)運(yùn)行一個經(jīng)典的批處理將這些有界數(shù)據(jù)劃分為動態(tài)會話窗口购公。</center>

無論使用哪種方式,使用批處理引擎計算會話窗口并不是十分理想的雁歌。更好的方法是以流的方式建立會話宏浩,我們將會在之后進(jìn)行講解。

無限數(shù)據(jù)——流式計算

與基于批處理的無限數(shù)據(jù)處理方法的臨時特性相反靠瞎,流系統(tǒng)專門為無限數(shù)據(jù)所建造比庄。我先前說過,在大多數(shù)真實世界里分布式輸入源中乏盐,你不僅僅需要解決無限數(shù)據(jù)的問題佳窑,還要解決:

  • 基于事件時間的高度無序性,這意味著如果你想要按照事件時間來分析數(shù)據(jù)的話父能,你需要處理時序問題神凑。
  • 事件時間變化的時間差,這意味著在一個常量Y時間內(nèi)何吝,你無法假設(shè)看到對應(yīng)給定的事件時間X內(nèi)發(fā)生的所有數(shù)據(jù)溉委。

以下有多種能夠解決這樣特性的數(shù)據(jù)的方法,我通常把它們歸為以下幾類:

  • 時間不可知
  • 近似算法
  • 按處理時間分片
  • 按事件時間分片

我們現(xiàn)在將花費(fèi)一些時間來講解每一種方法岔霸。

時間不可知

時間不可知處理本質(zhì)上跟時間沒有關(guān)系薛躬,其所有的關(guān)聯(lián)邏輯是數(shù)據(jù)本身俯渤。這些情況下只關(guān)心更多數(shù)據(jù)的到達(dá)呆细,因此并不需要使用流引擎對其進(jìn)行特殊的支持,只需要保證基本的數(shù)據(jù)傳送就足夠了。所以絮爷,本質(zhì)上所有的流系統(tǒng)都支持時間不可知(對于那些對于正確性有要求的場景來說趴酣,還需要排除不支持強(qiáng)一致的系統(tǒng))。通過簡單地將無限數(shù)據(jù)源切分成一系列有限數(shù)據(jù)集坑夯,然后獨(dú)立地處理這些有限數(shù)據(jù)集岖寞,批處理系統(tǒng)也同樣適用于處理時間不可知的無限數(shù)據(jù)源場景。我們將會講解一組這個領(lǐng)域中的具體的例子柜蜈,但由于處理時間不可知過程比較簡單仗谆,我們不會在這上面花太多時間。

過濾

時間不可知處理過程的一個非呈缏模基礎(chǔ)的形式是過濾隶垮。想象一個畫面,你在處理網(wǎng)絡(luò)流量日志秘噪,并且你想要過濾掉所有不來自某個特殊域的所有流量狸吞。那么你只要在每個記錄到達(dá)時,判定其是否來自那個特殊域指煎,來決定是留下還是丟棄蹋偏。在任何時間內(nèi),它都只決定于數(shù)據(jù)本身至壤,與數(shù)據(jù)源是否是無限的威始、是否是無序的以及事件的時間偏差沒有任何關(guān)系。

image

<center>圖5:無限數(shù)據(jù)的過濾像街。從左側(cè)流向右側(cè)的不同類型的數(shù)據(jù)在經(jīng)過過濾后字逗,成為均勻的、只包含一種類型的數(shù)據(jù)宅广。</center>

內(nèi)連接

另一種時間不可知的例子是內(nèi)連接(又名哈希連接)葫掉。當(dāng)連接兩個無限數(shù)據(jù)源時,如果你只關(guān)心這兩個無限數(shù)據(jù)源中共有的元素跟狱,那么它們的邏輯便是與時間無關(guān)的俭厚。當(dāng)你從其中一個數(shù)據(jù)源中得到一個值后,只需要將它緩存在一個持久的緩存里驶臊,然后等到另外一個數(shù)據(jù)源也傳來這個值挪挤,然后輸出它們善茎。(事實上悠菜,你可以會希望有一種垃圾回收裝置來處理那些沒有出現(xiàn)過的的與時間有關(guān)的連接元素。但是對于那些幾乎不出現(xiàn)不完全連接的例子嚷闭,這些就是小問題了纵寝。)

image

<center>圖6:對兩個無限數(shù)據(jù)源執(zhí)行內(nèi)連接论寨。在兩個數(shù)據(jù)源中都觀察到相同的匹配元素時,就執(zhí)行內(nèi)連接。</center>

如果語義成為了外連接葬凳,那么之前說過的完整性問題又會出現(xiàn):當(dāng)你看到連接的一邊绰垂,那你怎么能確定另外一邊能否出現(xiàn)?我必須告訴你火焰,你絕對不知道劲装,所以你不得不引入某種超時裝置,這就又涉及到了時間昌简。這種時間本質(zhì)是時間窗口分片占业,我們一會兒將會仔細(xì)研究它。

近似算法

image

<center>圖7:計算無限數(shù)據(jù)的近似值纯赎。數(shù)據(jù)經(jīng)過復(fù)雜的算法纺酸,會產(chǎn)生看起來或多或少像另一側(cè)的預(yù)期結(jié)果的輸出數(shù)據(jù)。</center>

第二類算法是近似算法址否,例如近似Top-N算法餐蔬、流式K-means算法等等。它們都是輸入無限數(shù)據(jù)佑附,然后提供給你輸出數(shù)據(jù)樊诺。這些近似算法的優(yōu)點(diǎn)是在通過設(shè)計之后,它們的開銷比較低音同,適合用于處理無限數(shù)據(jù)词爬。但它們也有缺點(diǎn),缺點(diǎn)是它們的數(shù)量有限权均,且實現(xiàn)復(fù)雜顿膨。近似的特性同時限制了它們的實用性。

值得一提的是叽赊,這些算法本質(zhì)上是有一些時間域的特性(例如恋沃,某種衰退機(jī)制)。與此同時必指,這些方法一般都在數(shù)據(jù)到達(dá)之后進(jìn)行處理囊咏,因此它們通常是用處理時間。對于那些能夠提供證明錯誤范圍的算法來說塔橡,這是十分重要的梅割。如果算法能夠通過數(shù)據(jù)到達(dá)的順序來預(yù)測錯誤的界限,那么就算是事件-時間漂移有變化葛家,對于無限數(shù)據(jù)來說都是可以忽略不計的了户辞。這是需要注意的一點(diǎn)。

近似算法本來是一個很有趣的話題癞谒,但是本質(zhì)上近似算法是一種時間不可知(如果不考慮它們自身的時間特征的話)底燎。它們使用起來相當(dāng)簡單刃榨,所以我們不再詳細(xì)介紹了。

時間窗口分片

其他兩個無限數(shù)據(jù)處理的方法也是事件窗口分片书蚪。在深入介紹它們的差異之前,我會花一些時間來講清楚時間窗口分片的具體含義迅栅。對于一個輸入數(shù)據(jù)源來說(無論是有限還是無限)殊校,分片就是按照時間區(qū)間把數(shù)據(jù)分成有限片再進(jìn)行處理。下圖展示了三種不同的分片模式读存。

image

<center>圖8:不同的分片模式为流。每個例子都包括了三個不同的鍵,并且突出顯示了窗口對齊(對于所有的數(shù)據(jù)都適用)以及窗口不對齊(只適用于數(shù)據(jù)子集)让簿。</center>

  • 固定窗口:固定窗口按照固定長度的時間進(jìn)行分片敬察。通常情況下(如圖8所示),固定窗口的分段適用于所有數(shù)據(jù)集尔当,這叫做對齊的窗口莲祸。在某些情況下,我們會希望對于不同的數(shù)據(jù)子集進(jìn)行不同的相位偏移椭迎,從而讓分片的完整度更加均勻锐帜。這就是非對齊窗口的一個示例,因為它們在數(shù)據(jù)之間變化畜号。
  • 滑動窗口:滑動窗口可以看做是固定窗口更一般的一個形式缴阎。滑動窗口由兩個量來定義:固定長度和固定周期简软。如果滑動時間比窗口小蛮拔,那么窗口重疊。如果滑動時間等于窗口痹升,那就是固定窗口建炫。如果滑動時間比窗口大,那么就會出現(xiàn)一種奇怪的采樣窗口疼蛾,即按照時間來看數(shù)據(jù)集的一部分子集數(shù)據(jù)踱卵。類似于固定窗口,滑動窗口通常是對齊的据过。但是在某些情況下可能會不對齊,這是為了性能的優(yōu)化绳锅。請注意西饵,圖8中的滑動窗口是為了給出滑動的感覺來繪制的;實際上鳞芙,所有的五個窗口都適用于整個數(shù)據(jù)集眷柔。
  • 會話單元:它是動態(tài)窗口的一個實例期虾。會話是在不活躍時間段的一連串事件,這個不活躍時間段通常比設(shè)定的超時時間長驯嘱。會話單元通常用于將一系列與時間相關(guān)的事件(例如一次觀看的視頻序列)分組在一起來隨時分析用戶的行為镶苞。會話單元很有趣,因為它們的長度無法事先定義鞠评,這完全取決于涉及的實際數(shù)據(jù)茂蚓。會話單元也是非對齊窗口的一個標(biāo)準(zhǔn)示例,因為在實際的情況下剃幌,不同子集數(shù)據(jù)的會話單元長度幾乎不可能一致地對齊聋涨。

我們討論的兩個領(lǐng)域——處理時間和事件時間是我們關(guān)心的兩個領(lǐng)域。窗口化在這兩個領(lǐng)域都是有意義的负乡,因此我們將詳細(xì)地討論每個領(lǐng)域牍白,看看它們有什么不同。由于按照處理時間進(jìn)行窗口分片是最普遍的抖棘,我們就從這里開始茂腥。

按照處理時間做時間窗口分片

image

<center>圖9:按照處理時間做時間窗口分片。根據(jù)它們到達(dá)管道的順序?qū)?shù)據(jù)收集到窗口中切省。</center>

當(dāng)按照處理時間做時間窗口分片時础芍,系統(tǒng)本質(zhì)上是將輸入的數(shù)據(jù)進(jìn)行緩存,在經(jīng)過一定的處理時間窗口之后再對緩存好的數(shù)據(jù)進(jìn)行處理数尿。例如仑性,在一個5分鐘的固定窗口中,系統(tǒng)會按照自己的系統(tǒng)時間緩存5分鐘以內(nèi)的數(shù)據(jù)右蹦,然后將這5分鐘內(nèi)的數(shù)據(jù)視為一個窗口诊杆,交由下一步的流程進(jìn)行處理。

用處理時間窗口分片有如下幾個很好的屬性:

  1. 簡單何陆。實現(xiàn)起來十分簡潔晨汹,你不用擔(dān)心隨著時間推移數(shù)據(jù)會失去順序,只需要在到達(dá)時將數(shù)據(jù)緩存贷盲,并在窗口關(guān)閉時將它們發(fā)送到下一步即可淘这。
  2. 判斷窗口的完整性很簡單。因為系統(tǒng)可以清楚地知道某窗口中的數(shù)據(jù)是否已經(jīng)全部被看到巩剖,所以數(shù)據(jù)的完整性很容易保證铝穷。這意味著,當(dāng)通過處理時間做時間窗口分片時佳魔,系統(tǒng)不需要以任何方式處理那些“遲到的”數(shù)據(jù)曙聂。
  3. 如果你關(guān)心的是事件被觀察到后的信息,那么按照處理時間做時間窗口分片就正是你所需要的方法鞠鲜。很多監(jiān)控場景都屬于這一類宁脊。比如你希望可以獲得某個網(wǎng)站的每秒請求量断国,再通過監(jiān)控這個數(shù)量來判斷網(wǎng)站是否有服務(wù)中斷,這時用處理時間做時間窗口分片就是最好的選擇榆苞。

除了這些優(yōu)點(diǎn)之外稳衬,這種方法也存在一個巨大的缺點(diǎn),即如果需要處理的數(shù)據(jù)具有與其相關(guān)的事件時間坐漏,而時間窗口需要反映數(shù)據(jù)的事件時間薄疚,那么這些數(shù)據(jù)就必須以事件時間的順序到達(dá)了。不幸的是仙畦,現(xiàn)實世界中输涕,按照事件時間排序并到達(dá)的數(shù)據(jù)幾乎是沒有的音婶。

我們來舉一個簡單的例子慨畸,想象一個手機(jī)中的應(yīng)用程序收集使用統(tǒng)計信息以供后期分析。當(dāng)手機(jī)在離網(wǎng)一段時間后(比如離開網(wǎng)絡(luò)衣式、處于飛行模式等)寸士,這期間記錄的數(shù)據(jù)就需要等到手機(jī)接入網(wǎng)絡(luò)后才能夠上傳。這就意味著數(shù)據(jù)可能會以幾分鐘碴卧、幾小時弱卡、幾天、幾周甚至更長的事件時間或者處理時間偏差到達(dá)住册。這時用處理時間做時間窗口分片就無法對這樣的數(shù)據(jù)進(jìn)行處理婶博。

再舉一個例子,許多分布式的數(shù)據(jù)源在系統(tǒng)正常的情況下能夠提供有序的事件時間的數(shù)據(jù)(或是接近有序)荧飞。不幸的是凡人,在系統(tǒng)健康得不到保證的時候就很難保證有序性了。比如某個處理多個大陸收集的數(shù)據(jù)的全球業(yè)務(wù)叹阔,洲際間的網(wǎng)絡(luò)帶寬一般都會受限(這是很常見的)挠轴,這時突然間一部分的輸入數(shù)據(jù)會比通常情況下更加晚到。如果繼續(xù)使用處理時間對數(shù)據(jù)做時間窗口分片耳幢,就無法有效反映出數(shù)據(jù)實際發(fā)生時的情景岸晦。相反,這時窗口內(nèi)的數(shù)據(jù)是一些任意組合的新舊數(shù)據(jù)睛藻。

在這兩種情況下启上,我們想要按照事件到達(dá)的順序按照事件時間進(jìn)行時間窗口分片,這樣才能保證數(shù)據(jù)到達(dá)的有序性店印。我們真正想要的是事件的時間窗口碧绞。

按照事件時間做時間窗口分片

當(dāng)你需要將事件按照發(fā)生時的時間分進(jìn)有限的塊內(nèi),那么就需要用到事件時間窗口吱窝。這是時間窗口分片的黃金標(biāo)準(zhǔn)讥邻。令人遺憾的是迫靖,目前大多數(shù)數(shù)據(jù)處理系統(tǒng)都缺乏對齊的本地支持(盡管支持強(qiáng)一致的系統(tǒng)(如Hadoop或Spark Streaming)經(jīng)過修改之后能夠支持這種方法)。

下圖顯示了一個將無限數(shù)據(jù)按照事件時間分片的實例兴使。

image

<center>圖10:按照事件時間用固定窗口分片系宜。根據(jù)數(shù)據(jù)發(fā)生的時間將數(shù)據(jù)收集到窗口中。白色箭頭將事件時間屬于同一個分片的數(shù)據(jù)放到同一個窗口中去发魄。</center>

圖中的白色箭頭線對應(yīng)著兩個特別的數(shù)據(jù)盹牧。這兩個數(shù)據(jù)都到達(dá)了處理時間窗口,但是與它們所屬的事件時間窗口不匹配励幼。因此汰寓,如果是按照處理時間來分片處理,但是我們關(guān)心的是事件發(fā)生時的信息苹粟,那么計算結(jié)果是不正確的有滑。正如人們所期望的那樣,用事件時間分片來保證事件時間計算的正確性是很好的嵌削。

這個方法來處理無限數(shù)據(jù)的另外一個好處就是你可以使用動態(tài)大小的窗口(如會話單元)毛好,不會出現(xiàn)在前面使用批處理引擎的時候,會話被分到兩個窗口內(nèi)的情況苛秕。

image

<center>圖11:按照事件時間窗口用會話單元做窗口分片肌访。將數(shù)據(jù)按照它們發(fā)生的時間和活動性收集到不同的會話窗口內(nèi)。白色箭頭將那些屬于同一個分片的數(shù)據(jù)放到同一個會話窗口中艇劫,按照正確的事件時間排序吼驶。</center>

當(dāng)然,強(qiáng)大的語義并不是免費(fèi)的店煞。按事件時間做時間窗口分片也不例外蟹演。由于窗口必須經(jīng)常比窗口本身的實際長度長,所以事件時間窗口有兩個明顯的缺點(diǎn):

  • 緩存:由于延長了窗口的使用壽命浅缸,需要更多的數(shù)據(jù)緩存轨帜。值得慶幸的是,持久性存儲已經(jīng)是大多數(shù)數(shù)據(jù)處理系統(tǒng)中最便宜的(其他的是CPU衩椒、網(wǎng)絡(luò)帶寬和RAM)蚌父。因此,這個問題沒有想象中的那么嚴(yán)重毛萌。而且苟弛,許多有用的聚合不要求將整個輸入集緩存起來(如總和、平均值)阁将,而是只要把中間的計算結(jié)果緩存下來然后遞增地累積就可以了膏秫。
  • 完整性:考慮到我們往往無法判定是否已經(jīng)收集到了一個窗口中的所有數(shù)據(jù),那么我們?nèi)绾沃朗裁磿r候才能將窗口中的數(shù)據(jù)交給下游去處理呢做盅?事實上缤削,我們根本就不知道窘哈。對于很多類型的輸入,系統(tǒng)可以通過類似MillWheel的水油じ摇(我們將在第二部分詳細(xì)討論它)給出合理準(zhǔn)確的完整性估計滚婉。但是對于正確性要求極高的場景中(如計費(fèi)),唯一真正的選擇是提供一個方法來讓引擎決定什么時候交出數(shù)據(jù)帅刀,以及如何讓系統(tǒng)不斷地修正結(jié)果让腹。處理窗口內(nèi)數(shù)據(jù)(或者缺少窗口)的完整性是一個十分令人感興趣的話題。但是最好能夠在一個具體的例子中來討論說明扣溺,我們下次再介紹骇窍。

結(jié)論

好吧!這篇包含太多信息了锥余。如果你已經(jīng)讀到這里的話:你應(yīng)該受到表揚(yáng)腹纳!在這一點(diǎn)上,我想這些大概是我想介紹內(nèi)容的一半哈恰。我們可以退一步只估,來回顧一下我們目前為止所學(xué)到的內(nèi)容志群,并且在進(jìn)入第二部分之前解決這些內(nèi)容着绷。盡管第一部分有些無聊,但令人興奮的是锌云,第二部分是樂趣真正開始的地方荠医。

回顧

總結(jié)一下,目前我已經(jīng)介紹了以下幾點(diǎn):

  1. 澄清術(shù)語桑涎,特別是將“流計算”的定義縮小為僅適用于執(zhí)行引擎彬向,同時使用了更多描述性術(shù)語,如將“無限數(shù)據(jù)”和近似/推測算法都放在流計算的概念下攻冷。
  2. 分析了精心設(shè)計的批處理系統(tǒng)和流計算系統(tǒng)娃胆,總結(jié)出流計算系統(tǒng)是批處理系統(tǒng)的功能超集,而像Lambda架構(gòu)這樣的概念最終會被流計算取代等曼。
  3. 提出了流計算系統(tǒng)所需的重要的兩個概念里烦,能夠幫助流計算追趕并最終超批處理:完整性和時間工具。
  4. 確定了事件時間和處理時間之間的重要差異禁谦,描述了這些差異在分析數(shù)據(jù)時出現(xiàn)的困難胁黑。根據(jù)完整性的概念,提出系統(tǒng)應(yīng)該適應(yīng)時間上的變化州泊,提供完整丧蘸、精確的結(jié)果。
  5. 分析了針對無限數(shù)據(jù)和有限數(shù)據(jù)的常用數(shù)據(jù)處理方法遥皂,主要通過批處理和流計算力喷。并且將無限數(shù)據(jù)的處理分為四類:時間不可知刽漂、近似、通過處理時間進(jìn)行窗口分片弟孟、通過事件時間進(jìn)行窗口分片爽冕。

下一步的內(nèi)容

本文提供了我們將在第二部分進(jìn)行探討的具體示例的基礎(chǔ)。第二部分大致包含以下內(nèi)容:

  • 從數(shù)據(jù)處理的概念上看披蕉,我們將從四個角度入手:什么颈畸、何處、何時以及怎么做没讲。
  • 詳細(xì)介紹如何在多個場景中處理簡單眯娱、具體的示例數(shù)據(jù)集,突出顯示數(shù)據(jù)流模型支持的多個用例以及涉及的具體API爬凑。這些例子將有助于推動本文介紹的事件時間和處理時間的概念徙缴,同時還將探索新的概念,如watermarks嘁信。
  • 比較現(xiàn)有的數(shù)據(jù)處理系統(tǒng)的重要特征于样,讓我們更好地選擇它們,并且鼓勵大家對它們進(jìn)行改善潘靖,幫助實現(xiàn)我們的最終目標(biāo):讓流計算成為大數(shù)據(jù)處理的最好的方式穿剖。

現(xiàn)在是個好時機(jī)∝砸纾回見糊余!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市单寂,隨后出現(xiàn)的幾起案子贬芥,更是在濱河造成了極大的恐慌,老刑警劉巖宣决,帶你破解...
    沈念sama閱讀 211,817評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蘸劈,死亡現(xiàn)場離奇詭異,居然都是意外死亡尊沸,警方通過查閱死者的電腦和手機(jī)威沫,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,329評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來椒丧,“玉大人壹甥,你說我怎么就攤上這事『” “怎么了句柠?”我有些...
    開封第一講書人閱讀 157,354評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我溯职,道長精盅,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,498評論 1 284
  • 正文 為了忘掉前任谜酒,我火速辦了婚禮叹俏,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘僻族。我一直安慰自己粘驰,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,600評論 6 386
  • 文/花漫 我一把揭開白布述么。 她就那樣靜靜地躺著蝌数,像睡著了一般。 火紅的嫁衣襯著肌膚如雪度秘。 梳的紋絲不亂的頭發(fā)上顶伞,一...
    開封第一講書人閱讀 49,829評論 1 290
  • 那天,我揣著相機(jī)與錄音剑梳,去河邊找鬼唆貌。 笑死,一個胖子當(dāng)著我的面吹牛垢乙,可吹牛的內(nèi)容都是我干的锨咙。 我是一名探鬼主播,決...
    沈念sama閱讀 38,979評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼侨赡,長吁一口氣:“原來是場噩夢啊……” “哼蓖租!你這毒婦竟也來了粱侣?” 一聲冷哼從身側(cè)響起羊壹,我...
    開封第一講書人閱讀 37,722評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎齐婴,沒想到半個月后油猫,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,189評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡柠偶,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,519評論 2 327
  • 正文 我和宋清朗相戀三年情妖,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片诱担。...
    茶點(diǎn)故事閱讀 38,654評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡毡证,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出蔫仙,到底是詐尸還是另有隱情料睛,我是刑警寧澤,帶...
    沈念sama閱讀 34,329評論 4 330
  • 正文 年R本政府宣布,位于F島的核電站恤煞,受9級特大地震影響屎勘,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜居扒,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,940評論 3 313
  • 文/蒙蒙 一概漱、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧喜喂,春花似錦瓤摧、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,762評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至诈茧,卻和暖如春产喉,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背敢会。 一陣腳步聲響...
    開封第一講書人閱讀 31,993評論 1 266
  • 我被黑心中介騙來泰國打工曾沈, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人鸥昏。 一個月前我還...
    沈念sama閱讀 46,382評論 2 360
  • 正文 我出身青樓塞俱,卻偏偏與公主長得像,于是被迫代替她去往敵國和親吏垮。 傳聞我的和親對象是個殘疾皇子障涯,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,543評論 2 349

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