1. 程式人生 > >網易大資料平臺架構實踐分享!

網易大資料平臺架構實踐分享!

隨著網易雲音樂、新聞、考拉、嚴選等網際網路業務的快速發展,網易開始加速大資料平臺建設,以提高資料獲取速度,提升資料分析效率,更快發揮資料價值。 本次演講主要分享網易如何圍繞和改造開源技術,以產品化思維打造網易自己的大資料平臺, 也會分享一下網易在大資料平臺構建和支撐網際網路業務過程中面臨的技術挑戰,以及我們在排程、安全、元資料管理、spark多租戶、SQL流計算、高效能查詢引擎等關鍵技術環節的實踐經驗。 最後會介紹一下,網易大資料平臺未來的技術路線規劃。

分享大綱:

1、大資料平臺概述

2、Sloth:實時計算

3、Kudu:實時更新儲存

4、Kyuubi:Spark 多租戶

5、未來規劃

正文:

2008年之前,網易一直在使用傳統資料庫軟體,隨著資料量的增大逐漸過渡到Hadoop平臺。2009年,網易發現單獨的Hadoop平臺不足以滿足內部資料量的需求,便開始著手研發相關工具。2014年之後,隨著網易雲音樂和網易考拉等業務的發展,網易原有工具也無法支撐龐大的資料使用訴求,網易開始進入平臺化階段,推出網易猛獁和網易有數兩款產品。

網易猛獁是面向網易集團內部的大資料平臺軟體,網易有數是企業級智慧視覺化分析平臺。網易之所以推出這兩款產品,是因為單純維護Hadoop並不能滿足資料使用訴求,我認為最核心的原因是大資料系統難以使用,以下是一個典型的資料處理流程:

資料從Kafka出發,通過Flink處理同時寫入HDFS和HBase。HDFS的資料經過Spark進一步處理最終將彙總資料返回HDFS,傳遞給BI軟體進行展示或者為線上資料提供支援。如果將大資料系統與資料庫核心做對比,我們發現Kafka其實類似於資料庫中的Redo log,Hbase/ES代表一個索引,經過進一步彙總最終形成物化檢視HDFS Parquet。

表和索引通過Kafka日誌保證一致,相當於將元件重新組成類資料庫核心的樣子讓各元件配合工作,保證系統的穩定性和效能。整體來看,這件事情比較複雜,一番折騰下來,我們認為大資料系統還是比較難用的,需要花費大量精力組裝搭配,雖然這也證明了大資料系統比較靈活,但確實進入門檻較高。

我們考慮要做一個大資料平臺,就需要先搞清楚我們的需求是什麼。我認為主要有以下四點:

一是可提供大資料的基礎能力;

二是在基礎之上提高使用效率,所謂的使用是指使用者在我們的大資料平臺上開發資料業務,包括資料倉庫、資料視覺化、推薦業務等的使用效率,這是大資料平臺的核心價值;

三是提升管理效率,運營一個大資料平臺會涉及到各方面的管理,比如升級、擴容、技術支援的代價等,我們需要提升管理效率進而降低成本。

四是多租戶安全,大資料平臺服務於整個公司,公司內部多條業務線都會使用,多租戶安全是必備功能。

在這些需求之下,網易大資料最終的整體架構如下:

整個平臺主要有四大特點:

一是統一元資料服務,Hive、Spark、Impala、HBase等元資料打通,也就是平臺上任意一張表既可用Hive查詢,也可用Spark、Impala來查,不需要在不同系統之間做元資料的同步。

二是流計算服務,我們用SQL作為開發方式,完全與離線SQL相容。

三是資料安全與許可權,Spark、Hive、Impala、HDFS等元件的許可權自動同步。從Spark、Hive、Impala進來的請求,許可權都可以得到控制,無論是通過表介面來訪問還是通過底層HDFS來訪問,許可權都不會有任何洩露。

此外,我們也做列級許可權控制以及角色訪問控制。在我們的平臺中,我們會為網易的每個使用者發放kerberos Key,我們採用kerberos認證,許可權可控制到個人級別,每個人的所有操作都會有審計。此外,我們提供一站式開發IDE,我們的客戶在IDE上進行資料開發,我們也提供一站式部署業務監控體系。

在技術方面,我們的思路是滿足大致平臺需求從大資料平臺的需求出發,採取自研和開源相結合的方式,在底層基礎元件方面以開源為主,在其上進行增強和改進。

在一些相關工具上,我們以自研來滿足使用者需求,我們做的事情主要包括Kafka服務化,我們把Kafka做成雲服務的方式,在日誌收集方面做了Data Stream系統,主要功能是把日誌收集到大資料平臺並轉成Hive表。我們也做了資料庫同步工具,完成資料庫到資料庫,資料庫到大資料系統之間的同步。

在Spark方面,我們做了多租戶和高可用。,引用我們引入開源專案Kudu解決資料實時性實施方面的問題。,並我們針對kudu在上面做了很多優化。,採用Ranger作為統一許可權控制中心,但Ranger效能有限,處理不了大量表和使用者場景,所以,我們不得不擴充套件Ranger,優化其效能使其可以支撐更多表和資料。

接下來,我會分幾個技術點介紹大資料方面的工作。首先,我先介紹一下Kudu,這是我們解決資料實時性的工具,Kudu的定位介於HBase和HDFS中間。我們認為,雖然HBase具備隨機訪問和更新能力,但它的資料查詢分析能力較差。HDFS的查詢分析和scan掃描效能較好,但它的資料實時性較差且更新能力不強。

Kudu兼具了二者的優點,掃描查詢效能較好且同時也有更新和隨機訪問的能力。如果將Kudu和HBase對比,它們同時是KV系統,最不同的地方有以下幾個方面:

一是Kudu採用Raft多副本協議,而HBase通過HDFS來做複製,這樣的好處是Kudu的可用性會好一些。此外,在資料分割槽方面分析上,HBase支援用Ranger分割槽,Kudu採用用Ranger、Hash組合分割槽。在使用HBase的過程中,我們經常會遇到資料熱點問題,所以設計schema時,通常不得不在Hbase會在key里加入一些隨機雜湊值,而,這就是Kudu組合分割槽則能有效的優勢,不用擔心資料熱點問題。

此外,在資料格式上,HBase在ColumnFamily內部採用屬於行存格式。在HBase內,我們很難設定很多ColumnFamily,因為會影響效能,每個ColumnFamily都會帶上主鍵元件,這會導致資料冗餘和變大,而Kudu的資料通過RowGroup形式組織,完全是列存結構,所以掃描效能會比較好。

整個Kudu的大致架構如下, 它有一個管理伺服器負責管理,資料通過分割槽方式分片到眾多切分成Tablet,然後儲存到Tablet Server。每個Tablet Server負責多個Tablet,每個Tablet對應多個MemRowSet。

MemRowSet寫滿之後就會存到磁碟形成DiskRowSet上,每個DiskRowSet是Base +Delta結構, 看起來與HBase類似,主要的不同在於前者掃描效能更優,因為Base中的Kudu屬於列存模式,所以效能更好。

其次,DiskRowSet之間沒有記錄重疊,這與HBase不太一樣。這樣做最大的好處在於掃描時不用多個DiskRowSet之間做合併,只需要掃描單個DiskRowSet之間掃描就可以了。

此外,Dalta資料結構用物理offset偏移量做key,掃描時可快速定位到記錄的變更很容易就可找到Delta的位置資訊,而HBase用記錄主鍵做邏輯定位,這就是Kudu掃描效能更佳的原因 效能相對更慢一些。

Kudu的問題主要有以下幾點,一是在使用Impala查詢引擎的情況下,效能與Parquet相比有不小差距。雖然官方測試報告中指出kudu的效能比Parquet更優,但經過我們的實際測量,結果剛好相反(下圖為實際測量結果,Q16、Q17、Q19相差十分明顯)。

其二,Kudu缺少Spilt和Merge功能,Ranger分割槽缺少自動分裂的過程,當分割槽越來越大之後,我們就沒有辦法處理熱點問題了。

為了解決上述問題,網易做的第一個優化是Kudu Runtime Filter,這是為了加速kudu的效能。比如,如果需要做大小表的join,一般可能有兩種做法,一是大表和小表都根據join key來做shuffle,把相同的join key資料shuffle到同一臺機器上,但這種做法開銷比較大。

二是小表廣播,將小表廣播到所有查詢伺服器上,與大表一起做join,網易在這部分採用的是Kudu Runtime Filter。

我們的做法是為小表join key生成Runtime Filter,這樣做的好處在於kudu在掃描底層資料時會拿Runtime Filter去底層過濾資料,這樣的結果就是返回Impala層的資料會大大減少。以下圖為例,紅色是一個的scan操作, 可以看到kudu返回的記錄數會變的很少,特別是返回資料集較小的情況下。

經過改進,Kudu的效能有了很大提升。下圖黑色的是原生kudu,橙色的是加入Runtime fliter的版本,二者對比,後者在效能上確是有很大提升。整體來看,kudu的效能比Parquet要低30%左右,但一般情況下是夠用的,因為畢竟它有資料更新的能力,自然會犧牲一些查詢效能。

此外,我們也做了kudu Tablet Split自動分裂功能,主要對Ranger分割槽做了分裂,分裂思路比較簡單,主要是修改元資料,整個過程瞬間線上完成,不會涉及資料真正的變更,。具體做法是在元資料上標識將一個Tablet分為兩個,此後都遵循該原則,但只有在Compaction時才會發生真正的物理分裂。

此外是主從協同。當主發生分裂時,會通過Raft協議同步所有副本同時分裂。通過這個方式,我們完成了Kudu的分裂,線上管理也很方便。

接下來介紹一下Kudu的應用場景,一是對實時性要求較高的場景,Kudu可以做到秒級實時,而HDFS只能做半小時以上的準實時,如果資料實時性要求很高,小檔案會比較多進而影響效能。

二是點查和多維分析融合,一個使用者的行為分析系統通常有兩類需求,一是指定使用者查詢;二是大批量使用者行為分析,這就涉及到多維分析。傳統。架構需要實現結合需要HBase和HDFS Parquet二者結合,點查單個使用者需要使用HBase,批量查詢需要使用HDFS,顯然這樣的成本比較高。如果使用Kudu,因為其可以同時滿足KV查詢和多維分析查詢,整體架構會比較簡單,成本也相對較低。

三是實時維表,在網際網路應用中,Hadoop會存一些使用者行為日誌,但還有一些資料在資料庫裡,比如商品、使用者等維表。資料庫裡的資料通常會每天全量匯入,實時性比較差,當然也可以選擇按小時匯入,但這樣資料庫壓力會很大,如果資料庫增量匯入大資料平臺,然後再做全量merge,實時性會比較差。

網易的解決方案是使用工具直接把資料庫實時同步到Kudu,Kudu的資料可以跟Hadoop使用者行為資料直接做join連查,這樣整個平臺的實時性會做到秒級,效能也不錯。

接下來,我想介紹一下我們的實時計算系統——Sloth。Sloth是一個基於SQL開發的流計算系統,它的SQL看起來與Hive SQL類似,同樣支援DDL、UDF,join子查詢等。我們的流計算系統基於Flink引擎開發,通過CodeGen的方式生成Flink程式碼,然後同步到叢集執行。

在效果上,我們做到了Exactly Once跟增量計算模型,通過實時計算SQL算出來的結果跟用離線計算出來的結果一樣,這是對資料正確性的重要保證。當然,Sloth也是在猛獁大資料平臺上開發的。

以上是Sloth的開發介面,我們設計了寫SQL的地方,同時也可以除錯並完成實時計算任務。以電商系統為例,我們需要對商家按照銷售額進行分類統計,比如說銷售額0-100之間做分類,100-200區間內歸為另一類,依此類推計算出每個區間內的商家個數。

以上圖為例,第一條計算每個商家的銷售總額,我們需要先定一個臨時表tmp,再針對tmp做一個GROUP BY,相當於把商家銷售額給GROUP BY計算,得出每個商家的銷售額。

第二條是計算每個區間內的商家個數。此時,我們可以用GROUP BY銷售額除以100,這是要查詢的臨時表tmp。兩條SQL跟離線完全一樣,如果表定義和實時計算一樣的話,你是可以拿到Hive上執行的。

只要通過這兩條SQL就可以完全實現計算任務開發,那它跟離線計算結果有什麼不一樣呢?它實時輸出結果,而離線是一次性輸出結果,提交這樣的SQL就不停的輸出銷售額的分類統計。

在這個任務下假設我們輸入的資料有四條(如下圖):第一個商家交易額30,然後第二個商家交易額10,第三個商家交易額80,再來第三個商家交易額50,我們來看看用不同的計算引擎出來的計算結果有哪些差異。

如果用MapReduce這樣的離線計算,我會得到四條資料會得到0~100區間內有2條記錄, 100~200區間內有1條記錄。但如果用流式計算,可能就會遇到問題,為什麼這麼說呢?如果你現在已經處理了3條資料,就是說(1,、30),(,2,、10),(3,、80)這三條資料,這個情況下你說出的輸出的結果是0-100有三個商家。當第四條資料參與計算後,系統可能就會輸出0-100有三個有3個商家,100-200有一個有1商家,這個結果就是有誤的,這是因為實時計算沒有去糾正已經輸出的計算結果。的原則是不停得計算並輸出結果。

那麼,這個問題如何解決呢?早期的Flink缺少該功能,我們就在Flink的基礎上做了改造。所謂的增量計算是指在遇到上述情況時需要撤銷前一步計算結果,上游運算元需要不停得向下遊運算元發出撤銷操作請求,直到資料糾正過來最終輸出正確結果。

通過該方式,我們保證了SQL計算的正確性。

一個SQL任務分為DDL和DML語句,Sloth通過SQL方式編寫, DDL的作用是在Kafka之上的DDL,也可定義在其他輸入源之上定義流表使用者的job就是定義在Kafka之上的DDL,也可定義在其他輸入語言之上。流表定義完成之後,我們需要做就可以編寫很多DML操作資料,計算結果。

一個SQL的job分為DDL和DML語句,對於純SQL語句,我們需要先對其進行編譯。首先,我們編譯每條DDL,對每條DML單獨編譯每條SQL語句;其次,生成執行計劃,將不同SQL的執行計劃串聯起來,因為它們彼此之間存在輸入輸出關係。然後,根據不同SQL計劃之間的依賴關係,我們會生成一個全域性Sloth執行計劃;最後,我們將該執行計劃生成程式碼,將程式碼提交給Flink執行,這就是整個Sloth的執行過程。

接下來,我會介紹網易在Spark多租戶方面的工作,這個專案叫做Kyuubi(該專案的開源地址: https://github.com/netease-bigdata/kyuubi https://github.com/yaooqinn/kyuubi),實際上是類似於HiveSever2的程式。大家可能都知道,Hive一般有兩種使用模式,一種是client模式,所有的SQL解析都客戶端在這之中完成。一種是HiveSever2模式,整個SQL解析放到server端完成。

在公司實際使用過程中,我們更希望使用者的使用行為通過Server端完成,否則會很難管理,因為客戶端根本不在平臺掌控範圍之內,我們很難進行各種升級及配置變化。只有當MetaStore和HDFS 配置不暴露給使用者,我們才能更好得管控。Hive的社群比較完善,在這方面沒有問題,但是Spark還有些不足。其實,所謂的Kyuubi只是在類似HiveSever2的基礎上提供服務, 提供SparkSQL服務,而不是Hive SQL服務。

Kyuubi基於Spark Thrift Sever改造,Spark Thrift Sever類似於HiveSever2,但是它不夠完善。由於我們在此基礎上增加了多租戶的功能,因此可以支援網易內部各業務線的使用。要想實現多租戶功能,首先要把SparkContext變成多例項,之後每次執行代理真正的使用者身份執行;其次,我們提供了Spark SQL叢集,使用者請求負載均衡到每臺Kyuubi伺服器,並且這部分是高可用的,一臺伺服器掛了會立刻切換到另一臺。

此外,我們對安全性也進行了改進,支援kerbros。其實,整個網易猛獁平臺都是強安全認證系統,每個使用者都有自己的kerberos key tabkerbros,所有系統拿kerberoskerbros做認證訪問都是帶認證的,Kyuubi要融入這個體系同樣需要支援kerberoskerbros。

Kyuubi的主要特點如下:一是具備統一介面,與HiveSever2相比,Kyuubi提供SwiftThrift的API,無論是Beeline客戶端、JDBC客戶端、ODBC客戶端還是網易猛獁自助分析查詢平臺、有數視覺化BI平臺,Kyuubi都可以用標準的方式連線到Spark。

二是有彈性的資源控制能力,Kyuubi支援session級別的資源配置,每個session所需的佇列、資源核數和記憶體都可以進行配置。

三是支援SparkContext的動態快取。建立一個SparkContext耗時較長,所以我們要對SparkContext進行快取設定,讓使用者不需要每次查詢都動態建立SparkContext。

此外,我們也支援Spark動態資源分配特性,啟用SparkContext需要啟用一堆Spark執行器。如果業務需要較快的響應速度,那就直接發SQL,不需要等待程序啟用。

四是Kyuubi安全特性,首先是支援Kerberos還有代理執行,最後支援整合我們自己的spark-authorizer許可權驗證外掛,該外掛對Spark沒有侵入性,主要用於查詢優化的最後階段。實際上,具體許可權對接的是rRangerr中的許可權控制中心,通過整合Spark-authorizer,我們能夠做到細粒度的許可權控制。

此外,我們也支援服務的高可用和負載均衡,Kyuubi基於負載均衡的方式設計,通過將ZK作為Namespace來實現。具體過程為,Kyuubi將自己註冊到ZK,ZK形成服務列表,註明各服務的存活狀態,客戶端會與ZK通訊拿到該伺服器列表,從中挑選Kyuubi伺服器執行。通過這種方式,我們將負載均衡到眾多Spark查詢裝置上,從而避免了單點故障,保證了服務的可用性。

總結來看,Kyuubi以HiveServer2 Thrift API為介面協議,提供Spark SQL服務。相比傳統的Spark,Kyuubi主要增加了企業級特性,如果公司多租戶場景較多且業務線複雜,多租戶功能是比較要緊的事情比如多租戶、許可權、負載均衡等。

最後,我介紹一下網易在未來的規劃。首先,我們會進一步完善高效能查詢引擎。目前,我們正在用的查詢引擎是Impala,雖然效能較優,但我們還希望可以在與Kudu配合等方面進行更多優化。

二是實現實時和離線計算混步。針對網易目前龐大的叢集數量,我們希望可以通過混部步來解決該問題。首先,晚上是離線計算的高峰期,任務通常會等到所有資料完成也就是凌晨定時起來跑,實時計算的高峰期與使用者使用高峰期一樣都在白天,因此可以與離線計算實現錯峰執行。在叢集規模較大的情況下,這種方式的意義非常明顯,我們希望可以解決這種方式帶來的隔離、彈性等方面的問題。

三是整合更多硬體做加速,比如GPU或者FPGA。

四是智慧任務診斷和優化。因為網易內部資料量和任務非常龐大,我們希望可以通過智慧化任務診斷的方式輔助技術支援人員更好得完成工作,未來希望可以達到AIops的程度。