戰(zhàn):低成本分布式存儲(chǔ)選型與調(diào)優(yōu)指南)
做大數(shù)據(jù)平臺(tái)的人幾乎都經(jīng)歷過(guò)這種糾結(jié)業(yè)務(wù)量沒(méi)多大但HDFS三副本機(jī)制硬生生把存儲(chǔ)成本吃掉兩倍想換對(duì)象存儲(chǔ)省錢(qián)又擔(dān)心Hive跑SQL時(shí)延遲扛不住。前陣子我正好在內(nèi)部集群里完成了一套Hive和Ceph的整合方案整個(gè)過(guò)程踩了不少坑也沉淀了一些可復(fù)用的經(jīng)驗(yàn)這里把完整的選型思路、落地步驟和調(diào)優(yōu)過(guò)程分享出來(lái)給正在做分布式存儲(chǔ)選型的朋友一個(gè)參考。這次整合的背景很簡(jiǎn)單我們已有的Hive數(shù)倉(cāng)集群存儲(chǔ)水位逼近85%擴(kuò)容采購(gòu)周期長(zhǎng)而機(jī)房里有幾臺(tái)配置不錯(cuò)但磁盤(pán)閑置的機(jī)器加上Ceph集群本身就承載著部分業(yè)務(wù)數(shù)據(jù)。與其繼續(xù)往HDFS里填盤(pán)不如把Ceph的分布式存儲(chǔ)能力利用起來(lái)作為Hive的底層存儲(chǔ)擴(kuò)展。這套方案最終實(shí)現(xiàn)了Hive任務(wù)正常跑、存儲(chǔ)成本下降、擴(kuò)容靈活的目標(biāo)整個(gè)過(guò)程從環(huán)境準(zhǔn)備到生產(chǎn)上線大約花了兩周時(shí)間。1. Hive和Ceph整合到底在解決什么真實(shí)問(wèn)題1.1 從HDFS存儲(chǔ)成本痛點(diǎn)說(shuō)起Hive本身不是一個(gè)存儲(chǔ)系統(tǒng)它只是把SQL翻譯成MapReduce或Spark任務(wù)的計(jì)算框架底層數(shù)據(jù)還是落在HDFS上。HDFS為了保證數(shù)據(jù)可靠性采用多副本機(jī)制默認(rèn)三副本意味著1TB的業(yè)務(wù)數(shù)據(jù)實(shí)際占用3TB物理空間這是業(yè)內(nèi)公認(rèn)的成本大頭。很多中小團(tuán)隊(duì)的數(shù)據(jù)量撐死幾十TB卻被HDFS的副本策略搞得存儲(chǔ)資源緊張。Ceph則完全是另一套思路。它底層通過(guò)CRUSH算法把數(shù)據(jù)打散到整個(gè)集群的OSD上靠副本或糾刪碼來(lái)保障可靠性。兩者并非天然互斥但可以組合Ceph提供彈性可擴(kuò)展的存儲(chǔ)底座Hive繼續(xù)提供SQL分析能力。這個(gè)組合最直接的價(jià)值就是可以把存儲(chǔ)從計(jì)算節(jié)點(diǎn)中解耦出來(lái)——計(jì)算資源不夠就加計(jì)算節(jié)點(diǎn)存儲(chǔ)不夠就擴(kuò)Ceph OSD互不綁架。1.2 這套方案適合誰(shuí)不適合誰(shuí)先潑一盆冷水如果你們的Hive集群已經(jīng)有完善的HDFS架構(gòu)、日常任務(wù)對(duì)延遲極度敏感那沒(méi)必要折騰Ceph整合。這個(gè)方案的典型適用場(chǎng)景有兩個(gè)第一是存儲(chǔ)成本壓力大、希望利用通用硬件構(gòu)建低成本存儲(chǔ)層第二是業(yè)務(wù)數(shù)據(jù)量有較大增長(zhǎng)預(yù)期希望存儲(chǔ)層具備彈性擴(kuò)容能力。另外團(tuán)隊(duì)最好具備一定的Linux系統(tǒng)管理能力和Ceph基礎(chǔ)運(yùn)維經(jīng)驗(yàn)因?yàn)檎线^(guò)程中涉及Ceph客戶端配置、掛載、權(quán)限處理等一系列操作出問(wèn)題要能自己排查。如果團(tuán)隊(duì)連Ceph都還沒(méi)接觸過(guò)建議先搭一套測(cè)試環(huán)境練手不要直接上生產(chǎn)。2. 三條技術(shù)路線的選型邏輯RBD、RGW、CephFS2.1 三種方式的原理與對(duì)比Hive和Ceph整合并不是只有一種做法根據(jù)數(shù)據(jù)訪問(wèn)路徑的差異業(yè)內(nèi)主流方案大致分三類。我畫(huà)了張不太嚴(yán)謹(jǐn)?shù)牟輬D在腦子里過(guò)了很多遍這里直接用表格對(duì)比集成方式原理訪問(wèn)路徑適合場(chǎng)景主要限制RBD塊存儲(chǔ)把Ceph的塊設(shè)備掛載到Hive節(jié)點(diǎn)作為本地文件系統(tǒng)使用Hive - 本地文件系統(tǒng) - RBD - Ceph集群離線數(shù)倉(cāng)、跑批任務(wù)、對(duì)延遲不敏感的批處理掛載節(jié)點(diǎn)數(shù)量受限需要客戶端支持RGW對(duì)象存儲(chǔ)通過(guò)S3協(xié)議讓Hive直接讀寫(xiě)Ceph對(duì)象存儲(chǔ)Hive - S3A連接器 - RGW - Ceph集群外部表、數(shù)據(jù)湖、歸檔冷數(shù)據(jù)S3協(xié)議有額外開(kāi)銷小文件性能差CephFS文件存儲(chǔ)把CephFS掛載為Hive數(shù)據(jù)目錄的共享文件系統(tǒng)Hive - CephFS掛載點(diǎn) - MDS - Ceph集群多節(jié)點(diǎn)共享數(shù)據(jù)、遷移過(guò)渡期元數(shù)據(jù)性能受MDS限制海量小文件場(chǎng)景吃力2.2 我的選型判斷我在這次整合中最先排除的是CephFS方案。原因是我們的Hive跑批任務(wù)會(huì)產(chǎn)生大量中間文件元數(shù)據(jù)操作非常頻繁CephFS的元數(shù)據(jù)服務(wù)器在這種負(fù)載下容易成為瓶頸。雖然CephFS的NFS/CIFS導(dǎo)出能力很吸引人但對(duì)Hive這種高并發(fā)元數(shù)據(jù)操作的場(chǎng)景來(lái)說(shuō)生產(chǎn)環(huán)境穩(wěn)定性還有待驗(yàn)證。最終我選擇了RBD和RGW雙軌并行的方式熱數(shù)據(jù)、頻繁查詢的庫(kù)表放在RBD掛載的目錄下冷數(shù)據(jù)、歸檔表通過(guò)S3協(xié)議放到RGW對(duì)象存儲(chǔ)中。這個(gè)組合既保證了熱數(shù)據(jù)的訪問(wèn)性能又讓冷數(shù)據(jù)享受到對(duì)象存儲(chǔ)的低成本優(yōu)勢(shì)算是一個(gè)比較務(wù)實(shí)的折中方案。3. Ceph集群準(zhǔn)備與Pool配置細(xì)節(jié)3.1 環(huán)境規(guī)劃與版本選擇Ceph版本選的是Octopus15.2.x雖然已經(jīng)不算最新但勝在穩(wěn)定社區(qū)資料豐富。Hive用的是3.1.2Hadoop為3.2.1。這里有個(gè)版本搭配的細(xì)節(jié)如果打算走S3協(xié)議路線Hive所在節(jié)點(diǎn)的Hadoop版本必須帶S3A文件系統(tǒng)支持建議Hadoop 3.x起步2.x雖然也能用但S3A兼容性差一些尤其是分片上傳和多線程下載這塊差距明顯。集群環(huán)境我簡(jiǎn)單列一下參考配置你們可以按實(shí)際規(guī)模調(diào)整組件配置數(shù)量Ceph MON2C4G系統(tǒng)盤(pán)SSD3Ceph OSD4C16G3塊HDD1塊SSD(WAL)6Ceph RGW4C8G2Hive節(jié)點(diǎn)8C32G千兆網(wǎng)卡33.2 創(chuàng)建存儲(chǔ)池和RBD鏡像的完整操作Ceph集群裝好后第一步是創(chuàng)建專門(mén)的存儲(chǔ)池。這里很多人會(huì)忽略pool的pg_num設(shè)置直接默認(rèn)值往上懟后面性能會(huì)很難看。我的做法是先估算數(shù)據(jù)量再根據(jù)OSD數(shù)量反推PG數(shù)量。經(jīng)驗(yàn)公式是PG數(shù)除以O(shè)SD數(shù)結(jié)果落在100到200之間比較合理。# 創(chuàng)建存儲(chǔ)池pg_num根據(jù)集群規(guī)模計(jì)算 ceph osd pool create hive_data_pool 128 128 ceph osd pool application enable hive_data_pool rbd # 創(chuàng)建RBD鏡像size根據(jù)需要設(shè)置 rbd create hive-data-disk --size 2048 --pool hive_data_pool # 查看鏡像信息 rbd info hive_data_pool/hive-data-diskRGW那邊需要單獨(dú)準(zhǔn)備一個(gè)存放桶索引的pool我習(xí)慣把元數(shù)據(jù)池和數(shù)據(jù)池分開(kāi)建避免對(duì)象數(shù)據(jù)和索引互相干擾ceph osd pool create rgw_buckets_data 256 256 ceph osd pool create rgw_buckets_index 64 64 ceph osd pool application enable rgw_buckets_data rgw ceph osd pool application enable rgw_buckets_index rgw創(chuàng)建好pool之后別忘了配置配額管理。生產(chǎn)環(huán)境中如果不設(shè)配額某個(gè)業(yè)務(wù)方誤操作往桶里灌了幾十TB數(shù)據(jù)你連回滾的機(jī)會(huì)都沒(méi)有。給常用bucket設(shè)置配額是存儲(chǔ)運(yùn)維的基本素養(yǎng)。4. 用RBD為Hive DataNode擴(kuò)容的落地步驟4.1 客戶端安裝與塊設(shè)備映射Ceph RBD的方式本質(zhì)上就是把Ceph的塊設(shè)備當(dāng)作一塊遠(yuǎn)程硬盤(pán)掛載到Hive節(jié)點(diǎn)上然后在上面格式化文件系統(tǒng)。這個(gè)方式的優(yōu)勢(shì)是Hive完全感知不到Ceph的存在它只覺(jué)得自己的磁盤(pán)變大了??蛻舳藱C(jī)器上需要先安裝ceph-common然后把Ceph集群的ceph.conf配置文件復(fù)制到客戶端節(jié)點(diǎn)的/etc/ceph/目錄下同時(shí)準(zhǔn)備好認(rèn)證keyring# 所有Hive節(jié)點(diǎn)上執(zhí)行 yum install -y ceph-common # 拷貝配置和認(rèn)證信息在Ceph管理節(jié)點(diǎn)執(zhí)行 scp /etc/ceph/ceph.conf roothive-node1:/etc/ceph/ scp /etc/ceph/ceph.client.admin.keyring roothive-node1:/etc/ceph/ # 映射RBD設(shè)備 rbd map hive_data_pool/hive-data-disk --id admin映射成功后系統(tǒng)里會(huì)出現(xiàn)一個(gè)類似 /dev/rbd0 的塊設(shè)備。這個(gè)過(guò)程我第一次操作時(shí)踩了個(gè)坑沒(méi)有加載rbd內(nèi)核模塊導(dǎo)致map命令直接報(bào)錯(cuò)。需要先確認(rèn)modprobe rbd lsmod | grep rbd4.2 文件系統(tǒng)格式化與自動(dòng)掛載配置塊設(shè)備映射成功后接下來(lái)的操作就跟普通物理硬盤(pán)完全一樣了。格式化的文件系統(tǒng)我推薦XFS而非ext4原因很簡(jiǎn)單XFS對(duì)大數(shù)據(jù)量和高并發(fā)寫(xiě)入的支撐能力更強(qiáng)而且支持在線擴(kuò)容以后RBD鏡像擴(kuò)大時(shí)不用卸載分區(qū)。# 格式化注意確認(rèn)設(shè)備名別把系統(tǒng)盤(pán)格式化了 mkfs.xfs /dev/rbd0 # 手動(dòng)掛載測(cè)試 mkdir -p /data/hive/warehouse mount /dev/rbd0 /data/hive/warehouse df -h | grep rbd0手動(dòng)掛載測(cè)試沒(méi)問(wèn)題之后配置開(kāi)機(jī)自動(dòng)掛載。這里有個(gè)重要細(xì)節(jié)RBD設(shè)備在系統(tǒng)重啟后名稱可能變化直接寫(xiě) /dev/rbd0 到fstab里是不安全的必須使用UUID或者寫(xiě)一個(gè)systemd的unit服務(wù)在ceph-rbd服務(wù)起來(lái)之后再執(zhí)行掛載。我的處理方式是在rc.local里延遲執(zhí)行cat /etc/rc.d/rc.local EOF sleep 10 rbd map hive_data_pool/hive-data-disk --id admin sleep 3 mount /dev/rbd0 /data/hive/warehouse EOF chmod x /etc/rc.d/rc.local4.3 Hive數(shù)據(jù)目錄切換與驗(yàn)證目錄掛載好之后把Hive的數(shù)據(jù)目錄指過(guò)去。如果是從HDFS遷移要注意數(shù)據(jù)拷貝的完整性和權(quán)限保留如果是全新環(huán)境直接在core-site.xml和hive-site.xml里配置即可。# hive-site.xml中設(shè)置warehouse目錄 # 注意這里指的是Hive在本地文件系統(tǒng)上的臨時(shí)目錄不代表HDFS數(shù)據(jù)目錄 # 我們的做法是依然保留HDFS作為默認(rèn)warehouse # 將RBD掛載目錄作為Hive的臨時(shí)執(zhí)行目錄 # 具體配置為 # hive.exec.scratchdir/data/hive/warehouse/tmp # hive.exec.local.scratchdir/data/hive/warehouse/tmp/local這里有個(gè)容易被誤解的點(diǎn)需要說(shuō)明Hive默認(rèn)的warehouse還是在HDFS上RBD掛載目錄更多是作為本地臨時(shí)目錄、中間結(jié)果存儲(chǔ)和Spark Shuffle溢寫(xiě)目錄。如果你指望把Hive數(shù)倉(cāng)的表數(shù)據(jù)全部直接落在RBD上那等于放棄HDFS的數(shù)倉(cāng)底座這個(gè)架構(gòu)取舍需要團(tuán)隊(duì)達(dá)成一致。我們采用RBD作為臨時(shí)目錄后最明顯的改善是跑大批量ETL任務(wù)時(shí)NameNode的壓力顯著下降了——大量臨時(shí)文件的增刪不再經(jīng)過(guò)元數(shù)據(jù)節(jié)點(diǎn)。5. 用S3協(xié)議打通Hive與RGW對(duì)象存儲(chǔ)5.1 RGW的S3兼容端點(diǎn)配置RBD雖然好用但它是塊級(jí)別的跨集群、跨地域的共享能力不足。對(duì)象存儲(chǔ)方案彌補(bǔ)了這個(gè)短板。Ceph的RGW組件對(duì)外提供S3兼容接口Hive可以通過(guò)Hadoop的S3A文件系統(tǒng)直接讀寫(xiě)這些數(shù)據(jù)。RGW配置本身不復(fù)雜關(guān)鍵是正確設(shè)置region和endpoint。我遇到過(guò)最磨人的問(wèn)題就是region不匹配導(dǎo)致S3A連接失敗。Ceph默認(rèn)的region叫us-east-1而Hadoop的S3A客戶端如果指定了別的region握手就會(huì)失敗。RGW服務(wù)啟動(dòng)后通過(guò)下面的命令創(chuàng)建S3訪問(wèn)密鑰# 創(chuàng)建S3用戶 radosgw-admin user create --uidhive_user --display-nameHive User # 輸出中會(huì)有access_key和secret_key妥善保存5.2 Hive通過(guò)S3A讀寫(xiě)外部表的配置拿到access_key和secret_key之后在Hive節(jié)點(diǎn)上配置S3A相關(guān)的core-site.xml項(xiàng)property namefs.s3a.endpoint/name valuehttp://rgw-server:7480/value /property property namefs.s3a.access.key/name value你的AK/value /property property namefs.s3a.secret.key/name value你的SK/value /property property namefs.s3a.path.style.access/name valuetrue/value /property property namefs.s3a.connection.ssl.enabled/name valuefalse/value /propertypath.style.access這個(gè)參數(shù)是關(guān)鍵。老牌對(duì)象存儲(chǔ)如AWS S3默認(rèn)用虛擬主機(jī)風(fēng)格訪問(wèn)bucket但Ceph RGW通常需要path-style訪問(wèn)也就是endpoint后面直接跟bucket名而不做DNS解析。很多線上事故都是這個(gè)參數(shù)沒(méi)設(shè)對(duì)導(dǎo)致的。配置完成后就可以在Hive里建外部表指向S3了CREATE EXTERNAL TABLE s3_test_logs ( log_time STRING, user_id STRING, action STRING ) ROW FORMAT DELIMITED FIELDS TERMINATED BY , LOCATION s3a://hive-bucket/logs/;5.3 典型查詢驗(yàn)證與性能表現(xiàn)表建好之后跑一條簡(jiǎn)單的count查詢驗(yàn)證連通性。首次查詢?nèi)绻l(fā)現(xiàn)特別慢不要急著懷疑Ceph性能先檢查小文件數(shù)量。S3A客戶端訪問(wèn)小文件的性能損耗非常大因?yàn)槊總€(gè)文件都要建立獨(dú)立的HTTP連接。我的處理辦法是先用Hive的INSERT OVERWRITE把分散的小文件合并成大文件INSERT OVERWRITE TABLE s3_test_logs SELECT * FROM s3_test_logs;這條SQL默認(rèn)會(huì)產(chǎn)生一些臨時(shí)文件但后續(xù)合并后的輸出文件數(shù)會(huì)減少很多。實(shí)測(cè)下來(lái)RGW路徑下1GB左右的文件單查詢掃描時(shí)間在秒級(jí)到十幾秒之間作為冷數(shù)據(jù)查詢是合格的。6. 生產(chǎn)環(huán)境中的性能調(diào)優(yōu)與故障復(fù)盤(pán)6.1 關(guān)鍵性能參數(shù)清單整合方案跑了一段時(shí)間后我總結(jié)了幾個(gè)對(duì)性能影響最明顯的參數(shù)按重要性排列如下參數(shù)推薦值作用fs.s3a.fast.upload.bufferdisk使用磁盤(pán)緩沖避免堆內(nèi)存溢出fs.s3a.fast.upload.active.blocks8并發(fā)上傳塊數(shù)提高吞吐fs.s3a.multipart.size128M分片上傳大小兼顧并發(fā)和開(kāi)銷fs.s3a.connection.maximum64最大HTTP連接數(shù)rbd cachetrueRBD客戶端緩存提升讀性能rbd cache size134217728緩存大小128MB按內(nèi)存余量調(diào)pool pg_num按OSD數(shù)量計(jì)算打散均勻性直接影響IO分布有一點(diǎn)要提醒RBD的緩存是客戶端內(nèi)存緩存如果節(jié)點(diǎn)內(nèi)存緊張建議調(diào)小甚至關(guān)閉。我們有次內(nèi)存告警排查到最后就是RBD緩存加JVM堆內(nèi)存加操作系統(tǒng)Page Cache湊一起把內(nèi)存擠爆了。6.2 我在線上遇到的兩個(gè)問(wèn)題第一個(gè)是RBD映射的塊設(shè)備偶爾出現(xiàn)IO卡住。排查發(fā)現(xiàn)是Ceph集群中有兩個(gè)OSD down了數(shù)據(jù)處于降級(jí)狀態(tài)但監(jiān)控告警沒(méi)觸發(fā)。RBD的讀寫(xiě)路徑對(duì)OSD狀態(tài)非常敏感一旦有OSD異常IO延遲立刻放大幾倍。解決方式有兩個(gè)層面一是把Ceph的監(jiān)控告警做完善OSD down超過(guò)5分鐘必須告警二是在Hive節(jié)點(diǎn)側(cè)給RBD掛載目錄調(diào)整IO超時(shí)時(shí)間避免因?yàn)閱未蜪O卡死導(dǎo)致Spark任務(wù)整體失敗。第二個(gè)是S3A路徑下Hive查詢偶發(fā)報(bào)錯(cuò)錯(cuò)誤信息類似Connection pool shut down。這個(gè)問(wèn)題的根源是RGW后端的空閑連接被回收了但客戶端連接池不知道繼續(xù)使用舊連接。在core-site.xml里設(shè)置連接空閑檢查參數(shù)可以緩解property namefs.s3a.connection.ttl/name value30000/value /property這個(gè)問(wèn)題的排查過(guò)程有點(diǎn)曲折最開(kāi)始以為是網(wǎng)絡(luò)抖動(dòng)后來(lái)抓包發(fā)現(xiàn)是連接池里的連接已經(jīng)失效但客戶端沒(méi)有感知。調(diào)整TTL后問(wèn)題消失。6.3 日常運(yùn)維監(jiān)控建議整合方案上線后日常運(yùn)維需要關(guān)注的指標(biāo)比以前多了一圈。Ceph側(cè)要盯OSD狀態(tài)、PG分布、集群IO延遲Hive側(cè)要關(guān)注臨時(shí)目錄磁盤(pán)使用率、S3A連接數(shù)、RBD掛載點(diǎn)的讀寫(xiě)延遲。我的建議是至少配置以下幾項(xiàng)監(jiān)控告警Ceph集群health狀態(tài)變化特別是PG變成inactive或degradedOSD down數(shù)量超過(guò)閾值比如大于等于2RBD掛載點(diǎn)的IO延遲突增超過(guò)基線3倍S3A接口的錯(cuò)誤率對(duì)應(yīng)RGW的訪問(wèn)日志做統(tǒng)計(jì)存儲(chǔ)池容量使用率超過(guò)70%就要提前規(guī)劃擴(kuò)容監(jiān)控工具有條件的用Prometheus加GrafanaCeph本身提供exporterHive節(jié)點(diǎn)上用node_exporter加自定義腳本采集RBD指標(biāo)組合起來(lái)基本夠用。沒(méi)條件用腳本加crontab跑檢查也行但告警延遲會(huì)高一些。這套Hive和Ceph的整合方案上線到現(xiàn)在存儲(chǔ)成本降了接近40%因?yàn)槔鋽?shù)據(jù)全部走了對(duì)象存儲(chǔ)熱數(shù)據(jù)的臨時(shí)文件也不再占用HDFS的副本空間。如果你所在的團(tuán)隊(duì)也在盤(pán)算給Hive找個(gè)合適的存儲(chǔ)底座建議先拿非核心業(yè)務(wù)跑一段時(shí)間把監(jiān)控、告警、容災(zāi)這些都梳理清楚再逐步擴(kuò)大范圍。存儲(chǔ)架構(gòu)的變化不像應(yīng)用代碼那樣可以隨時(shí)回滾謹(jǐn)慎一點(diǎn)不吃虧。