美團(tuán)點(diǎn)評(píng) Flink 實(shí)時(shí)數(shù)倉(cāng)經(jīng)驗(yàn)分享

轉(zhuǎn)載:原文地址

實(shí)時(shí)數(shù)倉(cāng)建設(shè)目的

解決傳統(tǒng)數(shù)倉(cāng)的問(wèn)題

實(shí)時(shí)數(shù)倉(cāng)是一個(gè)很容易讓人產(chǎn)生混淆的概念。實(shí)時(shí)數(shù)倉(cāng)本身似乎和把 PPT 黑色的背景變得更白一樣患雏,從傳統(tǒng)的經(jīng)驗(yàn)來(lái)講,我們認(rèn)為數(shù)倉(cāng)有一個(gè)很重要的功能辈毯,即能夠記錄歷史陨舱。通常械荷,數(shù)倉(cāng)都是希望從業(yè)務(wù)上線的第一天開(kāi)始有數(shù)據(jù)罪塔,然后一直記錄到現(xiàn)在。但實(shí)時(shí)處理技術(shù)养葵,又是強(qiáng)調(diào)當(dāng)前處理狀態(tài)的一門(mén)技術(shù)征堪,所以我們認(rèn)為這兩個(gè)相對(duì)對(duì)立的方案重疊在一起的時(shí)候,它注定不是用來(lái)解決一個(gè)比較廣泛?jiǎn)栴}的一種方案关拒。于是佃蚜,我們把實(shí)時(shí)數(shù)倉(cāng)建設(shè)的目的定位為解決由于傳統(tǒng)數(shù)據(jù)倉(cāng)庫(kù)數(shù)據(jù)時(shí)效性低解決不了的問(wèn)題。由于這個(gè)特點(diǎn)着绊,我們給定了兩個(gè)原則:

  • 傳統(tǒng)數(shù)倉(cāng)能解決的問(wèn)題谐算,實(shí)時(shí)數(shù)倉(cāng)就不解決了。比如上個(gè)月的一些歷史的統(tǒng)計(jì)归露,這些數(shù)據(jù)是不會(huì)用實(shí)時(shí)數(shù)倉(cāng)來(lái)建設(shè)的洲脂。
  • 問(wèn)題本身就不太適合用數(shù)倉(cāng)來(lái)解決,也不用實(shí)時(shí)數(shù)倉(cāng)解決剧包。比如業(yè)務(wù)性很強(qiáng)的需求恐锦,或者是對(duì)時(shí)效性要求特別高的需求。這些需求我們也不建議通過(guò)實(shí)時(shí)數(shù)倉(cāng)這種方式來(lái)進(jìn)行解決疆液。

當(dāng)然為了讓我們整個(gè)系統(tǒng)看起來(lái)像是一個(gè)數(shù)倉(cāng)一铅,我們還是給自己提了一些要求的。這個(gè)要求其實(shí)跟我們建立離線數(shù)倉(cāng)的要求是一樣的堕油,首先實(shí)時(shí)的數(shù)倉(cāng)是需要面向主題的潘飘,然后具有集成性,并且保證相對(duì)穩(wěn)定掉缺。離線數(shù)倉(cāng)和實(shí)時(shí)數(shù)倉(cāng)的區(qū)別在于離線數(shù)據(jù)倉(cāng)庫(kù)是一個(gè)保存歷史累積的數(shù)據(jù)卜录,而我們?cè)诮ㄔO(shè)實(shí)時(shí)數(shù)倉(cāng)的時(shí)候,我們只保留上一次批處理到當(dāng)前的數(shù)據(jù)眶明。這個(gè)說(shuō)法非常的拗口艰毒,但是實(shí)際上操作起來(lái)還是蠻輕松的。通常來(lái)講解決方案是保留大概三天的數(shù)據(jù)赘来,因?yàn)楸A羧斓臄?shù)據(jù)的話现喳,可以穩(wěn)定地保證兩天完整的數(shù)據(jù),這樣就能保證犬辰,在批處理流程還沒(méi)有處理完昨天的數(shù)據(jù)的這段間隙嗦篱,依然能夠提供一個(gè)完整的數(shù)據(jù)服務(wù)。

實(shí)時(shí)數(shù)倉(cāng)的應(yīng)用場(chǎng)景

image
  • 實(shí)時(shí) OLAP 分析

OLAP 分析本身就非常適合用數(shù)倉(cāng)去解決的一類(lèi)問(wèn)題幌缝,我們通過(guò)實(shí)時(shí)數(shù)倉(cāng)的擴(kuò)展灸促,把數(shù)倉(cāng)的時(shí)效性能力進(jìn)行提升。甚至可能在分析層面上都不用再做太多改造涵卵,就可以使原有的 OLAP 分析工具具有分析實(shí)時(shí)數(shù)據(jù)的能力浴栽。

  • 實(shí)時(shí)數(shù)據(jù)看板

這種場(chǎng)景比較容易接受,比如天貓雙11的實(shí)時(shí)大屏滾動(dòng)展示核心數(shù)據(jù)的變化轿偎。實(shí)際上對(duì)于美團(tuán)來(lái)講典鸡,不光有促銷(xiāo)上的業(yè)務(wù),還有一些主要的門(mén)店業(yè)務(wù)坏晦。對(duì)于門(mén)店的老板而言萝玷,他們可能在日常的每一天中也會(huì)很關(guān)心自己當(dāng)天各個(gè)業(yè)務(wù)線上的銷(xiāo)售額。

  • 實(shí)時(shí)特征

實(shí)時(shí)特征指通過(guò)匯總指標(biāo)的運(yùn)算來(lái)對(duì)商戶或者用戶標(biāo)記上一些特征昆婿。比如多次購(gòu)買(mǎi)商品的用戶后臺(tái)會(huì)判定為優(yōu)質(zhì)用戶球碉。另外,商戶銷(xiāo)售額稿仓蛆,后臺(tái)會(huì)認(rèn)為該商戶商的熱度更高睁冬。然后,在做實(shí)時(shí)精準(zhǔn)運(yùn)營(yíng)動(dòng)作時(shí)可能會(huì)優(yōu)先考慮類(lèi)似的門(mén)店或者商戶看疙。

  • 實(shí)時(shí)業(yè)務(wù)監(jiān)控

美團(tuán)點(diǎn)評(píng)也會(huì)對(duì)一些核心業(yè)務(wù)指標(biāo)進(jìn)行監(jiān)控豆拨,比如說(shuō)當(dāng)線上出現(xiàn)一些問(wèn)題的時(shí)候,可能會(huì)導(dǎo)致某些業(yè)務(wù)指標(biāo)下降能庆,我們可以通過(guò)監(jiān)控盡早發(fā)現(xiàn)這些問(wèn)題辽装,進(jìn)而來(lái)減少損失。

如何建設(shè)實(shí)時(shí)數(shù)倉(cāng)

實(shí)時(shí)數(shù)倉(cāng)概念映射

我們通過(guò)離線數(shù)倉(cāng)開(kāi)發(fā)和實(shí)時(shí)數(shù)倉(cāng)開(kāi)發(fā)的對(duì)應(yīng)關(guān)系表相味,幫助大家快速清晰的理解實(shí)時(shí)數(shù)倉(cāng)的一些概念拾积。
image
  • 編程方式

離線開(kāi)發(fā)最常見(jiàn)的方案就是采用 Hive SQL 進(jìn)行開(kāi)發(fā),然后加上一些擴(kuò)展的 udf 丰涉。映射到實(shí)時(shí)數(shù)倉(cāng)里來(lái)拓巧,我們會(huì)使用 Flink SQL ,同樣也是配合 udf 來(lái)進(jìn)行開(kāi)發(fā)一死。

  • 作業(yè)執(zhí)行層面

離線處理的執(zhí)行層面一般是 MapReduce 或者 Spark Job 肛度,對(duì)應(yīng)到實(shí)時(shí)數(shù)倉(cāng)就是一個(gè)持續(xù)不斷運(yùn)行的 Flink Streaming 的程序。

  • 數(shù)倉(cāng)對(duì)象層面

離線數(shù)倉(cāng)實(shí)際上就是在使用 Hive 表投慈。對(duì)于實(shí)時(shí)數(shù)倉(cāng)來(lái)講承耿,我們對(duì)表的抽象是使用 Stream Table 來(lái)進(jìn)行抽象冠骄。

  • 物理存儲(chǔ)

離線數(shù)倉(cāng),我們多數(shù)情況下會(huì)使用 HDFS 進(jìn)行存儲(chǔ)加袋。實(shí)時(shí)數(shù)倉(cāng)凛辣,我們更多的時(shí)候會(huì)采用像 Kafka 這樣的消息隊(duì)列來(lái)進(jìn)行數(shù)據(jù)的存儲(chǔ)。

實(shí)時(shí)數(shù)倉(cāng)的整體架構(gòu)

在此之前我們做過(guò)一次分享职烧,是關(guān)于為什么選擇 Flink 來(lái)做實(shí)時(shí)數(shù)倉(cāng)扁誓,其中重點(diǎn)介紹了技術(shù)組件選型的原因和思路,具體內(nèi)容參考《美團(tuán)點(diǎn)評(píng)基于 Flink 的實(shí)時(shí)數(shù)倉(cāng)建設(shè)實(shí)踐》蚀之。本文分享的主要內(nèi)容是圍繞數(shù)據(jù)本身來(lái)進(jìn)行的蝗敢,下面是我們目前的實(shí)時(shí)數(shù)倉(cāng)的數(shù)據(jù)架構(gòu)圖。

《美團(tuán)點(diǎn)評(píng)基于 Flink 的實(shí)時(shí)數(shù)倉(cāng)建設(shè)實(shí)踐》https://tech.meituan.com/2018/10/18/meishi-data-flink.html

image

從數(shù)據(jù)架構(gòu)圖來(lái)看足删,實(shí)時(shí)數(shù)倉(cāng)的數(shù)據(jù)架構(gòu)會(huì)跟離線數(shù)倉(cāng)有很多類(lèi)似的地方寿谴。比如分層結(jié)構(gòu);比如說(shuō) ODS 層失受,明細(xì)層拭卿、匯總層,乃至應(yīng)用層贱纠,它們命名的模式可能都是一樣的峻厚。盡管如此,實(shí)時(shí)數(shù)倉(cāng)和離線數(shù)倉(cāng)還是有很多的區(qū)別的谆焊。跟離線數(shù)倉(cāng)主要不一樣的地方惠桃,就是實(shí)時(shí)數(shù)倉(cāng)的層次更少一些。以我們目前建設(shè)離線數(shù)倉(cāng)的經(jīng)驗(yàn)來(lái)看辖试,數(shù)倉(cāng)的第二層遠(yuǎn)遠(yuǎn)不止這么簡(jiǎn)單辜王,一般都會(huì)有一些輕度匯總層這樣的概念,其實(shí)第二層會(huì)包含很多層罐孝。另外一個(gè)就是應(yīng)用層呐馆,以往建設(shè)數(shù)倉(cāng)的時(shí)候,應(yīng)用層其實(shí)是在倉(cāng)庫(kù)內(nèi)部的莲兢。在應(yīng)用層建設(shè)好后汹来,會(huì)建同步任務(wù),把數(shù)據(jù)同步到應(yīng)用系統(tǒng)的數(shù)據(jù)庫(kù)里改艇。在實(shí)時(shí)數(shù)倉(cāng)里面收班,所謂 APP 層的應(yīng)用表,實(shí)際上就已經(jīng)在應(yīng)用系統(tǒng)的數(shù)據(jù)庫(kù)里了谒兄。上圖摔桦,雖然畫(huà)了 APP 層,但它其實(shí)并不算是數(shù)倉(cāng)里的表承疲,這些數(shù)據(jù)本質(zhì)上已經(jīng)存過(guò)去了邻耕。為什么主題層次要少一些鸥咖?是因?yàn)樵趯?shí)時(shí)處理數(shù)據(jù)的時(shí)候,每建一個(gè)層次兄世,數(shù)據(jù)必然會(huì)產(chǎn)生一定的延遲啼辣。為什么匯總層也會(huì)盡量少建?是因?yàn)樵趨R總統(tǒng)計(jì)的時(shí)候碘饼,往往為了容忍一部分?jǐn)?shù)據(jù)的延遲,可能會(huì)人為的制造一些延遲來(lái)保證數(shù)據(jù)的準(zhǔn)確悲伶。舉例艾恼,統(tǒng)計(jì)事件中的數(shù)據(jù)時(shí)醉者,可能會(huì)等到 10:00:05 或者 10:00:10再統(tǒng)計(jì)蜡饵,確保 10:00 前的數(shù)據(jù)已經(jīng)全部接受到位了,再進(jìn)行統(tǒng)計(jì)醒第。所以花沉,匯總層的層次太多的話柳爽,就會(huì)更大的加重人為造成的數(shù)據(jù)延遲。建議盡量減少層次碱屁,特別是匯總層一定要減少磷脯,最好不要超過(guò)兩層。明細(xì)層可能多一點(diǎn)層次還好娩脾,會(huì)有這種系統(tǒng)明細(xì)的設(shè)計(jì)概念赵誓。第二個(gè)比較大的不同點(diǎn)就是在于數(shù)據(jù)源的存儲(chǔ)。在建設(shè)離線數(shù)倉(cāng)的時(shí)候柿赊,可能整個(gè)數(shù)倉(cāng)都全部是建立在 Hive 表上俩功,都是跑在 Hadoop 上。但是碰声,在建設(shè)實(shí)時(shí)數(shù)倉(cāng)的時(shí)候诡蜓,同一份表,我們甚至可能會(huì)使用不同的方式進(jìn)行存儲(chǔ)胰挑。比如常見(jiàn)的情況下蔓罚,可能絕大多數(shù)的明細(xì)數(shù)據(jù)或者匯總數(shù)據(jù)都會(huì)存在 Kafka 里面,但是像維度數(shù)據(jù)瞻颂,可能會(huì)存在像 Tair 或者 HBase 這樣的 kv 存儲(chǔ)的系統(tǒng)中脚粟,實(shí)際上可能匯總數(shù)據(jù)也會(huì)存進(jìn)去,具體原因后面詳細(xì)分析蘸朋。除了整體結(jié)構(gòu)核无,我們也分享一下每一層建設(shè)的要點(diǎn)。

■ ODS 層的建設(shè)

數(shù)據(jù)來(lái)源盡可能統(tǒng)一利用分區(qū)保證數(shù)據(jù)局部有序

image

首先第一個(gè)建設(shè)要點(diǎn)就是 ODS 層藕坯,其實(shí) ODS 層建設(shè)可能跟倉(cāng)庫(kù)不一定有必然的關(guān)系团南,只要使用 Flink 開(kāi)發(fā)程序噪沙,就必然都要有實(shí)時(shí)的數(shù)據(jù)源。目前主要的實(shí)時(shí)數(shù)據(jù)源是消息隊(duì)列吐根,如 Kafka正歼。而我們目前接觸到的數(shù)據(jù)源,主要還是以 binlog拷橘、流量日志和系統(tǒng)日志為主局义。這里面我主要想講兩點(diǎn): 首先第一個(gè)建設(shè)要點(diǎn)就是 ODS層,其實(shí)ODS層建設(shè)可能跟這個(gè)倉(cāng)庫(kù)不一定有必然的關(guān)系冗疮,只要你使用這個(gè)flink開(kāi)發(fā)程序萄唇,你必然都要有這種實(shí)時(shí)的數(shù)據(jù)源。目前的主要的實(shí)時(shí)數(shù)據(jù)源就是消息隊(duì)列术幔,如kafka另萤。我們目前接觸到的數(shù)據(jù)源,主要還是以binlog诅挑、流量日志和系統(tǒng)日志為主四敞。這里面我主要想講兩點(diǎn),一個(gè)這么多數(shù)據(jù)源我怎么選拔妥?我們認(rèn)為以數(shù)倉(cāng)的經(jīng)驗(yàn)來(lái)看:
首先就是數(shù)據(jù)源的來(lái)源盡可能要統(tǒng)一忿危。這個(gè)統(tǒng)一有兩層含義:

  • 第一個(gè)統(tǒng)一就是實(shí)時(shí)的數(shù)據(jù)源本身要跟自己統(tǒng)一,比如你選擇從某個(gè)系統(tǒng)接入某一種數(shù)據(jù)没龙,要么都從binlog來(lái)接癌蚁,要么都從系統(tǒng)日志來(lái)接,最好不要混著接兜畸。在不知道數(shù)據(jù)生產(chǎn)的流程的情況下努释,一部分通過(guò)binlog接入一部分通過(guò)系統(tǒng)日志接入,容易出現(xiàn)數(shù)據(jù)亂序的問(wèn)題咬摇。

  • 第二個(gè)統(tǒng)一是指實(shí)時(shí)和離線的統(tǒng)一伐蒂,這個(gè)統(tǒng)一可能更重要一點(diǎn)。雖然我們是建設(shè)實(shí)時(shí)數(shù)倉(cāng)肛鹏,但是本質(zhì)上還是數(shù)倉(cāng)逸邦,作為一個(gè)團(tuán)隊(duì)來(lái)講,倉(cāng)庫(kù)里的指標(biāo)的計(jì)算邏輯和數(shù)據(jù)來(lái)源應(yīng)該完全一致在扰,不能讓使用數(shù)據(jù)的人產(chǎn)生誤解缕减。如果一個(gè)數(shù)據(jù)兩個(gè)團(tuán)隊(duì)都能為你提供,我們建議選擇跟離線同學(xué)一致的數(shù)據(jù)來(lái)源芒珠。包括我們公司本身也在做一些保證離線和實(shí)時(shí)采用的數(shù)據(jù)源一致的工作桥狡。

第二個(gè)要點(diǎn)就是數(shù)據(jù)亂序的問(wèn)題,我們?cè)诓杉瘮?shù)據(jù)的時(shí)候會(huì)有一個(gè)比較大的問(wèn)題,可能同一條數(shù)據(jù)裹芝,由于分區(qū)的存在部逮,這條數(shù)據(jù)先發(fā)生的狀態(tài)后消費(fèi)到,后發(fā)生的狀態(tài)先消費(fèi)到嫂易。我們?cè)诮鉀Q這一問(wèn)題的時(shí)候采用的是美團(tuán)內(nèi)部的一個(gè)數(shù)據(jù)組件兄朋。其實(shí),保證數(shù)據(jù)有序的主要思路就是利用 kafka 的分區(qū)來(lái)保證數(shù)據(jù)在分區(qū)內(nèi)的局部有序怜械。至于具體如何操作颅和,可以參考《美團(tuán)點(diǎn)評(píng)基于 Flink 的實(shí)時(shí)數(shù)倉(cāng)建設(shè)實(shí)踐》。這是我們美團(tuán)數(shù)據(jù)同步部門(mén)做的一套方案缕允,可以提供非常豐富的策略來(lái)保證同一條數(shù)據(jù)是按照生產(chǎn)順序進(jìn)行保序消費(fèi)的峡扩,實(shí)現(xiàn)在源頭解決數(shù)據(jù)亂序的問(wèn)題。

■ DW 層的建設(shè)

解決原始數(shù)據(jù)中數(shù)據(jù)存在噪聲灼芭、不完整和數(shù)據(jù)形式不統(tǒng)一的情況有额。形成規(guī)范般又,統(tǒng)一的數(shù)據(jù)源彼绷。如果可能的話盡可能和離線保持一致。

明細(xì)層的建設(shè)思路其實(shí)跟離線數(shù)倉(cāng)的基本一致茴迁,主要在于如何解決 ODS 層的數(shù)據(jù)可能存在的數(shù)據(jù)噪聲寄悯、不完整和形式不統(tǒng)一的問(wèn)題,讓它在倉(cāng)庫(kù)內(nèi)是一套滿足規(guī)范的統(tǒng)一的數(shù)據(jù)源堕义。我們的建議是如果有可能的話猜旬,最好入什么倉(cāng)怎么入倉(cāng),這個(gè)過(guò)程和離線保持一致倦卖。尤其是一些數(shù)據(jù)來(lái)源比較統(tǒng)一洒擦,但是開(kāi)發(fā)的邏輯經(jīng)常變化的系統(tǒng),這種情況下怕膛,我們可能采用的其實(shí)是一套基于配置的入倉(cāng)規(guī)則熟嫩。可能離線的同學(xué)有一套入倉(cāng)的系統(tǒng)褐捻,他們配置好規(guī)則就知道哪些數(shù)據(jù)表上數(shù)據(jù)要進(jìn)入實(shí)時(shí)數(shù)倉(cāng)掸茅,以及要錄入哪些字段,然后實(shí)時(shí)和離線是采用同一套配置進(jìn)行入倉(cāng)柠逞,這樣就可以保證我們的離線數(shù)倉(cāng)和實(shí)時(shí)數(shù)倉(cāng)在 DW 層長(zhǎng)期保持一個(gè)一致的狀態(tài)昧狮。實(shí)際上建設(shè) DW 層其實(shí)主要的工作主要是以下4部分。
image

唯一標(biāo)紅的就是模型的規(guī)范化板壮,其實(shí)模型的規(guī)范化逗鸣,是一個(gè)老生常談的問(wèn)題,可能每個(gè)團(tuán)隊(duì)在建設(shè)數(shù)倉(cāng)之前,都會(huì)先把自己的規(guī)范化寫(xiě)出來(lái)慕购。但實(shí)際的結(jié)果是我們會(huì)看到其實(shí)并不是每一個(gè)團(tuán)隊(duì)最終都能把規(guī)范落地聊疲。在實(shí)時(shí)的數(shù)倉(cāng)建設(shè)當(dāng)中,我們要特別強(qiáng)調(diào)模型的規(guī)范化沪悲,是因?yàn)閷?shí)施數(shù)倉(cāng)有一個(gè)特點(diǎn)获洲,就是本身實(shí)時(shí)作業(yè)是一個(gè)7×24 小時(shí)調(diào)度的狀態(tài),所以當(dāng)修改一個(gè)字段的時(shí)候殿如,可能要付出的運(yùn)維代價(jià)會(huì)很高贡珊。在離線數(shù)倉(cāng)中,可能改了某一個(gè)表涉馁,只要一天之內(nèi)把下游的作業(yè)也改了门岔,就不會(huì)出什么問(wèn)題。但是實(shí)時(shí)數(shù)倉(cāng)就不一樣了烤送,只要改了上游的表結(jié)構(gòu)寒随,下游作業(yè)必須是能夠正確解析上游數(shù)據(jù)的情況下才可以。另外使用像 kafka 這樣的系統(tǒng)帮坚,它本身并不是結(jié)構(gòu)化的存儲(chǔ)妻往,沒(méi)有元數(shù)據(jù)的概念,也不可能像改表一樣试和,直接把之前不規(guī)范的表名讯泣、表類(lèi)型改規(guī)范。要在事后進(jìn)行規(guī)范代價(jià)會(huì)很大阅悍。所以建議一定要在建設(shè)之初就盡快把這些模型的規(guī)范化落地好渠,避免后續(xù)要投入非常大的代價(jià)進(jìn)行治理。

  • 重復(fù)數(shù)據(jù)處理

除了數(shù)據(jù)本身我們會(huì)在每條數(shù)據(jù)上額外補(bǔ)充一些信息节视,應(yīng)對(duì)實(shí)時(shí)數(shù)據(jù)生產(chǎn)環(huán)節(jié)的一些常見(jiàn)問(wèn)題

image
  • 唯一鍵和主鍵

我們會(huì)給每一條數(shù)據(jù)都補(bǔ)充一個(gè)唯一鍵和一個(gè)主鍵拳锚,這兩個(gè)是一對(duì)的,唯一鍵就是標(biāo)識(shí)是唯一一條數(shù)據(jù)的寻行,主鍵是標(biāo)記為一行數(shù)據(jù)霍掺。一行數(shù)據(jù)可能變化很多次,但是主鍵是一樣的寡痰,每一次變化都是其一次唯一的變化抗楔,所以會(huì)有一個(gè)唯一鍵。唯一鍵主要解決的是數(shù)據(jù)重復(fù)問(wèn)題拦坠,從分層來(lái)講连躏,數(shù)據(jù)是從我們倉(cāng)庫(kù)以外進(jìn)行生產(chǎn)的,所以很難保證我們倉(cāng)庫(kù)以外的數(shù)據(jù)是不會(huì)重復(fù)的贞滨∪肴龋可能有些人交付數(shù)據(jù)給也會(huì)告知數(shù)據(jù)可能會(huì)有重復(fù)拍棕。生成唯一鍵的意思是指我們需要保證 DW 層的數(shù)據(jù)能夠有一個(gè)標(biāo)識(shí),來(lái)解決可能由于上游產(chǎn)生的重復(fù)數(shù)據(jù)導(dǎo)致的計(jì)算重復(fù)問(wèn)題勺良。生成主鍵绰播,其實(shí)最主要在于主鍵在 kafka 進(jìn)行分區(qū)操作,跟之前接 ODS 保證分區(qū)有序的原理是一樣的尚困,通過(guò)主鍵蠢箩,在 kafka 里進(jìn)行分區(qū)之后,消費(fèi)數(shù)據(jù)的時(shí)候就可以保證單條數(shù)據(jù)的消費(fèi)是有序的事甜。

  • 版本和批次

版本和批次這兩個(gè)其實(shí)又是一組谬泌。當(dāng)然這個(gè)內(nèi)容名字可以隨便起,最重要的是它的邏輯逻谦。首先掌实,版本。版本的概念就是對(duì)應(yīng)的表結(jié)構(gòu)邦马,也就是 schema 一個(gè)版本的數(shù)據(jù)贱鼻。由于在處理實(shí)時(shí)數(shù)據(jù)的時(shí)候,下游的腳本依賴表上一次的 schema 進(jìn)行開(kāi)發(fā)的滋将。當(dāng)數(shù)據(jù)表結(jié)構(gòu)發(fā)生變化的時(shí)候邻悬,就可能出現(xiàn)兩種情況:第一種情況,可能新加或者刪減的字段并沒(méi)有用到耕渴,其實(shí)完全不用感知拘悦,不用做任何操作就可以了齿兔。另外一種情況橱脸,需要用到變動(dòng)的字段。此時(shí)會(huì)產(chǎn)生一個(gè)問(wèn)題分苇,在 Kafka 的表中添诉,就相當(dāng)于有兩種不同的表結(jié)構(gòu)的數(shù)據(jù)。這時(shí)候其實(shí)需要一個(gè)標(biāo)記版本的內(nèi)容來(lái)告訴我們医寿,消費(fèi)的這條數(shù)據(jù)到底應(yīng)該用什么樣的表結(jié)構(gòu)來(lái)進(jìn)行處理栏赴,所以要加一個(gè)像版本這樣的概念。
第二靖秩,批次须眷。批次實(shí)際上是一個(gè)更不常見(jiàn)的場(chǎng)景,有些時(shí)候可能會(huì)發(fā)生數(shù)據(jù)重導(dǎo)沟突,它跟重啟不太一樣花颗,重啟作業(yè)可能就是改一改,然后接著上一次消費(fèi)的位置啟動(dòng)惠拭。而重導(dǎo)的話扩劝,數(shù)據(jù)消費(fèi)的位置會(huì)發(fā)生變化。比如,今天的數(shù)據(jù)算錯(cuò)了棒呛,領(lǐng)導(dǎo)很著急讓我改聂示,然后我需要把今天的數(shù)據(jù)重算,可能把數(shù)據(jù)程序修改好之后簇秒,還要設(shè)定程序鱼喉,比如從今天的凌晨開(kāi)始重新跑。這個(gè)時(shí)候由于整個(gè)數(shù)據(jù)程序是一個(gè) 7x24 小時(shí)的在線狀態(tài)趋观,其實(shí)原先的數(shù)據(jù)程序不能停蒲凶,等重導(dǎo)的程序追上新的數(shù)據(jù)之后,才能把原來(lái)的程序停掉拆内,最后使用重導(dǎo)的數(shù)據(jù)來(lái)更新結(jié)果層的數(shù)據(jù)旋圆。在這種情況下,必然會(huì)短暫的存在兩套數(shù)據(jù)麸恍。這兩套數(shù)據(jù)想要進(jìn)行區(qū)分的時(shí)候灵巧,就要通過(guò)批次來(lái)區(qū)分。其實(shí)就是所有的作業(yè)只消費(fèi)指定批次的數(shù)據(jù)抹沪,當(dāng)重導(dǎo)作業(yè)產(chǎn)生的時(shí)候刻肄,只有消費(fèi)重導(dǎo)批次的作業(yè)才會(huì)消費(fèi)這些重導(dǎo)的數(shù)據(jù),然后數(shù)據(jù)追上之后融欧,只要把原來(lái)批次的作業(yè)都停掉就可以了敏弃,這樣就可以解決一個(gè)數(shù)據(jù)重導(dǎo)的問(wèn)題。

維度數(shù)據(jù)建設(shè)

其次就是維度數(shù)據(jù)噪馏,我們的明細(xì)層里面包括了維度數(shù)據(jù)麦到。關(guān)于維度的數(shù)據(jù)的處理,實(shí)際上是先把維度數(shù)據(jù)分成了兩大類(lèi)采用不同的方案來(lái)進(jìn)行處理欠肾。

  • 變化頻率低的維度

第一類(lèi)數(shù)據(jù)就是一些變化頻率比較低的數(shù)據(jù)瓶颠,這些數(shù)據(jù)其實(shí)可能是一些基本上是不會(huì)變的數(shù)據(jù)。比如說(shuō)刺桃,一些地理的維度信息粹淋、節(jié)假日信息和一些固定代碼的轉(zhuǎn)換。
image

這些數(shù)據(jù)實(shí)際上我們采用的方法就是直接可以通過(guò)離線倉(cāng)庫(kù)里面會(huì)有對(duì)應(yīng)的維表瑟慈,然后通過(guò)一個(gè)同步作業(yè)把它加載到緩存中來(lái)進(jìn)行訪問(wèn)桃移。還有一些維度數(shù)據(jù)創(chuàng)建得會(huì)很快,可能會(huì)不斷有新的數(shù)據(jù)創(chuàng)建出來(lái)葛碧,但是一旦創(chuàng)建出來(lái)借杰,其實(shí)也就不再會(huì)變了。比如說(shuō)吹埠,美團(tuán)上開(kāi)了一家新的門(mén)店第步,門(mén)店所在的城市名字等這些固定的屬性疮装,其實(shí)可能很長(zhǎng)時(shí)間都不會(huì)變,取最新的那一條數(shù)據(jù)就可以了粘都。這種情況下廓推,我們會(huì)通過(guò)公司內(nèi)部的一些公共服務(wù),直接去訪問(wèn)當(dāng)前最新的數(shù)據(jù)翩隧。最終樊展,我們會(huì)包一個(gè)維度服務(wù)的這樣一個(gè)概念來(lái)對(duì)用戶進(jìn)行屏蔽,具體是從哪里查詢相關(guān)細(xì)節(jié)堆生,通過(guò)維度服務(wù)即可關(guān)聯(lián)具體的維度信息专缠。

  • 變化頻率高的維度

第二類(lèi)是一些變化頻率較高的數(shù)據(jù)。比如常見(jiàn)的病人心腦科的狀態(tài)變動(dòng)淑仆,或者某一個(gè)商品的價(jià)格等涝婉。這些東西往往是會(huì)隨著時(shí)間變化比較頻繁,比較快蔗怠。而對(duì)于這類(lèi)數(shù)據(jù)墩弯,我們的處理方案就稍微復(fù)雜一點(diǎn)。首先對(duì)于像價(jià)格這樣變化比較頻繁的這種維度數(shù)據(jù)寞射,會(huì)監(jiān)聽(tīng)它的變化渔工。比如說(shuō),把價(jià)格想象成維度桥温,我們會(huì)監(jiān)聽(tīng)維度價(jià)格變化的消息引矩,然后構(gòu)建一張價(jià)格變換的拉鏈表。
image

一旦建立了維度拉鏈表侵浸,當(dāng)一條數(shù)據(jù)來(lái)的時(shí)候旺韭,就可以知道,在這個(gè)數(shù)據(jù)某一時(shí)刻對(duì)應(yīng)的準(zhǔn)確的維度是多少通惫,避免了由于維度快速的變化導(dǎo)致關(guān)聯(lián)錯(cuò)維度的問(wèn)題茂翔。另一類(lèi)如新老客這維度混蔼,于我們而言其實(shí)是一種衍生維度履腋,因?yàn)樗旧聿⒉皇蔷S度的計(jì)算方式,是用該用戶是否下過(guò)單來(lái)計(jì)算出來(lái)的惭嚣,所以它其實(shí)是用訂單數(shù)據(jù)來(lái)算出來(lái)的一個(gè)維度遵湖。所以類(lèi)似訂單數(shù)的維度,我們會(huì)在 DW 層建立一些衍生維度的計(jì)算模型晚吞,然后這些計(jì)算模型輸出的其實(shí)也是拉鏈表延旧,記錄下一個(gè)用戶每天這種新老客的變化程度,或者可能是一個(gè)優(yōu)質(zhì)用戶的變化的過(guò)程槽地。由于建立拉鏈表本身也要關(guān)聯(lián)維度迁沫,所以可以通過(guò)之前分組 key 的方式來(lái)保障不亂序芦瘾,這樣還是將其當(dāng)做一個(gè)不變的維度來(lái)進(jìn)行關(guān)聯(lián)。通過(guò)這種方式來(lái)建立拉鏈表相對(duì)麻煩集畅,所以實(shí)際上建議利用一些外部組件的功能近弟。實(shí)際操作的時(shí)候,我們使用的是 Hbase挺智。HBase 本身支持?jǐn)?shù)據(jù)多版本的祷愉,而且它能記錄數(shù)據(jù)更新的時(shí)間戳,取數(shù)據(jù)的時(shí)候赦颇,甚至可以用這個(gè)時(shí)間戳來(lái)做索引二鳄。所以實(shí)際上只要把數(shù)據(jù)存到 HBase 里,再配合上 mini-versions 媒怯,就可以保證數(shù)據(jù)不會(huì)超時(shí)死掉订讼。上面也提到過(guò),整個(gè)實(shí)時(shí)數(shù)倉(cāng)有一個(gè)大原則扇苞,不處理離線數(shù)倉(cāng)能處理的過(guò)程躯嫉。相當(dāng)于處理的過(guò)程,只需要處理三天以內(nèi)的數(shù)據(jù)杨拐,所以還可以通過(guò)配置 TTL 來(lái)保證 HBase 里的這些維度可以盡早的被淘汰掉祈餐。因?yàn)楹芏嗵煲郧暗木S度,實(shí)際上也不會(huì)再關(guān)聯(lián)了哄陶,這樣就保證維度數(shù)據(jù)不會(huì)無(wú)限制的增長(zhǎng)帆阳,導(dǎo)致存儲(chǔ)爆炸。

維度數(shù)據(jù)使用

處理維度數(shù)據(jù)之后屋吨,這個(gè)維度數(shù)據(jù)怎么用蜒谤?

image

第一種方案,也是最簡(jiǎn)單的方案至扰,就是使用 UDTF 關(guān)聯(lián)鳍徽。其實(shí)就是寫(xiě)一個(gè) UDTF 去查詢上面提到的維度服務(wù),具體來(lái)講就是用 LATERAL TABLE 關(guān)鍵詞來(lái)進(jìn)行關(guān)聯(lián)敢课,內(nèi)外關(guān)聯(lián)都是支持的阶祭。另外一種方案就是通過(guò)解析 SQL ,識(shí)別出關(guān)聯(lián)的維表以及維表中的字段直秆,把它原本的查詢進(jìn)行一次轉(zhuǎn)化為原表.flatmap (維表)濒募,最后把整個(gè)操作的結(jié)果轉(zhuǎn)換成一張新的表來(lái)完成關(guān)聯(lián)操作。但是這個(gè)操作要求使用者有很多周邊的系統(tǒng)來(lái)進(jìn)行配合圾结,首先需要能解析 SQL 瑰剃,同時(shí)還能識(shí)別文本,記住所有維表的信息筝野,最后還要可以執(zhí)行 SQL 轉(zhuǎn)化晌姚,所以這套方案適合一些已經(jīng)有成熟的基于 Flink SQL 的 SQL開(kāi)發(fā)框架的系統(tǒng)來(lái)使用粤剧。如果只是單純的寫(xiě)封裝的代碼,建議還是使用 UDTF 的方式來(lái)進(jìn)行關(guān)聯(lián)會(huì)非常的簡(jiǎn)單挥唠,而且效果也是一樣的俊扳。

■ 匯總層的建設(shè)

在建設(shè)實(shí)時(shí)數(shù)倉(cāng)的匯總層的時(shí)候,跟離線的方案其實(shí)會(huì)有很多一樣的地方猛遍。

image

第一點(diǎn)是對(duì)于一些共性指標(biāo)的加工馋记,比如說(shuō) pv、uv懊烤、交易額這些運(yùn)算梯醒,我們會(huì)在匯總層進(jìn)行統(tǒng)一的運(yùn)算。另外腌紧,在各個(gè)腳本中多次運(yùn)算茸习,不僅浪費(fèi)算力,同時(shí)也有可能會(huì)算錯(cuò)壁肋,需要確保關(guān)于指標(biāo)的口徑是統(tǒng)一在一個(gè)固定的模型里面的号胚。本身 Flink SQL 已經(jīng)其實(shí)支持了非常多的計(jì)算方法,包括這些 count distinct 等都支持浸遗。值得注意的一點(diǎn)是猫胁,它在使用 count distinct 的時(shí)候,他會(huì)默認(rèn)把所有的要去重的數(shù)據(jù)存在一個(gè) state 里面跛锌,所以當(dāng)去重的基數(shù)比較大的時(shí)候弃秆,可能會(huì)吃掉非常多的內(nèi)存,導(dǎo)致程序崩潰髓帽。這個(gè)時(shí)候其實(shí)是可以考慮使用一些非精確系統(tǒng)的算法菠赚,比如說(shuō) BloomFilter 非精確去重、 HyperLogLog 超低內(nèi)存去重方案郑藏,這些方案可以極大的減少內(nèi)存的使用衡查。第二點(diǎn)就是 Flink 比較有特色的一個(gè)點(diǎn),就是 Flink 內(nèi)置非常多的這種時(shí)間窗口必盖。Flink SQL 里面有翻滾窗口拌牲、滑動(dòng)窗口以及會(huì)話窗口,這些窗口在寫(xiě)離線 SQL 的時(shí)候是很難寫(xiě)出來(lái)的筑悴,所以可以開(kāi)發(fā)出一些更加專(zhuān)注的模型们拙,甚至可以使用一些在離線開(kāi)發(fā)當(dāng)中比較少使用的一些比較小的時(shí)間窗口。比如說(shuō)阁吝,計(jì)算最近10分鐘的數(shù)據(jù),這樣的窗口可以幫助我們建設(shè)一些基于時(shí)間趨勢(shì)圖的應(yīng)用械拍。但是這里面要注意一點(diǎn)突勇,就是一旦使用了這個(gè)時(shí)間窗口装盯,要配置對(duì)應(yīng)的 TTL 參數(shù),這樣可以減少內(nèi)存的使用甲馋,提高程序的運(yùn)行效率埂奈。另外贫悄,如果 TTL 不夠滿足窗口的話株搔,也有可能會(huì)導(dǎo)致數(shù)據(jù)計(jì)算的錯(cuò)誤鞋邑。第三點(diǎn)偷仿,在匯總層進(jìn)行多維的主題匯總盏阶,因?yàn)閷?shí)時(shí)倉(cāng)庫(kù)本身是面向主題的稼跳,可能每一個(gè)主題會(huì)關(guān)心的維度都不一樣匾效,所以我們會(huì)在不同的主題下惩妇,按照這個(gè)主題關(guān)心的維度對(duì)數(shù)據(jù)進(jìn)行一些匯總碧聪,最后來(lái)算之前說(shuō)過(guò)的那些匯總指標(biāo)冒版。但是這里有一個(gè)問(wèn)題,如果不使用時(shí)間窗口的話逞姿,直接使用 group by 辞嗡,它會(huì)導(dǎo)致生產(chǎn)出來(lái)的數(shù)據(jù)是一個(gè) retract 流,默認(rèn)的 kafka 的 sink 它是只支持 append 模式滞造,所以在這里要進(jìn)行一個(gè)轉(zhuǎn)化续室。如果想把這個(gè)數(shù)據(jù)寫(xiě)入 kafka 的話,需要做一次轉(zhuǎn)化谒养,一般的轉(zhuǎn)化方案實(shí)際上是把撤回流里的 false 的過(guò)程去掉猎贴,把 true 的過(guò)程保存起來(lái),轉(zhuǎn)化成一個(gè) append stream 蝴光,然后就可以寫(xiě)入到 kafka 里了她渴。第四點(diǎn),在匯總層會(huì)做一個(gè)比較重要的工作蔑祟,就是衍生維度的加工趁耗。如果衍生維度加工的時(shí)候可以利用 HBase 存儲(chǔ),HBase 的版本機(jī)制可以幫助你更加輕松地來(lái)構(gòu)建一個(gè)這種衍生維度的拉鏈表疆虚,可以幫助你準(zhǔn)確的 get 到一個(gè)實(shí)時(shí)數(shù)據(jù)當(dāng)時(shí)的準(zhǔn)確的維度苛败。

倉(cāng)庫(kù)質(zhì)量保證

經(jīng)過(guò)上面的環(huán)節(jié),如果你已經(jīng)建立好了一個(gè)倉(cāng)庫(kù)径簿,你會(huì)發(fā)現(xiàn)想保證倉(cāng)庫(kù)的正常的運(yùn)行或者是保證它高質(zhì)量的運(yùn)行罢屈,其實(shí)是一個(gè)非常麻煩的過(guò)程,它要比一線的操作復(fù)雜得多篇亭,所以我們?cè)诮ㄔO(shè)完倉(cāng)庫(kù)之后缠捌,需要建設(shè)很多的周邊系統(tǒng)來(lái)提高我們的生產(chǎn)效率。下面介紹一下我們目前使用的一些工具鏈系統(tǒng)译蒂,工具鏈系統(tǒng)的功能結(jié)構(gòu)圖如下圖曼月。
image

首先谊却,工具鏈系統(tǒng)包括一個(gè)實(shí)時(shí)計(jì)算平臺(tái),主要的功能是統(tǒng)一提交作業(yè)和一些資源分配以及監(jiān)控告警哑芹,但是實(shí)際上無(wú)論是否開(kāi)發(fā)數(shù)倉(cāng)炎辨,大概都需要這樣的一個(gè)工具,這是開(kāi)發(fā) Flink 的基本工具聪姿。對(duì)于我們來(lái)講碴萧,跟數(shù)倉(cāng)相關(guān)的主要工具有兩塊:

  • 系統(tǒng)管理模塊,這個(gè)模塊實(shí)際上是我們的實(shí)時(shí)和離線是一起使用的末购。其中知識(shí)庫(kù)管理模塊破喻,主要是用來(lái)記錄模型中表和字段的一些信息,另外就是一些工單的解決方法也會(huì)維護(hù)進(jìn)去招盲。Flink 管理主要是用來(lái)管理一些我們公司自己開(kāi)發(fā)的一些 Flink 相關(guān)的系統(tǒng)組件低缩。

  • 重點(diǎn)其實(shí)還是我們整個(gè)用來(lái)開(kāi)發(fā)實(shí)時(shí)數(shù)倉(cāng) ETL 的一個(gè)開(kāi)發(fā)工具。主要是如下幾點(diǎn):

  • SQL 及 UDF 管理曹货,管理 SQL 腳本和 UDF咆繁,以及對(duì) UDF 進(jìn)行配置。

  • 任務(wù)日志查看和任務(wù)監(jiān)控顶籽。

  • 調(diào)度管理玩般,主要是管理任務(wù)的重導(dǎo)和重傳。

  • 數(shù)據(jù)資產(chǎn)管理礼饱,管理實(shí)時(shí)和離線的元數(shù)據(jù)坏为,以及任務(wù)依賴信息。

其實(shí)整個(gè)這條工具鏈镊绪,每個(gè)工具都有它自己特定的用場(chǎng)場(chǎng)景匀伏,下面重點(diǎn)講解其中兩個(gè)。

元數(shù)據(jù)與血緣管理

■ 元數(shù)據(jù)管理我們?cè)?Flink SQL 的開(kāi)發(fā)過(guò)程中蝴韭,每一個(gè)任務(wù)都要重新把元數(shù)據(jù)重新寫(xiě)一遍够颠。因?yàn)?kafka 以及很多的緩存組件,如 Tair榄鉴、Redis 都不支持元數(shù)據(jù)的管理履磨,所以我們一定要盡早建設(shè)元數(shù)據(jù)管理系統(tǒng)。****■ 血緣管理血緣其實(shí)對(duì)于實(shí)時(shí)數(shù)倉(cāng)來(lái)講比較重要庆尘,在上文中也提到過(guò)剃诅,在實(shí)時(shí)的作業(yè)的運(yùn)維過(guò)程當(dāng)中,一旦對(duì)自己的作業(yè)進(jìn)行了修改驶忌,必須保證下游都是能夠準(zhǔn)確的解析新數(shù)據(jù)的這樣一個(gè)情況矛辕。如果是依賴于這種人腦去記憶,比如說(shuō)誰(shuí)用我的銷(xiāo)售表或者口頭通知這種方式來(lái)講的話,效率會(huì)非常的低如筛,所以一定要建立一套就是血緣的管理機(jī)制堡牡。要知道到底是誰(shuí)用了生產(chǎn)的表抒抬,然后上游用了誰(shuí)的杨刨,方便大家再進(jìn)行修改的時(shí)候進(jìn)行周知,保證我們整個(gè)實(shí)時(shí)數(shù)倉(cāng)的穩(wěn)定擦剑。

image

元數(shù)據(jù)和血緣管理系統(tǒng)妖胀,最簡(jiǎn)單的實(shí)現(xiàn)方式大概分為以下三點(diǎn):

  • 通過(guò)元數(shù)據(jù)服務(wù)生成 Catalog

首先通過(guò)元數(shù)據(jù)系統(tǒng),把元數(shù)據(jù)系統(tǒng)里的元數(shù)據(jù)信息加載到程序中來(lái)惠勒,然后生成 Flink Catalog 赚抡。這樣就可以知道當(dāng)前作業(yè)可以消費(fèi)哪些表,使用哪些表纠屋。

  • 解析 DDL 語(yǔ)句創(chuàng)建更新表

當(dāng)作業(yè)進(jìn)行一系列操作涂臣,最終要輸出某張表的時(shí)候,解析作業(yè)里面關(guān)于輸出部分的 DDL 代碼售担,創(chuàng)建出新的元數(shù)據(jù)信息寫(xiě)入到元數(shù)據(jù)系統(tǒng)赁遗。

  • 作業(yè)信息和運(yùn)行狀態(tài)寫(xiě)入元數(shù)據(jù)

作業(yè)本身的元數(shù)據(jù)信息以及它的運(yùn)行狀態(tài)也會(huì)同步到元數(shù)據(jù)系統(tǒng)里面來(lái),讓這些信息來(lái)幫助我們建立血緣關(guān)系族铆。最終的系統(tǒng)可以通過(guò)數(shù)據(jù)庫(kù)來(lái)存儲(chǔ)這些信息岩四,如果你設(shè)計(jì)的系統(tǒng)沒(méi)那么復(fù)雜,也可以使用文件來(lái)進(jìn)行存儲(chǔ)哥攘。重點(diǎn)是需要盡快建立一套這樣的系統(tǒng)剖煌,不然在后續(xù)的開(kāi)發(fā)和運(yùn)維過(guò)程當(dāng)中都會(huì)非常的痛苦。

數(shù)據(jù)質(zhì)量驗(yàn)證

將實(shí)時(shí)數(shù)據(jù)寫(xiě)入 Hive逝淹,使用離線數(shù)據(jù)持續(xù)驗(yàn)證實(shí)時(shí)數(shù)據(jù)的準(zhǔn)確性耕姊。

當(dāng)建設(shè)完一個(gè)數(shù)倉(cāng)之后,尤其是第一次建立之后栅葡,一定會(huì)非常懷疑自己數(shù)據(jù)到底準(zhǔn)不準(zhǔn)茉兰。在此之前的驗(yàn)證方式就是通過(guò)寫(xiě)程序去倉(cāng)庫(kù)里去查,然后來(lái)看數(shù)據(jù)對(duì)不對(duì)妥畏。在后續(xù)的建設(shè)過(guò)程中我們發(fā)現(xiàn)每天這樣人為去對(duì)比太累了邦邦。我們就采取了一個(gè)方案,把中間層的表寫(xiě)到 Hive 里面去醉蚁,然后利用離線數(shù)據(jù)豐富的質(zhì)量驗(yàn)證工具去對(duì)比離線和實(shí)時(shí)同一模型的數(shù)據(jù)差異燃辖,最后根據(jù)設(shè)定的閾值進(jìn)行監(jiān)控報(bào)警。這個(gè)方案雖然并不能及時(shí)的發(fā)現(xiàn)實(shí)時(shí)數(shù)據(jù)的問(wèn)題网棍,但是可以幫助你在上線前了解實(shí)時(shí)模型的準(zhǔn)確程度黔龟。然后進(jìn)行任務(wù)的改造,不斷提高數(shù)據(jù)的準(zhǔn)確率。另外這個(gè)方案還可以檢驗(yàn)離線數(shù)據(jù)的準(zhǔn)確性氏身。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末巍棱,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子蛋欣,更是在濱河造成了極大的恐慌航徙,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,104評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件陷虎,死亡現(xiàn)場(chǎng)離奇詭異到踏,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)尚猿,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)窝稿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人凿掂,你說(shuō)我怎么就攤上這事伴榔。” “怎么了庄萎?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,697評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵踪少,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我惨恭,道長(zhǎng)秉馏,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,836評(píng)論 1 298
  • 正文 為了忘掉前任脱羡,我火速辦了婚禮萝究,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘锉罐。我一直安慰自己帆竹,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,851評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布脓规。 她就那樣靜靜地躺著栽连,像睡著了一般。 火紅的嫁衣襯著肌膚如雪侨舆。 梳的紋絲不亂的頭發(fā)上秒紧,一...
    開(kāi)封第一講書(shū)人閱讀 52,441評(píng)論 1 310
  • 那天,我揣著相機(jī)與錄音挨下,去河邊找鬼熔恢。 笑死,一個(gè)胖子當(dāng)著我的面吹牛臭笆,可吹牛的內(nèi)容都是我干的叙淌。 我是一名探鬼主播秤掌,決...
    沈念sama閱讀 40,992評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼鹰霍!你這毒婦竟也來(lái)了闻鉴?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,899評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤茂洒,失蹤者是張志新(化名)和其女友劉穎孟岛,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體获黔,經(jīng)...
    沈念sama閱讀 46,457評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蚀苛,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,529評(píng)論 3 341
  • 正文 我和宋清朗相戀三年在验,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了玷氏。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,664評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡腋舌,死狀恐怖盏触,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情块饺,我是刑警寧澤赞辩,帶...
    沈念sama閱讀 36,346評(píng)論 5 350
  • 正文 年R本政府宣布,位于F島的核電站授艰,受9級(jí)特大地震影響辨嗽,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜淮腾,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,025評(píng)論 3 334
  • 文/蒙蒙 一糟需、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧谷朝,春花似錦洲押、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,511評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至专钉,卻和暖如春挑童,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背跃须。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,611評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工站叼, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人回怜。 一個(gè)月前我還...
    沈念sama閱讀 49,081評(píng)論 3 377
  • 正文 我出身青樓大年,卻偏偏與公主長(zhǎng)得像换薄,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子翔试,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,675評(píng)論 2 359