我們一起聊聊 StarRocks 升級注意事項
前段時間升級了生產環境的 StarRocks,從 3.3.3 升級到了 3.3.9,期間還是踩了不少坑所以在這里記錄下。
圖片
因為我們的集群使用的是存算分離的版本,也是使用官方提供的 operator 部署在 kubernetes 里的,所以沒法按照官方的流程進入虛擬機手動啟停對應的服務。
只能使用 operator 提供的方案手動修改對應組件的鏡像版本,后續的升級操作交給 operator 去完成。
圖片
理論上這個升級流程沒什么問題,修改鏡像版本之后只需要安靜等待他滾動更新即可。
元數據備份與恢復
但考慮到之前在社區看到有存算分離集群升級失敗導致數據丟失的案例,我們的全量業務已經切換到 StarRocks,如果數據丟失那需要花幾天時間進行數據同步,這在業務上是無法接受的,所以我們最好是可以在升級前備份數據,即便是升級失敗數據依然還在。
圖片
原本官方社區是有提供數據備份與恢復能力的,但是我們使用的存算分離集群不支持??,而想要獲得社區版的支持應該還要等一段時間,即便是支持了我們升級到那個版本依然是需要備份的。
圖片
好消息,在最新的 3.4.1 版本中已經支持了快照備份了,只是作為一個新 feature,穩定性還有待觀察。
所以我們的計劃是在當前這個版本(3.3.3)能否自己備份數據,由于我們是存算分離的版本,所以數據主要分為兩部分:
- 存儲在所有 FE 節點里的 meta 元數據
- 存儲在云存儲里的業務數據
備份的時候自然就需要備份這兩部分的數據。
備份元數據
在元數據里存放了所有的數據庫、表、視圖等信息,具體在磁盤的結構如下:
|-- bdb
| |-- 00000000.jdb
| |-- je.config.csv
| |-- je.info.0
| |-- je.info.0.lck
| |-- je.lck
| `-- je.stat.csv
|-- image
| |-- ROLE
| |-- VERSION
| |-- image.327375
| |-- starmgr
| | `-- image.390
| `-- v2
| |-- checksum.327375
| `-- image.327375
bdb 目錄主要是用于 leader 選舉的,理論上并不需要備份,真正需要的是 image 目錄下的 image.327375 等元數據文件。
圖片
圖片
里面是用 JSON 存儲的各種類型的元數據,FE 在啟動的時候會讀取該文件,然后根據不同的類型取不同的偏移量讀取其中的元數據加載到內存里。
我們的 FE 一共有三個節點,需要找到其中的 leader 節點(理論上只需要備份 leader 節點即可,其他節點會在 leader 啟動后同步過去),直接將這個 meta 目錄備份到本地即可:
在開始之前需要停掉所有的寫入任務,暫停所有的物化視圖刷新。
# inactive 所有的物化視圖
SELECT CONCAT('ALTER MATERIALIZED VIEW ', TABLE_NAME, ' INACTIVE;') FROM information_schema.materialized_views;
# 手動創建鏡像
ALTER SYSTEM CREATE IMAGE;
# 找到 leader 節點
SHOW FRONTENDS;
然后進入 leader 節點備份元數據:
k exec -it kube-starrocks-fe-0-n sr -- bash
tar -zcvf meta.tar.gz meta/
# 下載備份元數據到本地
k cp starrocks-fe-0:/opt/starrocks/fe/meta/image.tar.gz image.tar.gz -n starrocks -c fe --retries=5
備份云存儲數據
云存儲的備份就需要結合你使用的云廠商來備份了,通常他們都有提供對應的備份能力。
要注意的是我們再備份的時候需要記錄在存儲桶里的目錄名稱,之后還原的時候名稱得保持一致才行。
恢復元數據
當出現極端情況升級失敗的時候,我們需要把元數據覆蓋回去;但由于我們的應用運行在容器里,不可以在應用啟動之后再替換元數據。
只能在應用啟動之前將之前備份的元數據覆蓋回去,這里可以使用 kubernetes 中的 initContainers 提前將數據復制到應用容器里。
在開始之前我們需要先把備份的元數據打包為一個鏡像。
FROM busybox
ADD meta.tar.gz /temp
然后我們需要手動修改 FE 的 statefulset 的資源,創建一個 initContainers。
initContainers:
-name:copy-file-init
image:meta:0.0.1
command:["/bin/sh","-c"]
args:["rm-rf/meta-target/*&&cp-r/temp/meta/./meta-target"]
volumeMounts:
-name:fe-meta
mountPath:"/meta-target"
原理就是在 initContainers 中掛載原本 FE 的元數據目錄,這樣就可以直接將之前備份的元數據覆蓋過去。
當然也可以直接使用 k8s 的 go client 用代碼的方式來修改,會更容易維護。
還原的時候需要先將云存儲里的數據先還原之后再還原元數據。
物化視圖刷新策略
真正升級的時候倒是沒有碰到升級失敗的情況,所以沒有走恢復流程;但是卻碰到了一個更麻煩的事情。
物化視圖作為基表
我們在升級前將所有的物化視圖設置為了 INACTIVE,升級成功后需要將他們都改為 ACTIVE。
第一個問題是如果某個物化視圖 MV1 的基表也是一個物化視圖 MV-base,這樣會導致 MV1 的全量刷新。
我之前在這個 PR 里新增了一個參數:excluded_refresh_tables 可以用于排除基表發生變化的時候刷新物化視圖,但是忘記了基表也是物化視圖的場景。
圖片
所以在這個 PR 中修復了該問題,現在基表是物化視圖的時候也可以使用了。
物化視圖手動 ACTIVE
前面提到在升級之前需要將所有的物化視圖設置為 INACTIVE,升級成功后再手動設置為 ACTIVE。
我們在手動 ACTIVE 之后發現這些物化視圖又在做全量刷新了,于是我們檢查了代碼。
圖片
發現在使用 ALTER MATERIALIZED VIEW order_mv ACTIVE; 修改視圖狀態的時候會強制刷新物化視圖的所有分區。
圖片
force: true 的時候會直接跳過基表的分區檢查,導致分區的全量刷新。
圖片
同時會在 ACTIVE 的時候將視圖基表的 baseTableVisibleVersionMap 版本號緩存清空,FE 需要在刷新的時候判斷當前需要刷新的分區是否存在與緩存中,如果存在的話說明不需要刷新,現在被清空后就一定會被刷新。
所以我提了一個 PR 可以在 ACTIVE 物化視圖的時候人工判斷是否需要刷新:
alter materialized view mv_test1 ACTIVE WITH NO_VALIDATION
這樣帶上 NO_VALIDATION 參數后就 force=false 也就不會全量刷新了。
如果在 ACTIVE 物化視圖的時候碰到類似場景,可以在這個 PR 發布之后加上 NO_VALIDATION 來跳過刷新。
參考鏈接: