分享嘉賓:高大月@美團點評,Apache Kylin PMC成員,Druid Commiter 編輯整理:Druid中國用戶組 6th MeetUp 出品平臺:DataFunTalk -- 導讀: 長久以來,對SQL和許可權的支持一直是Druid的軟肋。雖然社區早在0.9和0.12版本就分別添加了對S ...
分享嘉賓:高大月@美團點評,Apache Kylin PMC成員,Druid Commiter
編輯整理:Druid中國用戶組 6th MeetUp
出品平臺:DataFunTalk
--
導讀: 長久以來,對SQL和許可權的支持一直是Druid的軟肋。雖然社區早在0.9和0.12版本就分別添加了對SQL和Security的支持,但根據我們瞭解,考慮到功能的成熟度和穩定性,真正把SQL和Security用起來的用戶是比較少的。本次分享將介紹社區SQL和Security方案的原理,以及美團點評在落地這兩個功能的過程中所遇到的問題、做出的改進、和最終取得的效果。下麵開始今天的分享:
我今天的分享內容包括四部分。首先,和大家介紹一下美團對Druid的使用現狀,以及我們在構建Druid平臺的過程中遇到的挑戰。第二部分,介紹Druid SQL的基本原理和使用方式,以及我們在使用Druid SQL的過程中遇到的問題和做的一些改進。第三部分,介紹Druid在數據安全上提供的支持,以及我們結合自身業務需求在Druid Security上的實踐經驗。最後,對今天的分享內容做一個總結。
--
01 Druid在美團的現狀和挑戰
1.Druid應用現狀
美團從16年開始使用Druid,集群版本從0.8發展到現在的0.12版本。線上有兩個Druid集群, 總共大概有70多個數據節點。
數據規模上,目前有500多張表,100TB的存儲,最大的表每天從Kafka攝入的消息量在百億級別。查詢方面,每天的查詢量有1700多萬次,這裡包括了一些程式定時發起的查詢,比如風控場景中定時觸發的多維查詢。性能方面,不同的應用場景會有不同的要求,但整體上TP99響應時間在一秒內的表占了80%,這和我們對Druid的定位——秒級實時OLAP引擎是一致的。
2.Druid平臺化挑戰
把Druid作為一個服務提供給業務使用的過程中,我們主要遇到了易用性、安全性、穩定性三方面的挑戰。
易用性:業務會關心Druid的學習和使用成本有多高,是否能很快接入。大家知道,Druid本身對數據寫入和查詢只提供了基於JSON的API介面,你需要去學習介面的使用方法,瞭解各種欄位的含義,使用成本是很高的。這是我們希望通過平臺化去解決的問題。
安全性:數據是很多業務的核心資產之一,業務非常關心Druid服務能否保障他們的數據安全。Druid較早的版本對安全的支持較弱,因此這一塊也是我們去年重點建設的部分。
穩定性:一方面需要解決開源系統落地過程中出現的各種穩定性問題,另一方面,如何在查詢邏輯不可控的情況下,在一個多租戶的環境中定位和解決問題,也是很大的挑戰。
--
02 Druid SQL的應用和改進
在Druid SQL出現之前,Druid查詢通過基於JSON的DSL來表達(下圖)。這種查詢語言首先學習成本很高,用戶需要知道Druid提供了哪些queryType,每種queryType需要傳哪些參數,如何選擇合適的queryType等。其次是使用成本高,應用需要實現JSON請求的生成邏輯和響應JSON的解析邏輯。
通過Druid SQL,你可以將上面的複雜JSON寫成下麵的標準SQL。SQL帶來的便利是顯而易見的,一方面對於程式員和數據分析師沒有額外的學習成本,另一方面可以使用類似JDBC的標準介面,大大降低了門檻。
1.Druid SQL簡介
下麵我簡單地介紹一下Druid SQL。
首先,Druid SQL是0.10版本新增的一個核心模塊,由Druid社區提供持續的支持和優化,因此不管是穩定性還是完善性,都會比其他給Druid添加SQL方言的項目更好。
從原理上看,Druid SQL主要實現了從SQL到原生JSON查詢語言的翻譯層。由於只是做了一層語言的翻譯,好處是Druid SQL對集群的穩定性和性能不會有很大影響,缺點是受限於原生JSON查詢的能力,Druid SQL只實現了SQL功能的一個子集。
調用方式上,Druid SQL提供了HTTP和JDBC兩種方式來滿足不同應用的需求。最後表達力上,Druid SQL幾乎能表達所有JSON查詢能實現的邏輯,並且它能自動幫你選擇最合適的queryType。
下麵是三個Druid SQL的例子。
第一個例子是近似TopN查詢。對於根據某個指標分析單個維度TopN值的需求,原生的JSON查詢提供了一種近似TopN演算法的實現。Druid SQL能夠識別出這種模式,生成對應的近似TopN查詢。
第二個例子是半連接。我們知道Druid是不支持靈活JOIN的,但業務經常會有這樣的需求,就是以第一個查詢的結果作為第二個查詢的過濾條件,用SQL表達的話就是in subquery,或者半連接。Druid SQL對這種場景做了特殊支持,用戶不需要在應用層發起多個查詢,而是寫成in subquery的形式就行了。Druid SQL會先執行子查詢,將結果物化成外層查詢過濾條件,然後再執行外層的查詢。
最後是一個嵌套GroupBy的例子。Druid SQL能夠識別出這種多層的GroupBy結構,生成對應的原生嵌套GroupBy JSON 。
2.Druid SQL架構
下麵介紹Druid SQL的整體架構。
Druid SQL是在查詢代理節點Broker中實現的功能,主要包含Server和SQL Layer兩個模塊。
Server模塊負責接收和解析請求,包括HTTP和JDBC兩類 。對於普通的HTTP請求,新增相應的REST Endpoint即可。對於JDBC,Druid復用了Avatica項目的JDBC Driver和RPC定義,因此只需要實現Avatica的SPI就行了。由於Avatica的RPC也是基於HTTP的,因此兩者可以使用同一個Jetty Server。
SQL Layer負責將SQL翻譯成原生的JSON查詢,是基於Calcite項目實現的。Calcite是一個通用的SQL優化器框架,能夠將標準SQL解析、分析、優化成具體的執行計劃,在大數據領域得到了廣泛的使用。圖中淺綠色的組件是Calcite提供的,淺藍色的組件是Druid實現的,主要包括三個。
首先,DruidSchema組件為Calcite提供查詢解析和驗證需要的元數據,例如集群中包含哪些表,每張表各個欄位的名稱和類型等信息。RulesSet組件定義了優化器使用的轉換規則。由於Druid SQL只做語言翻譯,因此這裡都是一些邏輯優化規則(例如投影消除、常量摺疊等),不包含物理優化。通過RulesSet,Calcite會將邏輯計劃轉成DruidRel節點,DruidRel包含了查詢的所有信息。最後,QueryMaker組件會嘗試將DruidRel轉成一個或多個原生JSON查詢,這些JSON查詢最終提交到Druid的QueryExecution模塊執行。
3.API選擇: HTTP or JDBC
Druid SQL提供了HTTP和JDBC兩種介面,我應該用哪個?我們的經驗是,HTTP適用於所有編程語言,Broker無狀態,運維較簡單;缺點是客戶端處理邏輯相對較多。JDBC對於Java應用更友好,但是會導致Broker變成有狀態節點,這點在做複雜均衡時需要格外註意。另外JDBC還有一些沒有解決的BUG,如果你使用JDBC介面,需要額外關註。
4.改進
下麵介紹我們對Druid SQL做的一些改進。
第一個改進是關於Schema推導的性能優化。我們知道Druid是一個schema-less系統,它不要求所有的數據的schema相同,那如何定義Druid表的schema呢?社區的實現方式是:先通過SegmentMetadataQuery計算每個segment的schema,然後合併segment schema得到表的segment,最後在segment發生變化時重新計算整個表的schema。
社區的實現在我們的場景下遇到了三個問題。第一是Broker啟動時間過長。我們一個集群有60萬個segment,測試發現光計算這些segment的schema就需要半小時。這會導致Broker啟動後,需要等半個小時才能提供服務。第二個問題是Broker需要在記憶體中緩存所有Segment的元數據,導致常駐記憶體增加,另外schema刷新會帶來很大的GC壓力。第三個問題是,社區方案提交的元數據查詢量級與Broker和Segment個數的乘積成正比的,因此擴展性不好。
針對這個問題,我們分析業務需求和用法後發現:首先schema變更是一個相對低頻的操作,也就是說大部分segment的schema是相同的,不需要去重覆計算。另外,絕大數情況業務都只需要用最新的schema來查詢。因此,我們的解決方案是,只使用最近一段時間,而不是所有的segment來推導schema。改造後,broker計算schema的時間從半小時降低到了20秒,GC壓力也顯著降低了。
第二個優化是關於日誌和監控。請求日誌和監控指標是我們在運維過程中重度依賴的兩個工具,比如慢查詢的定位、SLA指標的計算、流量回放測試等都依賴日誌和監控。但是0.12版本的SQL既沒有請求日誌,也沒有監控指標,這是在上線前必須要解決的問題。我們的目標有兩個:首先能記錄所有SQL請求的基本信息,例如請求時間、用戶、SQL內容,耗時等;其次能將SQL請求和原生的JSON查詢關聯起來。因為執行層面的指標都是JSON查詢粒度的,我們需要找到JSON查詢對應的原始SQL查詢。
我們的解決方案已經合併到0.14版本。首先,我們會給每個SQL請求分配唯一的sqlQueryId。然後我們擴展了RequestLogger介面,添加了輸出SQL日誌的方法。下圖是一個例子,對於每個SQL請求,除了輸出SQL內容外,也會輸出它的sqlQueryId,可以用來與客戶端的日誌做關聯。還會輸出SQL對應的每個JSON查詢的queryId,可以用來和JSON查詢做關聯分析。
第三個改進雖然比較小,但是對服務的穩定性很重要。我們知道,JSON查詢要求用戶指定查詢的時間範圍,Druid會利用這個範圍去做分區裁剪,這對提高性能非常重要。但是Druid SQL並沒有這方面的限制。用戶寫SQL經常會忘記加時間範圍的限定,從而導致全表掃描,占用大量的集群資源,是一個很大的風險。所以我們添加了對where條件的檢查,如果用戶沒有指定時間戳欄位的過濾條件,查詢會直接報錯。
--
03 Druid Security的實踐經驗
首先介紹我們在數據安全上面臨的問題。當時使用的是0.10版本,這個版本在數據安全上沒有任何的支持,所有的API都沒有訪問控制,任何人都能訪問甚至刪除所有的數據,這對業務的數據安全來說是一個非常大的隱患。
我們希望實現的目標有五點:所有API都經過認證、實現DB粒度的許可權控制、所有數據訪問都有審計日誌、業務能平滑升級到安全集群、對代碼的改動侵入性小。
為了實現這些目標,我們首先調研了Druid在後續版本中新增的安全功能。
1.Druid Security 功能和原理
0.11版本支持了端到端的傳輸層加密(TLS),能夠實現客戶端到集群,以及集群各個節點之間的傳輸層安全。0.12版本引入了可擴展的認證和鑒權框架,並且基於這個框架,提供了BA和Kerberos等認證方式,以及一個基於角色的鑒權模塊。
下麵這張圖介紹認證鑒權框架的原理和配置。
2.Druid Security社區方案缺點
社區方案能滿足我們大部分的需求,但還存在一些問題。
第一個問題是我們發現瀏覽器對BA認證的支持很差。因此對於Web控制台,我們希望走統一的SSO認證。
第二個問題是為了支持業務平滑過渡到安全集群,上線初期必須相容非認證的請求,當時我們使用的0.12版本沒有該功能。
第三個問題是社區基於角色的鑒權模塊只提供了底層的管理API,用戶直接使用這些API非常不方便。
最後一個問題是社區還不支持審計日誌。
針對這些問題,我們做了三個主要的改進。
3.改進
改進一:基於DB的訪問控制
首先,為了簡化許可權的管理,我們引入了DB的概念,並實現了DB粒度的訪問控制。業務通過DB的讀寫賬號訪問DB中的表。
改進二:自動管理許可權DB
通過任務接入平臺維護DB和DataSource的映射關係,併在DB和DataSource發生變化時,調用鑒權模塊介面更新許可權DB。
改進三:支持SSO認證和非認證訪問
自定義認證鏈條,通過SSO認證Filter實現Web控制台的SSO認證,通過非安全訪問Filter兜底,相容非認證的請求。
註意事項
(1)使用0.13以上版本 (或者cherrypick高版本的bugfix)
(2)上線流程
- 啟用basic-security功能,用allowAll兜底
- 初始化許可權DB,創建匿名用戶並授權
- 將allowAll替換為anonymous
- 逐步回收匿名用戶的許可權
(3)上線順序:coordinator->overlord->broker->historical->middleManager
--
04 總結
1.關於SQL
(1)如果還在用原生的JSON查詢語言,強烈建議試一試
(2)社區在不斷改進SQL模塊,建議使用最新版本
(3)Druid SQL本質上是一個語言翻譯層
- 對查詢性能和穩定性沒有太大影響
- 受限於Druid本身的查詢處理能力,支持的SQL功能有限
(4) 要留意的坑
- 大集群的schema推導效率
- Broker需要等schema初始化後再提供服務(#6742)
2.關於Security
(1)Druid包含一下Security特性,建議升級到最新版本使用
- 傳輸層加密
- 認證鑒權框架
- BA和Kerberos認證
- RBAC鑒權
(2)認證鑒權框架足夠靈活,可根據自身需求擴展
(3)經歷生產環境考驗,完成度和穩定性足夠好
(4)上線前應充分考慮相容性和節點更新順序
今天的分享就到這裡,謝謝大家。
本文首發於微信公眾號“DataFunTalk”
嘉賓介紹:
高大月,Apache Kylin PMC成員,Druid Commiter,開源和資料庫技術愛好者,有多年的SQL引擎和大數據系統開發經驗。目前在美團點評負責OLAP引擎的內核開發、平臺化建設、業務落地等工作。
註:歡迎轉載,轉載請留言或私信。