Spark-Streaming 流式數(shù)據(jù)處理

目前為止,已經(jīng)討論了機(jī)器學(xué)習(xí)和批處理模式的數(shù)據(jù)挖掘。現(xiàn)在審視持續(xù)處理流數(shù)據(jù),實(shí)時(shí)檢測(cè)其中的事實(shí)和模式,好像從湖泊來到了河流。

先研究一下不斷改變的動(dòng)態(tài)環(huán)境帶來的挑戰(zhàn),在列出流處理應(yīng)用的先決條件(如,與Twitter的TCP Sockets)之后, 結(jié)合Spark, Kafka and Flume 把數(shù)據(jù)放入一個(gè)低延遲,高吞吐量,可縮放的處理流水線。

要點(diǎn)如下:

? 分析流式應(yīng)用架構(gòu)的挑戰(zhàn),約束和需求

? 利用Spark Streaming 從 TCP socket 中處理實(shí)時(shí)數(shù)據(jù)

? 連接 Twitter 服務(wù),準(zhǔn)實(shí)時(shí)解析 tweets

? 使用 Spark, Kafka 和 Flume 建立一個(gè)可靠,容錯(cuò),可縮放,高吞吐量,低延遲的集成應(yīng)用

? 以 Lambda 和 Kappa 的架構(gòu)范式結(jié)尾

Spark Streaming在數(shù)據(jù)密集型應(yīng)用中的位置

按照慣例, 先看一下最初的數(shù)據(jù)密集型應(yīng)用架構(gòu),指明我們所感興趣的 Spark Streaming 模塊的所處位置.

下圖著重指明了整體架構(gòu)中的Spark Streaming模塊,Spark SQL和 Spark MLlib:

5-1 Streaming 在數(shù)據(jù)密集型應(yīng)用架構(gòu)的位置

數(shù)據(jù)流可以來自股票市場(chǎng)的時(shí)序分析,企業(yè)交易,各種交互,事件,web流量,點(diǎn)擊流,和傳感器數(shù)據(jù)等,都是及時(shí)且?guī)в袝r(shí)間戳的數(shù)據(jù)。用例有欺詐檢測(cè)和防偽,移動(dòng)的交叉銷售和銷售提升,或者交通預(yù)警。這些數(shù)據(jù)流需要及時(shí)處理以便于監(jiān)測(cè),例如 異常檢測(cè),異常奇點(diǎn),垃圾郵件,欺詐和入侵; 也可提供基礎(chǔ)的統(tǒng)計(jì),見解,趨勢(shì),和推薦。 某些情形,總結(jié)性的匯總信息需要存儲(chǔ)以備將來使用。從架構(gòu)范式的角度看,我們從面向服務(wù)的架構(gòu)轉(zhuǎn)為事件驅(qū)動(dòng)的架構(gòu)。

數(shù)據(jù)的流處理有兩個(gè)模型:

? 在數(shù)據(jù)到達(dá)時(shí)及時(shí)處理每條記錄,在處理前不需要在容器中緩存記錄,比如
Twitter's Storm, Yahoo's S4, 和 Google's MillWheel.

? 微型批處理 或者小間隔執(zhí)行批處理計(jì)算,例如
Spark Streaming and Storm Trident. 根據(jù)微型批處理設(shè)置的時(shí)間窗口,將流入的數(shù)據(jù)記錄緩沖到一個(gè)容器中。
Spark Streaming 經(jīng)常用來與 Storm 比較,這是兩種不同的流數(shù)據(jù)模型。 Spark Streaming 基于微型批處理,而 Storm 基于及時(shí)處理流入的數(shù)據(jù)。 Storm 也提供了微型批處理選項(xiàng) 即 Storm Triden。

流處理應(yīng)用的主要驅(qū)動(dòng)因素的時(shí)間延遲。時(shí)延從 RPC (short for Remote Procedure Call) 的毫秒 到幾秒 到微信批處理方案的幾分鐘不等。
RPC 允許請(qǐng)求程序與遠(yuǎn)程服務(wù)器之間的同步操作。線程允許多個(gè) RPC 調(diào)用的并發(fā)。

分布式RPC 模型實(shí)現(xiàn)的一個(gè)實(shí)例就是 Apache Storm.
Storm 實(shí)現(xiàn)了無邊界元組的無狀態(tài)毫秒級(jí)延遲處理,結(jié)合數(shù)據(jù)流作為噴發(fā)源使用了拓?fù)浠蚨ㄏ颦h(huán)圖的及時(shí),提供了過濾, join, 聚合和轉(zhuǎn)換.
Storm 也實(shí)現(xiàn)了一個(gè)高層抽象叫做 Trident , 與Spark類似, 以微型批處理進(jìn)行流式數(shù)據(jù)處理。

考慮時(shí)延的限制, 從毫秒到秒級(jí), Storm 是個(gè)很好的候選. 對(duì)于秒到分鐘級(jí), Spark Streaming and Storm Trident
是最佳選擇。 對(duì)于若干分鐘以上, Spark 和 NoSQL 數(shù)據(jù)庫如
Cassandra 和HBase 是合適的方案. 對(duì)于多小時(shí)運(yùn)算海量數(shù)據(jù),Hadoop 是理想的競(jìng)爭(zhēng)者。
盡管吞吐量逾時(shí)延相關(guān),但不是一個(gè)簡(jiǎn)單的反線性關(guān)系。
如果處理一條消息需要2 ms, 只取決于延遲的情況, 可以假設(shè)吞吐量限制在500條消息每秒。如果緩存了8ms的數(shù)據(jù),那么批處理允許更高的吞吐量。 10 ms 時(shí)延, 系統(tǒng)可以緩沖10,000 條消息. 為了一個(gè)可忍受的時(shí)延增長(zhǎng),我們要顯著的增加吞吐量。這是Spark Streaming 微型批處理的一個(gè)魔法。

Spark Streaming 內(nèi)部工作方式

Spark Streaming 充分利用了 Spark 的核心架構(gòu),作為流處理功能的入口點(diǎn),它構(gòu)建在 SparkContext 的 StreamingContext 之上. 集群管理器將至少單獨(dú)分片一個(gè)工作節(jié)點(diǎn)作為接收器,這是一個(gè)長(zhǎng)時(shí)間運(yùn)行的任務(wù)執(zhí)行器來處理進(jìn)入的流數(shù)據(jù)。
執(zhí)行器創(chuàng)建 Discretized Streams 或者從輸入數(shù)據(jù)流中得來的 DStreams, DStream 默認(rèn)為另一個(gè)worker 的緩存。 接收器服務(wù)于輸入數(shù)據(jù)流,多個(gè)接收器提升了并行性,產(chǎn)生多個(gè)DStreams , Spark 用它unite 或 join RDD.

下圖給出了 Spark Streaming 的那邊工作概要。客戶端通過集群管理器與
Spark 集群交互 ,Spark Streaming 有一個(gè)專屬的worker 運(yùn)行著長(zhǎng)任務(wù)來接待輸入的數(shù)據(jù)流,轉(zhuǎn)化為 discretized streams 或DStreams. 接收器采集,緩存,復(fù)制數(shù)據(jù),然后放入一個(gè) RDDs的流.


5-2 Spark Streaming 內(nèi)部工作方式

Spark 接收器能夠從多種數(shù)據(jù)源接收數(shù)據(jù)。核心的輸入源包括從TCP socket 和 HDFS/Amazon S3 到 Akka Actors. 其它的數(shù)據(jù)源包括
Apache Kafka, Apache Flume, Amazon Kinesis, ZeroMQ, Twitter, 以及其它用戶定義的接收器。

我們可以區(qū)分資源是否可靠,可靠的數(shù)據(jù)源可以確認(rèn)數(shù)據(jù)的接收憑證以及副本能否重發(fā),非可靠數(shù)據(jù)源指接收器不能確認(rèn)消息的接收憑證。 Spark 可以對(duì)workers,分區(qū)和接收器的數(shù)量進(jìn)行縮放。

下圖給出了Spark Streaming 可能的數(shù)據(jù)源和持久化選項(xiàng):

5-3 Spark Streaming 概覽

Spark Streaming 的底層基礎(chǔ)

Spark Streaming 由接收器, Discretized Streams 和 用于持久化的Spark Connectors 組成.
作為 Spark Core, 基本的數(shù)據(jù)結(jié)構(gòu)是 RDD, 基本編程抽是 Discretized Stream 或 DStream.

下圖解釋了看做 RDDs連續(xù)序列的 Discretized Streams. DStream 的批處理間隔是可配置的。

5-4 RDD-Descretized Stream

DStreams 是在批處理間隔是對(duì)流入數(shù)據(jù)的快照。時(shí)間步長(zhǎng)可以從500ms 到幾秒,DStream 的底層結(jié)構(gòu)是一個(gè) RDD.
一個(gè)DStream 基本上是 RDDs的一個(gè)連續(xù)序列。這使得Spark Streaming 非常強(qiáng)大,可以充分利用Spark Core 中已有的函數(shù),數(shù)據(jù)轉(zhuǎn)換和動(dòng)作, 可以與Spark SQL 對(duì)話, 在流入的數(shù)據(jù)流上執(zhí)行SQL 查詢和 Spark MLlib. 通用的及基于鍵值對(duì)RDDs的數(shù)據(jù)轉(zhuǎn)換同樣適用。DStreams 得益于 RDDs 內(nèi)部體系和容錯(cuò)機(jī)制。 discretized stream 有額外的轉(zhuǎn)換和輸出操作。DStream 的大多數(shù)通用操作是 transform 和 foreachRDD.

下圖給出了 DStreams的生命周期,將消息通過微型批處理實(shí)現(xiàn)創(chuàng)建成 RDDs ,RDDs上的數(shù)據(jù)轉(zhuǎn)換函數(shù)和動(dòng)作 觸發(fā)了 Spark jobs. 從上而下分布解釋:

  1. 輸入流中, 流入的消息緩存在容器中,時(shí)間窗口有微型批處理分配.
  1. 在 discretized stream 步驟中, 緩存的微型批處理轉(zhuǎn)化成 DStream RDDs.
  2. Mapped DStream 是通過使用轉(zhuǎn)換函數(shù)從原始的 DStream中獲得的. 這三個(gè)步驟構(gòu)成了在預(yù)定義時(shí)間窗口的所接收數(shù)據(jù)的轉(zhuǎn)換。 底層的數(shù)據(jù)結(jié)構(gòu)是RDD, 我們保留了轉(zhuǎn)換中的數(shù)據(jù)世系。
  3. 最后一步是 RDD上的一個(gè)動(dòng)作,觸發(fā)了Spark job.


    5-5 Dstream

數(shù)據(jù)轉(zhuǎn)換可以無狀態(tài)的或者有狀態(tài)的。無狀態(tài)意味著沒有狀態(tài)需要程序維護(hù),而有狀態(tài)意味著程序保持狀態(tài),前面所記住的操作可能影響當(dāng)前的操作。一個(gè)有狀態(tài)操作需要或修改一些系統(tǒng)的狀態(tài),無狀態(tài)操作則不是。 無狀態(tài)數(shù)據(jù)轉(zhuǎn)換在一個(gè)時(shí)間點(diǎn)處理每個(gè)批處理中的一個(gè)
DStream. 有狀態(tài)數(shù)據(jù)轉(zhuǎn)換處理多個(gè)批處理來獲得結(jié)果,需要可配置的目錄檢查點(diǎn)。檢查點(diǎn)是容錯(cuò)體系的主要機(jī)制, Spark Streaming 周期性存儲(chǔ)一個(gè)應(yīng)用的數(shù)據(jù)和元數(shù)據(jù)。Spark Streaming 中的有狀態(tài)數(shù)據(jù)轉(zhuǎn)換有兩種類型:updateStateByKey 和 windowed transformations.

updateStateByKey 維護(hù)了在 Pair RDD 中一個(gè)流中的每個(gè)鍵值的狀態(tài)。當(dāng)DStream中的鍵值漲停被更新時(shí)返回一個(gè)新的狀態(tài)。 一個(gè)例子是tweets的stream 中運(yùn)行了given hashtags 的個(gè)數(shù)統(tǒng)計(jì)。Windowed transformations 在多個(gè)批處理的滑動(dòng)窗口中執(zhí)行。一個(gè)窗口有一個(gè)定義好的長(zhǎng)度或時(shí)間單元的區(qū)間,是多個(gè)單一
DStream 處理的間隔,定義了一個(gè)窗口轉(zhuǎn)換中有多少個(gè)批處理或窗口轉(zhuǎn)換中計(jì)算的頻率。

下面的 schema 在 DStreams上的窗口操作,在給定長(zhǎng)度和滑動(dòng)間隔時(shí)生成 window DStreams :


5-6 Windowing on Dstreams

函數(shù)示例是 countByWindow (windowLength, slideInterval). 在 DStream上的一個(gè)滑動(dòng)窗口中,計(jì)算每個(gè)單元素RDD的元素個(gè)數(shù),返回一個(gè)新的DStream. 通過每60秒計(jì)算一次tweets流中指定的hashtags的數(shù)據(jù)作為示例的解釋。 窗口的時(shí)間幀是指定的。分鐘級(jí)的窗口長(zhǎng)度是有道理的。
由于是計(jì)算和內(nèi)存密集型的,所以小時(shí)級(jí)的窗口長(zhǎng)度是不推薦的。在Cassandra 或 HBase 這樣的數(shù)據(jù)中聚合數(shù)據(jù)更為方便。窗口數(shù)據(jù)轉(zhuǎn)換計(jì)算出的結(jié)果是基于窗口長(zhǎng)度和窗口滑動(dòng)間隔的。
Spark 的性能受窗口長(zhǎng)度,窗口滑動(dòng)間隔,和持久化的影響。

構(gòu)建容錯(cuò)系統(tǒng)

實(shí)時(shí)流處理系統(tǒng)必須是 24/7可用的,這需要在各種錯(cuò)誤發(fā)生時(shí)系統(tǒng)是可靠的。 Spark 和 RDD 抽象 被設(shè)計(jì)成可以無縫處理集群中任何節(jié)點(diǎn)的故障.

Spark Streaming 容錯(cuò)處理的主要機(jī)制是 核對(duì)檢驗(yàn)點(diǎn),自動(dòng)重啟驅(qū)動(dòng), 和自動(dòng)故障切換。檢驗(yàn)點(diǎn)中存儲(chǔ)了應(yīng)用的狀態(tài),使它 Spark能夠從驅(qū)動(dòng)故障中國年恢復(fù)。

Spark Version 1.2 通過寫前日志, 可靠的接收器, 和文件流保證了數(shù)據(jù)的零丟失。 寫前日志代表了接收數(shù)據(jù)的容錯(cuò)存儲(chǔ)。出現(xiàn)故障要求重新計(jì)算結(jié)果。
DStream 操著有著準(zhǔn)確的語意。數(shù)據(jù)轉(zhuǎn)換可能計(jì)算多次,但產(chǎn)生相同的結(jié)果。 DStream 輸出操作至少有一個(gè)語意。輸出操作也可能執(zhí)行多次。

以TCP sockets處理實(shí)時(shí)數(shù)據(jù)

理解了流操作的基礎(chǔ),先在TCP socket 上作實(shí)驗(yàn)。 TCP socket 建立在客戶端和服務(wù)器之間 的雙工通信,通過已建的連接交互數(shù)據(jù)。 WebSocket 與Http 連接不一樣,是長(zhǎng)連接。
HTTP 不會(huì)在server側(cè)保持一個(gè)連接并連續(xù)推送數(shù)據(jù)到web瀏覽器。很多 web應(yīng)用因而通過AJAX和XML請(qǐng)求采用了長(zhǎng)輪詢 . WebSockets 是HTML5 中實(shí)現(xiàn)的標(biāo)準(zhǔn),支持現(xiàn)代的 web瀏覽器并稱為了實(shí)時(shí)通訊的跨平臺(tái)標(biāo)準(zhǔn)。

創(chuàng)建TCP sockets

運(yùn)行netcat 創(chuàng)建一個(gè) TCP Socket Server, 這是Linux系統(tǒng)中的一個(gè)小工具可以作為數(shù)據(jù)服務(wù)器,命令如下:

#
#  Socket  Server
#
an@an-VB:~$  nc  -lk  9999
hello  world
how  are  you
hello   world
cool  it  works

一旦 netcat運(yùn)行起來, 以Spark Streaming 的客戶端打開第二個(gè)控制臺(tái)來接收和處理數(shù)據(jù)。 一旦 Spark Streaming 客戶端控制臺(tái)監(jiān)聽我們的鍵入單詞并處理, 就是反饋, hello world.

處理實(shí)時(shí)數(shù)據(jù)

我們將使用 Spark 提供的Spark
Streaming 示例程序 network_wordcount.py. 可以從GitHub 獲得 https://github.com/apache/spark/blob/master/examples/src/main/python/streaming/network_wordcount.py.
代碼如下:

"""
Counts  words  in  UTF8  encoded,  '\n'  delimited  text  received  from  the
network  every  second.
Usage:  network_wordcount.py  <hostname>  <port>
<hostname>  and  <port>  describe  the  TCP  server  that  Spark  Streaming
would  connect  to  receive  data.
To  run  this  on  your  local  machine,  you  need  to  first  run  a  Netcat
server
`$  nc  -lk  9999`
and  then  run  the  example
`$  bin/spark-submit  examples/src/main/python/streaming/network_
wordcount.py  localhost  9999`
"""

from  __future__  import  print_function


import  sys
from  pyspark.streaming  import  StreamingContext


if  __name__  ==  "__main__":

    if  len(sys.argv)  !=  3:

        print("Usage:  network_wordcount.py  <hostname>  <port>",
file=sys.stderr)

        exit(-1)
  
    sc  = SparkContext(appName="PythonStreamingNetworkWordCount")
    ssc = StreamingContext(sc,  1)  
    lines  =  ssc.socketTextStream(sys.argv[1], int(sys.argv[2]))

    counts  =  lines.flatMap(lambda  line:  line.split("  "))\
.map(lambda  word:  (word,  1))\

    .reduceByKey(lambda  a,  b:  a+b) 


ssc.start()  

ssc.awaitTermination()

解釋一下程序的過程:

  1. 第一行代碼初始化 :
    ssc = StreamingContext(sc, 1)

2.接著, 建立流式計(jì)算.

  1. 連接localhost 或 127.0.0.1 的9999端口從接收數(shù)據(jù)中得到一個(gè)或多個(gè) DStream 對(duì)象 :
    stream = ssc.socketTextStream("127.0.0.1", 9999)

  2. 定義DStream 的計(jì)算: 數(shù)據(jù)轉(zhuǎn)換和輸出操作:
    stream.map(x: lambda (x,1)) .reduce(a+b) .print()

  3. 開始計(jì)算:
    ssc.start()

  4. 手工刮起活錯(cuò)誤處理完成時(shí)中斷程序:
    ssc.awaitTermination()

  5. 當(dāng)?shù)竭_(dá)完成條件時(shí),可以手工完成處理:
    ssc.stop()
    通過瀏覽Spark 的監(jiān)測(cè)主頁localhost:4040 可以監(jiān)測(cè)Spark Streaming 流應(yīng)用 .

這里是程序運(yùn)行的結(jié)果以及netcat記錄的字符:

#
#  Socket  Client
#  
an@an-VB:~/spark/spark-1.5.0-bin-hadoop2.6$  ./bin/spark-submit
examples/src/main/python/streaming/network_wordcount.py  localhost  9999

連接localhost 的9999端口 運(yùn)行Spark Streaming network_count 程序:

an@an-VB:~/spark/spark-1.5.0-bin-hadoop2.6$  ./bin/spark-submit  examples/
src/main/python/streaming/network_wordcount.py  localhost  9999
-------------------------------------------
Time:  2015-10-18  20:06:06
-------------------------------------------
(u'world',  1)
(u'hello',  1)

-------------------------------------------
Time:  2015-10-18  20:06:07
-------------------------------------------
.  .  .
-------------------------------------------
Time:  2015-10-18  20:06:17
-------------------------------------------
(u'you',  1)
(u'how',  1)
(u'are',  1)

-------------------------------------------
Time:  2015-10-18  20:06:18
-------------------------------------------

.  .  .

-------------------------------------------
Time:  2015-10-18  20:06:26
-------------------------------------------
(u'',  1)
(u'world',  1)
(u'hello',  1)


因此, 已經(jīng)建立了本地9999端口的socket連接,流式處理
netcat 發(fā)送的數(shù)據(jù) , 執(zhí)行發(fā)送消息的單純統(tǒng)計(jì)。

實(shí)時(shí)控制Twitter數(shù)據(jù)

Twitter 提供了兩個(gè) APIs. 搜索 API允許我們根據(jù)搜索條目獲得過去的 tweets. 這就是我們前面章節(jié)如何從Twitter采集數(shù)據(jù)的方式。我們的目的是通過,Twitter 提供的實(shí)時(shí)streaming API ,從博客世界接收用戶剛發(fā)送的 tweets .

實(shí)時(shí)處理Tweets

下面的程序連接了 Twitter服務(wù),處理流入的 tweets單不包括已刪除或無效的 tweets,實(shí)時(shí)解析相關(guān)tweet提取 screen 名稱, 或 tweet text, retweet count, geo-location 信息. 處理過的 tweets 通過Spark Streaming 收集到一個(gè)RDD Queue,然后每隔一秒顯示在控制臺(tái)上 :


"""


Twitter  Streaming  API  Spark  Streaming  into  an  RDD-Queue  to  process
tweets  live Create  a  queue  of  RDDs  that  will  be  mapped/reduced  one  at  a  time  in 1  second  intervals.

To  run  this  example  use
'$  bin/spark-submit  examples/AN_Spark/AN_Spark_Code/s07_
twitterstreaming.py'
"""

#
import  time
from  pyspark  import  SparkContext
from  pyspark.streaming  import  StreamingContext
import  twitter
import  dateutil.parser
import  json
 # Connecting  Streaming  Twitter  with  Streaming  Spark  via  Queue 
 
 class  Tweet(dict):
    def  __init__(self,  tweet_in):
        super(Tweet,  self).__init__(self)
        if  tweet_in  and  'delete'  not  in  tweet_in:
            self['timestamp']  =  dateutil.parser.parse(tweet_
            in[u'created_at']
            ).replace(tzinfo=None).isoformat()
            self['text']  =  tweet_in['text'].encode('utf-8')
            #self['text']  =  tweet_in['text']
            self['hashtags']  =  [x['text'].encode('utf-8')  for  x  in
            tweet_in['entities']['hashtags']]
            #self['hashtags']  =  [x['text']  for  x  in  tweet_
            in['entities']['hashtags']]
            self['geo']  =  tweet_in['geo']['coordinates']  if  tweet_
            in['geo']  else  None
            self['id']  =  tweet_in['id']
            self['screen_name']  =  tweet_in['user']['screen_name'].
            encode('utf-8')
            #self['screen_name']  =  tweet_in['user']['screen_name']
            self['user_id']  =  tweet_in['user']['id'`
    
    def  connect_twitter():
        twitter_stream  =  twitter.TwitterStream(auth=twitter.OAuth(
        token  =  "get_your_own_credentials",
        token_secret  =  "get_your_own_credentials",
        consumer_key  =  "get_your_own_credentials",
        consumer_secret  =  "get_your_own_credentials"))
        return  twitter_stream
    
    def  get_next_tweet(twitter_stream):
        stream  =  twitter_stream.statuses.sample(block=True)
        tweet_in  =  None
        while  not  tweet_in  or  'delete'  in  tweet_in:
            tweet_in  =  stream.next()
            tweet_parsed  =  Tweet(tweet_in)
        return  json.dumps(tweet_parsed)
    
    def  process_rdd_queue(twitter_stream):
        #  Create  the  queue  through  which  RDDs  can  be  pushed  to
        #  a  QueueInputDStream
        rddQueue  =  []
        for  i  in  range(3):
            rddQueue  +=  [ssc.sparkContext.parallelize([get_next_
            tweet(twitter_stream)],  5)]
        
        lines  =  ssc.queueStream(rddQueue)
        lines.pprint()
        
    if  __name__  ==  "__main__":
        sc  =  SparkContext(appName="PythonStreamingQueueStream")
        ssc  =  StreamingContext(sc,  1)
        
        #  Instantiate  the  twitter_stream
        twitter_stream  =  connect_twitter()
        #  Get  RDD  queue  of  the  streams  json  or  parsed
        process_rdd_queue(twitter_stream)
        
        ssc.start()
        time.sleep(2)
        ssc.stop(stopSparkContext=True,  stopGraceFully=True)

運(yùn)行這個(gè)程序,有如下輸出:

an@an-VB:~/spark/spark-1.5.0-bin-hadoop2.6$ bin/spark-submit examples/
AN_Spark/AN_Spark_Code/s07_twitterstreaming.py


Time: 2015-11-03 21:53:14

{"user_id": 3242732207, "screen_name": "cypuqygoducu", "timestamp":
"2015-11-03T20:53:04", "hashtags": [], "text": "RT @VIralBuzzNewss:
Our Distinctive Edition Holiday break Challenge Is In this article!
Hooray!... - https://t.co/9d8wumrd5v https://t.co/\u2026", "geo": null,
"id": 661647303678259200}


Time: 2015-11-03 21:53:15

{"user_id": 352673159, "screen_name": "melly_boo_orig", "timestamp":
"2015-11-03T20:53:05", "hashtags": ["eminem"], "text": "#eminem
https://t.co/GlEjPJnwxy", "geo": null, "id": 661647307847409668}


Time: 2015-11-03 21:53:16

{"user_id": 500620889, "screen_name": "NBAtheist", "timestamp": "2015-11-
03T20:53:06", "hashtags": ["tehInterwebbies", "Nutters"], "text": "See?
That didn't take long or any actual effort. This is #tehInterwebbies
... #Nutters Abound! https://t.co/QS8gLStYFO", "geo": null, "id":
661647312062709761}


我們有了一個(gè)用Spark流式接收并飛速地處理它們.

  

# 構(gòu)建一個(gè)穩(wěn)定縮放的流式應(yīng)用
 

攝取數(shù)據(jù)是從各種源中獲取數(shù)據(jù)并馬上處理或存儲(chǔ)起來稍后處理的過程。數(shù)據(jù)消費(fèi)系統(tǒng)是分散的,可以從架構(gòu)或物理上與數(shù)據(jù)源分開。數(shù)據(jù)攝取經(jīng)常通過手工腳本實(shí)現(xiàn)或基本的自動(dòng)化。實(shí)際上,可以調(diào)用象 Flume 和Kafka這樣的高層框架。數(shù)據(jù)攝取的挑戰(zhàn)來自原數(shù)據(jù)的物理分散和暫態(tài)導(dǎo)致的集成集成脆弱性。對(duì)于天氣,交通,社交媒體,網(wǎng)絡(luò)行為,傳感器,安全,監(jiān)控來說,數(shù)據(jù)產(chǎn)品是連續(xù)的。 

不斷增長(zhǎng)的數(shù)據(jù)容量和流量以及變化的數(shù)據(jù)結(jié)構(gòu)和語意是數(shù)據(jù)攝取混亂并有錯(cuò)誤傾向。   

我們的目標(biāo)是更加的敏捷,可靠和伸縮性。數(shù)據(jù)攝取的敏捷性,可靠性和伸縮性決定了流水線的健康程度。敏捷性意味著可以集成新的數(shù)據(jù)源,并按需改變現(xiàn)存的數(shù)據(jù)源。  為了保證安全可靠, 需要從基礎(chǔ)設(shè)施上防止數(shù)據(jù)丟失,防止下游應(yīng)用在入口處得到的數(shù)據(jù)遭到破壞。伸縮性避免了攝取瓶頸,能夠保持?jǐn)?shù)據(jù)的快速處理。

![5-7 數(shù)據(jù)攝取模式](http://upload-images.jianshu.io/upload_images/73516-67ae0d0ec431c4ee?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

  使所有數(shù)據(jù)得到快速的響應(yīng),核心驅(qū)動(dòng)是統(tǒng)一日志。統(tǒng)一日志是實(shí)時(shí)訂閱的集中化企業(yè)結(jié)構(gòu)化日志。所有的組織數(shù)據(jù)放到一個(gè)中心化的日志中。記錄編號(hào)從零開始,被看作是一個(gè)提交日志或者 journal.   Unified  Log  的概念是Kappa 架構(gòu)的核心宗旨。
Unified  Log 的特性如下:
  
  ? Unified:  針對(duì)所有組織的單一部署。  
  
? Append  only: 事件是可追加且不可變的  
  

? Ordered: 在一個(gè)切片內(nèi)每個(gè)事件有位惟一的偏移量  
  

 
? Distributed:  考慮容錯(cuò), Unified  Log 冗余分布在集群的各臺(tái)主機(jī)上 
  

 
? Fast:  系統(tǒng)每秒攝取成千上萬的消息  

#搭建 Kafka

為了獨(dú)立數(shù)據(jù)上行和數(shù)據(jù)消費(fèi),需要對(duì)數(shù)據(jù)提供者和消費(fèi)者解耦合。 由于雙方有不同的周期和約束,  Kafka 可以解耦合數(shù)據(jù)處理的流水線.Apache  Kafka  是一個(gè)分布式的發(fā)布訂閱消息系統(tǒng),也可以理解成一個(gè)分布式的提交日志。消息按照話題存儲(chǔ).  

Apache  Kafka  有如下特性. 它支持:
 
  

? 高容量事件的高吞吐量  

 

? 新的和派生的 feeds 的實(shí)時(shí)處理   

  
? 低時(shí)延的企業(yè)級(jí)消息系統(tǒng)

  
?容錯(cuò)歸功于分區(qū)內(nèi)的分布式消息存儲(chǔ),每個(gè)消息都有一個(gè)惟一的序列  ID 叫做  offset.
Consumers  通過 元組(offset,  partition,  topic)檢查它們的指針.  


深入解剖一下 Kafka.Kafka 有三個(gè)基本組件:  producers, consumers 和brokers.  Producers 


  
推送并寫數(shù)據(jù)到brokers.  Consumers 從broker 拉取并讀到數(shù)據(jù).  Brokers不推送消息給consumers. Consumers 從brokers拉取數(shù)據(jù). 分布式協(xié)作由 Apache  Zookeeper完成.
brokers以話題形式存儲(chǔ)和管理數(shù)據(jù). 話題分割到復(fù)制分區(qū)內(nèi)。數(shù)據(jù)持久化broker,  在存留期間并不移除.  如果一個(gè)consumer 失敗了,  它總是回到broker  再次獲取數(shù)據(jù).  






Kafka  需要 Apache  ZooKeeper支持.  ZooKeeper 是分布式應(yīng)用的一個(gè)高性能協(xié)調(diào)服務(wù)。它集中管理配置,注冊(cè)或命名服務(wù),組的成員關(guān)系,鎖, 服務(wù)器間的同步協(xié)調(diào),提供了層次化命名空間,有元數(shù)據(jù),監(jiān)測(cè)統(tǒng)計(jì)和集群狀態(tài)。  ZooKeeper  可以快速地引入 brokers和  consumers,然后在集群內(nèi)重新均衡。 




Kafka  producers 不需要 ZooKeeper.  Kafka  brokers  使用  ZooKeeper提供通用的狀態(tài)信息在故障的時(shí)候選舉leader.  Kafka  consumers  使用ZooKeeper  跟蹤消息的偏移量.  新版本的 Kafka 將通過 ZooKeeper  保存consumers,并提取Kafka 中特定的話題信息 .Kafka 為producers提供了自動(dòng)的負(fù)載均衡.
下圖描述了Kafka  的建立過程:  
![5-8 Kafka 架構(gòu)](http://upload-images.jianshu.io/upload_images/73516-37737e3f1c926923?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)  

## 安裝測(cè)試Kafka
下載 Apache  Kafka  執(zhí)行文件 
http://kafka.apache.org/downloads.html  按下列步驟安裝軟件:
 
1. 下載代碼 . 
2. 
下載  0.8.2.0  版本并解壓:
>  tar  -xzf  kafka_2.10-0.8.2.0.tgz
>  cd  kafka_2.10-0.8.2.0  

3.啟動(dòng)zooeeper. 使用一個(gè)方便的腳步讓Kafka 得到 ZooKeeper 的一個(gè)單節(jié)點(diǎn)實(shí)例   

.

bin/zookeeper-server-start.sh config/zookeeper.properties

an@an-VB:~/kafka/kafka_2.10-0.8.2.0$ bin/zookeeper-server-start.sh
config/zookeeper.properties

[2015-10-31 22:49:14,808] INFO Reading configuration from:
config/zookeeper.properties (org.apache.zookeeper.server.quorum.
QuorumPeerConfig)

[2015-10-31 22:49:14,816] INFO autopurge.snapRetainCount set to 3
(org.apache.zookeeper.server.DatadirCleanupManager)..


4.啟動(dòng) Kafka  server:
  

bin/kafka-server-start.sh config/server.properties

an@an-VB:~/kafka/kafka_2.10-0.8.2.0$ bin/kafka-server-start.sh
config/server.properties

[2015-10-31 22:52:04,643] INFO Verifying properties (kafka.utils.
VerifiableProperties)

[2015-10-31 22:52:04,714] INFO Property broker.id is overridden to
0 (kafka.utils.VerifiableProperties)

[2015-10-31 22:52:04,715] INFO Property log.cleaner.enable is
overridden to false (kafka.utils.VerifiableProperties)

[2015-10-31 22:52:04,715] INFO Property log.dirs is overridden to
/tmp/kafka-logs (kafka.utils.VerifiableProperties)
[2013-04-22
15:01:47,051] INFO Property socket.send.buffer.bytes is overridden
to 1048576 (kafka.utils.VerifiableProperties)


5.創(chuàng)建主題.  這里創(chuàng)建一個(gè)名為 test 的主題,只有一個(gè)分區(qū)和一個(gè)副本  :
 

bin/kafka-topics.sh --create --zookeeper localhost:2181
--replication-factor 1 --partitions 1 --topic test


6.如果運(yùn)行 list  topic  命令,可以看到這一主題:
 

bin/kafka-topics.sh --list --zookeeper localhost:2181
Test

an@an-VB:~/kafka/kafka_2.10-0.8.2.0$ bin/kafka-topics.sh --create
--zookeeper localhost:2181 --replication-factor 1 --partitions 1
--topic test

Created topic "test".
an@an-VB:~/kafka/kafka_2.10-0.8.2.0$ bin/kafka-topics.sh --list
--zookeeper localhost:2181
test


7.通過創(chuàng)建一個(gè)  producer  and  consumer來檢查Kafka  的安裝。 先創(chuàng)建一個(gè)  producer ,從控制臺(tái)鍵入消息:  

an@an-VB:~/kafka/kafka_2.10-0.8.2.0$ bin/kafka-console-producer.sh
--broker-list localhost:9092 --topic test

[2015-10-31 22:54:43,698] WARN Property topic is not valid (kafka.
utils.VerifiableProperties)

This is a message

This is another message



 


8. 啟動(dòng)一個(gè) consumer  檢查接收到的消息:
an@an-VB:~$  cd  kafka/
an@an-

VB:~/kafka$ cd kafka_2.10-0.8.2.0/

an@an-VB:~/kafka/kafka_2.10-0.8.2.0$ bin/kafka-console-consumer.sh
--zookeeper localhost:2181 --topic test --from-beginning

This is a message
This is another message




consumer 正確接收消息的過程:  

1. 檢查Kafka  和  Spark  Streaming  consumer.  使用 Spark
Streaming  Kafka  單詞統(tǒng)計(jì)示例. 要注意的是:  當(dāng)發(fā)送Spark
job的時(shí)候,必須綁定 Kafka  包,  --packages  org.apache.
spark:spark-streaming-kafka_2.10:1.5.0.  命令如下:

./bin/spark-submit --packages org.apache.spark:spark-streaming-
kafka_2.10:1.5.0 \ examples/src/main/python/streaming/kafka_
wordcount.py
localhost:2181 test


2 當(dāng)用Kafka 啟動(dòng)Spark  Streaming  單詞計(jì)算程序的時(shí)候,  得到下面的輸出:  

an@an-VB:~/spark/spark-1.5.0-bin-hadoop2.6$ ./bin/spark-submit
--packages org.apache.spark:spark-streaming-kafka_2.10:1.5.0
examples/src/main/python/streaming/kafka_wordcount.py
localhost:2181 test


Time: 2015-10-31 23:46:33

(u'', 1)
(u'from', 2)
(u'Hello', 2)
(u'Kafka', 2)


Time: 2015-10-31 23:46:34


Time: 2015-10-31 23:46:35

3.安裝Kafka  Python  driver 以便對(duì) Producers  and  Consumers  編程,并使用python 與Kafka  and  Spark 交互.  我門使用David  Arthur開發(fā)的庫,  aka,  Mumrah
on  GitHub 網(wǎng)址 (https://github.com/mumrah).  安裝明亮如下:  

pip install kafka-python
an@an-VB:~$ pip install kafka-python

Collecting kafka-python

Downloading kafka-python-0.9.4.tar.gz (63kB)
...

Successfully installed kafka-python-0.9.4

## 開發(fā) producers
  

下面的程序創(chuàng)建了一個(gè)簡(jiǎn)單的Kafka  Producer ,來發(fā)送一個(gè)消息 *this  is  a  message  sent  from  the  Kafka  producer*:  5次,帶時(shí)間戳: 

kafka producer

import time

from kafka.common import LeaderNotAvailableError

from kafka.client import KafkaClient

from kafka.producer import SimpleProducer

from datetime import datetime

def print_response(response=None):
if response:
print('Error: {0}'.format(response[0].error))
print('Offset: {0}'.format(response[0].offset))

def main():
kafka = KafkaClient("localhost:9092")
producer = SimpleProducer(kafka)
try:
time.sleep(5)
topic = 'test'
for i in range(5):
time.sleep(1)
msg = 'This is a message sent from the kafka producer: '
+ str(datetime.now().time()) + ' -- '
+ str(datetime.now().strftime("%A, %d %B %Y
%I:%M%p"))
print_response(producer.send_messages(topic, msg))
except LeaderNotAvailableError:
# https://github.com/mumrah/kafka-python/issues/249
time.sleep(1)
print_response(producer.send_messages(topic, msg))

kafka.close()

if name == "main":
main()


運(yùn)行程序,產(chǎn)生如下輸出:

an@an-VB:~/spark/spark-1.5.0-bin-hadoop2.6/examples/AN_Spark/AN_Spark_
Code$ python s08_kafka_producer_01.py
Error: 0
Offset: 13
Error: 0
Offset: 14
Error: 0
Offset: 15
Error: 0
Offset: 16
Error: 0
Offset: 17
an@an-VB:~/spark/spark-1.5.0-bin-hadoop2.6/examples/AN_Spark/AN_Spark_Code$

沒有錯(cuò)誤,并且Kafka  broker 給出了消息的偏移量。

## 開發(fā) consumers
為了從 Kafka  brokers獲取消息,  開發(fā)一個(gè)Kafka  consumer: 

kafka consumer

consumes messages from "test" topic and writes them to console.

from kafka.client import KafkaClient
from kafka.consumer import SimpleConsumer

def main():
kafka = KafkaClient("localhost:9092")
print("Consumer established connection to kafka")
consumer = SimpleConsumer(kafka, "my-group", "test")
for message in consumer:
# This will wait and print messages as they become available
print(message)

if name == "main":
main()


運(yùn)行程序, 可以確認(rèn)consumer  收到了所有消息:

an@an-VB:~$ cd ~/spark/spark-1.5.0-bin- hadoop2.6/examples/AN_Spark/AN_Spark_Code/
an@an-VB:~/spark/spark-1.5.0-bin-h(huán)adoop2.6/examples/AN_Spark/AN_Spark_Code$ python s08_kafka_consumer_01.py

Consumer established connection to kafka
OffsetAndMessage(offset=13, message=Message(magic=0, attributes=0,
key=None, value='This is a message sent from the kafka producer:
11:50:17.867309Sunday, 01 November 2015 11:50AM'))
...
OffsetAndMessage(offset=17, message=Message(magic=0, attributes=0,
key=None, value='This is a message sent from the kafka producer:
11:50:22.051423Sunday, 01 November 2015 11:50AM'))


## 在Kafka 上開發(fā)Spark   Streaming   consumer    
基于Spark  Streaming  中提供的示例代碼,  創(chuàng)建 一個(gè)Kafka的  Spark  Streaming  consumer,并對(duì)Brokers中存儲(chǔ)的消息執(zhí)行 單詞統(tǒng)計(jì): 

Kafka Spark Streaming Consumer

from future import print_function

import sys

from pyspark import SparkContext
from pyspark.streaming import StreamingContext
from pyspark.streaming.kafka import KafkaUtils

if name == "main":
if len(sys.argv) != 3:
print("Usage: kafka_spark_consumer_01.py <zk> <topic>",
file=sys.stderr)
exit(-1)

sc  =  SparkContext(appName="PythonStreamingKafkaWordCount")
ssc  =  StreamingContext(sc,  1)

zkQuorum,  topic  =  sys.argv[1:]
kvs  =  KafkaUtils.createStream(ssc,  zkQuorum,  "spark-streaming-
consumer",  {topic:  1})
lines  =  kvs.map(lambda  x:  x[1])
counts  =  lines.flatMap(lambda  line:  line.split("  "))  \
.map(lambda  word:  (word,  1))  \
.reduceByKey(lambda  a,  b:  a+b)
counts.pprint()

ssc.start()
ssc.awaitTermination()

執(zhí)行程序,并運(yùn)行  Spark  submit  命令:

./bin/spark-submit --packages org.apache.spark:spark-streaming-
kafka_2.10:1.5.0 examples/AN_Spark/AN_Spark_Code/s08_kafka_spark_
consumer_01.py localhost:2181 test


得到如下輸出:


an@an-VB:~$ cd spark/spark-1.5.0-bin-hadoop2.6/
an@an-VB:~/spark/spark-1.5.0-bin-hadoop2.6$ ./bin/spark-submit
--packages org.apache.spark:spark-streaming-kafka_2.10:1.5.0
examples/AN_Spark/AN_Spark_Code/s08_kafka_spark_consumer_01.py
localhost:2181 test
...
:: retrieving :: org.apache.spark#spark-submit-parent
confs: [default]
0 artifacts copied, 10 already retrieved (0kB/18ms)


Time: 2015-11-01 12:13:16


Time: 2015-11-01 12:13:17


Time: 2015-11-01 12:13:18


Time: 2015-11-01 12:13:19

(u'a', 5)
(u'the', 5)
(u'11:50AM', 5)
(u'from', 5)
(u'This', 5)
(u'11:50:21.044374Sunday,', 1)
(u'message', 5)
(u'11:50:20.036422Sunday,', 1)
(u'11:50:22.051423Sunday,', 1)
(u'11:50:17.867309Sunday,', 1)
...


Time: 2015-11-01 12:13:20


Time: 2015-11-01 12:13:21


# 探索flume
Flume 是一個(gè)連續(xù)攝取數(shù)據(jù)的系統(tǒng),最初被設(shè)計(jì)成一個(gè)日志聚會(huì)系統(tǒng),但演變?yōu)榭梢蕴幚砣魏晤愋偷牧魇录?shù)據(jù)。
Flume 是一個(gè)分布式,可靠的,具有伸縮性的流水線系統(tǒng),可以有效地采集,聚會(huì),傳輸大容量數(shù)據(jù),內(nèi)置支持上下文路由,過濾復(fù)制,和多路復(fù)用。 容錯(cuò)和健壯性好,擁有可調(diào)的可靠性機(jī)制,多種故障切換和恢復(fù)機(jī)制.  它使用簡(jiǎn)單可擴(kuò)展的數(shù)據(jù)模型應(yīng)用于實(shí)時(shí)分析。


Flume  提供了:
  

? 保證傳輸?shù)恼Z意
  

? 低時(shí)延可靠的數(shù)據(jù)傳輸
  

? 不需要編碼的聲明式配置
  

? 可擴(kuò)展和定制的設(shè)置  


? 集成了大多數(shù)通用的端點(diǎn)數(shù)據(jù)源 


 Flume  包括以下元素:
? Event:  一個(gè)事件是Flume從源到目的地址傳輸數(shù)據(jù)的基本單元.  象一條消息那樣,對(duì) Flume  而言是不透明的字節(jié)數(shù)組,通過可選的頭信息來做上下文路由。 

? Client:  一個(gè) client  生產(chǎn)和傳輸事件.  客戶端把 Flume和數(shù)據(jù)消費(fèi)者解耦合,是一個(gè)生成事件并把它們發(fā)送到一個(gè)或多個(gè)代理 的實(shí)體,可以是定制的客戶端或者
 Flume  log4J  程序 或  潛入到應(yīng)用中的代理.


? Agent:  一個(gè)代理是一個(gè)容器,承載了源,信道, sinks, 和其它元素使數(shù)據(jù)能在不同地址間傳輸。它對(duì)托管的組件提供了配置,生命周期管理和監(jiān)控。代理在物理上是一個(gè)運(yùn)行 Flume的Java 虛擬機(jī)。

 
? Source:  源師Flume 接收事件的實(shí)體,至少使用一個(gè)信道,通過該信道輪詢數(shù)據(jù)或者等待數(shù)據(jù)發(fā)送給它,有各種采集數(shù)據(jù)的源,例如  log4j  logs 和 syslogs.
 

 
? Sink:  Sink 是一個(gè)實(shí)體,將信道中的數(shù)據(jù)排空并發(fā)送到下一個(gè)目的地址。 sinks 允許數(shù)據(jù)被流式發(fā)送到一定范圍的目的地址。 Sinks  支持序列化到用戶的格式.  例如 HDFS  sink 將事件寫到 HDFS.  
? Channel:  信道是源和sink之間的管道,緩存流入的事件之道sink 將信道中的數(shù)據(jù)排空。源給信道提供事件,Sink 排空信道。 信道解耦合了上下行系統(tǒng),抑制了上行數(shù)據(jù)的突發(fā)性, 客服了下行故障。為了實(shí)現(xiàn)這一目的,關(guān)鍵是調(diào)整處理事件的信道容量。
信道提供了兩種層次的持久化:  內(nèi)存型信道和文件型信道。當(dāng)JVM崩潰時(shí),內(nèi)存型信道是不穩(wěn)定的,
而文件型信道通過寫前日志 把信息存儲(chǔ)到硬盤,所以可以回復(fù)。信道是全事務(wù)型的。
  

下圖解釋了這些概念: 
![5-8 Flume](http://upload-images.jianshu.io/upload_images/73516-7d3adb34cfd7e520?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

# 基于Flume, Kafka和Spark開發(fā)數(shù)據(jù)流水線
利用我們已學(xué)的知識(shí),可以構(gòu)建一個(gè)彈性的數(shù)據(jù)處理流水線。通過Flume 將數(shù)據(jù)攝取和傳輸放到一起,把Kafka 這樣的可靠的發(fā)布訂閱消息系統(tǒng)作為數(shù)據(jù)代理,最后使用Spark Streaming 完成高速的計(jì)算處理。  
下圖解釋了流式數(shù)據(jù)流水線的組成 connect,  collect,  conduct,  compose,  consume,  consign,  和 control.
 這些活動(dòng)根據(jù)用例來配置: 

+ Connect 建立了streaming  API的綁定 


+ Collect  創(chuàng)建了采集線程.
 
+ Compose 專注于處理數(shù)據(jù)
+ Consume  為消費(fèi)系統(tǒng)提供處理后的數(shù)據(jù)
+  
Consign  負(fù)責(zé)數(shù)據(jù)持久化
+  Control  負(fù)責(zé)系統(tǒng)、數(shù)據(jù)和營(yíng)養(yǎng)的統(tǒng)籌和監(jiān)控。

![5-9 Streaming 數(shù)據(jù)流水線](http://upload-images.jianshu.io/upload_images/73516-b699f887eae27464?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)  

下圖介紹了流式數(shù)據(jù)流水線的概念及關(guān)鍵組件:  Spark  Streaming,  Kafka,  Flume,  和低時(shí)延數(shù)據(jù)庫.  在消費(fèi)或控制型應(yīng)用中,需要實(shí)時(shí)監(jiān)控系統(tǒng),或者在超出一定閾值時(shí)實(shí)時(shí)發(fā)送告警。

![5-10 flume kafka streaming](http://upload-images.jianshu.io/upload_images/73516-7f86ba52cae59131?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

下圖介紹了Spark 在處理單平臺(tái)運(yùn)動(dòng)數(shù)據(jù)和閑置數(shù)據(jù)的獨(dú)特能力,即根據(jù)不同的用例需求與多個(gè)持久化數(shù)據(jù)存儲(chǔ)無縫對(duì)接。

![5-11 運(yùn)動(dòng)數(shù)據(jù)處理](http://upload-images.jianshu.io/upload_images/73516-5c84b86dbc5e131f?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)  

這張圖是到目前為止所談?wù)摰乃懈拍睢m敳棵枋隽肆魇教幚砹魉€。底部描述了批處理流水線 ,兩者共享位于中間的通用持久化層,包含各種模式的持久化和序列化。 

# Lambda 和Kappa 架構(gòu)
現(xiàn)在有兩種流行的架構(gòu)范式:   Lambda  和 Kappa  架構(gòu).  

Lambda  是Storm 創(chuàng)建者何主要提交者 Nathan  Marz 的作品.  他倡導(dǎo)在所有數(shù)據(jù)上構(gòu)建功能型架構(gòu)。批處理分支是Hadoop 的最初設(shè)想 , 是歷史數(shù)據(jù)的高時(shí)延高吞吐量的預(yù)處理,然后用于消費(fèi)。實(shí)時(shí)處理分支由Storm設(shè)計(jì)的,可以增量處理流數(shù)據(jù),快速產(chǎn)生結(jié)論性見解,從存儲(chǔ)中實(shí)時(shí)聚合數(shù)據(jù)。
Kappa 是Kafka 的主要提交者之一  Jay  Kreps 和他在 Confluent  (previously  at  LinkedIn)的同事的作品.  它倡導(dǎo)全部流式流水線,和前面談到的統(tǒng)一日志,是企業(yè)級(jí)的高效實(shí)現(xiàn).

 

## 理解 Lambda 架構(gòu)

Lambda 架構(gòu)結(jié)合了批處理和流式處理,在所有數(shù)據(jù)上提供了統(tǒng)一的查詢機(jī)制。有三層:  存儲(chǔ)預(yù)計(jì)算信息的批處理層,增量進(jìn)行流式實(shí)時(shí)處理的速度層,服務(wù)層合并了批處理和實(shí)時(shí)處理的隨機(jī)查詢。 下圖給出了 Lambda  的架構(gòu)。 

![5-12 Lambda](http://upload-images.jianshu.io/upload_images/73516-38c3e27b45f22d05?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)  

## 理解Kappa 架構(gòu)
Kappa 架構(gòu)目標(biāo)是全企業(yè)的流模式驅(qū)動(dòng),起源于  Jay  Kreps 和他在LinkedIn的同事的一個(gè)評(píng)論文章。
 從那時(shí)起,他們利用Apache
Kafka 創(chuàng)建了 Confluent  with  Apache,并作為
 Kappa  架構(gòu)的主要促成者.  基本宗旨是使用統(tǒng)一日志作為企業(yè)信息架構(gòu)的主干,進(jìn)而移動(dòng)到流處理模式。  

統(tǒng)一日志是一個(gè)集中的企業(yè)結(jié)構(gòu)化日志,用于實(shí)時(shí)訂閱。所有組織的數(shù)據(jù)放入到一個(gè)集中的日志,記錄寫入時(shí)從零開始做標(biāo)記,可以時(shí)提及日志或日志集合。統(tǒng)一日志的概念是 
Kappa 架構(gòu)的核心宗旨.
統(tǒng)一日志的特點(diǎn)如下:
  
? Unified:  所有組織的同一部署  

? Append  only:  事件是可追加且不可修改的 


? Ordered:  每個(gè)事件在分片內(nèi)有唯一的偏移量 
  


? Distributed: 出于容錯(cuò)考慮,  統(tǒng)一日志分布于在集群的不同主機(jī)上。  



? Fast:  系統(tǒng)每秒攝取成千上萬的數(shù)據(jù)
   



下面的截圖展示了 Jay  Kreps 宣稱對(duì)  Lambda  架構(gòu)的保留意見.  他關(guān)于Lambda架構(gòu)的主要保留意見是在Hadoop  and  Storm兩個(gè)不同的系統(tǒng)中實(shí)現(xiàn)了相同的工作每個(gè)有著各自的特性,以及隨之而來的復(fù)雜性。
Kappa  通過Apache  Kafka 既處理了實(shí)時(shí)數(shù)據(jù),也處理了歷史數(shù)據(jù)。

![5-13 Kappa](http://upload-images.jianshu.io/upload_images/73516-6690e2afef745ba5?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 

# 小結(jié)

我門列舉了流式處理架構(gòu)應(yīng)用的基礎(chǔ),描述了他們的挑戰(zhàn),約束和優(yōu)勢(shì)。深入了解了Spark  Streaming  的內(nèi)部工作原理包括如何Spark  Core 適用,以及與Spark  SQL  和 Spark  MLlib對(duì)話, 通過TCP sockets 解釋了流處理概念,接下來,是從Twitter 服務(wù)中實(shí)時(shí)攝取tweet。使用Kafka最大限度地增加了流處理架構(gòu)的彈性,討論了上下行數(shù)據(jù)與消費(fèi)者之間的解耦合。  還討論了Flume—這個(gè)可靠,靈活,伸縮性數(shù)據(jù)攝取和傳輸?shù)牧魉€系統(tǒng)。結(jié)合Flume,  Kafka,  和Spark  在時(shí)變領(lǐng)域交付了非并行健壯性,速度和敏捷性.  

在結(jié)尾觀察和點(diǎn)評(píng)了兩種流處理架構(gòu)范式  Lambda 和 Kappa  架構(gòu). Lambda  架構(gòu)在通用的查詢前端結(jié)合了 批處理和流數(shù)據(jù). 最初想法形成了 Hadoop和Storm的愿景.  Spark  有自己的批處理和流處理范式,  以共有代碼為基礎(chǔ)提供了單一的環(huán)境,從而有效地在現(xiàn)實(shí)中使用這一架構(gòu)。Kappa  架構(gòu)宣揚(yáng)了同一日志的概念,  這創(chuàng)建了面向事件的架構(gòu),企業(yè)的所有數(shù)據(jù)通過信道傳輸?shù)揭粋€(gè)中心化的提交日志,同時(shí)對(duì)所有消費(fèi)者實(shí)時(shí)使用。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,345評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,494評(píng)論 3 416
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,283評(píng)論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,953評(píng)論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,714評(píng)論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,186評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,255評(píng)論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,410評(píng)論 0 288
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,940評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,776評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,976評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,518評(píng)論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,210評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,642評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,878評(píng)論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,654評(píng)論 3 391
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,958評(píng)論 2 373

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