Hadoop原理
分為HDFS與Yarn兩個部分。HDFS有Namenode和Datanode兩個部分。每個節點占用一個電腦。Datanode定時向Namenode發送心跳包,心跳包中包含Datanode的校驗等信息,用來監控Datanode。HDFS將數據分為塊,默認為64M每個塊信息按照配置的參數分別備份在不同的Datanode,而數據塊在哪個節點上,這些信息都存儲到Namenode上面。Yarn是MapReduce2,可以集成更多的組件,如spark、mpi等。MapReduce包括Jobtraker與Tasktraker兩個部分。其中JobTraker是在主節點上,負責整體的調度。Tasktraker在slave節點上,當提交任務后,將其交給Jobtraker進行調度,調度到該任務之后就會將jar包發送到響應的Tasktraker,以實現分布式中移動計算資源而非移動數據。因為這些任務都是並發執行的,所以每個任務需要調用哪個節點的數據必須非常的明確,通常這一部分是通過Jobtraker進行指揮。
在MapReduce的開始,每個block作為一個Map輸入,Map輸入后就進入shuffle階段。Shuffle階段主要分為Map和Reduce兩個階段。在Map Shuffle階段,Map輸入按用戶的程序進行處理,生成的結果按key排序,然后進入內存,溢出后形成一個spill寫入磁盤,這樣多個spill在這個節點中進行多路歸並排序(勝者樹)形成一個排序文件寫入磁盤,這期間那些Map文件交給那些節點處理由Jobtraker進行調度,最后生成一個大排序的文件,並且刪除spill。之后,再將多個節點上已經排序的文件進行行多路歸並排序(一個大文件N分到n個節點,每個節點分為k個spill,一個spill長度s,時間復雜度是N(logn(n個節點多路歸並排序) + logk(每個節點內k個spill排序) + logs(每個spill內部進行排序)),N=nks,所以最后的復雜度還是NlogN)。
完成Map Shuffle階段后通知Jobtraker進入Reduce Shuffle階段。在這個階段,因為已經排序,很容易將用戶的程序直接作用到相同key的數據上,這些數據作為Reduce的輸入進行處理,最終將輸出的結果數據寫入到HDFS上,並刪除磁盤數據。Map一般多,Reduce少,所以通過Hash的方法將Map文件映射到Reduce上,進行處理,這個階段叫做Patition。為了避免譬如所有數據相加這種操作使得數據負載移動的數量少的Reduce階段,造成效率低下的結果,我們可以在在Map Shuffle階段加一個Combine階段,這個Combine是在每一台節點上將已經排序好的文件進行一次Reduce並將結果作為Reduce Shuffle階段的輸入,這樣可以大大減少數據的輸入量。通常Reduce的個數通過用戶來指定,通常和CPU個數相適應才能使其效率達到最大。
HBase原理
Hbase是列存儲數據庫。其存儲的組織結構就是將相同的列族存儲在一起,因此得名的。Hbase存儲有行鍵,作為唯一標識,列表示為<列族>:<列>存儲信息,如address:city,address:provice,然后是時間戳。
Hbase物理模型中,有一個總結點HMaster,通過其自帶的zookeeper與客戶端相連接。Hbse作為分布式每一個節點作為一個RegionServer,維護Region的狀態和管理。Region是數據管理的基本單位。最初只有一個,通過擴充后達到閾值然后分裂,通過Server控制其規模。在RegionServer中,每一個store作為一個列族。當數據插入進來,新數據成為Memstore,寫入內存,當Memstore達到閾值后,通過Flashcache進程將數據寫入storeFile,也就是當內存數據增多后溢出成一個StoreFile寫入磁盤,這里和Hadoop的spill類似,這個過程是在HDFS上進行的操作。所以數據的插入並不是追加的過程,而是積累成大塊數據后一並寫入。當StoreFile數量過多時,進行合並,將形成一個大的StoreFile並且刪除掉原來的StoreFile。再當StoreFile大小超過一定閾值后,分裂成Region。
HBase有一個ROOT表和META表。META表記錄用戶Region的信息,但是隨着數據增多,META也會增大,進而分裂成多個Region ,那我們用ROOT表記錄下META的信息,是一個二級表,而zookeeper中記錄ROOT表的location。當我們需找找到一條信息時,先去zookeeper查找ROOT,從ROOT中查找META找到META位置,在進入META表中尋找該數據所在Region,再讀取該Region的信息。HBase適合大量插入又同時讀的情況,其瓶頸是硬盤的傳輸速度而不再是像Oracle一樣瓶頸在硬盤的尋道速度。
Zookeeper原理
Zookeeper是一個資源管理庫,對節點進行協調、通信、失敗處理、節點損壞的處理等,是一個無中心設計,主節點通過選舉產生。Zookeeper的節點是Znode。每一個節點可以存放1M的數據,client訪問服務器時創建一個Znode,可以是短暫的Znode,其上可以放上觀察Watcher對node進行監控。Zookeeper有高可用性,每個機器復制一份數據,只要有一般以上的機器可以正常的運行,整個集群就可以工作。比如6台的集群容忍2台斷開,超過兩台達到一般的數量就不可以,因此集群通常都是奇數來節約資源。
Zookeeper使用zab協議,是一個無中心協議,通過選舉的方式產生leader,通過每台機器的信息擴散選舉最閑的資源利用較少的節點作為主控。同時當配置數據有更改更新時,在每個節點上有配置watcher並觸發讀取更改,。因此能夠保證一致性。每個節點通過leader廣播的方式,使所有follower同步。
Zookeeper可以實現分布式鎖機制。通過watcher監控,對每個Znode的鎖都有一個獨一的編號,按照序號的大小比較,來分配鎖。當一個暫時Znode完結后刪除本節點,通知leader完結,之后下一個Znode獲取鎖進行操作。
Kafka原理
Kafka是分布式發布-訂閱消息系統。它最初由LinkedIn公司開發,之后成為Apache項目的一部分。Kafka是一種快速、可擴展的、設計內在就是分布式的,分區的和可復制的提交日志服務。它被設計為一個分布式系統,易於向外擴展;它同時為發布和訂閱提供高吞吐量;它支持多訂閱者,當失敗時能自動平衡消費者;它將消息持久化到磁盤,因此可用於批量消費,例如ETL,以及實時應用程序。broker和生產者、消費者各自都是集群,集群中的各個實例他們之間是對等的,集群擴充節點很方便。
Kafka的基本概念包括話題、生產者、消費者、代理或者kafka集群。話題是特定類型的消息流。消息是字節的有效負載,話題是消息的分類名或種子名。生產者是能夠發布消息到話題的任何對象。已發布的消息保存在一組服務器中,它們被稱為代理或Kafka集群。消費者可以訂閱一個或多個話題,並從Broker拉數據,從而消費這些已發布的消息。
Kafka的存儲布局非常簡單。話題的每個分區對應一個邏輯日志。物理上,一個日志為相同大小的一組分段文件。每次生產者發布消息到一個分區,代理就將消息追加到最后一個段文件中。當發布的消息數量達到設定值或者經過一定的時間后,段文件真正寫入磁盤中。寫入完成后,消息公開給消費者。段文件機制和Hadoop中spill類似。消費者始終從特定分區順序地獲取消息,如果消費者知道特定消息的偏移量,也就說明消費者已經消費了之前的所有消息。消費者向代理發出異步拉請求,准備字節緩沖區用於消費。每個異步拉請求都包含要消費的消息偏移量與其它消息系統不同,Kafka代理是無狀態的。這意味着消費者必須維護已消費的狀態信息。這些信息由消費者自己維護,代理完全不管。消費者可以故意倒回到老的偏移量再次消費數據。這違反了隊列的常見約定,但被證明是許多消費者的基本特征。
kafka的broker在配置文件中可以配置最多保存多少小時的數據和分區最大的空間占用,過期的和超量的數據會被broker自動清除掉。
Kafka會記錄offset到zk,同時又在內存中維護offset,允許快速的checkpoint,如果consumer比partition多是浪費,因為kafka不允許partition上並行consumer讀取。同時,consumer比partition少,一個consumer會對應多個partition,有可能導致partition中數據的讀取不均勻,也不能保證數據間的順序性,kafka只有在一個partition讀取的時候才能保證時間上是有順序的。增加partition或者consumer或者broker會導致rebalance,所以rebalance后consumer對應的partition會發生變化。
Spark原理
spark 可以很容易和yarn結合,直接調用HDFS、Hbase上面的數據,和hadoop結合。配置很容易。spark發展迅猛,框架比hadoop更加靈活實用。減少了延時處理,提高性能效率實用靈活性。也可以與hadoop切實相互結合。
spark核心部分分為RDD。Spark SQL、Spark Streaming、MLlib、GraphX、Spark R等核心組件解決了很多的大數據問題,其完美的框架日受歡迎。其相應的生態環境包括zepplin等可視化方面,正日益壯大。大型公司爭相實用spark來代替原有hadoop上相應的功能模塊。Spark讀寫過程不像hadoop溢出寫入磁盤,都是基於內存,因此速度很快。另外DAG作業調度系統的寬窄依賴讓Spark速度提高。
RDD是彈性分布式數據也是spark的核心,完全彈性的,如果數據丟失一部分還可以重建。有自動容錯、位置感知調度和可伸縮性,通過數據檢查點和記錄數據更新金象容錯性檢查。通過SparkContext.textFile()加載文件變成RDD,然后通過transformation構建新的RDD,通過action將RDD存儲到外部系統。
RDD使用延遲加載,也就是懶加載,只有當用到的時候才加載數據。如果加載存儲所有的中間過程會浪費空間。因此要延遲加載。一旦spark看到整個變換鏈,他可以計算僅需的結果數據,如果下面的函數不需要數據那么數據也不會再加載。轉換RDD是惰性的,只有在動作中才可以使用它們。
Spark分為driver和executor,driver提交作業,executor是application早worknode上的進程,運行task,driver對應為sparkcontext。Spark的RDD操作有transformation、action。Transformation對RDD進行依賴包裝,RDD所對應的依賴都進行DAG的構建並保存,在worknode掛掉之后除了通過備份恢復還可以通過元數據對其保存的依賴再計算一次得到。當作業提交也就是調用runJob時,spark會根據RDD構建DAG圖,提交給DAGScheduler,這個DAGScheduler是在SparkContext創建時一同初始化的,他會對作業進行調度處理。當依賴圖構建好以后,從action開始進行解析,每一個操作作為一個task,每遇到shuffle就切割成為一個taskSet,並把數據輸出到磁盤,如果不是shuffle數據還在內存中存儲。就這樣再往前推進,直到沒有算子,然后運行從前面開始,如果沒有action的算子在這里不會執行,直到遇到action為止才開始運行,這就形成了spark的懶加載,taskset提交給TaskSheduler生成TaskSetManager並且提交給Executor運行,運行結束后反饋給DAGScheduler完成一個taskSet,之后再提交下一個,當TaskSet運行失敗時就返回DAGScheduler並重新再次創建。一個job里面可能有多個TaskSet,一個application可能包含多個job。