HBase读写流程、flush、文件合并、region拆分
HBase存儲原理(架構)
HBase依賴于Zookeeper和Hadoop的,所以在啟動HBase前需要啟動Zookeeper和Hadoop。
HMaster用于管理整個HBase集群,即管理每個HRegionServer,它掌握著整個集群的元數據信息,同時會將相應的數據存儲到Zookeeper(元數據信息、高可用信息等)。
HMaster的職責:
1)管理用戶對Table的增、刪、改、查操作;
2)記錄region在哪臺 Hregion server上;
3)在Region Split 后,負責新Region的分配;
4)新機器加入時,管理 HRegion Server的負載均衡,調整Region分布;
5)在 HRegion Server 宕機后,負責失效 HRegion Server 上的Regions 遷移。
HRegionServer是每臺機器上的一個Java進程(一臺機器只有一個HRegionServer進程),用來處理客戶端的讀寫請求(和Hadoop的DataNode類似),并維護著元數據信息。
HRegionServer的職責:
1) HRegion Server 主要負責響應用戶I/O請求,向HDFS文件系統中讀寫數據,是 HBASE中最核心的模塊。
2) HRegion Server 管理了很多 table 的分區,也就是region。
每個HRegionServer有一個HLog(有且僅有一個)。HLog是操作日志,用來做災難恢復的,當客戶端發起一個寫請求時,會先往HLog中寫再往Memory Store中寫。假設沒有HLog,我們進行一個寫請求,會首先寫到Memory Store上,等到Memory Store到達一定容量后,才會flush到StoreFile中。但是如果在這之前主機斷電了呢?那這部分操作的數據全丟失了。這顯然不是我們想到的結果,于是就有了HLog。
每個HRegionServer里面有多個HRegion,一個HRegion對應于HBase的一張表(也可能是表的一部分,因為表太大了會切分,表和HRegion的對應關系是一對多),當這張表到一定大小的時候會進行切分,切分成兩個HRegion,切分出來的新的HRegion會保存到另一臺機器上。每個HRegionServer里面有多個HRegion,可以理解為有多張表。
每個HRegion里面有多個Store(一張表中有多個列族),一個Store對應于HBase一張表的一個列族,。按照這個原理,我們在設計列族的時候,可以把經常查詢的列放在同一個列族,這樣可以提高效率,因為同一個列族在同一個文件里面(不考慮切分)。
每個Store有一個內存級別的存儲Memory Store(有且僅有一個)。當Memory Store達到一定大小或一定時間后會進行數據刷寫(flush),寫到磁盤中(即HFile)。
每個Store有多個磁盤級別的存儲StoreFile,Memory Store每刷寫一次就形成一個StoreFile,HFile是StoreFile在HDFS上的存儲格式。
HBase讀原理
在上圖中,我們模擬一下客戶端讀取數據過程,假設Zookeeper存放的meta表在RS1機器上,meta表存放的內容如下,Student表行鍵范圍在1-100的存放在RS4上,在101~200的存放在RS3上,等等。
meta表: _________________________________________________ | 表名 | rowkey范圍 | 所在位置 | |____________|________________|_________________| | Student | 1 ~ 100 | RS4 | |____________|________________|_________________| | Student | 101 ~ 200 | RS3 | |____________|________________|_________________| | Teacher | 1 ~ 500 | RS1 | |____________|________________|_________________| | ··· | |_______________________________________________|客戶端現在要讀取Student表的第100行,具體步驟如下:
客戶端向Zookeeper發起請求,請求元數據所在RegionServer,Zookeeper集群存放的是HBase的meta表所在位置。
Zookeeper返回給客戶端元數據所在RegionServer(即RS1)。
客戶端收到應答后去請求RS1,請求查詢Student表的rowkey=100數據所在位置。
在RS1上查詢meta表可知該數據在RS4機器上,即返回給客戶端rowkey所在位置(RS4)。
客戶端收到應答后去請求RS4讀數據。
RS4查詢數據返回給客戶端。查詢時先去內存(MemStore)查找,因為內存是最新的數據,如果找到了就返回結果,如果沒找到則去緩存(blockcache(每個HRegionServer只有一個))找,如果找到了就返回結果,如果還沒找到就去磁盤(StoreFile)找,如果在磁盤找到了,則先將結果寫入緩存(blockcache),再返回給客戶端,寫入緩存是為了下次查詢提高效率。
注:blockcache中存儲數據來源即Hfile的標記,在讀blockcache后,再進行讀取未標記的Hfile與MemStore進行數據合并取對應版本數據,返回并保存至blockcache,再返回至client
在整個讀過程中HMaster并沒有參與,即讀流程與HMaster無關,所以如果HMaster掛了,也是可以讀數據的。
HBase寫原理
HBase的寫是比讀快的,為什么呢,看下面的寫過程,同樣假設Zookeeper存放的meta表在RS1機器上,meta表存放的內容如下,Student表行鍵范圍在1100的存放在RS4上,在101200的存放在RS3上,等等。
meta表:
meta表: _________________________________________________ | 表名 | rowkey范圍 | 所在位置 | |____________|________________|_________________| | Student | 1 ~ 100 | RS2 | |____________|________________|_________________| | Student | 101 ~ 200 | RS1 | |____________|________________|_________________| | Teacher | 1 ~ 500 | RS1 | |____________|________________|_________________| | ··· | |_______________________________________________|客戶端現在要插入數據給Student表,其中rowkey=100,具體步驟如下:
客戶端向Zookeeper發起請求,請求元數據所在RegionServer,Zookeeper集群存放的是HBase的meta表所在位置。
Zookeeper返回給客戶端元數據所在RegionServer(即RS1)。
客戶端收到應答后去請求RS1,請求查詢Student表的rowkey=100數據所在位置。
在RS1上查詢meta表可知該數據在RS2機器上,即返回給客戶端rowkey所在位置(RS2)。
客戶端收到應答后去請求RS4寫入數據。
RS2收到請求,先將數據寫入HLog,再將數據寫入MemStore,寫入MemStore后就返回給客戶端寫入成功信息,此時,客戶端的寫流程完成了。
因為寫入內存就結束了寫流程,不用訪問磁盤,所以總體比讀流程是快一點的。
同樣,在整個寫流程中HMaster也沒有參與,所以如果HMaster掛了,也是可以進行寫數據的。但是,如果時間長了,表的大小一直變大,而HMaster卻掛了,即不會觸發Region切分,這樣就會導致數據傾斜,系統就變得不安全了。
HBase數據flush刷寫過程
在hbase-default.xml配置文件中有這么幾項配置(見下面)
1.hbase.hregion.memstore.flush.size
默認值:128M
MemStore 級別限制,當 Region 中任意一個 MemStore 的大小(壓縮后的大小)達到了設定值,會觸發 MemStore flush。
2.hbase.regionserver.optionalcacheflushinterval
默認值:3600000
HBase 定期刷新 MemStore,默認周期為1小時,確保 MemStore 不會長時間沒有持久化。為避免所有的 MemStore 在同一時間都進行 flush,定期的 flush 操作有 20000 左右的隨機延時。
3.hbase.hregion.memstore.block.multiplier
默認值:2 (3.0版本是4)
Region 級別限制,當 Region 中所有 MemStore 的大小總和達到了設定值(hbase.hregion.memstore.block.multiplier * hbase.hregion.memstore.flush.size,默認 2* 128M = 256M),會觸發 MemStore flush,禁止當前Region讀寫
4.hbase.regionserver.global.memstore.upperLimit
默認值:0.4
Region Server 級別限制,當一個 Region Server 中所有 MemStore 的大小總和達到了設定值(hbase.regionserver.global.memstore.upperLimit * hbase_heapsize,默認 0.4 * RegionServer堆內存大小),會觸發全部 MemStore flush,不管MemStore有多小。而且regionserver級別的flush會阻塞客戶端讀寫。
5.hbase.regionserver.global.memstore.lowerLimit
默認值:0.38
與 hbase.regionserver.global.memstore.upperLimit 類似,區別是:當一個 Region Server 中所有 MemStore 的大小總和達到了設定值(hbase.regionserver.global.memstore.lowerLimit * hbase_heapsize,默認 0.38 * RS堆內存大小),會觸發部分 MemStore flush。
Flush 順序是按照 Region 的總 MemStore 大小,由大到小執行,先操作 MemStore 最大的 Region,再操作剩余中最大的 Region,直至總體 MemStore 的內存使用量低于設定值(hbase.regionserver.global.memstore.lowerLimit * hbase_heapsize)。
6.hbase.regionserver.maxlogs
默認值:32
當一個 Region Server 中 HLog 數量達到設定值,系統會選取最早的一個 HLog 對應的一個或多個 Region 進行 flush。
當增加 MemStore 的大小以及調整其他的 MemStore 的設置項時,也需要去調整 HLog 的配置項。否則,WAL的大小限制可能會首先被觸發。因而,將利用不到其他專門為Memstore而設計的優化。
需要關注的 HLog 配置是 HLog 文件大小,由參數 hbase.regionserver.hlog.blocksize 設置(默認512M),HLog 大小達到上限,或生成一個新的 HLog
通過WAL限制來觸發Memstore的flush并非最佳方式,這樣做可能會會一次flush很多Region,盡管“寫數據”是很好的分布于整個集群,進而很有可能會引發flush“大風暴”。
7.手動觸發
用戶可以通過shell命令一下分別對一個 Table 或者一個 Region 進行 flush:
hbase> flush ‘TABLENAME’
hbase> flush ‘REGIONNAME’
8.其他
執行 Compact 和 Split 之前,會進行一次 flush。
需要注意的是HBase的最小flush單元是HRegion而不是單個MemStore。
Flush是由HMaster觸發的,Flush順序是按照Memstore由大到小執行,先Flush Memstore最大的Region,再執行次大的,直至總體Memstore內存使用量低于閾值(hbase.regionserver.global.memstore.lowerLimit)。
Flush 阻止更新的情況
1.出現上述(2)的情況,Region 下所有 Memstore 的總大小超過了 MemStore 默認大小的倍數,該 Region 在 flush 完成前會 block 新的更新請求。
2.出現上述(3)的情況,RegionServer 所有 MemStore 占整個堆的最大比例超過 hbase.regionserver.global.memstore.upperLimit 設置值,該 RegionServer 的更新請求會被 block,一直到 MemStore 恢復閾值一下。
更新被阻塞對單個節點和整個集群的影響都很大,需要關注 MemStore 的大小和 Memstore Flush Queue 的長度。
Memstore Flush 流程
為了減少 flush 過程對讀寫的影響,HBase 采用了類似于兩階段提交的方式,將整個 flush 過程分為三個階段:
prepare 階段:遍歷當前 Region 中的所有 MemStore,將 MemStore 中當前數據集 kvset 做一個快照 snapshot,然后再新建一個新的 kvset,后期的所有寫入操作都會寫入新的 kvset 中。整個 flush 階段讀操作讀 MemStore 的部分,會分別遍歷新的 kvset 和 snapshot。prepare 階段需要加一把 updateLock 對寫請求阻塞,結束之后會釋放該鎖。因為此階段沒有任何費時操作,因此持鎖時間很短。
flush 階段:遍歷所有 MemStore,將 prepare 階段生成的 snapshot 持久化為臨時文件,臨時文件會統一放到目錄.tmp下。這個過程因為涉及到磁盤IO操作,因此相對比較耗時。
commit 階段:遍歷所有的 MemStore,將 flush 階段生成的臨時文件移到指定的 Column family 目錄下,生成對應的 Storefile(HFile) 和 Reader,把 Storefile 添加到 HStore 的 Storefiles 列表中,最后再清空 prepare 階段生成的 snapshot。
HBase數據compaction合并過程
由于在flush過程中,可能會產生很多小文件(這很好理解,比如有兩個MemStore,一個很大,一個很小,然后就觸發了flush操作,那么那個小的就形成了小文件),我們都知道,HDFS不適合存儲小文件,所以在寫入HDFS之前會進行合并操作。
在hbase-default.xml配置文件中有這么幾項配置:
hbase.hregion.majorcompaction:一個region進行 major compaction合并的周期,在這個點的時候, 這個region下的所有hfile會進行合并,默認是7天,major compaction非常耗資源,建議生產關閉(設置為0),在應用空閑時間手動觸發。
hbase.hstore.compactionThreshold:一個store里面允許存的hfile的個數,超過這個個數會被寫到新的一個hfile里面 也即是每個region的每個列族對應的memstore在fulsh為hfile的時候,默認情況下當超過3個hfile的時候就會對這些文件進行合并重寫為一個新文件,設置個數越大可以減少觸發合并的時間,但是每次合并的時間就會越長。
在我們利用shell命令或者API刪除數據的時候,數據并沒有被刪除,而是被打上標記,而是在這里的compaction合并過程中才會被完全刪除。
轉自:https://blog.csdn.net/hzj1998/article/details/99116931
region拆分
Region自動切分是HBase能夠擁有良好擴張性的最重要因素之一,也必然是所有分布式系統追求無限擴展性的一副良藥。
Region切分觸發策略 在最新穩定版(1.2.6)中,HBase已經有多達6種切分觸發策略。當然,每種觸發策略都有各自的適用場景,用戶可以根據業務在表級別選擇不同的切分觸發策略。常見的切分策略如下圖:
ConstantSizeRegionSplitPolicy:0.94版本前默認切分策略。這是最容易理解但也最容易產生誤解的切分策略,從字面意思來看,當region大小大于某個閾值(hbase.hregion.max.filesize)之后就會觸發切分,實際上并不是這樣,真正實現中這個閾值是對于某個store來說的,即一個region中最大store的大小大于設置閾值之后才會觸發切分。store大小為壓縮后的文件大小(采用壓縮的場景)。
弊 端: 切分策略對于大表和小表沒有明顯的區分。閾值(hbase.hregion.max.filesize)設置較大對大表比較友好,但是小表就有可能不會觸發分裂,極端情況下可能就1個,這對業務來說并不是什么好事。如果設置較小則對小表友好,但一個大表就會在整個集群產生大量的region,這對于集群的管理、資源使用、failover來說都不是一件好事。
IncreasingToUpperBoundRegionSplitPolicy: 0.94版本~2.0版本默認切分策略。這種切分策略微微有些復雜,總體來看和ConstantSizeRegionSplitPolicy思路相同,一個region中最大store大小大于設置閾值就會觸發切分。但是這個閾值并不像ConstantSizeRegionSplitPolicy是一個固定的值,而是會在一定條件下不斷調整,調整規則和region所屬表在當前regionserver上的region個數有關系 :(#regions) * (#regions) * (#regions) * flush size * 2,當然閾值并不會無限增大, 最大值為用戶設置的MaxRegionFileSize。
優點: 這種切分策略很好的彌補了ConstantSizeRegionSplitPolicy的短板,能夠自適應大表和小表。而且在大集群條件下對于很多大表來說表現很優秀,但并不完美。
弊 端: 這種策略下很多小表會在大集群中產生大量小region,分散在整個集群中。而且在發生region遷移時也可能會觸發region分裂。
SteppingSplitPolicy : 2.0版本默認切分策略。這種切分策略的切分閾值又發生了變化,相比IncreasingToUpperBoundRegionSplitPolicy簡單了一些,依然和待分裂region所屬表在當前regionserver上的region個 數有關系,如果region個數等于1,切分閾值為flush size * 2,否則為MaxRegionFileSize。這種切分策略對于大集群中的大表、小表會比IncreasingToUpperBoundRegionSplitPolicy更加友好,小表不會再產生大量的小region,而是適可而止。
另外, 還有一些其他分裂策略, 比如使用DisableSplitPolicy: 可以禁止region 發生分裂; 而KeyPrefixRegionSplitPolicy ,DelimitedKeyPrefixRegionSplitPolicy 對 于 切 分 策 略 依 然 依 據 默 認 切 分 策 略 , 但 對 于 切 分 點 有 自 己 的 看 法 , 比 如KeyPrefixRegionSplitPolicy要求必須讓相同的PrefixKey待在一個region中。
在用法上,一般情況下使用默認切分策略即可,也可以在cf級別設置region切分策略,命令為: create’table’{NAME=>‘cf’,SPLIT_POLICY=>‘org.apache.hadoop.hbase.regionserver. ConstantSizeRegionSpli
region切分策略會觸發region切分,切分開始之后的第一件事就是尋找切分點-splitpoint。所有默認切分策略,無論是ConstantSizeRegionSplitPolicy、IncreasingToUpperBoundRegionSplitPolicy抑或是SteppingSplitPolicy,對于切分點的定義都是一致的。當然,用戶手動執行切分時是可以指定切分點進行切分的,這里并不討論這種情況。
那切分點是如何定位的呢?整個region中最大store中的最大文件中最中心的一個block的首個rowkey。這是一句比較消耗腦力的語句,需要細細品味。另外,HBase還規定,如果定位到的rowkey是整個文件的首個rowkey或者最后一個rowkey的話,就認為沒有切分點。
什么情況下會出現沒有切分點的場景呢?最常見的就是一個文件只有一個block,執行split的時候就會發現無法切分。很多新同學 在測試split的時候往往都是新建一張新表,然后往新表中插入幾條數據并執行一下flush,再執行split,奇跡般地發現數據表并沒有真正執行切分。原因就在這里,這個時候仔細的話你翻看debug日志是可以看到這樣的日志滴:
Region 核 心 切 分 流 程
HBase將整個切分過程包裝成了一個事務,意圖能夠保證切分事務的原子性。整個分裂事務過程分為三個階段:prepare – execute– (rollback) ,操作模版如下:
prepare階段: 在內存中初始化兩個子region,具體是生成兩個HRegionInfo對象,包含tableName、regionName、startkey、endkey等。同時會生成一個transaction journal,這個對象用來記錄切分的進展,具體見rollback階段。
execute階段:切分的核心操作。見下圖(來自Hortonworks):
3.在父存儲目錄下新建臨時文件夾,split保存split后的daughter region信息。
4.關閉parent region:parent region 關閉數據寫入并觸發flush操作,將寫入region的數據全部持久化到磁盤,此后短時間內客戶端落在父region上的請求都會拋出異常NotServingRegionException。
5. 核心分裂步驟:在.split文件夾下新建兩個子文件夾,稱之為daughter A、daughter B,并在文件夾中生成reference文件, 分別指向父region中對應文件。這個步驟是所有步驟中最核心的一個環節,生成reference文件日志如下所示: 2017-08-12 11:53:38,158 DEBUG [StoreOpene-0155388346c3c919d3f05d7188e885e0-1] regionserver.StoreFileInfo: reference’hdfs://hdfscluster/hbase-rsgroup/data/default/music/0155388346c3c919d3f05d7188e885e0/cf/d24415c4fb44427b8f698143e5c4d9dc00 其中reference文件名為d24415c4fb44427b8f698143e5c4d9dc.00bb6239169411e4d0ecb6ddfdbacf66,格式看起來比較特殊,那這種文件名具體什么含義呢?那來看看該reference文件指向的父region文件,根據日志可以看到,切分的父region是00bb6239169411e4d0ecb6ddfdbacf66,對應的切分文件是d24415c4fb44427b8f698143e5c4d9dc,可見reference文件名是個信息量很大的命名方式,如下所示:
除此之外,還需要關注reference文件的文件內容,reference文件是一個引用文件(并非linux鏈接文件),文件內容很顯然不是用戶數據。文件內容其實非常簡單, 主要有兩部分構成: 其一是切分點splitkey, 其二是一個boolean類型的變量( true 或者false),true表示該reference文件引用的是父文件的上半部分(top),而false表示引用的是下半部分 (bottom)。為什么存儲的是這兩部分內容?且聽下文分解。
看官可以使用hadoop命令親自來查看reference文件的具體內容: hadoopdfs-cat/hbase-rsgroup/data/default/music/0155388346c3c919d3f05d7188e885e0/cf/d24415c4fb44427b8f698 6. 父region分裂為兩個子region后,將daughter A、daughter B拷貝到HBase根目錄下,形成兩個新的region。
rollback階段: 如果execute階段出現異常,則執行rollback操作。為了實現回滾,整個切分過程被分為很多子階段,回滾程序會根據當前進展到哪個子階段清理對應的垃圾數據。代碼中使用 JournalEntryType 來表征各個子階段,具體見下圖:
Region切分事務性保證
整個region切分是一個比較復雜的過程,涉及到父region中HFile文件的切分、兩個子region的生成、系統meta元數據的更改等很多子步驟,因此必須保證整個切分過程的事務性,即要么切分完全成功,要么切分完全未開始,在任何情況下也不能出現切分只完成一半的情況。
為了實現事務性,hbase設計了使用狀態機(見SplitTransaction類)的方式保存切分過程中的每個子步驟狀態,這樣一旦出現異常,系統可以根據當前所處的狀態決定是否回滾,以及如何回滾。遺憾的是,目前實現中這些中間狀態都只存儲在內存中,因此一旦在切分過程中出現regionserver宕機的情況,有可能會出現切分處于中間狀態的情況,也就是RIT狀態。這種情況下需要使用hbck工具進行具體查看并分析解決方案。在2.0版本之后,HBase實現了新的分布式事務框架Procedure V2(HBASE-12439),新框架將會使用HLog存儲這種單機事務(DDL操作、Split操作、Move操作等)的中間狀態,因此可以保證即使在事務執行過程中參與者發生了宕機,依然可以使用HLog作為協調者對事務進行回滾操作或者重試提交,大大減少甚至杜絕RIT現象。這也是是2.0在可用性方面最值得期待的一個亮點!!!
Region切分對其他模塊的影響
通過region切分流程的了解,我們知道整個region切分過程并沒有涉及數據的移動,所以切分成本本身并不是很高,可以很快完成。切分后子region的文件實際沒有任何用戶數據,文件中存儲的僅是一些元數據信息-切分點rowkey等,那通過引用文件如何查找數據呢?子region的數據實際在什么時候完成真正遷移?數據遷移完成之后父region什么時候會被刪掉?
這里就會看到reference文件名、文件內容的實際意義啦。整個流程如下圖所示:
(1)根據reference文件名(region名+真實文件名)定位到真實數據所在文件路徑。
(2)定位到真實數據文件就可以在整個文件中掃描待查KV了么?非也。因為reference文件通常都只引用了數據文件的一半數據, 以切分點為界,要么上半部分文件數據,要么下半部分數據。那到底哪部分數據?切分點又是哪個點?還記得上文又提到reference 文件的文件內容吧,沒錯,就記錄在文件中。
答案是子region發生major_compaction時,我們知道compaction的執行實際上是將store中所有小文件一個KV一個KV從小到大讀出來之后再順序寫入一個大文件,完成之后再將小文件刪掉,因此compaction本身就需要讀取并寫入大量數據。子region執行major_compaction后會將父目錄中屬于該子region的所有數據讀出來并寫入子region目錄數據文件中??梢妼祿w移放到compaction這個階段來做,是一件順便的事。
實際上HMaster會啟動一個線程定期遍歷檢查所有處于splitting狀態的父region,確定檢查父region是否可以被清理。檢測線程首先會在meta表中揪出所有split列為true的region,并加載出其分裂后生成的兩個子region(meta表中splitA列和splitB列),只需要檢查此兩個子region是否還存在引用文件,如果都不存在引用文件就可以認為該父region對應的文件可以被刪除?,F在再來看看上文中父目錄在meta表中的信息,就大概可以理解為什么會存儲這些信息了:
4. split模塊在生產線的一些坑?
有些時候會有同學反饋說集群中部分region處于長時間RIT,region狀態為spliting。通常情況下都會建議使用hbck看下什么報錯, 然后再根據hbck提供的一些工具進行修復,hbck提供了部分命令對處于split狀態的rit region進行修復,主要的命令如下: -fixSplitParents Try to force offline split parents to be online.-removeParents Try to offline and sideline lingering parents and keep daughter regions.-fixReferenceFiles Try to offline lingering reference store files
其中最常見的問題是 : ERROR:Foundlingeringreferencefilehdfs://mycluster/hbase/news_user_actions/3b3ae24c65fc5094bc2acfebaa7a56de/ 簡單解釋一下,這個錯誤是說reference文件所引用的父region文件不存在了,如果查看日志的話有可能看到如下異常:java.io.IOException: java.io.IOException: java.io.FileNotFoundException: File does not exist:/hbase/news_user_actions/b7
父region文件為什么會莫名其妙不存在?經過和朋友的討論,確認有可能是因為官方bug導致,詳見HBASE-13331。這個jira是說HMaster在確認父目錄是否可以被刪除時,如果檢查引用文件(檢查是否存在、檢查是否可以正常打開)拋出IOException異常, 函數就會返回沒有引用文件,導致父region被刪掉。正常情況下應該保險起見返回存在引用文件,保留region,并打印日志手工介入查看。如果大家也遇到類似的問題,可以看看這個問題,也可以將修復patch打到線上版本或者升級版本。
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的HBase读写流程、flush、文件合并、region拆分的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: i99900k设计配什么主板
- 下一篇: iphone如何区分官翻机(iPhone