【大数据】如何用形象的比喻描述大数据的技术生态?Hadoop、Hive、Spark 之间是什么关系?
1
Hadoop只是一套工具的總稱,它包含三部分:HDFS,Yarn,MapReduce,功能分別是分布式文件存儲、資源調度和計算。
按理來說,這就足夠了,就可以完成大數據分析了。
但第一個問題就是麻煩。這一套相當于用Yarn調度資源,讀取HDFS文件內容進行MR計算。要寫Java代碼,但做數據的最好的工具是什么?SQL!所以Hive相當于這一套標準流程的SQL化。
Hive可以簡單理解為,Hadoop之上添加了自己的SQL解析和優化器,寫一段SQL,解析為Java代碼,然后去執行MR,底層數據還是在HDFS上。
這看起來挺完美,但問題是程序員發現好慢啊。原因是MR,它需要頻繁寫讀文件。這時基于內存的Spark出現了,Spark是替代MR的,它會為SQL生成有向無環圖,加上各種算子和寬窄依賴的優化,使得計算速度達到了新的高度。
按理說這就完美解決了呀。但是,我們回頭想想,這些數據怎么來的呢?我們是不是到目前為止都是在處理靜態的數據呢?像比如線上支付校驗這種需要實時返回結果的總不能等著Spark批量算吧。解決問題之前,我們回頭再想想,數據怎么來的。
一般數據包含兩種:業務數據和日志數據。業務數據就是數據庫中的結構性的數據,規規整整。業務數據怎么到Hive呢?開源上一般通過Sqoop進行導入,比如一張表,數據少每天我把表全部導入一遍,這叫全量同步;
數據特別大,就只同步每天變化和新增的,這是增量同步。但這種同步比較滯后,都是在夜深人靜集群的計算資源比較空閑的時候做的,對應的也是離線分析。實時的數據產生了該怎么拿到呢?
2
實時怎么理解?來一批處理一批,再細一點兒,來一條,處理一條。
比如,你買一件東西,平臺數據庫中會多一條訂單數據,app會產生行為日志數據。訂單數據插入數據庫時一般會有binlog,即記錄插入、更新或刪除的數據,我們只要能實時拿到這一條binlog,就相當于拿到了實時數據。
binlog怎么拿呢?這就要說道數據庫的主從備份機制,一般本身就是拿主庫的binlog同步到備份庫,剛好有一個叫canal的工具可以把自己偽裝成備份庫,來拉取主庫的binlog,再解析、包裝最后拋出,就相當于實時拿到數據了!
canal拿到了binlog就能直接處理了嗎?可以,但有件事兒大家想一想。馬上五一了,加入一下子超級多人下單消費,canal拋出的消息我們下游一下子消費不完咋辦呢?比如快遞員每天都只給你派送一件快遞,你拿到之后錢貨兩清。然后突然一天快遞員給你送一千件到你樓下,你下樓一件一件搬,快遞員還得等你搬完才能回去,這得等到啥時候。
聰明的你馬上想到了,放快遞柜呀,你有時間慢慢搬不就行了,也不占用快遞員的時間了。這就是消息隊列,Kafka 就是起這樣的作用:異步、解耦、消峰。canal的數據一般會拋到kafka或RocketMQ,可以保存一段時間。然后下游程序再去實時拉取消息來計算。
3
說了這么多下游,下游到底由誰來消費計算這些實時數據呢?還記得Spark嗎,沒錯它又來了,Spark streaming就是處理實時流數據的好手。
Spark 是一整套組件的統稱,比如你可以用 Java 寫 Spark 任務,用 Spark SQL 去寫 SQL,可以用 Spark MLib 完成機器學習的模型訓練等等,Spark Streaming 就是用來微批地處理流式數據的。
具體而言,離線數據我們是等半夜數據都抽到 Hive 中再計算,**而 Spark Streaming 則是實時數據來一小批,它就處理一小批。**所以本質上講,Spark Streaming 還是批處理,只不過是每一批數據很少,并且處理很及時,從而達到實時計算的目的。
Spark 本身的流行使得 Spark Streaming 也一直大范圍使用。
這一套有什么邏輯缺陷嗎?
我們可以想一想,實時數據和離線數據最大的差異,是時效性。離線數據像湖水,該多少就多少,就在那里;實時數據像水流,綿綿不絕。時間,便是非常重要的一個特質。當一條數據來的時候,我們需要知道這條數據是什么時候產生的,這便是業務時間。但我們拿到這條數據時往往是業務時間之后的一小會,這邊是處理時間。真正世界里的實時數據肯定不是像 Spark Streaming 那樣一批一批來的,而是一個一個的事件。對此,Flink 幫助我們解決了這些問題。
4
無論是業務數據還是日志數據,往往都有相應的時間標志字段,代表著這條消息的業務時間。你可以讓 Flink 選擇這個時間,這樣,Flink 就知道當前處理到哪個時間點了。
Flink 不同于 Spark Streaming 的微批次處理,它是一條一條數據處理的。這樣的數據一般是先來后到的,但難免會有些數據沿途受阻晚來了幾秒鐘,這就會導致兩個問題:數據延遲和亂序數據。這也是做實時數據的非常關注的問題。如何防止數據延遲?如果是上游數據遲了,就加大上游資源;如果是數據突然激增,導致 Flink 處理不過來導致任務出現延遲,就加大 Flink 的資源,比如并發。
數據亂序呢?
同樣的,我們一般也通過上游和 Flink 本身來分別保證。
我們上面提到了消息的快遞柜 Kafka,Kafka 有分區的概念,就像是不同的通道,一條消息來了后,可以走 A,也可以走 B,也可以走 C。那么問題來了,現在面試官問你,業務數據拋入 Kafka,如何保證消息的順序性呢?
順序性一般有兩方面需要保證。我們舉一個小小的例子,一個用戶下單的場景,有兩個基本共識:
-
同一個用戶的訂單狀態會先后變化;
-
不同用戶的不同訂單也有先后之分。
所以我們解決數據的順序性一般也是從這兩方面考慮。如果你還記得大學高數里的多元函數求偏導,對于 x 和 y 兩個變量,求 x 的偏導會假設 y 為常量,反之同理。我們考慮這個問題也一樣,如果不能同時兼顧這兩方面,那就一個一個去優化吧!這種思想也稱為貪婪算法,在很多地方都有應用,這里暫時說到這里。
回到問題,那么如何保證同一用戶的訂單順序呢?很簡單,前面我們提到的鏈路是,數據庫中插入或更新數據時,會實時產生該條數據的 binlog,canal 獲取、解析、包裝這條 binlog 并拋入 Kafka。
而 Kafka 由于有分區的存在,很可能同一個訂單的消息會被發送到不同的分區中,這樣的話,如果下游的 Flink 任務消費不同分區速率不同,就可能導致先到的數據反而被后消費,產生順序誤差。解決的辦法即保證同一訂單的消息進入 Kafka 的同一分區即可。Kafka 的每一條消息都會有 messageKey 和 message 兩個結構,如果沒有直接給消息指定分區,那么 messageKey 決定了消息進入哪個分區,在 canal 中,我們便可以設定消息如何進入 Kafka。數據庫中的業務數據,會存在一張張的表中,表一般都會有主鍵,來唯一標識一條數據,我們一般也就是通過設定 canal 選擇 binlog 所在表的主鍵來決定其進入 Kafka 的分區。這樣,就基本解決了第一個問題。
但這只保證了同一訂單數據的順序性,并未保證不同訂單之間的順序性。聰明的你可能已經想到,如果 Kafka 只設定一個分區那不就保證了嗎?但這其實算是本末倒置,Kafka 本身相當于快遞柜,多個分區相當于多個柜子,能存儲更多的數據,提高并發,如果為了順序性而犧牲并發量,那就得不償失了,而且一般本身數據的亂序無論是在概率和重要性方面都不如并發重要的。就比如我要統計每小時的訂單數,即使數據亂序了,只要在窗口區間內計算結果也不怎么受影響。
但這并不是說我們就不考慮數據在全局的順序性了。
我們如何去認識亂序或延遲數據呢?既然這種情況是偶發性的,那么一般可以這么做,在實時的流數據中,如果想要拿到 T 時刻的數據,只要等一小會兒比如 1s,就能保證在 T+1s 的時刻拿到 T 時刻的所有數據。
上面這句話其實理解起來也很簡單,比如幼兒園老師組織小朋友們春游,約定了早上 8:00 集合發車,即 8:00 觸發一個事件。但總有那么幾個調皮搗蛋的學生會遲到幾分鐘,于是老師說好的 8 點發車實際上是8:05,大家覺得也沒啥問題,回家就跟家長說,我們今天 8:00 發車春游啦。在
Flink 中,這種機制就叫做 watermark。
上面我們說過,每一條數據一般都會自帶一個時間字段,來標志這條數據的業務時間,即什么時候發生的。然后 Flink 提取這個時間字段,就知道了目前 Flink 任務進行到幾點了。
那么既然要考慮亂序或遲到數據,我們一般也會讓 Flink 當前的時間稍微遲幾秒鐘。比如我們認為大部分情況下亂序或遲到的數據都在 1s 以內,那么來一條數據,比如這條數據自帶的時間是 08:00:01,那我們就認為 08:00:00 時刻的數據才剛到齊。但回過頭來說,在大多數場景下,畢竟亂序或遲到數據算是占比很小了。
總結
以上是生活随笔為你收集整理的【大数据】如何用形象的比喻描述大数据的技术生态?Hadoop、Hive、Spark 之间是什么关系?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【操作】鼠标hover效果——元素凸起并
- 下一篇: mybatis框架中的queryWrap