關於簡單介紹Mapreduce,Hbase,Kafka,Zookeeper

1.1. zookeeper是幹什麼的?

Zookeeper 是 分佈式協調服務,

分佈式應用程序可以基於它實現同步服務,配置維護和命名服務等

1.2. zookeeper節點類型

Znode有兩種類型:

短暫(ephemeral)(斷開連接自己刪除)

持久(persistent)(斷開連接不刪除)

Znode有四種形式的目錄節點(默認是persistent 

PERSISTENT

PERSISTENT_SEQUENTIAL(持久序列/test0000000019 

EPHEMERAL

EPHEMERAL_SEQUENTIAL

創建znode時設置順序標識,znode名稱後會附加一個值

順序號是一個單調遞增的計數器,由父節點維護

在分佈式系統中,順序號可以被用於爲所有的事件進行全局排序,這樣客戶端可以通過順序號推斷事件的順序

Zookpeeper的基本架構

這裏寫圖片描述
1 每個Server在內存中存儲了一份數據;
2 Zookeeper啓動時,將從實例中選舉一個leader(Paxos協議);
3 Leader負責處理數據更新等操作(Zab協議);
4 一個更新操作成功,當且僅當大多數Server在內存中成功修改
數據。
這裏寫圖片描述


1.3. zookeeper選舉機制

1.3.1. zookeeper的選舉機制(全新集羣)

以一個簡單的例子來說明整個選舉的過程.
假設有五臺服務器組成的zookeeper集羣,它們的id1-5,同時它們都是最新啓動的,也就是沒有歷史數據,在存放數據量這一點上,都是一樣的.假設這些服務器依序啓動,來看看會發生什麼.
1) 服務器1啓動,此時只有它一臺服務器啓動了,它發出去的報沒有任何響應,所以它的選舉狀態一直是LOOKING狀態
2) 服務器2啓動,它與最開始啓動的服務器1進行通信,互相交換自己的選舉結果,由於兩者都沒有歷史數據,所以id值較大的服務器2勝出,但是由於沒有達到超過半數以上的服務器都同意選舉它(這個例子中的半數以上是3),所以服務器1,2還是繼續保持LOOKING狀態.
3) 服務器3啓動,根據前面的理論分析,服務器3成爲服務器1,2,3中的老大,而與上面不同的是,此時有三臺服務器選舉了它,所以它成爲了這次選舉的leader.
4) 服務器4啓動,根據前面的分析,理論上服務器4應該是服務器1,2,3,4中最大的,但是由於前面已經有半數以上的服務器選舉了服務器3,所以它只能接收當小弟的命了.
5) 服務器5啓動,4一樣,當小弟.

1.3.2. 非全新集羣的選舉機制(數據恢復)

那麼,初始化的時候,是按照上述的說明進行選舉的,但是當zookeeper運行了一段時間之後,有機器down掉,重新選舉時,選舉過程就相對複雜了。

需要加入數據idleader id和邏輯時鐘。

數據id:數據新的id就大,數據每次更新都會更新id

Leader id:就是我們配置的myid中的值,每個機器一個。

邏輯時鐘:這個值從0開始遞增,每次選舉對應一個值,也就是說:  如果在同一次選舉中,那麼這個值應該是一致的 ;  邏輯時鐘值越大,說明這一次選舉leader的進程更新.

選舉的標準就變成:

1、邏輯時鐘小的選舉結果被忽略,重新投票

2、統一邏輯時鐘後,數據id大的勝出

3、數據id相同的情況下,leader id大的勝出

根據這個規則選出leader

1.4. 說說共享鎖

共享鎖在同一個進程中很容易實現,

但是在跨進程或者在不同 Server 之間就不好實現了。

Zookeeper 卻很容易實現這個功能,

實現方式也是需要獲得鎖的 Server 創建一個 EPHEMERAL_SEQUENTIAL(短暫序列化目錄節點,

然後調用 getChildren方法獲取當前的目錄節點列表中最小的目錄節點 是不是 就是自己創建的目錄節點?

如果正是自己創建的,那麼它就獲得了這個鎖,

如果不是那麼它就調用 exists(String path, boolean watch) 方法並監控 Zookeeper 上目錄節點列表的變化,

一直到自己創建的節點是列表中最小編號的目錄節點,從而獲得鎖,

釋放鎖很簡單,只要刪除前面它自己所創建的目錄節點就行了。

應用於選主


請介紹一下MapReduce的工作原理。

【解】MapReduce是一個分佈式計算框架,用於大規模數據集的並行運算。簡單地說,MapReduce就是”任務的分解與結果的彙總”:將一個大的數據處理任務劃分成許多個子任務,並將這些子任務分配給各個節點並行處理,然後通過整合各個節點的中間結果,得到最終結果。

MapReduce是主從架構,在master上跑的是JobTracker/ResourceManager,負責資源分配與任務調度;而各個slave上跑的是TaskTracker/NodeManager,負責執行任務,並定期向master彙報最新狀態與執行進度。

對於一個MR任務,它的輸入、輸出以及中間結果都是<key, value>鍵值對:

  • Map:<k1, v1> ——> list(<k2, v2>)
  • Reduce:<k2, list(v2)> ——> list(<k3, v3>)

MR程序的執行過程主要分爲三步:Map階段、Shuffle階段、Reduce階段,如下圖:

  1. Map階段

    • 分片(Split):map階段的輸入通常是HDFS上文件,在運行Mapper前,FileInputFormat會將輸入文件分割成多個split ——1個split至少包含1個HDFS的Block(默認爲64M);然後每一個分片運行一個map進行處理。

    • 執行(Map):對輸入分片中的每個鍵值對調用map()函數進行運算,然後輸出一個結果鍵值對。

      • Partitioner:對 map 函數的輸出進行partition,即根據key或value及reduce的數量來決定當前的這對鍵值對最終應該交由哪個reduce處理。默認是對key哈希後再以reduce task數量取模,默認的取模方式只是爲了避免數據傾斜。然後該key/value對以及partitionIdx的結果都會被寫入環形緩衝區。
    • 溢寫(Spill):map輸出寫在內存中的環形緩衝區,默認當緩衝區滿80%,啓動溢寫線程,將緩衝的數據寫出到磁盤。

      • Sort:在溢寫到磁盤之前,使用快排對緩衝區數據按照partitionIdx, key排序。(每個partitionIdx表示一個分區,一個分區對應一個reduce)
      • Combiner:如果設置了Combiner,那麼在Sort之後,還會對具有相同key的鍵值對進行合併,減少溢寫到磁盤的數據量。
    • 合併(Merge):溢寫可能會生成多個文件,這時需要將多個文件合併成一個文件。合併的過程中會不斷地進行 sort & combine 操作,最後合併成了一個已分區且已排序的文件。

  2. Shuffle階段:廣義上Shuffle階段橫跨Map端和Reduce端,在Map端包括Spill過程,在Reduce端包括copy和merge/sort過程。通常認爲Shuffle階段就是將map的輸出作爲reduce的輸入的過程

    • Copy過程:Reduce端啓動一些copy線程,通過HTTP方式將map端輸出文件中屬於自己的部分拉取到本地。Reduce會從多個map端拉取數據,並且每個map的數據都是有序的。

    • Merge過程:Copy過來的數據會先放入內存緩衝區中,這裏的緩衝區比較大;當緩衝區數據量達到一定閾值時,將數據溢寫到磁盤(與map端類似,溢寫過程會執行 sort & combine)。如果生成了多個溢寫文件,它們會被merge成一個有序的最終文件。這個過程也會不停地執行 sort & combine 操作。

  3. Reduce階段:Shuffle階段最終生成了一個有序的文件作爲Reduce的輸入,對於該文件中的每一個鍵值對調用reduce()方法,並將結果寫到HDFS。

你能簡單描述一下HBase嗎?能畫出它的架構圖嗎?

HBase是一個面向列的 NoSQL 分佈式數據庫,它利用HDFS作爲底層存儲系統。那麼,HBase相對於傳統的關係型數據庫有什麼不同呢?

  • HBase是schema-free的,它的列是可以動態增加的(僅僅定義列族),並且爲空的列不佔物理存儲空間。
  • HBase是基於列存儲的,每個列族都由幾個文件保存,不同的列族的文件是分離的。
  • HBase自動切分數據,使得數據存儲自動具有很好的橫向擴展性。
  • HBase沒有任何事務,提供了高併發讀寫操作的支持。

HBase中的Table是一個稀疏的、多維度的、排序的映射表,這張表的索引是[RowKey, ColumnFamily, ColumnQualifier, Timestamp],其中Timestamp表示版本,默認獲取最新版本。HBase是通過RowKey來檢索數據的,RowKey是Table設計的核心,它按照ASCII有序排序,因此應儘量避免順序寫入。RowKey設計應該注意三點:

  • 唯一原則:在HBase中rowkey可以看成是表的主鍵,必須保證其唯一性。
  • 散列原則:由於rowkey是按字典有序的,故應避免rowkey連續有序而導致在某一臺RegionServer上堆積的現象。例如可以拼接隨機數、將時間戳倒序等。
  • 長度原則:設計時RowKey要儘量短,這樣可以提高有效數據的比例,節省存儲空間,也可以提高查詢的性能。

下面是HBase的整體架構圖:


2、你說了解kafka,能簡單描述一下Kafka嗎?能畫出它的架構圖嗎?

Kafka是一個高吞吐、易擴展的分佈式發佈-訂閱消息系統,它能夠將消息持久化到磁盤,用於批量的消費。Kafka中有以下幾個概念:

  • Topic:特指Kafka處理的消息源(feeds of messages)的不同分類。
  • Partition:Topic物理上的分組,一個topic可以分爲多個partition,每個partition是一個有序的隊列。partition中的每條消息都會被分配一個有序的id(offset)。
  • Broker:Kafa集羣中包含一臺或多臺服務器,這種服務器被稱爲broker。
  • Producer:生產者,向Kafka的一個topic發佈消息。
  • Consumers:消費者,從kafka的某個topic讀取消息。

Kafka一些重要設計思想

  • Consumergroup:各個consumer可以組成一個組,每個消息只能被組中的一個consumer消費,如果一個消息可以被多個consumer消費的話,那麼這些consumer必須在不同的組。
  • 消息狀態:在Kafka中,消息的狀態被保存在consumer中,broker不會關心哪個消息被消費了被誰消費了,只記錄一個offset值(指向partition中下一個要被消費的消息位置),這就意味着如果consumer處理不好的話,broker上的一個消息可能會被消費多次。
  • 消息持久化:Kafka中會把消息持久化到本地文件系統中,並且保持極高的效率。
  • 消息有效期:Kafka會長久保留其中的消息,以便consumer可以多次消費,當然其中很多細節是可配置的。
  • 批量發送:Kafka支持以消息集合爲單位進行批量發送,以提高push效率。
  • push-and-pull : Kafka中的Producer和consumer採用的是push-and-pull模式,即Producer只管向broker push消息,consumer只管從broker pull消息,兩者對消息的生產和消費是異步的。
  • Kafka集羣中broker之間的關係:不是主從關係,各個broker在集羣中地位一樣,我們可以隨意的增加或刪除任何一個broker節點。
  • 負載均衡方面: Kafka提供了一個 metadata API來管理broker之間的負載(對Kafka0.8.x而言,對於0.7.x主要靠zookeeper來實現負載均衡)。
  • 同步異步:Producer採用異步push方式,極大提高Kafka系統的吞吐率(可以通過參數控制是採用同步還是異步方式)。
  • 分區機制partition:Kafka的broker端支持消息分區,Producer可以決定把消息發到哪個分區,在一個分區中消息的順序就是Producer發送消息的順序,一個主題中可以有多個分區,具體分區的數量是可配置的。分區的意義很重大,後面的內容會逐漸體現。
  • 離線數據裝載:Kafka由於對可拓展的數據持久化的支持,它也非常適合向Hadoop或者數據倉庫中進行數據裝載。

消息發送時都被髮送到一個topic,其本質就是一個目錄,而topic由是由一些Partition Logs(分區日誌)組成

我們可以看到,每個Partition中的消息都是有序的,生產的消息被不斷追加到Partition log上,其中的每一個消息都被賦予了一個唯一的offset值。

Kafka集羣會保存所有的消息,不管消息有沒有被消費;我們可以設定消息的過期時間,只有過期的數據纔會被自動清除以釋放磁盤空間。比如我們設置消息過期時間爲2天,那麼這2天內的所有消息都會被保存到集羣中,數據只有超過了兩天才會被清除。

kafka中的數據是持久化的並且能夠容錯的。Kafka允許用戶爲每個topic設置副本數量,副本數量決定了有幾個broker來存放寫入的數據。如果你的副本數量設置爲3,那麼一份數據就會被存放在3臺不同的機器上,那麼就允許有2個機器失敗。一般推薦副本數量至少爲2,這樣就可以保證增減、重啓機器時不會影響到數據消費。如果對數據持久化有更高的要求,可以把副本數量設置爲3或者更多。

Kafka中的topic是以partition的形式存放的,每一個topic都可以設置它的partition數量,Partition的數量決定了組成topic的log的數量。Producer在生產數據時,會按照一定規則(這個規則是可以自定義的)把消息發佈到topic的各個partition中。上面將的副本都是以partition爲單位的,不過只有一個partition的副本會被選舉成leader作爲讀寫用。

4.2消息可靠性

在消息系統中,保證消息在生產和消費過程中的可靠性是十分重要的,在實際消息傳遞過程中,可能會出現如下三中情況:

  • 一個消息發送失敗
  • 一個消息被髮送多次
  • 最理想的情況:exactly-once ,一個消息發送成功且僅發送了一次

有許多系統聲稱它們實現了exactly-once,但是它們其實忽略了生產者或消費者在生產和消費過程中有可能失敗的情況。比如雖然一個Producer成功發送一個消息,但是消息在發送途中丟失,或者成功發送到broker,也被consumer成功取走,但是這個consumer在處理取過來的消息時失敗了。
從Producer端看:Kafka是這麼處理的,當一個消息被髮送後,Producer會等待broker成功接收到消息的反饋(可通過參數控制等待時間),如果消息在途中丟失或是其中一個broker掛掉,Producer會重新發送(我們知道Kafka有備份機制,可以通過參數控制是否等待所有備份節點都收到消息)。
從Consumer端看:前面講到過partition,broker端記錄了partition中的一個offset值,這個值指向Consumer下一個即將消費message。當Consumer收到了消息,但卻在處理過程中掛掉,此時Consumer可以通過這個offset值重新找到上一個消息再進行處理。Consumer還有權限控制這個offset值,對持久化到broker端的消息做任意處理。

4.3 備份機制

備份機制是Kafka0.8版本的新特性,備份機制的出現大大提高了Kafka集羣的可靠性、穩定性。有了備份機制後,Kafka允許集羣中的節點掛掉後而不影響整個集羣工作。一個備份數量爲n的集羣允許n-1個節點失敗。在所有備份節點中,有一個節點作爲lead節點,這個節點保存了其它備份節點列表,並維持各個備份間的狀體同步


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章