<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                [TOC] # HBASE內部原理 ## 1 系統架構 ![](https://box.kancloud.cn/9aa44d384315ef5b5ed63f9ee328fe64_550x298.png) ### Client 1. 包含訪問hbase的接口,client維護著一些cache來加快對hbase的訪問,比如regione的位置信息。 ### Zookeeper 1) 保證任何時候,集群中只有一個master 2) 存貯所有Region的尋址入口----root表在哪臺服務器上。 3) 實時監控Region Server的狀態,將Region server的上線和下線信息實時通知給Master 4) 存儲Hbase的schema,包括有哪些table,每個table有哪些column family ### Master職責 1) 為Region server分配region 2) 負責region server的負載均衡 3) 發現失效的region server并重新分配其上的region 4) HDFS上的垃圾文件回收 5) 處理schema更新請求 ### Region Server職責 1) Region server維護Master分配給它的region,處理對這些region的IO請求 2) Region server負責切分在運行過程中變得過大的region > 可以看到,client訪問hbase上數據的過程并不需要master參與(尋址訪問zookeeper和region server,數據讀寫訪問regione server),master僅僅維護者table和region的元數據信息,負載很低。 ## 2 物理存儲 ### 1、整體結構 ![](https://box.kancloud.cn/f59b2c308e80769d26d6582a7d2643c4_521x325.png) 1) Table中的所有行都按照row key的字典序排列。 2) Table 在行的方向上分割為多個Hregion。 3) region按大小分割的(默認10G),每個表一開始只有一個region,隨著數據不斷插入表,region不斷增大,當增大到一個閥值的時候,Hregion就會等分會兩個新的Hregion。當table中的行不斷增多,就會有越來越多的Hregion。 4) Hregion是Hbase中分布式存儲和負載均衡的最小單元。最小單元就表示不同的Hregion可以分布在不同的HRegion server上。但一個Hregion是不會拆分到多個server上的。 5) HRegion雖然是負載均衡的最小單元,但并不是物理存儲的最小單元。 > 事實上,HRegion由一個或者多個Store組成,每個store保存一個column family。 > 每個Strore又由一個memStore和0至多個StoreFile組成。如上圖 ![](https://box.kancloud.cn/b52b09bab060c4441aa66288e206cfd2_306x226.png) ### 2、STORE FILE & HFILE結構 > StoreFile以HFile格式保存在HDFS上。 > 附:HFile的格式為: ![](https://box.kancloud.cn/cf0d2778695adfb951c5a13ba4c9b3c6_555x161.png) > 首先HFile文件是不定長的,長度固定的只有其中的兩塊:Trailer和FileInfo。正如圖中所示的,Trailer中有指針指向其他數 據塊的起始點。 > File Info中記錄了文件的一些Meta信息,例如:AVG_KEY_LEN, AVG_VALUE_LEN, LAST_KEY, COMPARATOR, MAX_SEQ_ID_KEY等。 > Data Index和Meta Index塊記錄了每個Data塊和Meta塊的起始點。 > Data Block是HBase I/O的基本單元,為了提高效率,HRegionServer中有基于LRU的Block Cache機制。每個Data塊的大小可以在創建一個Table的時候通過參數指定,大號的Block有利于順序Scan,小號Block利于隨機查詢。 每個Data塊除了開頭的Magic以外就是一個個KeyValue對拼接而成, Magic內容就是一些隨機數字,目的是防止數據損壞。 > HFile里面的每個KeyValue對就是一個簡單的byte數組。但是這個byte數組里面包含了很多項,并且有固定的結構。我們來看看里面的具體結構: ![](https://box.kancloud.cn/f20a6404efa2b70b84f682dba8c206f6_553x93.png) > 開始是兩個固定長度的數值,分別表示Key的長度和Value的長度。緊接著是Key,開始是固定長度的數值,表示RowKey的長度,緊接著是 RowKey,然后是固定長度的數值,表示Family的長度,然后是Family,接著是Qualifier,然后是兩個固定長度的數值,表示Time Stamp和Key Type(Put/Delete)。Value部分沒有這么復雜的結構,就是純粹的二進制數據了。 > HFile分為六個部分: 1. Data Block 段–保存表中的數據,這部分可以被壓縮 2. Meta Block 段 (可選的)–保存用戶自定義的kv對,可以被壓縮。 3. File Info 段–Hfile的元信息,不被壓縮,用戶也可以在這一部分添加自己的元信息。 4. Data Block Index 段–Data Block的索引。每條索引的key是被索引的block的第一條記錄的key。 5. Meta Block Index段 (可選的)–Meta Block的索引。 6. Trailer–這一段是定長的。保存了每一段的偏移量,讀取一個HFile時,會首先 讀取Trailer,Trailer保存了每個段的起始位置(段的Magic Number用來做安全check),然后,DataBlock Index會被讀取到內存中,這樣,當檢索某個key時,不需要掃描整個HFile,而只需從內存中找到key所在的block,通過一次磁盤io將整個 block讀取到內存中,再找到需要的key。DataBlock Index采用LRU機制淘汰。 > HFile的Data Block,Meta Block通常采用壓縮方式存儲,壓縮之后可以大大減少網絡IO和磁盤IO,隨之而來的開銷當然是需要花費cpu進行壓縮和解壓縮。 > 目標Hfile的壓縮支持兩種方式:Gzip,Lzo。 ### 3 Memstore與storefile > 一個region由多個store組成,每個store包含一個列族的所有數據 > Store包括位于內存的memstore和位于硬盤的storefile > 寫操作先寫入memstore,當memstore中的數據量達到某個閾值,Hregionserver啟動flashcache進程寫入storefile,每次寫入形成單獨一個storefile > 當storefile大小超過一定閾值后,會把當前的region分割成兩個,并由Hmaster分配給相應的region服務器,實現負載均衡 > 客戶端檢索數據時,先在memstore找,找不到再找storefile ### 4、HLog(WAL log) > WAL 意為Write ahead log(http://en.wikipedia.org/wiki/Write-ahead_logging),類似mysql中的binlog,用來 做災難恢復只用,Hlog記錄數據的所有變更,一旦數據修改,就可以從log中進行恢復。 > 每個Region Server維護一個Hlog,而不是每個Region一個。這樣不同region(來自不同table)的日志會混在一起,這樣做的目的是不斷追加單個文件相對于同時寫多個文件而言,可以減少磁盤尋址次數,因此可以提高對table的寫性能。帶來的麻煩是,如果一臺region server下線,為了恢復其上的region,需要將region server上的log進行拆分,然后分發到其它region server上進行恢復。 > HLog文件就是一個普通的Hadoop Sequence File: 1) HLog Sequence File 的Key是HLogKey對象,HLogKey中記錄了寫入數據的歸屬信息,除了table和region名字外,同時還包括 sequence number和timestamp,timestamp是”寫入時間”,sequence number的起始值為0,或者是最近一次存入文件系統中sequence number。 2) HLog Sequece File的Value是HBase的KeyValue對象,即對應HFile中的KeyValue,可參見上文描述。 ## 3 尋址機制 ### 1、尋址示意圖 ![](https://box.kancloud.cn/df7668d48ac9fa1410602067eb31f0c7_506x286.png) ### 2、-ROOT-和.META.表結構 ![](https://box.kancloud.cn/efd0ad53b9f4675deeb2f9997b1f94fb_425x144.png) > .META.行記錄結構 ![](https://box.kancloud.cn/eaa82c10689d9119d6d99bbe83566ee8_425x276.png) ### 3、尋址流程 > 現在假設我們要從Table2里面插尋一條RowKey是RK10000的數據。那么我們應該遵循以下步驟: 1. 從.META.表里面查詢哪個Region包含這條數據。 2. 獲取管理這個Region的RegionServer地址。 3. 連接這個RegionServer, 查到這條數據。 > 系統如何找到某個row key (或者某個 row key range)所在的region > bigtable 使用三層類似B+樹的結構來保存region位置。 > 第一層是保存zookeeper里面的文件,它持有root region的位置。 > 第二層root region是.META.表的第一個region其中保存了.META.表其它region的位置。通過root region,我們就可以訪問.META.表的數據。 > .META.是第三層,它是一個特殊的表,保存了hbase中所有數據表的region 位置信息。 > 說明: 1) root region永遠不會被split,保證了最需要三次跳轉,就能定位到任意region 。 2) META.表每行保存一個region的位置信息,row key 采用表名+表的最后一行編碼而成。 3) 為了加快訪問,.META.表的全部region都保存在內存中。 4) client會將查詢過的位置信息保存緩存起來,緩存不會主動失效,因此如果client上的緩存全部失效,則需要進行最多6次網絡來回,才能定位到正確的region(其中三次用來發現緩存失效,另外三次用來獲取位置信息)。 ### 4 讀寫過程 #### 1 讀請求過程: 1) 客戶端通過zookeeper以及root表和meta表找到目標數據所在的regionserver 2) 聯系regionserver查詢目標數據 3) regionserver定位到目標數據所在的region,發出查詢請求 4) region先在memstore中查找,命中則返回 5) 如果在memstore中找不到,則在storefile中掃描(可能會掃描到很多的storefile----bloomfilter) #### 2、寫請求過程: 1) client向region server提交寫請求 2) region server找到目標region 3) region檢查數據是否與schema一致 4) 如果客戶端沒有指定版本,則獲取當前系統時間作為數據版本 5) 將更新寫入WAL log 6) 將更新寫入Memstore 7) 判斷Memstore的是否需要flush為Store文件。 > 細節描述: * hbase使用MemStore和StoreFile存儲對表的更新。 * 數據在更新時首先寫入Log(WAL log)和內存(MemStore)中,MemStore中的數據是排序的,當MemStore累計到一定閾值時,就會創建一個新的MemStore,并 且將老的MemStore添加到flush隊列,由單獨的線程flush到磁盤上,成為一個StoreFile。于此同時,系統會在zookeeper中記錄一個redo point,表示這個時刻之前的變更已經持久化了。 * 當系統出現意外時,可能導致內存(MemStore)中的數據丟失,此時使用Log(WAL log)來恢復checkpoint之后的數據。 * StoreFile是只讀的,一旦創建后就不可以再修改。因此Hbase的更新其實是不斷追加的操作。當一個Store中的StoreFile達到一定的閾值后,就會進行一次合并(minor_compact, major_compact),將對同一個key的修改合并到一起,形成一個大的StoreFile,當StoreFile的大小達到一定閾值后,又會對 StoreFile進行split,等分為兩個StoreFile。 * 由于對表的更新是不斷追加的,compact時,需要訪問Store中全部的 StoreFile和MemStore,將他們按row key進行合并,由于StoreFile和MemStore都是經過排序的,并且StoreFile帶有內存中索引,合并的過程還是比較快。 ## 5 Region管理 ### (1) region分配 > 任何時刻,一個region只能分配給一個region server。master記錄了當前有哪些可用的region server。以及當前哪些region分配給了哪些region server,哪些region還沒有分配。當需要分配的新的region,并且有一個region server上有可用空間時,master就給這個region server發送一個裝載請求,把region分配給這個region server。region server得到請求后,就開始對此region提供服務。 ### (2) region server上線 > master使用zookeeper來跟蹤region server狀態。當某個region server啟動時,會首先在zookeeper上的server目錄下建立代表自己的znode。由于master訂閱了server目錄上的變更消息,當server目錄下的文件出現新增或刪除操作時,master可以得到來自zookeeper的實時通知。因此一旦region server上線,master能馬上得到消息。 ### (3) region server下線 > 當region server下線時,它和zookeeper的會話斷開,zookeeper而自動釋放代表這臺server的文件上的獨占鎖。master就可以確定: 1) region server和zookeeper之間的網絡斷開了。 2) region server掛了。 > 無論哪種情況,region server都無法繼續為它的region提供服務了,此時master會刪除server目錄下代表這臺region server的znode數據,并將這臺region server的region分配給其它還活著的同志。 ## 6 Master工作機制 ### 1) master上線 > master啟動進行以下步驟: 1) 從zookeeper上獲取唯一一個代表active master的鎖,用來阻止其它master成為master。 2) 掃描zookeeper上的server父節點,獲得當前可用的region server列表。 3) 和每個region server通信,獲得當前已分配的region和region server的對應關系。 4) 掃描.META.region的集合,計算得到當前還未分配的region,將他們放入待分配region列表。 ### 2) master下線 > 由于master只維護表和region的元數據,而不參與表數據IO的過程,master下線僅導致所有元數據的修改被凍結(無法創建刪除表,無法修改表的schema,無法進行region的負載均衡,無法處理region 上下線,無法進行region的合并,唯一例外的是region的split可以正常進行,因為只有region server參與),表的數據讀寫還可以正常進行。因此master下線短時間內對整個hbase集群沒有影響。 > 從上線過程可以看到,master保存的信息全是可以冗余信息(都可以從系統其它地方收集到或者計算出來) > 因此,一般hbase集群中總是有一個master在提供服務,還有一個以上的‘master’在等待時機搶占它的位置。 > 動手練習(增刪改查) ## HBASE原理圖 ![](https://box.kancloud.cn/d9ded7633864b1f7f27e00940f7c73fe_1784x2056.png) ## 7 HBASE參數 ### 配置優化 ~~~ zookeeper.session.timeout ~~~ > 默認值:3分鐘(180000ms) > 說明:RegionServer與Zookeeper間的連接超時時間。當超時時間到后,ReigonServer會被Zookeeper從RS集群清單中移除,HMaster收到移除通知后,會對這臺server負責的regions重新balance,讓其他存活的RegionServer接管. > 調優: > 這個timeout決定了RegionServer是否能夠及時的failover。設置成1分鐘或更低,可以減少因等待超時而被延長的failover時間。 > 不過需要注意的是,對于一些Online應用,RegionServer從宕機到恢復時間本身就很短的(網絡閃斷,crash等故障,運維可快速介入),如果調低timeout時間,反而會得不償失。因為當ReigonServer被正式從RS集群中移除時,HMaster就開始做balance了(讓其他RS根據故障機器記錄的WAL日志進行恢復)。當故障的RS在人工介入恢復后,這個balance動作是毫無意義的,反而會使負載不均勻,給RS帶來更多負擔。特別是那些固定分配regions的場景。 ~~~ hbase.regionserver.handler.count ~~~ > 默認值:10 * 說明:RegionServer的請求處理IO線程數。 > 調優: 1. 這個參數的調優與內存息息相關。 2. 較少的IO線程,適用于處理單次請求內存消耗較高的Big PUT場景(大容量單次PUT或設置了較大cache的scan,均屬于Big PUT)或ReigonServer的內存比較緊張的場景。 3. 較多的IO線程,適用于單次請求內存消耗低,TPS要求非常高的場景。設置該值的時候,以監控內存為主要參考。 4. 這里需要注意的是如果server的region數量很少,大量的請求都落在一個region上,因快速充滿memstore觸發flush導致的讀寫鎖會影響全局TPS,不是IO線程數越高越好。 5. 壓測時,開啟Enabling RPC-level logging,可以同時監控每次請求的內存消耗和GC的狀況,最后通過多次壓測結果來合理調節IO線程數。 6. 這里是一個案例?Hadoop and HBase Optimization for Read Intensive Search Applications,作者在SSD的機器上設置IO線程數為100,僅供參考。 ~~~ hbase.hregion.max.filesize ~~~ > 默認值:256M * 說明:在當前ReigonServer上單個Reigon的最大存儲空間,單個Region超過該值時,這個Region會被自動split成更小的region。 > 調優: 1. 小region對split和compaction友好,因為拆分region或compact小region里的storefile速度很快,內存占用低。缺點是split和compaction會很頻繁。 2. 特別是數量較多的小region不停地split, compaction,會導致集群響應時間波動很大,region數量太多不僅給管理上帶來麻煩,甚至會引發一些Hbase的bug。 3. 一般512以下的都算小region。 4. 大region,則不太適合經常split和compaction,因為做一次compact和split會產生較長時間的停頓,對應用的讀寫性能沖擊非常大。此外,大region意味著較大的storefile,compaction時對內存也是一個挑戰。 5. 當然,大region也有其用武之地。如果你的應用場景中,某個時間點的訪問量較低,那么在此時做compact和split,既能順利完成split和compaction,又能保證絕大多數時間平穩的讀寫性能。 6. 既然split和compaction如此影響性能,有沒有辦法去掉? 7. compaction是無法避免的,split倒是可以從自動調整為手動。 8. 只要通過將這個參數值調大到某個很難達到的值,比如100G,就可以間接禁用自動split(RegionServer不會對未到達100G的region做split)。 9. 再配合RegionSplitter這個工具,在需要split時,手動split。 10. 手動split在靈活性和穩定性上比起自動split要高很多,相反,管理成本增加不多,比較推薦online實時系統使用。 11. 內存方面,小region在設置memstore的大小值上比較靈活,大region則過大過小都不行,過大會導致flush時app的IO wait增高,過小則因store file過多影響讀性能。 ~~~ hbase.regionserver.global.memstore.upperLimit/lowerLimit ~~~ > 默認值:0.4/0.35 * upperlimit說明:hbase.hregion.memstore.flush.size 這個參數的作用是當單個Region內所有的memstore大小總和超過指定值時,flush該region的所有memstore。RegionServer的flush是通過將請求添加一個隊列,模擬生產消費模式來異步處理的。那這里就有一個問題,當隊列來不及消費,產生大量積壓請求時,可能會導致內存陡增,最壞的情況是觸發OOM。 * 這個參數的作用是防止內存占用過大,當ReigonServer內所有region的memstores所占用內存總和達到heap的40%時,HBase會強制block所有的更新并flush這些region以釋放所有memstore占用的內存。 * lowerLimit說明: 同upperLimit,只不過lowerLimit在所有region的memstores所占用內存達到Heap的35%時,不flush所有的memstore。它會找一個memstore內存占用最大的region,做個別flush,此時寫更新還是會被block。lowerLimit算是一個在所有region強制flush導致性能降低前的補救措施。在日志中,表現為 “** Flush thread woke up with memory above low water.” > 調優: * 這是一個Heap內存保護參數,默認值已經能適用大多數場景。 * 參數調整會影響讀寫,如果寫的壓力大導致經常超過這個閥值,則調小讀緩存hfile.block.cache.size增大該閥值,或者Heap余量較多時,不修改讀緩存大小。 * 如果在高壓情況下,也沒超過這個閥值,那么建議你適當調小這個閥值再做壓測,確保觸發次數不要太多,然后還有較多Heap余量的時候,調大hfile.block.cache.size提高讀性能。 * 還有一種可能性是?hbase.hregion.memstore.flush.size保持不變,但RS維護了過多的region,要知道 region數量直接影響占用內存的大小。 hfile.block.cache.size > 默認值:0.2 * 說明:storefile的讀緩存占用Heap的大小百分比,0.2表示20%。該值直接影響數據讀的性能。 * 調優:當然是越大越好,如果寫比讀少很多,開到0.4-0.5也沒問題。如果讀寫較均衡,0.3左右。如果寫比讀多,果斷默認吧。設置這個值的時候,你同時要參考? > hbase.regionserver.global.memstore.upperLimit?,該值是memstore占heap的最大百分比,兩個參數一個影響讀,一個影響寫。如果兩值加起來超過80-90%,會有OOM的風險,謹慎設置。 ~~~ hbase.hstore.blockingStoreFiles ~~~ 默認值:7 * 說明:在flush時,當一個region中的Store(Coulmn Family)內有超過7個storefile時,則block所有的寫請求進行compaction,以減少storefile數量。 * 調優:block寫請求會嚴重影響當前regionServer的響應時間,但過多的storefile也會影響讀性能。從實際應用來看,為了獲取較平滑的響應時間,可將值設為無限大。如果能容忍響應時間出現較大的波峰波谷,那么默認或根據自身場景調整即可。 ~~~ hbase.hregion.memstore.block.multiplier ~~~ > 默認值:2 * 說明:當一個region里的memstore占用內存大小超過hbase.hregion.memstore.flush.size兩倍的大小時,block該region的所有請求,進行flush,釋放內存。雖然我們設置了region所占用的memstores總內存大小,比如64M,但想象一下,在最后63.9M的時候,我Put了一個200M的數據,此時memstore的大小會瞬間暴漲到超過預期的hbase.hregion.memstore.flush.size的幾倍。這個參數的作用是當memstore的大小增至超過hbase.hregion.memstore.flush.size 2倍時,block所有請求,遏制風險進一步擴大。 * 調優: 這個參數的默認值還是比較靠譜的。如果你預估你的正常應用場景(不包括異常)不會出現突發寫或寫的量可控,那么保持默認值即可。如果正常情況下,你的寫請求量就會經常暴長到正常的幾倍,那么你應該調大這個倍數并調整其他參數值,比如 > hfile.block.cache.sizehbase.regionserver.global.memstore.upperLimit/lowerLimit,以預留更多內存,防止HBase server OOM。 ~~~ hbase.hregion.memstore.mslab.enabled ~~~ > 默認值:true * 說明:減少因內存碎片導致的Full GC,提高整體性能。 * 調優:詳見 http://kenwublog.com/avoid-full-gc-in-hbase-using-arena-allocation ### 其他 #### 啟用LZO壓縮 > LZO對比Hbase默認的GZip,前者性能較高,后者壓縮比較高,具體參見?Using LZO Compression 。對于想提高HBase讀寫性能的開發者,采用LZO是比較好的選擇。對于非常在乎存儲空間的開發者,則建議保持默認。 > 不要在一張表里定義太多的Column Family > Hbase目前不能良好的處理超過包含2-3個CF的表。因為某個CF在flush發生時,它鄰近的CF也會因關聯效應被觸發flush,最終導致系統產生更多IO。 > 批量導入 > 在批量導入數據到Hbase前,你可以通過預先創建regions,來平衡數據的負載。詳見?Table Creation: Pre-Creating Regions > 避免CMS concurrent mode failure > HBase使用CMS GC。默認觸發GC的時機是當年老代內存達到90%的時候,這個百分比由 -XX:CMSInitiatingOccupancyFraction=N 這個參數來設置。concurrent mode failed發生在這樣一個場景: 當年老代內存達到90%的時候,CMS開始進行并發垃圾收集,于此同時,新生代還在迅速不斷地晉升對象到年老代。當年老代CMS還未完成并發標記時,年老代滿了,悲劇就發生了。CMS因為沒內存可用不得不暫停mark,并觸發一次stop the world(掛起所有jvm線程),然后采用單線程拷貝方式清理所有垃圾對象。這個過程會非常漫長。為了避免出現concurrent mode failed,建議讓GC在未到90%時,就觸發。 通過設置?-XX:CMSInitiatingOccupancyFraction=N 這個百分比, 可以簡單的這么計算。如果你的?hfile.block.cache.size 和?hbase.regionserver.global.memstore.upperLimit 加起來有60%(默認),那么你可以設置 70-80,一般高10%左右差不多。 ### Hbase客戶端優化 ~~~ AutoFlush ~~~ * 將HTable的setAutoFlush設為false,可以支持客戶端批量更新。即當Put填滿客戶端flush緩存時,才發送到服務端。 * 默認是true。 ~~~ Scan Caching ~~~ * scanner一次緩存多少數據來scan(從服務端一次抓多少數據回來scan)。 * 默認值是 1,一次只取一條。 ~~~ Scan Attribute Selection ~~~ * scan時建議指定需要的Column Family,減少通信量,否則scan操作默認會返回整個row的所有數據(所有Coulmn Family)。 ~~~ Close ResultScanners ~~~ * 通過scan取完數據后,記得要關閉ResultScanner,否則RegionServer可能會出現問題(對應的Server資源無法釋放)。 ~~~ Optimal Loading of Row Keys ~~~ * 當你scan一張表的時候,返回結果只需要row key(不需要CF, qualifier,values,timestaps)時,你可以在scan實例中添加一個filterList,并設置 MUST_PASS_ALL操作,filterList中add?FirstKeyOnlyFilter或KeyOnlyFilter。這樣可以減少網絡通信量。 ~~~ Turn off WAL on Puts ~~~ * 當Put某些非重要數據時,你可以設置writeToWAL(false),來進一步提高寫性能。writeToWAL(false)會在Put時放棄寫WAL log。風險是,當RegionServer宕機時,可能你剛才Put的那些數據會丟失,且無法恢復。 ~~~ 啟用Bloom Filter ~~~ * Bloom Filter通過空間換時間,提高讀操作性能。 ## 8 HBASE性能優化 1) hbase.hregion.max.filesize應該設置多少合適 2) autoflush=false的影響 3) 從性能的角度談table中family和qualifier的設置 4) hbase.regionserver.handler.count詳解 ### 1 hbase.hregion.max.filesize應該設置多少合適 ~~~ 默認值:256M ~~~ > 說明: * Maximum HStoreFile size. If any one of a column families' HStoreFiles has grown to exceed this value, the hosting HRegion is split in two. * HStoreFile的最大值。如果任何一個Column Family(或者說HStore)的HStoreFiles的大小超過這個值,那么,其所屬的HRegion就會Split成兩個。 > 調優: * hbase中hfile的默認最大值(hbase.hregion.max.filesize)是256MB,而google的bigtable論文中對tablet的最大值也推薦為100-200MB,這個大小有什么秘密呢? *   眾所周知hbase中數據一開始會寫入memstore,當memstore滿64MB以后,會flush到disk上而成為storefile。當storefile數量超過3時,會啟動compaction過程將它們合并為一個storefile。這個過程中會刪除一些timestamp過期的數據,比如update的數據。而當合并后的storefile大小大于hfile默認最大值時,會觸發split動作,將它切分成兩個region。 *   lz進行了持續insert壓力測試,并設置了不同的hbase.hregion.max.filesize,根據結果得到如下結論:值越小,平均吞吐量越大,但吞吐量越不穩定;值越大,平均吞吐量越小,吞吐量不穩定的時間相對更小。 > 為什么會這樣呢?推論如下: 1) 當hbase.hregion.max.filesize比較小時,觸發split的機率更大,而split的時候會將region offline,因此在split結束的時間前,訪問該region的請求將被block住,客戶端自我block的時間默認為1s。當大量的region同時發生split時,系統的整體訪問服務將大受影響。因此容易出現吞吐量及響應時間的不穩定現象 2) 當hbase.hregion.max.filesize比較大時,單個region中觸發split的機率較小,大量region同時觸發split的機率也較小,因此吞吐量較之小hfile尺寸更加穩定些。但是由于長期得不到split,因此同一個region內發生多次compaction的機會增加了。compaction的原理是將原有數據讀一遍并重寫一遍到hdfs上,然后再刪除原有數據。無疑這種行為會降低以io為瓶頸的系統的速度,因此平均吞吐量會受到一些影響而下降。 > 綜合以上兩種情況,hbase.hregion.max.filesize不宜過大或過小,256MB或許是一個更理想的經驗參數。對于離線型的應用,調整為128MB會更加合適一些,而在線應用除非對split機制進行改造,否則不應該低于256MB ### 2 autoflush=false的影響 >   無論是官方還是很多blog都提倡為了提高hbase的寫入速度而在應用代碼中設置autoflush=false,然后lz認為在在線應用中應該謹慎進行該設置。原因如下: 1) autoflush=false的原理是當客戶端提交delete或put請求時,將該請求在客戶端緩存,直到數據超過2M(hbase.client.write.buffer決定)或用戶執行了hbase.flushcommits()時才向regionserver提交請求。因此即使htable.put()執行返回成功,也并非說明請求真的成功了。假如還沒有達到該緩存而client崩潰,該部分數據將由于未發送到regionserver而丟失。這對于零容忍的在線服務是不可接受的。 2) autoflush=true雖然會讓寫入速度下降2-3倍,但是對于很多在線應用來說這都是必須打開的,也正是hbase為什么讓它默認值為true的原因。當該值為true時,每次請求都會發往regionserver,而regionserver接收到請求后第一件事就是寫hlog,因此對io的要求是非常高的,為了提高hbase的寫入速度,應該盡可能高地提高io吞吐量,比如增加磁盤、使用raid卡、減少replication因子數等    ### 3 從性能的角度談table中family和qualifier的設置 >   對于傳統關系型數據庫中的一張table,在業務轉換到hbase上建模時,從性能的角度應該如何設置family和qualifier呢? >   最極端的,①每一列都設置成一個family,②一個表僅有一個family,所有列都是其中的一個qualifier,那么有什么區別呢? >   從讀的方面考慮: *   family越多,那么獲取每一個cell數據的優勢越明顯,因為io和網絡都減少了。 *   如果只有一個family,那么每一次讀都會讀取當前rowkey的所有數據,網絡和io上會有一些損失。 *   當然如果要獲取的是固定的幾列數據,那么把這幾列寫到一個family中比分別設置family要更好,因為只需一次請求就能拿回所有數據。 >   從寫的角度考慮: 1) 內存方面來說,對于一個Region,會為每一個表的每一個Family分配一個Store,而每一個Store,都會分配一個MemStore,所以更多的family會消耗更多的內存。 2) 從flush和compaction方面說,目前版本的hbase,在flush和compaction都是以region為單位的,也就是說當一個family達到flush條件時,該region的所有family所屬的memstore都會flush一次,即使memstore中只有很少的數據也會觸發flush而生成小文件。這樣就增加了compaction發生的機率,而compaction也是以region為單位的,這樣就很容易發生compaction風暴從而降低系統的整體吞吐量。 3) 從split方面考慮,由于hfile是以family為單位的,因此對于多個family來說,數據被分散到了更多的hfile中,減小了split發生的機率。這是把雙刃劍。更少的split會導致該region的體積比較大,由于balance是以region的數目而不是大小為單位來進行的,因此可能會導致balance失效。而從好的方面來說,更少的split會讓系統提供更加穩定的在線服務。而壞處我們可以通過在請求的低谷時間進行人工的split和balance來避免掉。 > 因此對于寫比較多的系統,如果是離線應該,我們盡量只用一個family好了,但如果是在線應用,那還是應該根據應用的情況合理地分配family。 ### 4 hbase.regionserver.handler.count * RegionServer端開啟的RPC監聽器實例個數,也即RegionServer能夠處理的IO請求線程數。默認是10. * 此參數與內存息息相關。該值設置的時候,以監控內存為主要參考。 * 對于 單次請求內存消耗較高的Big PUT場景(大容量單次PUT或設置了較大cache的scan,均屬于Big PUT)或ReigonServer的內存比較緊張的場景,可以設置的相對較小。 * 對于 單次請求內存消耗低,TPS(TransactionPerSecond,每秒事務處理量)要求非常高的場景,可以設置的相對大些。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看