境下Doris存算分離架構(gòu)部署與驗證實戰(zhàn))
1. 為什么要在Docker里折騰Doris存算分離第一次接觸Doris存算分離架構(gòu)的人腦子里大概率會冒出一個疑問明明官方推薦用物理機或者Kubernetes部署為什么還要費勁把它塞進Docker里這個問題我在兩年前也糾結(jié)過后來在一個需要頻繁做版本驗證和架構(gòu)演示的場景里Docker方案反而成了最省事的選擇。先說清楚Doris存算分離到底解決了什么問題。傳統(tǒng)Doris架構(gòu)里BE節(jié)點既負責數(shù)據(jù)存儲又負責計算擴容的時候存儲和計算必須一起擴這就導致一個尷尬的局面你明明只是想在月底跑報表的時候多要一點算力結(jié)果不得不順帶買一堆磁盤。存算分離把這兩件事拆開了數(shù)據(jù)放在共享存儲層比如S3兼容對象存儲或者HDFS計算節(jié)點變成無狀態(tài)的可以隨用隨起、用完就釋放。這個思路和Snowflake、Databricks那套邏輯是一致的本質(zhì)上是為了讓資源彈性更細粒度。那Docker在這里扮演什么角色我的實際體會是Docker最適合做三件事第一快速搭建驗證環(huán)境驗證存算分離配置是否正確第二在單機上模擬多節(jié)點拓撲方便理解FE、BE、MSMeta Service之間的交互關(guān)系第三給團隊做架構(gòu)培訓時一套compose文件就能把整個集群拉起來比讓每個人裝虛擬機高效得多。但必須提前說清楚邊界Docker方案不適合直接上生產(chǎn)。原因后面會詳細展開核心問題是網(wǎng)絡(luò)和存儲的性能損耗以及容器編排帶來的運維復雜度。如果你是想找一個能跑通存算分離全流程、能理解各組件職責、能驗證配置參數(shù)的環(huán)境那這篇內(nèi)容就是為你準備的。我見過太多人一上來就照著官方文檔復制粘貼結(jié)果卡在MS服務(wù)起不來、BE注冊不上、S3配置報錯這些地方。下面我會按照實際搭建的順序把每個環(huán)節(jié)的坑和背后的邏輯都講透。2. 存算分離架構(gòu)里每個組件到底在干什么在動手寫compose文件之前必須先把架構(gòu)圖在腦子里畫清楚。很多人部署失敗的根本原因不是命令敲錯了而是根本沒搞明白每個容器之間是怎么通信的。2.1 FE、BE、MS三者的職責邊界Doris存算分離版本里FEFrontend的角色和存算一體時基本一致負責元數(shù)據(jù)管理、查詢解析和調(diào)度。但有一個關(guān)鍵變化FE不再直接管理數(shù)據(jù)副本的位置信息這部分職責交給了MSMeta Service。MS是一個獨立的服務(wù)它維護著哪個數(shù)據(jù)分片在對象存儲的哪個路徑下這張映射表。BEBackend在存算分離模式下變成了純計算節(jié)點。它啟動的時候會向FE注冊但實際讀取數(shù)據(jù)時是先從MS拿到數(shù)據(jù)位置然后直接去對象存儲拉數(shù)據(jù)。這意味著BE本地不需要掛載大容量磁盤只需要一塊小盤做緩存和臨時文件就夠了。這里有個容易混淆的點很多人以為存算分離后BE就不需要本地存儲了實際上BE還是需要本地磁盤做兩件事——一是緩存熱數(shù)據(jù)二是存放計算過程中的臨時文件。我建議至少給BE分配20GB以上的本地空間否則復雜查詢很容易因為臨時空間不足而失敗。2.2 對象存儲選型MinIO還是直接上云在Docker環(huán)境里驗證存算分離最方便的對象存儲當然是MinIO。它本身就是S3兼容的一個容器就能跑起來配置也簡單。但如果你手頭有云廠商的對象存儲賬號直接連云上的S3也行只是要注意網(wǎng)絡(luò)延遲會直接影響查詢性能。我一般會在compose里加一個MinIO容器原因很簡單所有組件都在本地網(wǎng)絡(luò)里調(diào)試的時候抓包、看日志都方便。用云存儲的話一旦出現(xiàn)權(quán)限或者路徑問題排查鏈路會拉得很長。MinIO的配置有幾個關(guān)鍵參數(shù)需要提前想好。首先是bucket名稱建議用doris-data這種一看就懂的命名。其次是access key和secret key在Docker環(huán)境里可以用簡單的字符串但要注意這些值需要同時配置在MS和BE的配置文件里任何一處不一致都會導致數(shù)據(jù)寫入失敗。2.3 網(wǎng)絡(luò)模式的選擇host還是bridge這是Docker部署Doris時第一個要做的關(guān)鍵決策。Doris的組件之間通信非常頻繁FE和BE之間、BE和MS之間、BE和對象存儲之間都有大量網(wǎng)絡(luò)交互。如果用默認的bridge網(wǎng)絡(luò)容器之間通過端口映射通信會引入額外的NAT開銷而且BE注冊到FE時上報的IP地址容易出問題。我的建議是直接用host網(wǎng)絡(luò)模式。這樣每個容器都共享宿主機的網(wǎng)絡(luò)棧IP地址就是宿主機的IP端口也不會沖突只要提前規(guī)劃好。缺點是端口不能重復所以FE的8030、9030BE的8040、9060MS的5000MinIO的9000和9001這些端口都要確保宿主機上沒有其他程序占用。如果非要用bridge模式那必須在BE的配置里顯式指定be_addr為宿主機的IP而不是容器內(nèi)部的IP。否則FE拿到的是容器IP其他組件根本訪問不到。這個坑我踩過不止一次表現(xiàn)就是BE顯示存活但查詢一直報超時。3. 手把手寫一份能跑通的compose文件網(wǎng)上能找到的Doris存算分離Docker示例不多而且很多都是存算一體時代的配置改了個名字根本跑不起來。下面這份compose文件是我在實際環(huán)境中反復調(diào)試后穩(wěn)定運行的版本每個參數(shù)都有存在的理由。3.1 基礎(chǔ)鏡像與版本選擇Doris的存算分離功能在2.1版本之后才比較穩(wěn)定我建議直接用3.x的鏡像。官方在Docker Hub上提供了apache/doris倉庫但存算分離相關(guān)的鏡像標簽需要仔細找。FE用apache/doris:fe-3.0.xBE用apache/doris:be-3.0.xMS用apache/doris:ms-3.0.x。這里有個細節(jié)三個組件的版本號必須完全一致小版本號都不能差。我曾經(jīng)用fe-3.0.1配be-3.0.2結(jié)果BE注冊時協(xié)議不兼容日志里報了一堆protobuf解析錯誤。統(tǒng)一版本是最基本的要求。MinIO用minio/minio:latest就行它足夠穩(wěn)定。但要注意MinIO的默認端口是9000API和9001控制臺如果宿主機上已經(jīng)有其他服務(wù)占了這兩個端口需要提前改掉。3.2 完整compose配置與逐行解讀version: 3.8 services: minio: image: minio/minio:latest network_mode: host environment: MINIO_ROOT_USER: dorisadmin MINIO_ROOT_PASSWORD: dorisadmin123 command: server /data --console-address :9001 volumes: - ./minio-data:/data doris-ms: image: apache/doris:ms-3.0.3 network_mode: host environment: MS_CONFIG_FILE: /opt/apache-doris/ms/conf/doris_cloud.conf volumes: - ./ms-conf:/opt/apache-doris/ms/conf - ./ms-log:/opt/apache-doris/ms/log depends_on: - minio doris-fe: image: apache/doris:fe-3.0.3 network_mode: host environment: FE_CONFIG_FILE: /opt/apache-doris/fe/conf/fe.conf volumes: - ./fe-conf:/opt/apache-doris/fe/conf - ./fe-log:/opt/apache-doris/fe/log - ./fe-meta:/opt/apache-doris/fe/doris-meta depends_on: - doris-ms doris-be: image: apache/doris:be-3.0.3 network_mode: host environment: BE_CONFIG_FILE: /opt/apache-doris/be/conf/be.conf volumes: - ./be-conf:/opt/apache-doris/be/conf - ./be-log:/opt/apache-doris/be/log - ./be-storage:/opt/apache-doris/be/storage depends_on: - doris-fe這份配置看起來簡單但每個掛載點都有講究。FE的doris-meta目錄必須持久化否則每次重啟FE都要重新初始化元數(shù)據(jù)之前建的庫和表全沒了。BE的storage目錄雖然存算分離后數(shù)據(jù)不在本地但緩存和臨時文件還在里面持久化能避免重啟后緩存全部失效。MS的配置文件doris_cloud.conf是整個部署里最關(guān)鍵的文件它需要告訴MS對象存儲的地址和憑證。下面是一個最小可用的配置示例# MS服務(wù)監(jiān)聽地址 host 0.0.0.0 port 5000 # 對象存儲配置 storage_type S3 s3_endpoint http://127.0.0.1:9000 s3_region us-east-1 s3_access_key dorisadmin s3_secret_key dorisadmin123 s3_bucket doris-data s3_prefix doris-cluster注意s3_endpoint這里用的是127.0.0.1因為host網(wǎng)絡(luò)模式下MS容器直接訪問宿主機的9000端口。如果你用的是bridge模式這里要改成MinIO容器的名稱或者對應的IP。3.3 FE和BE的關(guān)鍵配置項FE的fe.conf里需要加上存算分離的開關(guān)# 啟用存算分離模式 cloud_mode true # MS服務(wù)地址 cloud_meta_service_endpoint 127.0.0.1:5000 # 元數(shù)據(jù)目錄 meta_dir /opt/apache-doris/fe/doris-metaBE的be.conf配置稍微多一點# 啟用存算分離 cloud_mode true # MS服務(wù)地址 cloud_meta_service_endpoint 127.0.0.1:5000 # BE自身地址host模式下就是宿主機IP be_addr 127.0.0.1 # 本地存儲路徑用于緩存和臨時文件 storage_root_path /opt/apache-doris/be/storage # 緩存大小限制根據(jù)宿主機內(nèi)存調(diào)整 file_cache_size 10737418240file_cache_size這個參數(shù)值得單獨說一下。存算分離后每次查詢都要從對象存儲拉數(shù)據(jù)如果本地沒有緩存性能會非常差。我一般會把它設(shè)置為宿主機可用內(nèi)存的30%左右。比如宿主機有32GB內(nèi)存給BE分配10GB緩存是比較合理的。太小了緩存命中率低太大了容易和FE、MS搶內(nèi)存。4. 啟動順序與初始化過程中的真實坑配置文件寫好了不代表就能跑起來。Doris存算分離的啟動有嚴格的順序要求而且初始化過程中有幾個非常隱蔽的坑官方文檔里要么沒寫要么一筆帶過。4.1 為什么MS必須最先啟動MS是整個集群的元數(shù)據(jù)中樞FE和BE啟動時都會嘗試連接MS。如果MS沒起來FE會一直重試并最終報錯退出BE則會卡在注冊階段。所以啟動順序必須是MinIO → MS → FE → BE。但這里有個問題MS啟動后需要幾秒鐘初始化內(nèi)部狀態(tài)如果FE緊接著啟動可能會因為MS還沒準備好而連接失敗。我的做法是在compose里給FE加一個健康檢查依賴或者干脆手動分步啟動。手動啟動雖然麻煩一點但排查問題的時候更清晰。啟動MS后第一件事是看日志確認它是否成功連接到了MinIO。日志里會打印類似Successfully connected to S3 storage的信息。如果看到Access Denied說明access key或者secret key配錯了。如果看到Bucket not found說明bucket還沒創(chuàng)建需要先去MinIO控制臺建一個。4.2 FE首次啟動的元數(shù)據(jù)初始化FE第一次啟動時會自動初始化元數(shù)據(jù)這個過程大概需要10到30秒。日志里會看到Initialize metadata finished的字樣。如果卡在這里超過一分鐘大概率是cloud_meta_service_endpoint配置有問題FE連不上MS。初始化完成后需要用MySQL客戶端連接FE的9030端口執(zhí)行一條命令來確認存算分離模式是否生效SHOW FRONTENDS;如果返回結(jié)果里CloudMode字段是true說明FE已經(jīng)正確識別了存算分離模式。如果是false那就要檢查fe.conf里的cloud_mode配置是否被正確加載了。有時候配置文件掛載路徑不對容器里讀的還是默認配置這個坑很隱蔽。4.3 BE注冊失敗的三種典型表現(xiàn)BE注冊失敗是最常見的問題表現(xiàn)有三種第一種是BE進程直接退出日志里報Failed to connect to meta service。這通常是MS地址配錯了或者MS根本沒起來。第二種是BE進程活著但FE里SHOW BACKENDS看不到它。這種情況一般是be_addr配置有問題BE上報了一個FE訪問不到的IP。在host網(wǎng)絡(luò)模式下be_addr應該是宿主機的實際IP而不是127.0.0.1。我一開始圖省事寫了127.0.0.1結(jié)果FE和BE雖然在同一個宿主機上但FE是通過容器內(nèi)部回環(huán)地址去連的根本連不上。第三種是BE顯示存活但狀態(tài)是offline。這通常是BE和MS之間的通信有問題需要檢查BE日志里有沒有Failed to get storage info from MS之類的錯誤。排查BE注冊問題的時候我習慣先在BE容器里手動curl一下MS的健康檢查接口curl http://127.0.0.1:5000/health如果返回OK說明網(wǎng)絡(luò)是通的問題在配置上。如果連不上那就是網(wǎng)絡(luò)或者MS本身的問題。5. 驗證存算分離是否真正生效環(huán)境跑起來只是第一步更重要的是驗證存算分離架構(gòu)是否真的在工作。很多人部署完了建了個表插了幾條數(shù)據(jù)查詢能出結(jié)果就以為大功告成了。但實際上如果配置不對Doris可能悄悄退化成了存算一體模式數(shù)據(jù)還是寫在BE本地。5.1 建表時指定存儲策略在存算分離模式下建表需要顯式指定存儲策略。Doris 3.x里可以通過STORAGE POLICY來指定數(shù)據(jù)存放在哪個對象存儲路徑下。最簡單的驗證方法是建一張表插入數(shù)據(jù)然后去MinIO的控制臺看bucket里有沒有對應的文件生成。CREATE TABLE test_table ( id INT, name VARCHAR(50) ) ENGINEOLAP DUPLICATE KEY(id) DISTRIBUTED BY HASH(id) BUCKETS 1 PROPERTIES ( replication_num 1 );建完表后插入幾條數(shù)據(jù)INSERT INTO test_table VALUES (1, test1), (2, test2);然后登錄MinIO控制臺進入doris-data這個bucket應該能看到類似doris-cluster/xxx/yyy的路徑結(jié)構(gòu)里面存放著數(shù)據(jù)文件。如果bucket里空空如也那說明數(shù)據(jù)還是寫在BE本地了存算分離沒有真正生效。5.2 通過BE日志確認數(shù)據(jù)流向另一個驗證方法是看BE的日志。當BE從對象存儲讀取數(shù)據(jù)時日志里會有Read from S3或者Download from remote storage之類的記錄。如果日志里全是Read from local disk那就要回頭檢查配置了。我一般會在插入數(shù)據(jù)后手動觸發(fā)一次查詢?nèi)缓髏ail BE的日志tail -f ./be-log/be.INFO | grep -i s3\|remote如果能看到從S3讀取的記錄說明存算分離鏈路是通的。5.3 模擬BE節(jié)點故障后的數(shù)據(jù)可訪問性存算分離最大的價值就是BE無狀態(tài)節(jié)點掛了數(shù)據(jù)也不丟。驗證方法很簡單把BE容器停掉然后重新啟動一個新的BE容器看數(shù)據(jù)是否還能正常查詢。docker stop doris-be docker start doris-be等BE重新注冊成功后再執(zhí)行SELECT * FROM test_table如果數(shù)據(jù)還在說明數(shù)據(jù)確實存在對象存儲里BE本地沒有保留副本。這個驗證雖然簡單但能直觀地證明存算分離架構(gòu)在正常工作。6. 性能調(diào)優(yōu)與日常運維的實操心得Docker環(huán)境下的Doris存算分離性能肯定比不上物理機部署但通過一些調(diào)優(yōu)手段可以把它調(diào)整到能用的水平。下面這些參數(shù)是我在實際使用中反復調(diào)整后覺得比較有效的。6.1 緩存策略對查詢性能的影響存算分離后查詢性能的瓶頸往往在對象存儲的讀取速度上。本地緩存的大小和淘汰策略直接決定了查詢的響應時間。BE的file_cache_size前面已經(jīng)提過這里補充一個file_cache_evict_policy參數(shù)可以設(shè)置為LRU或者LFU。對于報表類查詢LFU最不經(jīng)常使用通常效果更好因為熱門數(shù)據(jù)會被頻繁訪問LFU能保證它們留在緩存里。另外MinIO本身也可以做緩存優(yōu)化。如果宿主機內(nèi)存充足可以給MinIO容器分配更大的內(nèi)存讓它在內(nèi)存里緩存熱點對象。MinIO的--cache參數(shù)可以配置本地緩存目錄和大小不過這個配置在Docker環(huán)境下需要額外掛載卷稍微麻煩一點。6.2 容器資源限制的合理設(shè)置Docker默認不限制容器資源這意味著BE可能會把宿主機的內(nèi)存吃光。我建議在compose里給每個容器加上資源限制deploy: resources: limits: memory: 16G reservations: memory: 8GFE和MS的內(nèi)存需求相對小一些8GB足夠。BE是內(nèi)存大戶建議至少給16GB如果宿主機內(nèi)存充裕給32GB更好。注意file_cache_size不能超過BE容器的內(nèi)存限制否則容器會被OOM Killer干掉。6.3 日志輪轉(zhuǎn)與磁盤空間管理Docker環(huán)境下磁盤空間是最容易出問題的地方。FE和BE的日志增長很快如果不做輪轉(zhuǎn)幾天就能把磁盤寫滿。我的做法是在宿主機上配置logrotate定期清理掛載出來的日志目錄。另外BE的storage目錄里會有緩存文件雖然可以自動淘汰但偶爾也會出現(xiàn)緩存文件堆積的情況需要定期檢查。還有一個容易被忽略的點Docker的鏡像和容器層也會占用大量空間。Doris的鏡像本身就有好幾個GB加上運行時的寫入層磁盤占用會持續(xù)增長。建議定期執(zhí)行docker system prune清理無用的鏡像和停止的容器。6.4 常見故障的快速排查清單最后整理一份我在實際運維中總結(jié)的排查清單遇到問題的時候可以按順序檢查故障現(xiàn)象可能原因排查方法FE啟動后立即退出MS未啟動或地址錯誤檢查MS日志和FE的cloud_meta_service_endpoint配置BE注冊不上be_addr配置錯誤在BE容器內(nèi)curl FE的8030端口查詢報S3權(quán)限錯誤access key或secret key不匹配對比MS和MinIO的配置查詢速度極慢緩存未生效或緩存太小檢查file_cache_size和BE日志中的緩存命中率數(shù)據(jù)寫入失敗bucket不存在或路徑無權(quán)限登錄MinIO控制臺確認bucket和路徑BE頻繁O(jiān)OM內(nèi)存限制太小或緩存配置過大調(diào)整容器內(nèi)存限制和file_cache_size這份清單不能覆蓋所有情況但能解決80%以上的常見問題。剩下的20%通常需要看具體日志Doris的日志信息還算詳細耐心讀一般都能找到線索。我在多次搭建Doris存算分離Docker環(huán)境的過程中最大的體會是配置文件的正確性只占成功因素的一半另一半是對組件之間通信關(guān)系的理解。知道FE為什么要連MS、BE為什么要上報自己的地址、數(shù)據(jù)為什么要經(jīng)過MS中轉(zhuǎn)這些底層邏輯清楚了遇到問題才能快速定位。Docker只是一個載體真正有價值的是對存算分離架構(gòu)本身的掌握。