使用 Iceberg on Kubernetes 打造新一代雲原生資料湖
阿新 • • 發佈:2020-11-06
## 背景
大資料發展至今,按照 Google 2003年釋出的《The Google File System》第一篇論文算起,已走過17個年頭。可惜的是 Google 當時並沒有開源其技術,“僅僅”是發表了三篇技術論文。所以回頭看,只能算是揭開了大資料時代的帷幕。隨著 Hadoop 的誕生,大資料進入了高速發展的時代,大資料的紅利及商業價值也不斷被釋放。現今大資料儲存和處理需求越來越多樣化,在後 Hadoop 時代,如何構建一個統一的資料湖儲存,並在其上進行多種形式的資料分析,成了企業構建大資料生態的一個重要方向。怎樣快速、一致、原子性地在資料湖儲存上構建起 Data Pipeline,成了亟待解決的問題。並且伴隨雲原生時代到來,雲原生天生具有的自動化部署和交付能力也正催化這一過程。本文就主要介紹如何利用 [Iceberg](https://iceberg.apache.org/) 與 Kubernetes 打造新一代雲原生資料湖。
## 何為 Iceberg
> Apache Iceberg is an open table format for huge analytic datasets. Iceberg adds tables to Presto and Spark that use a high-performance format that works just like a SQL table.
[Apache Iceberg](https://github.com/apache/iceberg) 是由 Netflix 開發開源的,其於2018年11月16日進入 Apache 孵化器,是 Netflix 公司資料倉庫基礎。Iceberg 本質上是一種專為海量分析設計的表格式標準,可為主流計算引擎如 Presto、Spark 等提供高效能的讀寫和元資料管理能力。Iceberg 不關注底層儲存(如 HDFS)與表結構(業務定義),它為兩者之間提供了一個抽象層,將資料與元資料組織了起來。
Iceberg 主要特性包括:
- ACID:具備 ACID 能力,支援 row level update/delete;支援 serializable isolation 與 multiple concurrent writers
- Table Evolution:支援 inplace table evolution(schema & partition),可像 SQL 一樣操作 table schema;支援 hidden partitioning,使用者無需顯示指定
- 介面通用化:為上層資料處理引擎提供豐富的表操作介面;遮蔽底層資料儲存格式差異,提供對 Parquet、ORC 和 Avro 格式支援
依賴以上特性,Iceberg 可幫助使用者低成本的實現 T+0 級資料湖。
## Iceberg on Kubernetes
傳統方式下,使用者在部署和運維大資料平臺時通常採用手動或半自動化方式,這往往消耗大量人力,穩定性也無法保證。Kubernetes 的出現,革新了這一過程。Kubernetes 提供了應用部署和運維標準化能力,使用者業務在實施 Kubernetes 化改造後,可執行在其他所有標準 Kubernetes 叢集中。在大資料領域,這種能力可幫助使用者快速部署和交付大資料平臺(大資料元件部署尤為複雜)。尤其在大資料計算儲存分離的架構中,Kubernetes 叢集提供的 Serverless 能力,可幫助使用者即拿即用的執行計算任務。並且再配合離線上混部方案,除了可做到資源統一管控降低複雜度和風險外,叢集利用率也會進一步提升,大幅降低成本。
我們可基於 Kubernetes 構建 Hadoop 大資料平臺:
![](https://img2020.cnblogs.com/other/2041406/202011/2041406-20201106180540439-1103927386.jpg)
在近幾年大熱的資料湖領域,通過傳統 Hadoop 生態構建實時資料湖,受制於元件定位與設計,較為複雜與困難。Iceberg 的出現使得依賴開源技術快速構建實時資料湖成為可能,這也是大資料未來發展方向 - 實時分析、倉湖一體與雲原生。引入 Iceberg 後,整體架構變為:
![](https://img2020.cnblogs.com/other/2041406/202011/2041406-20201106180540722-2023358975.jpg)
Kubernetes 負責應用自動化部署與資源管理排程,為上層遮蔽了底層環境複雜性。Iceberg + Hive MetaStore + HDFS 實現了基於 Hadoop 生態的實時資料湖,為大資料應用提供資料訪問及儲存。Spark、Flink 等計算引擎以 native 的方式執行在 Kubernetes 叢集中,資源即拿即用。與線上業務混部後,更能大幅提升叢集資源利用率。
## 如何構建雲原生實時資料湖
## 架構圖
![](https://img2020.cnblogs.com/other/2041406/202011/2041406-20201106180541096-625789314.jpg)
- 資源層:Kubernetes 提供資源管控能力
- 資料層:Iceberg 提供 ACID、table 等資料集訪問操作能力
- 儲存層:HDFS 提供資料儲存能力,Hive MetaStore 管理 Iceberg 表元資料,Postgresql 作為 Hive MetaStore 儲存後端
- 計算層:Spark native on Kubernetes,提供流批計算能力
### 建立 Kubernetes 叢集
首先通過官方二進位制或自動化部署工具部署 Kubernetes 叢集,如 [kubeadm](https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/install-kubeadm/),推薦使用騰訊雲建立 [TKE 叢集](https://cloud.tencent.com/product/tke)。
![](https://img2020.cnblogs.com/other/2041406/202011/2041406-20201106180541306-2085756844.jpg)
推薦配置為:3 臺 S2.2XLARGE16(8核16G)例項
### 部署 Hadoop 叢集
可通過開源 Helm 外掛或自定義映象在 Kubernetes 上部署 Hadoop 叢集,主要部署 HDFS、Hive MetaStore 元件。在騰訊雲 TKE 中推薦使用 [k8s-big-data-suite](https://github.com/tkestack/charts/tree/main/incubator/k8s-big-data-suite) 大資料應用自動化部署 Hadoop 叢集。
![](https://img2020.cnblogs.com/other/2041406/202011/2041406-20201106180541606-477970515.jpg)
k8s-big-data-suite 是我們基於生產經驗開發的大資料套件,可支援主流的大資料元件在 Kubernetes 上一鍵部署。部署之前請先按照要求做叢集初始化:
```
# 標識儲存節點,至少三個
$ kubectl label node xxx storage=true
```
部署成功後,連入 TKE 叢集檢視元件狀態:
```
$ kubectl get po
NAME READY STATUS RESTARTS AGE
alertmanager-tkbs-prometheus-operator-alertmanager-0 2/2 Running 0 6d23h
cert-job-kv5tm 0/1 Completed 0 6d23h
elasticsearch-master-0 1/1 Running 0 6d23h
elasticsearch-master-1 1/1 Running 0 6d23h
flink-operator-controller-manager-9485b8f4c-75zvb 2/2 Running 0 6d23h
kudu-master-0 2/2 Running 2034 6d23h
kudu-master-1 2/2 Running 0 6d23h
kudu-master-2 2/2 Running 0 6d23h
kudu-tserver-0 1/1 Running 0 6d23h
kudu-tserver-1 1/1 Running 0 6d23h
kudu-tserver-2 1/1 Running 0 6d23h
prometheus-tkbs-prometheus-operator-prometheus-0 3/3 Running 0 6d23h
superset-init-db-g6nz2 0/1 Completed 0 6d23h
thrift-jdbcodbc-server-1603699044755-exec-1 1/1 Running 0 6d23h
tkbs-admission-5559c4cddf-w7wtf 1/1 Running 0 6d23h
tkbs-admission-init-x8sqd 0/1 Completed 0 6d23h
tkbs-airflow-scheduler-5d44f5bf66-5hd8k 1/1 Running 2 6d23h
tkbs-airflow-web-84579bc4cd-6dftv 1/1 Running 2 6d23h
tkbs-client-844559f5d7-r86rb 1/1 Running 6 6d23h
tkbs-controllers-6b9b95d768-vr7t5 1/1 Running 0 6d23h
tkbs-cp-kafka-0 3/3 Running 2 6d23h
tkbs-cp-kafka-1 3/3 Running 2 6d23h
tkbs-cp-kafka-2 3/3 Running 2 6d23h
tkbs-cp-kafka-connect-657bdff584-g9f2r 2/2 Running 2 6d23h
tkbs-cp-schema-registry-84cd7cbdbc-d28jk 2/2 Running 4 6d23h
tkbs-grafana-68586d8f97-zbc2m 2/2 Running 0 6d23h
tkbs-hadoop-hdfs-dn-6jng4 2/2 Running 0 6d23h
tkbs-hadoop-hdfs-dn-rn8z9 2/2 Running 0 6d23h
tkbs-hadoop-hdfs-dn-t68zq 2/2 Running 0 6d23h
tkbs-hadoop-hdfs-jn-0 2/2 Running 0 6d23h
tkbs-hadoop-hdfs-jn-1 2/2 Running 0 6d23h
tkbs-hadoop-hdfs-jn-2 2/2 Running 0 6d23h
tkbs-hadoop-hdfs-nn-0 2/2 Running 5 6d23h
tkbs-hadoop-hdfs-nn-1 2/2 Running 0 6d23h
tkbs-hbase-master-0 1/1 Running 3 6d23h
tkbs-hbase-master-1 1/1 Running 0 6d23h
tkbs-hbase-rs-0 1/1 Running 3 6d23h
tkbs-hbase-rs-1 1/1 Running 0 6d23h
tkbs-hbase-rs-2 1/1 Running 0 6d23h
tkbs-hive-metastore-0 2/2 Running 0 6d23h
tkbs-hive-metastore-1 2/2 Running 0 6d23h
tkbs-hive-server-8649cb7446-jq426 2/2 Running 1 6d23h
tkbs-impala-catalogd-6f46fd97c6-b6j7b 1/1 Running 0 6d23h
tkbs-impala-coord-exec-0 1/1 Running 7 6d23h
tkbs-impala-coord-exec-1 1/1 Running 7 6d23h
tkbs-impala-coord-exec-2 1/1 Running 7 6d23h
tkbs-impala-shell-844796695-fgsjt 1/1 Running 0 6d23h
tkbs-impala-statestored-798d44765f-ffp82 1/1 Running 0 6d23h
tkbs-kibana-7994978d8f-5fbcx 1/1 Running 0 6d23h
tkbs-kube-state-metrics-57ff4b79cb-lmsxp 1/1 Running 0 6d23h
tkbs-loki-0 1/1 Running 0 6d23h
tkbs-mist-d88b8bc67-s8pxx 1/1 Running 0 6d23h
tkbs-nginx-ingress-controller-87b7fb9bb-mpgtj 1/1 Running 0 6d23h
tkbs-nginx-ingress-default-backend-6857b58896-rgc5c 1/1 Running 0 6d23h
tkbs-nginx-proxy-64964c4c79-7xqx6 1/1 Running 6 6d23h
tkbs-postgresql-5b9ddc464c-xc5nn 1/1 Running 1 6d23h
tkbs-postgresql-ha-pgpool-5cbf85d847-v5dsr 1/1 Running 1 6d23h
tkbs-postgresql-ha-postgresql-0 2/2 Running 0 6d23h
tkbs-postgresql-ha-postgresql-1 2/2 Running 0 6d23h
tkbs-prometheus-node-exporter-bdp9v 1/1 Running 0 6d23h
tkbs-prometheus-node-exporter-cdrqr 1/1 Running 0 6d23h
tkbs-prometheus-node-exporter-cv767 1/1 Running 0 6d23h
tkbs-prometheus-node-exporter-l82wp 1/1 Running 0 6d23h
tkbs-prometheus-node-exporter-nb4pk 1/1 Running 0 6d23h
tkbs-prometheus-operator-operator-f74dd4f6f-lnscv 2/2 Running 0 6d23h
tkbs-promtail-d6r9r 1/1 Running 0 6d23h
tkbs-promtail-gd5nz 1/1 Running 0 6d23h
tkbs-promtail-l9kjw 1/1 Running 0 6d23h
tkbs-promtail-llwvh 1/1 Running 0 6d23h
tkbs-promtail-prgt9 1/1 Running 0 6d23h
tkbs-scheduler-74f5777c5d-hr88l 1/1 Running 0 6d23h
tkbs-spark-history-7d78cf8b56-82xg7 1/1 Running 4 6d23h
tkbs-spark-thirftserver-5757f9588d-gdnzz 1/1 Running 4 6d23h
tkbs-sparkoperator-f9fc5b8bf-8s4m2 1/1 Running 0 6d23h
tkbs-sparkoperator-f9fc5b8bf-m9pjk 1/1 Running 0 6d23h
tkbs-sparkoperator-webhook-init-m6fn5 0/1 Completed 0 6d23h
tkbs-superset-54d587c867-b99kw 1/1 Running 0 6d23h
tkbs-zeppelin-controller-65c454cfb9-m4snp 1/1 Running 0 6d23h
tkbs-zookeeper-0 3/3 Running 0 6d23h
tkbs-zookeeper-1 3/3 Running 0 6d23h
tkbs-zookeeper-2 3/3 Running 0 6d23h
```
#### 注意
當前 TKE k8s-big-data-suite 1.0.3 在初始化 Postgresql 時,缺少對 Hive transaction 的支援,從而導致 Iceberg 表建立失敗。請先執行以下命令手動修復:
```
$ kubectl get pod | grep postgresql
tkbs-postgresql-5b9ddc464c-xc5nn 1/1 Running 1 7d18h
$ kubectl exec tkbs-postgresql-5b9ddc464c-xc5nn -- psql -c "UPDATE pg_database SET datallowconn = 'false' WHERE datname = 'metastore';SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = 'metastore'"; kubectl exec tkbs-postgresql-5b9ddc464c-xc5nn -- psql -c "drop database metastore"; kubectl exec tkbs-postgresql-5b9ddc464c-xc5nn -- psql -c "create database metastore"
$ kubectl get pod | grep client
tkbs-client-844559f5d7-r86rb 1/1 Running 7 7d18h
$ kubectl exec tkbs-client-844559f5d7-r86rb -- schematool -dbType postgres -initSchema
```
### 整合 Iceberg
當前 Iceberg 對 Spark 3.0 有較好支援,對比 Spark 2.4 有以下優勢:
![](https://img2020.cnblogs.com/other/2041406/202011/2041406-20201106180541961-39270141.jpg)
所以我們預設採用 Spark 3.0 作為計算引擎。Spark 整合 Iceberg,首先需引入 Iceberg jar 依賴。使用者可在提交任務階段手動指定,或將 jar 包直接引入 Spark 安裝目錄。為了便於使用,我們選擇後者。筆者已打包 Spark 3.0.1 的映象,供使用者測試使用:ccr.ccs.tencentyun.com/timxbxu/spark:v3.0.1。
我們使用 Hive MetaStore 管理 Iceberg 表資訊,通過 Spark Catalog 訪問和使用 Iceberg 表。在 Spark 中做如下配置:
```
spark.sql.catalog.hive_prod = org.apache.iceberg.spark.SparkCatalog
spark.sql.catalog.hive_prod.type = hive
spark.sql.catalog.hive_prod.uri = thrift://metastore-host:port
```
若使用 TKE k8s-big-data-suite 套件部署 Hadoop 叢集,可通過 Hive Service 訪問 Hive MetaStore:
```
$ kubectl get svc | grep hive-metastore
tkbs-hive-metastore ClusterIP 172.22.25