hbase权威指南学习笔记
                                                            生活随笔
收集整理的這篇文章主要介紹了
                                hbase权威指南学习笔记
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.                        
                                
                            
                            
                            一、簡介
 
1.列式存儲數據庫
 
以列為單位聚合數據,然后將列值順序的存入磁盤,而傳統數據庫時為行式數據庫,連續地存儲整行
 
列式數據庫:對于特定的查詢,不需要所有的值,在分析型數據庫最常見
 
1)關系型數據庫存在的問題
 
高并發的解決步驟
 
增加用于讀取的從服務器,將讀寫分離
 
增加緩存,如Memcached,但無法保證數據的一致性
 
將數據分區到多個數據庫中,運維成本高。分區主要描述了邏輯上水平劃分數據的方案,特點是將數據分文件或分服務器存儲,而不是連續存儲。數據的分區是在固定范圍內實施的:在傳入數據之前,必須提前劃分好數據的存儲范圍
 
一致性模型:數據庫必須保證每一步操作都是從一致的狀態到下一個一致的狀態 按照嚴格強度劃分: 嚴格一致性:數據的變化是原子的,一經改變及時生效 順序一致性:每個客戶端看到的數據依照它們操作執行的順序而變化 因果一致性:客戶端以因果關系順序觀察到數據的改變 最終一致性:在沒有更新數據的一段時間里,系統將通過廣播早證副本之間的數據一致性 弱一致性:沒有做出保證的情況下,所有的更新會通過廣播的形式傳遞,展現給不同客戶端的數據順序可能是不一樣
阻抗匹配:為一個給定問題找到一個理想的解決方案,除了使用通用的解決方案,還應該知道有什么可用的解決方案,從而找到最適合解決該問題的系統
2.表、行、列和單元格 最基本的單位是列,一列或多列形成一行,并由唯一的行健(row key)來確定存儲,一個表有若干行,其中每列可能有多個版本,在每個單元格中存儲了不同的值 一行由若干列組成,若干列又構成了一個列族,一個列族的所有列存儲在同一個底層文件中,這個存儲文件叫做HFile,列族需要在表創建的時候就定義好,常見的引用列的格式為family:qualifer,列族的數量有限制,但是列的數量沒有限制,列值也沒有長度和類型的限制 在Hbase中空值是沒有任何消耗的,它們不占用任何的存儲空間 每列或每個單元格的值都具有時間戳,默認由系統指定,也可以由用戶顯示設置 BigTable和Hbase的典型使用場景是webtable,存儲從互聯網中抓取的網頁 行數據的存儲操作都是原子的,可以讀寫任意數目的列,目前還不支持跨行事務和跨表事務
3.自動分區 Hbase中擴展和負載均衡的基本單元稱為region,region本質上是以行健排序的連續存儲的區間
4.存儲API API提供了建表、刪表、增加列族和刪除列族的操作,同時還提供了修改表和列族元數據的功能 scanAPI提供了高效遍歷某個范圍的行的功能 在服務器的地址空間中執行來自客戶端的代碼,支持這種功能的服務器框架叫做協處理器(coprocessor)
5.實現 每次更新數據時,都會先將數據記錄在提交日志上(commit log)中,在Hbase中這叫預寫日志(write-ahead log,WAL),然后才將這些數據寫入內存中的memstore中,到超過給定的最大值值,就寫到磁盤的HFile文件,HFile是不可被改變的 合并HFile機制 minor合并:將多個小文件(默認最小3個,最大10個)重寫到數據較少的大文件中,每個HFile都是經過歸類的,所以合并的速度很快,只受磁盤IO的影響 major合并:將一個region中一個列族的若干個HFile重寫到一個新的HFile中,major合并能掃描所有的鍵值對,順序重寫全部的數據
二、客戶端API:基礎知識 1.概述 Hbase主要的客戶端接口是有org.apache.hadoop.hbase.client包中的HTable提供的HTable類提供的,通過這個類用戶可以向Hbase存儲和檢索數據 所有修改數據的操作都保證了行級別的原子性 創建HTable實例是有代價的,每個實例都需要掃描.META.表,以檢查該表是否存在,是否可用,以及一些其他操作,因此推薦用戶在每個線程(在開始時)只創建一次HTable實例,而后在客戶端應用的生存期內復用這個對象,如果用戶需要使用多個HTable實例,應考慮使用HTablePool類 Hable(Configuration conf,"tableName")
2.CRUD操作 2.CRUD操作 2.1 put方法:向Hbase存儲數據 1)調用HTable的put方法格式: void put(Put put)或void put(List<put> puts) Put對象的構造方法如下 創建Put實例之后,就可以使用add方法 向該實例添加數據了,每一次調用add()都可以特定的添加一列數據,如果再加上一個時間戳選項,就能形成一個數據單元格。每個KeyValue實例包含器完成地址(行健、列族、列以及時間戳)和實際數據,KeyValue是Hbase在存儲架構中最底層的類 可以使用如下方法檢查是否存在特定的單元格,而不需要遍歷整個集合 通過客戶端訪問配置文件 當你調用任何一個靜態create()方法時,代碼會嘗試使用當前的java classpath來載入兩個配置文件hbase-default.xml和hbase-site.xml
Hbase的一個特殊功能是能為一個單元格存儲多個版本的數據,這個版本使用一個時間戳,必須確保所有服務器的時間都是正確的,并且相互之間是同步的,默認情況下Hbase會保留3個版本的數據 若需要頻繁的修改某些行,用戶有必要創建一個RowLock實例來防止其他用戶訪問這些行
2)KeyValue類 數據和坐標都是以java的byte[]形式存儲的,使用這種類型的目的是允許存儲任意類型的數據
3)客戶端的寫緩沖區 每一個put操作實際上都是一個RPC操作,它將客戶端數據傳送到服務器后返回,這只適合小數據量的操作,Hbase的API配備了一個客戶端的寫緩沖區(write buffer),緩沖區負責收集put操作,然后調用RPC操作一次性將put送往服務器,全局交換機制控制著該緩沖區是否在使用,其方法如下 void setAutoFlush(boolean autoFlush) 默認情況下,客戶端緩沖區是禁用的,可以通過將autoflush設置為false來激活緩沖區,通過setBufferSize(long size)來配置客戶端寫緩沖區的大小,默認大小是2M,為每一個用戶創建的HTable實例都設置緩沖器大小十分麻煩,可以在hbase-site.xml中添加一個較大的預設值,配置如下 <property> <name>hbase.client.write.value</name> <value>20971520</value> </property>
當需要強制把數據寫到服務器端時,用flushCommit()函數 隱式刷寫:在用戶調用put()或setBufferSize()時觸發,這兩個方法都會將目前占用的緩沖區大小和用戶配置的緩沖區大小進行比較,此外調用HTable的close()也會無條件地隱式刷寫 用戶可以通過訪問ArrayList<Put> getWriteBuffer()來訪問客戶端寫緩沖區的內容 如果用戶只存儲大單元格,那么客戶端緩沖區的作用就不大了 4)Put列表 調用void put(List<put> puts)時,客戶端先把所有的Put實例插入到本地寫緩沖區中,然后隱式的調用flushCache(),如果其中有失敗的Put實例(有些檢查是在客戶端完成的,如確認Put實例的內容是否為null或是否指定了列),那么后面的Put實例不會被添加到緩沖區,也不會觸發刷寫命令,當使用基于列表的Put調用時,用戶需要特別注意:用戶無法控制服務器執行put的順序,如果要保證寫入的順序,需要小心地使用這個操作。
5)原子性操作compare-and-set 有一種特別的put調用,其能保證自身操作的原子性:checkAndPut(row,family,qualifier,value,Put put),這種有原子性的操作經常被用于賬戶結余,狀態轉換或數據處理等場景 有一種特別的檢查通過checkAndPut()調用來完成,即只有在另外一個值不存在的情況下,才執行這個修改,要執行這種操作只需要將參數value設置為null Hbase提供的compare-and-set操作,只能檢查和修改同一行數據
2.2 get方法:客戶端獲取已存儲數據的方法 Result get(Get get); 1)單行Get 構造Get實例: Get(rowkey) Get(rowkey,RowLock rowLock) 可以通過多種標準篩選目標數據: Get addFamily(family):只能取得一個指定的列族 Get addColumn(family,qualifier):獲取指定的列 Get setTimeRange(long minStamp,long masStamp)、 Get setTimeStamp(long timeStamp) Get setMaxVersions(int maxVersions)
2)result類 get()返回的結果包含所有匹配的單元格數據,被封裝成一個Result類 常用方法: byte[] getValue(family,qualifier):取得特定單元格的值 byte[] value():返回第一列對應的最新單元格的值 byte[] getRow():返回行健 int size():檢查是否有對應的記錄 boolean isEmpty():檢查是否有對應的記錄 KeyValue[] raw() List<KeyValue> list():用戶可以方便的迭代數據 List<KeyValue> getColumn(family,qualifier) KeyValue getColumnLatest(family,qualifier) boolean containsColumn(family,qualifier) NavigableMap<byte[],NavigableMap[],NavigableMap<Long,byte[]>>> getMap():把請求返回的內容都裝入一個Map類實例中,可以遍歷所有結果
3)get列表 Result[] get(List<Get> gets); boolean exists(Get get):查看存儲的數據是否存在 getRowOrBefore(row,family):
2.3 刪除方法 1)單行刪除 void delete(Delete delete) Delete實例構造方法 Delete(rowkey) Delete(rowkey,long timestamp,RowLock rowLock) 常用方法 Delete deleteFamily(family[,long timestamp]) Delete deleteColumns(family,qualifier[,long timestamp]):沒指定timestamp,則刪除所有版本 Delete deleteColumn(family,qualifier[,long timestamp]):沒指定timestamp,則刪除最新版本
2)Delete的列表 void delete(List<Delete> deletes)
3)原子性操作compare-and-delete boolean checkAndDelete(row,qualifier,value,Delete delete)
2.4批處理操作 事實上許多基于列表的操作都是基于batch()方法是實現的。 方法: void batch(List<Row> actions,Object[] results) Object[] batch(List<Row> actions) 注:不可以將針對同一行數據的Put和Delete操作放在同一個批處理請求中 Row是Put、Get、Delete類的父類 當用戶使用batch()功能時,Put實例不會被客戶端寫入緩沖區中緩沖,batch()請求是同步的,會把操作直接發送給服務器 兩種方法相同點: get、put、delete操作都支持,如果執行時出現問題,客戶端將拋出異常并報告問題,都不適用客戶端的寫緩沖區 不同點: void batch(acitons,results):能訪問成功操作的結果,同時也可以獲取遠程失敗的異常 Object[] batch(actions):只返回客戶端異常,不能訪問程序執行中的部分結果 注:在檢查結果之前,所有的批處理操作都已經執行了:即使用戶收到異常,其他的操作也都已經執行了 批量處理可以感知暫時性錯誤(如NoServingRegionException)會多次重試這個操作,用戶可以通過調整hbase.client.retries.number配置項(默認為10)來增加或減少重試次數
2.5 行鎖 region服務器提供一個行鎖的特性,保證了只有一個客戶端能獲取一行的數據相應的鎖,同時對該行進行修改。用戶應該盡可能的避免使用行鎖,如果必須使用,那么一定要節約占用鎖的時間 Get不需要鎖:服務器應用了一個多版本的并發控制機制來保證行級讀操作,只有當一個變動被應用到整個行之后,客戶端才能讀出這個改動,當改動進行中時,所有的客戶端讀取到的數據都是將是所有列以前的版本
2.6 掃描 類似于數據庫中的游標 ResultScanner getScanner(Scan scan) ResultScanner getScanner(family) ResultScanner getScanner(family,qualifier) scan類的構造器 Scan() Scan(startRow,Filter filter) Scan(startRow) Scan(startRow,stopRow) 注:如果用戶只需要數據的子集,那么限制掃面的范圍就能發揮Hbase的優勢,如果不讀取整個列族,那么整個列族的文件都不會讀取,這就是列族存儲架構的優勢 1)ResultScanner類 掃描操作不會通過一次RPC請求返回所有匹配的行,而是以"行"為單位進行返回 Result next() Result[] next(int nbRows) void close() 要確保盡早釋放掃描器實例,當使用完ResultScanner之后應調用它的close()方法,釋放所有由掃描器控制的資源 就像行級鎖一樣,掃描器也使用同樣的租約超時限制,保護其不被時效的客戶端阻塞太久,通過如下配置 <property> <name>hbase.regionserver.lease.period</name> <value>120000</value> </property> 2)緩存與批量處理 如果一次RPC請求可以返回多行數據,這樣使用掃描器更有意義,可以由掃描器緩存實現,默認情況下,這個緩存是關閉的。可以從兩個層面打開它 在表的層面,這個表的所有掃描器實例的緩存都會生效,用戶使用一下的Htable方法設置表級的掃描器緩存: void setScannerCaching(int scannerCaching), int getScannerCaching():默認是1 在掃描器層面,這樣只會影響當前的掃描實例,用戶使用一下的Scan類的方法設置掃描器級的掃描器緩存: void setCaching(int scannerCaching) int getCaching():默認是1 此外用戶可以修改整個集群的配置 <property> <name>hbase.client.scanner.caching</name> <value>10</value> </property> 這樣所有scan的實例的掃描器緩存就都被設置為10了 注:當數據量非常大的行,可能超過客戶端進程的內存容量,解決方法:使用Scan類的批量操作 setBatch(int batch) int getBatch() 緩存是面向行一級的操作,而批量是面向列一級的操作。
 
 
 
2.8 各種特性 1)Htable使用方法 void close():使用完一個HTable實例后,需要調用一次close(),它會刷寫所有客戶端緩沖的寫操作 HTableDescriptor getTableDescripor():每個表都使用一個HTableDescriptor實例類來定義表結構 Map<HRegion,HServerAddress> getRegionInfo():獲取某一行數據的具體位置信息
三、客戶端API:高級特性 1.過濾器 Get和Scan兩個類都支持過濾器,過濾器的基本接口叫做Filter,用戶還可以通過繼承Filter類實現自己的需求 1.1 比較運算符 1.2 比較器 1.3 Hbase提供的第一類:比較過濾器 用戶創建實例時需要一個比較運算符和一個比較器實例 CompareFilter(CompareOp op,WriteableByteArrayComparable valueComparator)
 
 
1.4 Hbase提供的第二類:專用過濾器
1.5 附加過濾器(應用在其他過濾器上) 跳轉過濾器:SkipFilter(Filter filter):當被包裝的過濾器遇到一個需要過濾的KeyValue時,用戶可以擴展并過濾整行數據 全匹配過濾器:WhileMatchFilter
1.6 FilterList 需要多個過濾器共同限制返回到客戶端的結果 FilterList(List<Filter> rowFilters) FilterList(Operator op) FilterList(List<Filter> rowFilters,Operator op) 參數rowFilters以列表的形式組合過濾器,參數operator決定了組合它們的結果,默認是為MUST_PASS_ALL,使用ArrayList可以保證過濾器的執行順序與它們添加到列表中的順序一致
1.7 自定義過濾器 用戶可以實現Filter接口或者直接繼承FilterBase類
用戶自定義過濾器部署 編寫代碼-->打成jar包-->把文件發送到每個region服務器上-->修改hbase-env.sh文件如下 export HBASE_CLASSPATH="/hbase-book/target.aa.jar"-->重啟hbase
2 計數器 2.1 簡介 許多收集統計信息的應用有點擊流和在線廣告意見,這些需要被收集到日志文件中用戶后續的分析,用戶可以使用計數器做實時統計,從而放棄延遲較高的批處理操作 雖然用戶可以一次更新多個計數器,但是它們必須屬于同一行,更新多個計數器需要通過獨立的API調用,即多個RPC請求 初始化計數器:用戶不用初始化計數器,當用戶第一次使用計數器時,計數器自動設置為0,即當用戶創建一個新列時,計數器的值是0 在shell中操作計數器使用incr '<table>','<row>','<column>',[increment-value]與get_counter '<table>','<row>','<column>' 客戶端API操作計數器 1)單計數器 只能操作一個計數器:用戶需要自己設定列,方法由HTable提供的 long incrementColumnValue(row,family,qualifier,long amount) long incrementColumnValue(row,family,qualifier,long amount,boolean writeToWAL) 2)多計數器 Result increment(Increment increment) 需要創建一個Increment實例,構造方法如下 Increment() Increment(row) Increment(row,RowLock rowLock) 向其中加入實際的計數器:addColumn(family,qualifier,long maxStamp)
3.協處理器 協處理器允許用戶在region服務器上運行自己的代碼,也就是允許用戶執行region級的操作,并可以使用如觸發器類似的功能 另一類適合使用協處理器的場景就是權限控制 協處理器框架提供了一些類,用戶可以通過繼承這些類擴展自己的功能,主要有兩類,即observer和endpoint observer:回調函數(也被稱為鉤子函數,hook)在一些特定時間發生時。這些事件包括用戶產生的事件和服務器內部自動產生的事件 RegionObserver:用戶可以用這種處理器處理數據修改事件,它們與表的region聯系緊密 MasterObserver:可以被用作管理或DDL類型的操作,這些是集群級事件 WALObserver:提供控制WAL的鉤子函數
endpoint:通過添加一些遠程調用來動態擴展RPC協議,可以把它理解為與RDBMS中類似的存儲過程。endpoint可以與observer的實現組合起來直接作用于服務器的狀態
Coprocesspor類 所有協處理器的類都必須實現這個接口,它定義了協處理器的基本預定。提供了兩個被應用于框架的枚舉類Priority(SYSTEM,USER)和State 待續!!!!
4.HtablePool 為Hbase集群提供一個客戶端連接池,用戶可以通過以下任意一個構造器來創建池: HTablePool() HtablePool(Configuration conf,int maxSize) HtablePool(Configuration conf,int maxSize,HTableInterfaceFactory fac) HTableInterfaceFactory:用戶可以創建自定義的工廠類,例如,為Htable實例使用特定的配置,或可以讓實例完成一些初始化操作。如果用戶想自己擴展HtableInterfaceFactory,則必須實現兩個方法createHTableInterface(conf,tableName)和releaseHtableInterface 使用表實例池方式:getTable(String tableName);getTable(byte[] tableName);void putTable(HtableInterface table)
5.連接管理 每個HTable實例都需要建立和遠程主機的連接,這些連接在內部使用HConnection類表示,被HConnectionManager類管理并共享。用戶沒必要和這兩個類打交道,只需要創建一個Configuration實例,然后利用客戶端API使用這些類。 Hbase內部使用鍵值映射來存儲連接,使用Configuration實例作為鍵值映射的鍵。 HtablePool類,所有連接池中的Htable實例都自動共用一個提供的Configuration實例,共享它們的連接。 共享連接的缺點在于釋放,如果用戶不顯示關閉連接,它將一直存在,直到客戶端退出,建議用戶不在需要使用Htable時主動調用其close(),釋放資源,以下是顯式清理連接方法 deleteConnection(Configuration conf,boolean stop); deleteAllConnection(boolean stop)
四、客戶端API:管理功能 1.模式定義 1)表:使用表的主要原因是控制表中的所有列以達到共享表內的某些特性的目的 表描述符的構造函數: HTableDescriptor(); HTableDescriptor(String name); HTableDescriptor(byte[] name); HTableDescriptor(HTableDescriptor desc);
任意不相交的系統間的遠程通信都使用到了Hadoop RPC框架,需要遠程方法中參數都實現Writeable接口,進而能夠序列化對象并遠程傳輸
2)表屬性 表名一定不能以".","-"開頭,表名只能包含拉丁字母或數字、下劃線、".","-"
列族: void addFamily(HColumnDescriptor family) boolean hasFamily(byte[] c) HColumnDescriptor[] getColumnFamilies() HColumnDescriptor getFamily(byte[] column)
文件大小限制: long getMaxFileSize() void setMaxFileSize(long maxFileSize) 如果一個列族的存儲單元已使用的存儲空間超過了大小限制,region將發生拆分,maxFileSize默認值是256M 這個參數只是大致的預期值,而在某些特殊條件下,文件大小可能超過這個預期值(一行數據不能跨region存儲)
 
 
只讀:默認所有的表都可寫,對于特殊的表來說,只讀參數有特殊的用途。調用setReadOnly(boolean readOnly)設置
memstore刷寫大小:寫操作會寫入到寫緩沖區,人后按照合適的條件順序寫入到一個新的存儲文件(磁盤)中,可以通過setMemStoreFlushSize(long memstoreFlushSize),這個memstoreFlushSize的默認值是64MB
延遲日志刷寫: Hbase有兩種將WAL保存到磁盤的方式,一種是延遲日志刷寫,另一種不是,通過setDeferredLogFlush(boolean isDeferredLogFlush),isDeferredLogFlush的默認值為false
3)列族 列族定義了所有列的共享信息,并且可以通過客戶端創建任意數量的列。定位到某個具體的列需要列族名和列名合并在一起,以:分隔,如family:qualifier 構造方法: 列族名:getName()或getNameAsString() 不能被重命名,通常的做法是新建一個列族,然后使用API從舊列族中復制數據到新列族 列族名不能以"."開頭,也不能包含":"、"\"或ISO控制符
最大版本數:所有列族都限定了每個值能夠保留的最大版本數,Hbase會移除超過最大版本數的數據,通過setMaxVersions(int maxVersion)設置,這個maxVersion默認為3.
壓縮: Hbase支持插件式的壓縮算法,允許用戶選擇最合適的壓縮算法 塊大小: 在Hbase中,所有的存儲文件都被劃分為若干個小存儲塊,這些小存儲塊在get或scan操作時會加載到內存中,通過setBlockSize(int size)設置,默認大小是64KB 注:HFile的不同于HDFS中的塊,HDFS提到的塊是用于拆分大文件以提供分布式存儲,且便于MapReduce框架進行并行計算的存儲單元;而HBase中的塊主要用于高效加載和緩沖數據
緩存塊: Hbase順序的讀取一個數據塊到內存緩存中,這個參數默認是為true,每次讀取的塊都會緩存到內存中,但是如果順序讀取某個特定的列族,最好將這個屬性設置為false,通過setBlockCacheEnabled(boolean blockCacheEnabled)方法設置
生存期TTL: Hbase支持版本數據保存的時間,TTL設置了一個基于時間戳的臨界值,內部管理會自動檢查TTL的值是否達到上限,在major合并過程中時間戳被判定為超過TTL的數據會被刪掉,可以通過setTimeToLive(int timestamp)方法設置,TTL的參數為秒,默認值是Integer.MAX_VALUE,理解為永久保留
在內存中:setInMemory(boolean inMemory) 將inMemory設置為true只是一種承諾,或者說高優先級。在正常數據讀取過程中,塊數據被加載到緩沖區中并長期駐留在內存中,除非堆壓力過大,這個時候才會強制從內存中卸載這部分數據
布隆過濾器: 能夠減少特定訪問模式下的查詢時間,由于這種模式增加了內存和存儲的負擔,這個模式默認為關閉狀態 復制范圍:Hbase提供跨集群同步的功能,本地集群的數據更新可以及時同步到其他集群,復制范圍參數默認為0,即這個功能處于關閉狀態。可以通過setScope(int scope)設置,1表示開啟實時同步
2.HBaseAdmin HBaseAdmin提供了創建表、列族、檢查表是否存在,修改表結構和列族結構、以及刪除表功能 構造方法:HbaseAdmin(Configuration conf)
1)表操作 建表: void createTable(HTableDescriptor desc) void createTable(HTableDescriptor desc,byte[] startKey,byte[] endKey,int numRegions) void createTable(HTableDescriptor desc,byte[][] splitKeys) void createTableAsync(HTableDescriptor desc,byte[][] splitKeys) HTable類中的方法getStartEndKey()來獲取所有region的邊界
獲取所有表的列表,以及判斷是否存在 boolean tableExists(String tableName) boolean tableExists(byte[] tableName) HTableDescriptor[] listTables() HTableDescriptor getTableDescriptor(byte[] tableName)
刪除表: void deleteTable(String tableName) void deleteTable(byte[] tableName)
在刪除表之前需要將表禁用,region服務器會先將內存中近期內還未提交的已修改的數據刷寫到磁盤,然后關閉所有region,并更新這樣表的元數據,將所有region標記為下線狀態。
 
 
2)集群管理 允許用戶查看集群當前的狀態: static void checkHBaseAvailable(Configuration) ClusterStatus getClusterStatus() void closeRegion(String regionname,String hostAndport) 注:所有可用表的region都應該是在線狀態 void majorCompact(String tableNameOrRegionName)
五、可用的客戶端 1.REST、Thrift,Avro介紹 它們都支持大量的語言,Protocol Buffer與Thrift和Avro最大的不同是它沒有自己的RPC堆,而它生成的RPC定義需要被后來其他的RPC庫使用,Hbase提供了REST、Thrift、Avro的輔助服務,它們可以實現成專門的網關服務,這些服務運行在共享或專用的機器上。Thrift和Avro都有各自的RPC實現,所以網關服務僅是在它們的基礎上進行了封裝,至于REST,HBase則采用了自己的實現,并提供了訪問存儲數據的路徑。 每個請求使用一個服務而非建立一個連接的優勢在于用戶可以復用連接來獲得最優性能。 2.交互 1)使用原生Java:直接使用HTable并通過原生的RPC調用與HBase服務器進行交互。 2)REST: 操作:基于REST服務的客戶端是在能夠與HBase通信之前需要先啟動REST網關服務,使用hbase-daemon.sh start rest命令。REST服務提供了HBase表提供的所有操作,REST服務器返回的值都經過了base64Binary編碼。 支持的格式:通過使用HTTP Content-Type和Accept頭,調用者可以自動選擇發送和接收信息的數據格式 Plain(text/plain): XML(text/xml):默認的存儲和查詢格式是XML JSON(application/json):curl -H "Accept:application/json" http://<servername>:testtable/%01%02%03/colfam1:col1
REST的java客戶端: REST服務器同樣具有全面的java客戶端API,位于org.apache.hadoop.hbase.rest.client包中,其中核心類為RemoteHTable和RemoteAdmin
3)Thrift 在使用Thrift之前需要安裝Thrift,并且需要啟動HBase提供的Thrift Server 啟動Thrift命令:hbase-daemon.sh start thrift
4)Avro 在使用Thrift之前需要安裝Avro,并且需要啟動HBase提供的Avro Server 啟動Avro命令:hbase-daemon.sh start Avro
3.批量處理客戶端 1)Mapreduce:兩種方式,原生java API或Clojure 2)Hive Hive與Hbase之前的版本需要匹配,細微的RPC變化可能影響交互 3)pig 4)Cascading
4.shell 1)命令 引用名:命令行要求在使用表名和列名時需要通過單引號或雙引號對其進行引用。 引用值:命令行支持二進制、八進制、十六進制的輸入和輸出,用戶在引用時必須使用雙引號 使用逗號分隔參數 Ruby散列屬性: 一些命令中需要設置鍵值對屬性,使用Ruby散列按照以下方式來完成 {'key1'=>'val1','key2'=>'val2',...}
DDL命令 alter 使用modifyTable()修改現有表結構
DML命令:
工具命令: assgn 分配一個region到一臺region服務器中
復制命令:
腳本: 可以使用Nagios或其他監控工具發送腳本 用戶還以使用管道的形式運行命令
5.基于Web UI 1)master的web默認端口是60010,region服務默認端口是60030
六、與Mapreduce集成 1.類 InputFormat InputFormat負責:拆分輸入數據,同時返回一個RecordReader實例,定義了鍵值對象的類,并提供了next()遍歷數據 就HBase而言,它提供了一組專用的實現,叫TableInputFormatBase,該實現的子類是TableInputFormat mapper HBase提供了一個TableMapper類,將鍵的類型強制轉換為ImmutableBytesWritable類,同時將改制的類型強制轉換為Result類型,TableMapper類沒有實現具體的功能,它只是添加了鍵值對的簽名 Reducer HBase提供了一個TableReducer類 OutputFormat Hbase提供了一個TableOutputFormat
 
 
2.支撐類 Mapreduce的支撐類與TableMapReduceUtil類一同協作在HBase上執行Mapreduce任務,它有一個靜態方法能配置作業,病并使作業可以使用Hbase作為數據源或目標
3.在HBase上的Mapreduce 當運行Mapreduce作業所需庫中的文件不是綁定在Hadoop或Mapreduce框架中時,用戶就必須確保這些庫文在作業之前已經可用,用戶一般兩個選擇:在所有的任務節點上準備靜態的庫或直接提供作業所需的所有庫 1)靜態配置: 將jar文件復制到所有節點的常用路徑中 將這些jar文件的完整路徑寫入hadoop-env.sh配置文件中,按照如右方式編輯HADOOP-CLASSPATH變量:HADOOP-CLASSPATH="<extra-entries>":HADOOP-CLASSPATH 重啟所有的任務的NodeManager使變更生效 2)動態配置:Hadoop有一個特殊的功能,它可以讀取操作目錄中/lib目錄下所包含的所有庫的jar文件,用戶可以使用此功能生成所謂的胖jar文件,胖jar文件使用maven的Maven Assembly插件
七、架構 1.數據查找和傳輸 1)B+樹:它的葉節點項目鏈接并且有序,能夠通過主鍵對記錄進行高效的插入、查找以及刪除,它表能為一個動態、多層并由上下界的索引,同時要注意維護每一段所包含的鍵數目
2)LSM樹(log-structured merge-tree):輸入數據首先存儲在日志文件,這些文件內的數據完全有序,當有日志文件被修改時,對應的更新會被保存在內存中加速查詢,修改數據文件的操作通過滾動合并完成。
2.存儲 1)概覽 注:HBase主要處理兩種文件:一種是WAL文件,另一種是實際的數據文件,這兩種文件都是由HRegionServer管理
2)讀取數據流程
HRegionServer負責打開region,并創建一個對應的HRegion實例,它會為每個表的HColumnFamily創建一個Store實例,每個Store實例包含多個StoreFile(HFile的輕量級封裝)和一個MemStore,一個HRegionServer共享一個HLog實例
3)寫路徑
4)region拆分
5)合并 minor合并:負責重寫最后生成的幾個文件到一個更大的文件中,文件數量有hbase.hstore.compaction.min決定,默認值是3,minor合并處理的最大文件數默認為10,用戶可以通過hbase.hstore.compaction.max來配置 major合并:把所有文件壓縮成一個單獨的文件,在memstore被刷寫到磁盤后出發檢查,或shell命令major-compact后觸發,配置相關參數 hbase.hregion.majorcompaction(默認為24小時)和hbase.hregion.majorcompaction.jitter(默認為0.2)
6)HFile 注:文件長度可變,唯一固定的塊是File Info和Trailer,Trailer是指向其他快遞的指針,塊大小是由HColumnDescriptor配置的,該配置可以在創建表的時候由用戶指定,默認大小時64K,每一個塊都包含一個magic頭部和一定數量的序列化的KeyValue實例
7)WAL WAL存儲了對數據的所有更改,實現了WAL的類叫HLog類,HLog類的一個特性就是跟蹤修改,通過使用序列號來實現
3.ZooKeeper HBase使用ZooKeeper作為其協同服務組件,其主要功能包括跟蹤region服務器、保存root region的地址等 HBase建立的znode列表,默認為/hbase,這個znode的名稱由zookeeper.znode.parent屬性決定, 以下是znode的列表以及他們的作用 /hbase/hbaseid:包括clusterID,與存儲在HDFS上的hbase.id文件內容相同。 /hbase/master:包含服務器名稱 /hbase/replication:包含副本信息 /hbase/root-region-server:包含-ROOT-region所在的region服務器的機器名,這個經常在region定位中使用 /hbase/rs:所偶region服務器的根節點,集群使用它來跟蹤服務器異常 /hbase/shutdown:集群的啟動事假和關閉時間 /hbase/table:當表被禁用,信息會被添加到這個znode之下
4.復制 HBase復制可以作為一種災難恢復的方法,并且可以提供HBase層的高可用性 HBase復制中最基本的機構模式是"主推送",因為每個region服務器都有自己的WAL,所以很容易保存現在正在復制的位置 注:參與復制的集群可以不相等,主機群會通過隨機分配盡量均衡從集群的負載
1)常規處理 客戶端發送Put、Delete、或Increment到region服務器,這些請求包含的鍵值對會被region服務器轉化為WALEdit,同時WALEdit會被復制程序檢查,并以列族為單元復制數據。修改被添加到WAL中,并把實際數據添加到Memstore。 2)沒有反饋的從集群 如果從集群的region服務器沒有響應rpc請求,主集群的region服務器將會睡眠并按照配置的次數重試。如果從集群的region服務器還是不可用,主機全會重新選擇一臺其他的機器來提交修改 3)挑選要復制的目標集群 主集群的region服務器連接從集群的ZooKeeper群組,然后掃描/hbase/rs目錄來發現所有可用的并隨機選擇一部分服務器來復制數據(默認是10%)
 
 
八、高級用法 1.rowkey設計 1)高表與寬表 HBase中的表可以設計為高表和寬表,前者指表中列少兒行多,后者則正好相反。用戶應當盡量將需要查詢的維度或信息存儲在行健中,應為用它篩選的效率最高 此外,HBase只能按行分片,因此高表更有優勢
2)時間序列:當處理流式事件時,最常用的就是按時間序列組織數據,這些數據會被有序的存儲在一個特定的范圍內,到時系統產生讀寫熱點,解決這個問題的方法就是想辦法將數據分散到所有的region服務器上,有很多中方法,例如在行鍵前價格,通常情況下如下選擇
時間順序關系 每個列族下的列可以作為輔助索引單獨進行排序,主要內容在主要的列族下,索引放在另外一個列族下,為了編碼創建太多的列族,可以把所有輔助索引存儲在有一個單獨的列族下,同時列鍵的最左端使用索引ID這個前綴來表示不同的順序
 
 
2.輔助索引 輔助索引存儲了新坐標和現有坐標之間的映射關系,一些為可行的解決方案 由客戶端管理索引: 把責任完全轉移到應用層的典型做法是把一個數據表和一個查找/映射表結合起來,每當程序寫數據表的時候,它也同時更新映射表(輔助索引表)。讀數據時可以直接在主表進行查詢,從輔助索引表中先查找原表的行鍵,再在原表中讀取實際數據。優點:用戶可以按照需求設計映射表。缺點:Hbase不能保證跨行操作的原子性 用戶可以自由設計主索引和輔助索引之間的映射關系時,必須接受的缺點是用戶需要實現所有存儲和查找數據必需的方法
帶索引的事務型HBase 開源的ITHBase,擴展了HBase,最核心的擴展是增加了保證所有輔助索引,提供了一個IndexedTableDescriptor,提供了數據表的輔助索引操作支持,大多數類被添加了索引支持功能的類替換了
帶索引的HBase IHBase是完全在內存中維護索引,索引永遠都是同步的,不需要額外的事務控制,索引的定義由IdxIndexDescriptor類完成
3.搜索集成 使用任意關鍵字來搜索數據,滿足這種需要往往是集成一個完整的搜索引擎 Lucene:獨立于HBase使用的Lucene或其他派生類的解決方案可以通過Mapreduce建立索引。 HBasene:選擇的方法是直接在HBase內部建立搜索索引,同時為用戶提供Lucene的API,它把每個文檔的字段、詞存儲在一個單獨的行,同時包含這個詞的文檔儲存在這一行的列中
九、監控集群 1.監控框架 每個HBase進程都會提供一系列監控指標,這些監控指標可以被各種監控API和工具使用,包括JMX和Ganglia。每種服務器都有多組監控指標,這些監控指標按子系統分組并隸屬于一種服務器 HBase使用Hadoop的監控框架,并繼承了其所有類和特性,這個框架基于MetricsContext接口來處理監控數據點的生成,并使用這些數據點監控和繪圖 1)可用的實現列表: GangliaContext:用來推送監控指標到Ganglia FileContext:將監控指標寫入磁盤上一個文件中 TimeStampingFileContext:將監控指標寫入磁盤上一個文件中,但是為每個監控指標添加一個時間戳前綴 CompositeContext:允許為監控指標生成不止一個上下文 NullContext:監控指標框架的關閉選項,使用這個上下文時,不生成也不聚合監控指標 NullContextWithUpdateThread:不生成任何監控指標,但是啟動聚合統計線程。這種上下文在通過JMX檢索監控指標時使用
多重監控指標使用MetricsRecored分組,來描述一個具體的子系統。HBase使用這些組分別來保存master、region機器,以及其他服務器的統計信息,每個組都有唯一的名字:<context-name>.<record-name>.<metrics-name>。上下文有內置的定時器來觸發并將監控指標推送至目標
2)各種指標類型: 整型值:(IV) 長整型值:(LV) 速率(R):一個代表速率的浮點型值,可以是每秒操作或者消息數 字符串:存儲靜態的,基于文本的信息。并用來報告HBase版本信息和構建時間 時間變化整型(TVI):上下文會維護一個單調遞增累加計數器。框架使用這個方法對各種消息進行技術 時間變化長整型(TVL):用于增速較快的計數器 時間變化率(TVR):需要追蹤操作數或消息的數量,以及完成操作所用的時間,通常用來計算一次操作完成的平均時間 持續型時間變化率(PTVR):添加了對持續的周期性的監控指標的必要的支持。 3)master提供的監控指標
4)region服務器監控指標: 塊緩存監控指標 塊緩存用來保存底層HFile從HDFS讀取的存儲塊。count(LV)監控指標反映了當前緩存中保存的塊數目,size(LV)監控指標時占用java堆空間大小,free(LV)監控指標時堆空間為緩存保留的可用空間,evicted(LV)反映了命中緩存總數與請求緩存總數的關系 塊緩存追蹤追蹤緩存命中hit(LV)和緩存失效miss(LV)的數目,以及命中率hit radio(LV),其反映了命中緩存總數與請求緩存總數的關系。所有讀操作使用緩存,不管用戶是否制定過將使用的塊保留在緩存中。使用setCacheBlocks()僅僅影響塊的保留策略 合并監控 compaction size(PTVR)和compaction time(PTVR)分別代表需要合并的存儲文件總大小和操作花費時間 compaction queue size:用來監測一個region服務器有多少文件當前正在排隊等待合并
memstore監控指標 memstore size MB(IV):服務器上所有memstore總共占用的堆大小 flush queue zie(IV):將要被刷寫的region的數目
存儲監控指標: store files(IV):所有存儲文件的數目 store file index MB(IV):所有存儲文件的塊索引和元數據的總和大小
I/O監控指標: fs read latency(TVR):文件系統的讀延遲 fs write latency:寫延遲 fs sync latency:統計了預寫日志記錄同步到文件系統的延遲
RPC監控指標 Ganglia 組成: Ganglia監控守護進程(gmond):監控守護進程需要在每臺需要監控的機器上運行,它搜集本地數據,準備統計,然后被其他系統拉取。通過單一或組播方網絡消息傳播的主機變化情況,使用組播方式,每個監控守護進程可以獲取集群完整狀態,所有的服務器擁有同樣的組播地址 Ganglia元數據守護進程(gmetad):元數據守護進程安裝在一個中心節點上,作為整個集群的管理節點。元數據守護進程從一個或多個監控守護進程拉去數據來獲取整個集群的狀態,然后使用RDTool將這些信息存放在一個用于輪詢的時間序列數據庫中。 GangliaPHP:展示統計信息
十、性能優化 1.垃圾回收優化 垃圾回收時master通常不會產生問題,只需要添加到region服務器的啟動參數中。 用戶可以通過向hbase-env.sh配置文件中添加HBASE_OPTS或者HBASE_REGIONSERVER_OPTS變量來設置垃圾回收的相關選項。后者僅影響region服務器進程,也是推薦的修改方式 指定新生代的方式:-XX:MaxNewSize=128m -XX:NewSize=128m或-Xmn128m 注意:默認值對于多數region服務器面對的負載還是太小,所以她必須增大
建議在JRE日志中輸入垃圾回收的詳細信息,通過添加以下JRE選項: -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -Xloggc:$HBASE-HOME/logs/gc-hbase.log 該日志不會按日期定時滾動,需要手動處理(例如:使用基于crontab的每日滾動轉存任務)
通過不同的JRE參數來指定不同的垃圾回收實現策略,推薦的值是: -XX:+UseParNewGC and -XX:+UseConcMarkSweepGC UseParNewGC:停止運行java進程二期清空年輕代堆 ConcMarkSweepGC:不停止java進程的情況下異步并行的完成工作
2.預拆分region 管理接口中createTable()方法或shell中的create命令可以接受列表形式提供的拆分行健作為參數
3.負載均衡: master有一個內置的叫做均衡器的特性,在默認的情況下,均衡器每五分鐘運行一次,可以通過hbase.balancer.period屬性設置 均衡器有一個可以限制自身運行時間的上限,用戶可以通過hbase.balance.max.balancing屬性來設置,默認為均衡器間隔周期的一半
4.合并region HBase集成了一個工具能夠讓用戶在集群沒有工作時河北那個兩個相鄰的region,工具為org.apache.hadoop.hbase.util.Merge
5.客戶端API:最佳實踐 1)禁止自動刷寫:當有大量的寫入操作時,使用setAutoFlush(false)方法,確認HTable自動刷寫的特性已經關閉,如果禁用了自動刷寫,add(Put)操作指導寫緩沖區被填滿時才會被送出,可以調用HTable的flushCommits()方法顯式刷寫數據,調用HTable的close()也會隱式調用flushCommits() 2)使用掃面緩存:如果HBase被用作一個MapReduce作業的輸入源,請最好將作為MapReduce作業輸入掃描器實例的緩存用setCaching()方法設置為比默認值1大得多的值,使用默認值意味著map任務處理每條記錄都請求region服務器 3)限定掃描范圍 當Scan用來處理大量行時注意哪些屬性被選中了,從而限制掃描范圍 4)關閉ResultScanner 如果用戶忘記關閉由HTable.getScanner()返回的ResultScanner實例,則可能對服務器端造成影響,一定要在try/catche的finally塊中關閉ResultScanner 5)塊緩存用法 Scan實例通過setCacheBlock()方法來設置使用region服務器中的塊緩存,如果MapReduce作業中使用掃描,這個方法應當被設為false,對于那些頻繁訪問行的行,建議使用塊緩存 6)關閉Put上WAL 提高吞吐量方式,使用Put的writeToWAL(false)來關閉WAL,不過一旦region服務器故障就會丟失數據
6.配置 1)減少Zookeeper超時 默認在region服務器和ZooKeeper集群之間的超時時間是3分鐘,通過zookeeper.session.timeout屬性設置,在改變值之前,確認用戶服務器上JVM的垃圾回收機制是受控的 2)增加處理線程 hbase.regionserver.handler.count屬性定義了響應外部用戶訪問數據表請求的線程數,默認值10有些偏小,將這個值設置的高也有可能產生問題,并發的寫請求造成壓力 3)增加堆大小 如果用戶使用更好的服務器,可以給HBase分配8G內存或更大,用戶可以在hbase-env.sh文件中調整HBASE_HEAPSIZE的設置,master會默認1GB的堆運行,region服務器則會按照用戶單獨指定的堆空間運行 4)啟動數據壓縮 用戶應當為存儲文件啟動壓縮,尤其推薦使用Snappy或LZO壓縮 5)增加region大小 默認region大小為256M,用戶可以增加其大小,但是該參數的大小要仔細評估 6)調整塊緩存大小 控制堆中塊緩存大小的屬性是一個浮動點數類型的百分比,默認值是20%,可以通過perf.hfile.block.cache.size屬性改變這個值,看看是否存在許多塊被換出的情況,如果存在,則可以考慮增加塊緩存的大小。用戶負載大多數為讀請求是另一個增加緩存大小的原因。 7)調整memstore限制 內存存儲占用的堆大小用hbase.regionserver.global.memstore.upperLimit屬性來配置,默認值為40%,此外hbase.regionserver.global.memstore.lowerLimit屬性(默認為35%)用戶控制當服務器清空memstore之后剩余的大小,當用戶主要在處理讀請求時,可以考慮通知減少memstore的上線限來增加塊緩存的空間 8)增加阻塞時存儲文件數目 這個值通過hbase.hstore.blockingStoreFiles屬性來設置的,它決定了當存儲文件的數據達到閾值時,更新操作將會被阻塞,當應用經常遇到大負載的突發寫請求時,用戶可以稍微增加這個值來應對這種情況,其默認值是7 9)增加阻塞倍率 屬性hbase.hregion.memstore.block.multiplier的默認值是2,當memstore達到屬性multiplier乘以flush的大小限制時會阻止進一步更新 10)減少最大日志文件的限制 設置hbase.regionserver.maxlogs屬性使得用戶能夠控制基于磁盤的WAL文件數目,進而控制刷寫頻率,該參數的默認值是32
負載測試 Hbase有自己的性能評價工具,名為PE,使用命令:hbase org.apache.hadoop.hbase.PerformanceEvaluation YCSB:Yahoo的云服務基準測試系統也可用于對HBase集群進行超負荷測試
十一、集群管理 1.運維任務 1)減少節點 使用hbase-daemon.sh stop regionserver停止region服務器 如果關閉節點時負載均衡還在運行,則在復雜均衡和master恢復下線的region服務器之間可能存在競爭,要避免這種情況,使用shell命令:balance_switch false禁用負載均衡 HBase0.90.2之后引入了一種可以讓region服務器逐漸減少其負載并停止服務的方法,使用graceful_stop.sh腳本來完成 用戶也可以用graceful_stop.sh腳本來重啟服務器,并將之前屬于它的region移回原味(用戶可能選擇后者以保持數據的局部性),最簡單的滾動重啟可以使用如下命令(確認之前已經關閉負載均衡): for i in 'cat conf/regionservers|sort; do ./bin/graceful_stop.sh --restart --reload --debug $i; done $> /tmp/log.txt &
2.數據任務 1)導入/導出 HBase發布了一些有用的工具,其中兩個支持導入和導出MapReduce作業。這些工具包含在HBase的JAR文件中,用戶可以通過hadoop jar命令來獲得這些工具,使用格式:hadoop jar $HBASE_HOME/HBASE-0.91.0-SNAPSHOT.jar <command>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
                            
                        
                        
                        一致性模型:數據庫必須保證每一步操作都是從一致的狀態到下一個一致的狀態 按照嚴格強度劃分: 嚴格一致性:數據的變化是原子的,一經改變及時生效 順序一致性:每個客戶端看到的數據依照它們操作執行的順序而變化 因果一致性:客戶端以因果關系順序觀察到數據的改變 最終一致性:在沒有更新數據的一段時間里,系統將通過廣播早證副本之間的數據一致性 弱一致性:沒有做出保證的情況下,所有的更新會通過廣播的形式傳遞,展現給不同客戶端的數據順序可能是不一樣
阻抗匹配:為一個給定問題找到一個理想的解決方案,除了使用通用的解決方案,還應該知道有什么可用的解決方案,從而找到最適合解決該問題的系統
2.表、行、列和單元格 最基本的單位是列,一列或多列形成一行,并由唯一的行健(row key)來確定存儲,一個表有若干行,其中每列可能有多個版本,在每個單元格中存儲了不同的值 一行由若干列組成,若干列又構成了一個列族,一個列族的所有列存儲在同一個底層文件中,這個存儲文件叫做HFile,列族需要在表創建的時候就定義好,常見的引用列的格式為family:qualifer,列族的數量有限制,但是列的數量沒有限制,列值也沒有長度和類型的限制 在Hbase中空值是沒有任何消耗的,它們不占用任何的存儲空間 每列或每個單元格的值都具有時間戳,默認由系統指定,也可以由用戶顯示設置 BigTable和Hbase的典型使用場景是webtable,存儲從互聯網中抓取的網頁 行數據的存儲操作都是原子的,可以讀寫任意數目的列,目前還不支持跨行事務和跨表事務
3.自動分區 Hbase中擴展和負載均衡的基本單元稱為region,region本質上是以行健排序的連續存儲的區間
4.存儲API API提供了建表、刪表、增加列族和刪除列族的操作,同時還提供了修改表和列族元數據的功能 scanAPI提供了高效遍歷某個范圍的行的功能 在服務器的地址空間中執行來自客戶端的代碼,支持這種功能的服務器框架叫做協處理器(coprocessor)
5.實現 每次更新數據時,都會先將數據記錄在提交日志上(commit log)中,在Hbase中這叫預寫日志(write-ahead log,WAL),然后才將這些數據寫入內存中的memstore中,到超過給定的最大值值,就寫到磁盤的HFile文件,HFile是不可被改變的 合并HFile機制 minor合并:將多個小文件(默認最小3個,最大10個)重寫到數據較少的大文件中,每個HFile都是經過歸類的,所以合并的速度很快,只受磁盤IO的影響 major合并:將一個region中一個列族的若干個HFile重寫到一個新的HFile中,major合并能掃描所有的鍵值對,順序重寫全部的數據
二、客戶端API:基礎知識 1.概述 Hbase主要的客戶端接口是有org.apache.hadoop.hbase.client包中的HTable提供的HTable類提供的,通過這個類用戶可以向Hbase存儲和檢索數據 所有修改數據的操作都保證了行級別的原子性 創建HTable實例是有代價的,每個實例都需要掃描.META.表,以檢查該表是否存在,是否可用,以及一些其他操作,因此推薦用戶在每個線程(在開始時)只創建一次HTable實例,而后在客戶端應用的生存期內復用這個對象,如果用戶需要使用多個HTable實例,應考慮使用HTablePool類 Hable(Configuration conf,"tableName")
2.CRUD操作 2.CRUD操作 2.1 put方法:向Hbase存儲數據 1)調用HTable的put方法格式: void put(Put put)或void put(List<put> puts) Put對象的構造方法如下 創建Put實例之后,就可以使用add方法 向該實例添加數據了,每一次調用add()都可以特定的添加一列數據,如果再加上一個時間戳選項,就能形成一個數據單元格。每個KeyValue實例包含器完成地址(行健、列族、列以及時間戳)和實際數據,KeyValue是Hbase在存儲架構中最底層的類 可以使用如下方法檢查是否存在特定的單元格,而不需要遍歷整個集合 通過客戶端訪問配置文件 當你調用任何一個靜態create()方法時,代碼會嘗試使用當前的java classpath來載入兩個配置文件hbase-default.xml和hbase-site.xml
Hbase的一個特殊功能是能為一個單元格存儲多個版本的數據,這個版本使用一個時間戳,必須確保所有服務器的時間都是正確的,并且相互之間是同步的,默認情況下Hbase會保留3個版本的數據 若需要頻繁的修改某些行,用戶有必要創建一個RowLock實例來防止其他用戶訪問這些行
2)KeyValue類 數據和坐標都是以java的byte[]形式存儲的,使用這種類型的目的是允許存儲任意類型的數據
3)客戶端的寫緩沖區 每一個put操作實際上都是一個RPC操作,它將客戶端數據傳送到服務器后返回,這只適合小數據量的操作,Hbase的API配備了一個客戶端的寫緩沖區(write buffer),緩沖區負責收集put操作,然后調用RPC操作一次性將put送往服務器,全局交換機制控制著該緩沖區是否在使用,其方法如下 void setAutoFlush(boolean autoFlush) 默認情況下,客戶端緩沖區是禁用的,可以通過將autoflush設置為false來激活緩沖區,通過setBufferSize(long size)來配置客戶端寫緩沖區的大小,默認大小是2M,為每一個用戶創建的HTable實例都設置緩沖器大小十分麻煩,可以在hbase-site.xml中添加一個較大的預設值,配置如下 <property> <name>hbase.client.write.value</name> <value>20971520</value> </property>
當需要強制把數據寫到服務器端時,用flushCommit()函數 隱式刷寫:在用戶調用put()或setBufferSize()時觸發,這兩個方法都會將目前占用的緩沖區大小和用戶配置的緩沖區大小進行比較,此外調用HTable的close()也會無條件地隱式刷寫 用戶可以通過訪問ArrayList<Put> getWriteBuffer()來訪問客戶端寫緩沖區的內容 如果用戶只存儲大單元格,那么客戶端緩沖區的作用就不大了 4)Put列表 調用void put(List<put> puts)時,客戶端先把所有的Put實例插入到本地寫緩沖區中,然后隱式的調用flushCache(),如果其中有失敗的Put實例(有些檢查是在客戶端完成的,如確認Put實例的內容是否為null或是否指定了列),那么后面的Put實例不會被添加到緩沖區,也不會觸發刷寫命令,當使用基于列表的Put調用時,用戶需要特別注意:用戶無法控制服務器執行put的順序,如果要保證寫入的順序,需要小心地使用這個操作。
5)原子性操作compare-and-set 有一種特別的put調用,其能保證自身操作的原子性:checkAndPut(row,family,qualifier,value,Put put),這種有原子性的操作經常被用于賬戶結余,狀態轉換或數據處理等場景 有一種特別的檢查通過checkAndPut()調用來完成,即只有在另外一個值不存在的情況下,才執行這個修改,要執行這種操作只需要將參數value設置為null Hbase提供的compare-and-set操作,只能檢查和修改同一行數據
2.2 get方法:客戶端獲取已存儲數據的方法 Result get(Get get); 1)單行Get 構造Get實例: Get(rowkey) Get(rowkey,RowLock rowLock) 可以通過多種標準篩選目標數據: Get addFamily(family):只能取得一個指定的列族 Get addColumn(family,qualifier):獲取指定的列 Get setTimeRange(long minStamp,long masStamp)、 Get setTimeStamp(long timeStamp) Get setMaxVersions(int maxVersions)
2)result類 get()返回的結果包含所有匹配的單元格數據,被封裝成一個Result類 常用方法: byte[] getValue(family,qualifier):取得特定單元格的值 byte[] value():返回第一列對應的最新單元格的值 byte[] getRow():返回行健 int size():檢查是否有對應的記錄 boolean isEmpty():檢查是否有對應的記錄 KeyValue[] raw() List<KeyValue> list():用戶可以方便的迭代數據 List<KeyValue> getColumn(family,qualifier) KeyValue getColumnLatest(family,qualifier) boolean containsColumn(family,qualifier) NavigableMap<byte[],NavigableMap[],NavigableMap<Long,byte[]>>> getMap():把請求返回的內容都裝入一個Map類實例中,可以遍歷所有結果
3)get列表 Result[] get(List<Get> gets); boolean exists(Get get):查看存儲的數據是否存在 getRowOrBefore(row,family):
2.3 刪除方法 1)單行刪除 void delete(Delete delete) Delete實例構造方法 Delete(rowkey) Delete(rowkey,long timestamp,RowLock rowLock) 常用方法 Delete deleteFamily(family[,long timestamp]) Delete deleteColumns(family,qualifier[,long timestamp]):沒指定timestamp,則刪除所有版本 Delete deleteColumn(family,qualifier[,long timestamp]):沒指定timestamp,則刪除最新版本
2)Delete的列表 void delete(List<Delete> deletes)
3)原子性操作compare-and-delete boolean checkAndDelete(row,qualifier,value,Delete delete)
2.4批處理操作 事實上許多基于列表的操作都是基于batch()方法是實現的。 方法: void batch(List<Row> actions,Object[] results) Object[] batch(List<Row> actions) 注:不可以將針對同一行數據的Put和Delete操作放在同一個批處理請求中 Row是Put、Get、Delete類的父類 當用戶使用batch()功能時,Put實例不會被客戶端寫入緩沖區中緩沖,batch()請求是同步的,會把操作直接發送給服務器 兩種方法相同點: get、put、delete操作都支持,如果執行時出現問題,客戶端將拋出異常并報告問題,都不適用客戶端的寫緩沖區 不同點: void batch(acitons,results):能訪問成功操作的結果,同時也可以獲取遠程失敗的異常 Object[] batch(actions):只返回客戶端異常,不能訪問程序執行中的部分結果 注:在檢查結果之前,所有的批處理操作都已經執行了:即使用戶收到異常,其他的操作也都已經執行了 批量處理可以感知暫時性錯誤(如NoServingRegionException)會多次重試這個操作,用戶可以通過調整hbase.client.retries.number配置項(默認為10)來增加或減少重試次數
2.5 行鎖 region服務器提供一個行鎖的特性,保證了只有一個客戶端能獲取一行的數據相應的鎖,同時對該行進行修改。用戶應該盡可能的避免使用行鎖,如果必須使用,那么一定要節約占用鎖的時間 Get不需要鎖:服務器應用了一個多版本的并發控制機制來保證行級讀操作,只有當一個變動被應用到整個行之后,客戶端才能讀出這個改動,當改動進行中時,所有的客戶端讀取到的數據都是將是所有列以前的版本
2.6 掃描 類似于數據庫中的游標 ResultScanner getScanner(Scan scan) ResultScanner getScanner(family) ResultScanner getScanner(family,qualifier) scan類的構造器 Scan() Scan(startRow,Filter filter) Scan(startRow) Scan(startRow,stopRow) 注:如果用戶只需要數據的子集,那么限制掃面的范圍就能發揮Hbase的優勢,如果不讀取整個列族,那么整個列族的文件都不會讀取,這就是列族存儲架構的優勢 1)ResultScanner類 掃描操作不會通過一次RPC請求返回所有匹配的行,而是以"行"為單位進行返回 Result next() Result[] next(int nbRows) void close() 要確保盡早釋放掃描器實例,當使用完ResultScanner之后應調用它的close()方法,釋放所有由掃描器控制的資源 就像行級鎖一樣,掃描器也使用同樣的租約超時限制,保護其不被時效的客戶端阻塞太久,通過如下配置 <property> <name>hbase.regionserver.lease.period</name> <value>120000</value> </property> 2)緩存與批量處理 如果一次RPC請求可以返回多行數據,這樣使用掃描器更有意義,可以由掃描器緩存實現,默認情況下,這個緩存是關閉的。可以從兩個層面打開它 在表的層面,這個表的所有掃描器實例的緩存都會生效,用戶使用一下的Htable方法設置表級的掃描器緩存: void setScannerCaching(int scannerCaching), int getScannerCaching():默認是1 在掃描器層面,這樣只會影響當前的掃描實例,用戶使用一下的Scan類的方法設置掃描器級的掃描器緩存: void setCaching(int scannerCaching) int getCaching():默認是1 此外用戶可以修改整個集群的配置 <property> <name>hbase.client.scanner.caching</name> <value>10</value> </property> 這樣所有scan的實例的掃描器緩存就都被設置為10了 注:當數據量非常大的行,可能超過客戶端進程的內存容量,解決方法:使用Scan類的批量操作 setBatch(int batch) int getBatch() 緩存是面向行一級的操作,而批量是面向列一級的操作。
2.8 各種特性 1)Htable使用方法 void close():使用完一個HTable實例后,需要調用一次close(),它會刷寫所有客戶端緩沖的寫操作 HTableDescriptor getTableDescripor():每個表都使用一個HTableDescriptor實例類來定義表結構 Map<HRegion,HServerAddress> getRegionInfo():獲取某一行數據的具體位置信息
三、客戶端API:高級特性 1.過濾器 Get和Scan兩個類都支持過濾器,過濾器的基本接口叫做Filter,用戶還可以通過繼承Filter類實現自己的需求 1.1 比較運算符 1.2 比較器 1.3 Hbase提供的第一類:比較過濾器 用戶創建實例時需要一個比較運算符和一個比較器實例 CompareFilter(CompareOp op,WriteableByteArrayComparable valueComparator)
- 行過濾器(父類為比較過濾器)RowFilter
- 列族過濾器(父類為比較過濾器)FamilyFilter
- 列名過濾器(父類為比較過濾器)QualifierFilter
- 值過濾器(父類為比較過濾器)ValueFilter
- 參考列過濾器(父類為比較過濾器)DependentColumnFilter:可以把它理解為一個ValueFilter和一個時間戳過濾器的組合
1.4 Hbase提供的第二類:專用過濾器
- 單列值過濾器:SingleColumnValueFilter,用一列的值決定是否一行數據被過濾
- SingleColumnValueFilter(family,qualifier,CompareOp op,value)
- 單列值排除過濾器:SingleColumnValueExcludeFilter
- 前綴過濾器:PrefixFilte(byte[] prefix):返回所有與前綴匹配的行
- 分頁過濾器:PageFilter(int pageSize):用戶可以使用這個過濾器對結果進行分頁。當用戶創建分頁過濾器實例時,需要執行pageSize參數,注:物理上分離的服務器中并行執行過濾器操作時,需要注意,在不同的region服務器上并行執行的過濾器操作不能共享它們現在的狀態和邊界,因此每個過濾器都會在完成掃描前獲取pageCount行的結果,這種情況可能使分頁過濾器可能失效
- 行健過濾器:KeyOnlyFilter:只返回結果中的鍵
- FirstKeyOnlyFilter:訪問一行中第一列,這種過濾器通常用在行數統計的應用場景中
- InclusiveStopFilter(byte[] endRow):掃描操作中的開始行被包含在結果中,但終止行被排除在外,使用這個過濾器時,用戶可以將結束行包含在結果中
- 時間戳過濾器:TimestampFilter(List<Long> timestamps):當用戶需要在掃描結果中對版本進行細粒度的控制時,可以使用該過濾器
- 列計數過濾器:ColumnCountGetFilter(int limit,int offset):限制每行最多取回多少列,不太適合掃描操作,適合get()方法
- 列分頁過濾器:ColumnPaginationFilter(int limit,int offset):可以對一行的所有列進行分頁,它將跳過所有偏移量小于offset的列,并包含之后所有偏移量在limit之前(包含limit)的列
- 列前綴過濾器:ColumnPrefixFilter(byte[] prefix)
- 隨機行過濾器:RandomRowFilter(float chance)change在0到1之間
1.5 附加過濾器(應用在其他過濾器上) 跳轉過濾器:SkipFilter(Filter filter):當被包裝的過濾器遇到一個需要過濾的KeyValue時,用戶可以擴展并過濾整行數據 全匹配過濾器:WhileMatchFilter
1.6 FilterList 需要多個過濾器共同限制返回到客戶端的結果 FilterList(List<Filter> rowFilters) FilterList(Operator op) FilterList(List<Filter> rowFilters,Operator op) 參數rowFilters以列表的形式組合過濾器,參數operator決定了組合它們的結果,默認是為MUST_PASS_ALL,使用ArrayList可以保證過濾器的執行順序與它們添加到列表中的順序一致
1.7 自定義過濾器 用戶可以實現Filter接口或者直接繼承FilterBase類
用戶自定義過濾器部署 編寫代碼-->打成jar包-->把文件發送到每個region服務器上-->修改hbase-env.sh文件如下 export HBASE_CLASSPATH="/hbase-book/target.aa.jar"-->重啟hbase
2 計數器 2.1 簡介 許多收集統計信息的應用有點擊流和在線廣告意見,這些需要被收集到日志文件中用戶后續的分析,用戶可以使用計數器做實時統計,從而放棄延遲較高的批處理操作 雖然用戶可以一次更新多個計數器,但是它們必須屬于同一行,更新多個計數器需要通過獨立的API調用,即多個RPC請求 初始化計數器:用戶不用初始化計數器,當用戶第一次使用計數器時,計數器自動設置為0,即當用戶創建一個新列時,計數器的值是0 在shell中操作計數器使用incr '<table>','<row>','<column>',[increment-value]與get_counter '<table>','<row>','<column>' 客戶端API操作計數器 1)單計數器 只能操作一個計數器:用戶需要自己設定列,方法由HTable提供的 long incrementColumnValue(row,family,qualifier,long amount) long incrementColumnValue(row,family,qualifier,long amount,boolean writeToWAL) 2)多計數器 Result increment(Increment increment) 需要創建一個Increment實例,構造方法如下 Increment() Increment(row) Increment(row,RowLock rowLock) 向其中加入實際的計數器:addColumn(family,qualifier,long maxStamp)
3.協處理器 協處理器允許用戶在region服務器上運行自己的代碼,也就是允許用戶執行region級的操作,并可以使用如觸發器類似的功能 另一類適合使用協處理器的場景就是權限控制 協處理器框架提供了一些類,用戶可以通過繼承這些類擴展自己的功能,主要有兩類,即observer和endpoint observer:回調函數(也被稱為鉤子函數,hook)在一些特定時間發生時。這些事件包括用戶產生的事件和服務器內部自動產生的事件 RegionObserver:用戶可以用這種處理器處理數據修改事件,它們與表的region聯系緊密 MasterObserver:可以被用作管理或DDL類型的操作,這些是集群級事件 WALObserver:提供控制WAL的鉤子函數
endpoint:通過添加一些遠程調用來動態擴展RPC協議,可以把它理解為與RDBMS中類似的存儲過程。endpoint可以與observer的實現組合起來直接作用于服務器的狀態
Coprocesspor類 所有協處理器的類都必須實現這個接口,它定義了協處理器的基本預定。提供了兩個被應用于框架的枚舉類Priority(SYSTEM,USER)和State 待續!!!!
4.HtablePool 為Hbase集群提供一個客戶端連接池,用戶可以通過以下任意一個構造器來創建池: HTablePool() HtablePool(Configuration conf,int maxSize) HtablePool(Configuration conf,int maxSize,HTableInterfaceFactory fac) HTableInterfaceFactory:用戶可以創建自定義的工廠類,例如,為Htable實例使用特定的配置,或可以讓實例完成一些初始化操作。如果用戶想自己擴展HtableInterfaceFactory,則必須實現兩個方法createHTableInterface(conf,tableName)和releaseHtableInterface 使用表實例池方式:getTable(String tableName);getTable(byte[] tableName);void putTable(HtableInterface table)
5.連接管理 每個HTable實例都需要建立和遠程主機的連接,這些連接在內部使用HConnection類表示,被HConnectionManager類管理并共享。用戶沒必要和這兩個類打交道,只需要創建一個Configuration實例,然后利用客戶端API使用這些類。 Hbase內部使用鍵值映射來存儲連接,使用Configuration實例作為鍵值映射的鍵。 HtablePool類,所有連接池中的Htable實例都自動共用一個提供的Configuration實例,共享它們的連接。 共享連接的缺點在于釋放,如果用戶不顯示關閉連接,它將一直存在,直到客戶端退出,建議用戶不在需要使用Htable時主動調用其close(),釋放資源,以下是顯式清理連接方法 deleteConnection(Configuration conf,boolean stop); deleteAllConnection(boolean stop)
四、客戶端API:管理功能 1.模式定義 1)表:使用表的主要原因是控制表中的所有列以達到共享表內的某些特性的目的 表描述符的構造函數: HTableDescriptor(); HTableDescriptor(String name); HTableDescriptor(byte[] name); HTableDescriptor(HTableDescriptor desc);
任意不相交的系統間的遠程通信都使用到了Hadoop RPC框架,需要遠程方法中參數都實現Writeable接口,進而能夠序列化對象并遠程傳輸
2)表屬性 表名一定不能以".","-"開頭,表名只能包含拉丁字母或數字、下劃線、".","-"
列族: void addFamily(HColumnDescriptor family) boolean hasFamily(byte[] c) HColumnDescriptor[] getColumnFamilies() HColumnDescriptor getFamily(byte[] column)
文件大小限制: long getMaxFileSize() void setMaxFileSize(long maxFileSize) 如果一個列族的存儲單元已使用的存儲空間超過了大小限制,region將發生拆分,maxFileSize默認值是256M 這個參數只是大致的預期值,而在某些特殊條件下,文件大小可能超過這個預期值(一行數據不能跨region存儲)
只讀:默認所有的表都可寫,對于特殊的表來說,只讀參數有特殊的用途。調用setReadOnly(boolean readOnly)設置
memstore刷寫大小:寫操作會寫入到寫緩沖區,人后按照合適的條件順序寫入到一個新的存儲文件(磁盤)中,可以通過setMemStoreFlushSize(long memstoreFlushSize),這個memstoreFlushSize的默認值是64MB
延遲日志刷寫: Hbase有兩種將WAL保存到磁盤的方式,一種是延遲日志刷寫,另一種不是,通過setDeferredLogFlush(boolean isDeferredLogFlush),isDeferredLogFlush的默認值為false
3)列族 列族定義了所有列的共享信息,并且可以通過客戶端創建任意數量的列。定位到某個具體的列需要列族名和列名合并在一起,以:分隔,如family:qualifier 構造方法: 列族名:getName()或getNameAsString() 不能被重命名,通常的做法是新建一個列族,然后使用API從舊列族中復制數據到新列族 列族名不能以"."開頭,也不能包含":"、"\"或ISO控制符
最大版本數:所有列族都限定了每個值能夠保留的最大版本數,Hbase會移除超過最大版本數的數據,通過setMaxVersions(int maxVersion)設置,這個maxVersion默認為3.
壓縮: Hbase支持插件式的壓縮算法,允許用戶選擇最合適的壓縮算法 塊大小: 在Hbase中,所有的存儲文件都被劃分為若干個小存儲塊,這些小存儲塊在get或scan操作時會加載到內存中,通過setBlockSize(int size)設置,默認大小是64KB 注:HFile的不同于HDFS中的塊,HDFS提到的塊是用于拆分大文件以提供分布式存儲,且便于MapReduce框架進行并行計算的存儲單元;而HBase中的塊主要用于高效加載和緩沖數據
緩存塊: Hbase順序的讀取一個數據塊到內存緩存中,這個參數默認是為true,每次讀取的塊都會緩存到內存中,但是如果順序讀取某個特定的列族,最好將這個屬性設置為false,通過setBlockCacheEnabled(boolean blockCacheEnabled)方法設置
生存期TTL: Hbase支持版本數據保存的時間,TTL設置了一個基于時間戳的臨界值,內部管理會自動檢查TTL的值是否達到上限,在major合并過程中時間戳被判定為超過TTL的數據會被刪掉,可以通過setTimeToLive(int timestamp)方法設置,TTL的參數為秒,默認值是Integer.MAX_VALUE,理解為永久保留
在內存中:setInMemory(boolean inMemory) 將inMemory設置為true只是一種承諾,或者說高優先級。在正常數據讀取過程中,塊數據被加載到緩沖區中并長期駐留在內存中,除非堆壓力過大,這個時候才會強制從內存中卸載這部分數據
布隆過濾器: 能夠減少特定訪問模式下的查詢時間,由于這種模式增加了內存和存儲的負擔,這個模式默認為關閉狀態 復制范圍:Hbase提供跨集群同步的功能,本地集群的數據更新可以及時同步到其他集群,復制范圍參數默認為0,即這個功能處于關閉狀態。可以通過setScope(int scope)設置,1表示開啟實時同步
2.HBaseAdmin HBaseAdmin提供了創建表、列族、檢查表是否存在,修改表結構和列族結構、以及刪除表功能 構造方法:HbaseAdmin(Configuration conf)
1)表操作 建表: void createTable(HTableDescriptor desc) void createTable(HTableDescriptor desc,byte[] startKey,byte[] endKey,int numRegions) void createTable(HTableDescriptor desc,byte[][] splitKeys) void createTableAsync(HTableDescriptor desc,byte[][] splitKeys) HTable類中的方法getStartEndKey()來獲取所有region的邊界
獲取所有表的列表,以及判斷是否存在 boolean tableExists(String tableName) boolean tableExists(byte[] tableName) HTableDescriptor[] listTables() HTableDescriptor getTableDescriptor(byte[] tableName)
刪除表: void deleteTable(String tableName) void deleteTable(byte[] tableName)
在刪除表之前需要將表禁用,region服務器會先將內存中近期內還未提交的已修改的數據刷寫到磁盤,然后關閉所有region,并更新這樣表的元數據,將所有region標記為下線狀態。
2)集群管理 允許用戶查看集群當前的狀態: static void checkHBaseAvailable(Configuration) ClusterStatus getClusterStatus() void closeRegion(String regionname,String hostAndport) 注:所有可用表的region都應該是在線狀態 void majorCompact(String tableNameOrRegionName)
五、可用的客戶端 1.REST、Thrift,Avro介紹 它們都支持大量的語言,Protocol Buffer與Thrift和Avro最大的不同是它沒有自己的RPC堆,而它生成的RPC定義需要被后來其他的RPC庫使用,Hbase提供了REST、Thrift、Avro的輔助服務,它們可以實現成專門的網關服務,這些服務運行在共享或專用的機器上。Thrift和Avro都有各自的RPC實現,所以網關服務僅是在它們的基礎上進行了封裝,至于REST,HBase則采用了自己的實現,并提供了訪問存儲數據的路徑。 每個請求使用一個服務而非建立一個連接的優勢在于用戶可以復用連接來獲得最優性能。 2.交互 1)使用原生Java:直接使用HTable并通過原生的RPC調用與HBase服務器進行交互。 2)REST: 操作:基于REST服務的客戶端是在能夠與HBase通信之前需要先啟動REST網關服務,使用hbase-daemon.sh start rest命令。REST服務提供了HBase表提供的所有操作,REST服務器返回的值都經過了base64Binary編碼。 支持的格式:通過使用HTTP Content-Type和Accept頭,調用者可以自動選擇發送和接收信息的數據格式 Plain(text/plain): XML(text/xml):默認的存儲和查詢格式是XML JSON(application/json):curl -H "Accept:application/json" http://<servername>:testtable/%01%02%03/colfam1:col1
REST的java客戶端: REST服務器同樣具有全面的java客戶端API,位于org.apache.hadoop.hbase.rest.client包中,其中核心類為RemoteHTable和RemoteAdmin
3)Thrift 在使用Thrift之前需要安裝Thrift,并且需要啟動HBase提供的Thrift Server 啟動Thrift命令:hbase-daemon.sh start thrift
4)Avro 在使用Thrift之前需要安裝Avro,并且需要啟動HBase提供的Avro Server 啟動Avro命令:hbase-daemon.sh start Avro
3.批量處理客戶端 1)Mapreduce:兩種方式,原生java API或Clojure 2)Hive Hive與Hbase之前的版本需要匹配,細微的RPC變化可能影響交互 3)pig 4)Cascading
4.shell 1)命令 引用名:命令行要求在使用表名和列名時需要通過單引號或雙引號對其進行引用。 引用值:命令行支持二進制、八進制、十六進制的輸入和輸出,用戶在引用時必須使用雙引號 使用逗號分隔參數 Ruby散列屬性: 一些命令中需要設置鍵值對屬性,使用Ruby散列按照以下方式來完成 {'key1'=>'val1','key2'=>'val2',...}
DDL命令 alter 使用modifyTable()修改現有表結構
DML命令:
工具命令: assgn 分配一個region到一臺region服務器中
復制命令:
腳本: 可以使用Nagios或其他監控工具發送腳本 用戶還以使用管道的形式運行命令
5.基于Web UI 1)master的web默認端口是60010,region服務默認端口是60030
六、與Mapreduce集成 1.類 InputFormat InputFormat負責:拆分輸入數據,同時返回一個RecordReader實例,定義了鍵值對象的類,并提供了next()遍歷數據 就HBase而言,它提供了一組專用的實現,叫TableInputFormatBase,該實現的子類是TableInputFormat mapper HBase提供了一個TableMapper類,將鍵的類型強制轉換為ImmutableBytesWritable類,同時將改制的類型強制轉換為Result類型,TableMapper類沒有實現具體的功能,它只是添加了鍵值對的簽名 Reducer HBase提供了一個TableReducer類 OutputFormat Hbase提供了一個TableOutputFormat
2.支撐類 Mapreduce的支撐類與TableMapReduceUtil類一同協作在HBase上執行Mapreduce任務,它有一個靜態方法能配置作業,病并使作業可以使用Hbase作為數據源或目標
3.在HBase上的Mapreduce 當運行Mapreduce作業所需庫中的文件不是綁定在Hadoop或Mapreduce框架中時,用戶就必須確保這些庫文在作業之前已經可用,用戶一般兩個選擇:在所有的任務節點上準備靜態的庫或直接提供作業所需的所有庫 1)靜態配置: 將jar文件復制到所有節點的常用路徑中 將這些jar文件的完整路徑寫入hadoop-env.sh配置文件中,按照如右方式編輯HADOOP-CLASSPATH變量:HADOOP-CLASSPATH="<extra-entries>":HADOOP-CLASSPATH 重啟所有的任務的NodeManager使變更生效 2)動態配置:Hadoop有一個特殊的功能,它可以讀取操作目錄中/lib目錄下所包含的所有庫的jar文件,用戶可以使用此功能生成所謂的胖jar文件,胖jar文件使用maven的Maven Assembly插件
七、架構 1.數據查找和傳輸 1)B+樹:它的葉節點項目鏈接并且有序,能夠通過主鍵對記錄進行高效的插入、查找以及刪除,它表能為一個動態、多層并由上下界的索引,同時要注意維護每一段所包含的鍵數目
2)LSM樹(log-structured merge-tree):輸入數據首先存儲在日志文件,這些文件內的數據完全有序,當有日志文件被修改時,對應的更新會被保存在內存中加速查詢,修改數據文件的操作通過滾動合并完成。
2.存儲 1)概覽 注:HBase主要處理兩種文件:一種是WAL文件,另一種是實際的數據文件,這兩種文件都是由HRegionServer管理
2)讀取數據流程
- 聯系ZooKeeper子集群(quorum),通過ZooKeeper獲取含有-ROOT-表的region服務器來查找行健
- 通過含有-ROOT-的region服務器可以查詢到含有.meta.表中對應region服務器名,其中包內含請求的行健信息
- 以上信息都會緩存下來,只查找一次
- 通過查詢.META.服務器來獲取客戶端查詢的行健數據所在的region服務器,HBase會存儲這次查詢的信息
HRegionServer負責打開region,并創建一個對應的HRegion實例,它會為每個表的HColumnFamily創建一個Store實例,每個Store實例包含多個StoreFile(HFile的輕量級封裝)和一個MemStore,一個HRegionServer共享一個HLog實例
3)寫路徑
- 用戶發送HTable.put()請求到HRegion實例來大處理
- 決定數據是否需要寫到HLog類實現的預寫日志中,其中WAL是標準的Hadoop SequenceFile,并且存儲了HLogKey實例,這些鍵包含序列號和實際數據
- 一旦數據寫入到WAL中,數據就會放到MemStore中,同時檢查MemStore是否已經滿了,如果滿了就刷寫到磁盤中去。書寫請求由另一個HRegionServer的線程處理,生成一個新的HFile
4)region拆分
- 當region的存儲文件大于hbase.hregion.max.filesize大小或嫘祖層面的配置的大小時,region會被一分為二
- 為新region創建兩個對應的文件,每個region為原region的一半,通過在父region中創建split目錄來完成。
- 關閉該region,此后該region不再接受任何請求。
- region服務器通過split目錄中設立必需的文件接受來準備新的子region,包括新region的目錄和參考文件。
- 把這兩個新region目錄移動表目錄
- .META.表中父region的狀態會被更新,以表示其現在拆分的節點和子節點是什么
- 兩個子region準備好后,將會被同一個服務器并行打開,打開的過程包括更新.META.表,同時也會初始化為兩個region并對region中的內容進行合并,合并過程中替換引用文件之前會把父region的存儲文件異步重寫到兩個子region中,在region的.tmp目錄進行
- 最終父region被清理,master被告知查分的情況,并且可以由于負載均衡而把新region移動到其他的HRegionServer上
5)合并 minor合并:負責重寫最后生成的幾個文件到一個更大的文件中,文件數量有hbase.hstore.compaction.min決定,默認值是3,minor合并處理的最大文件數默認為10,用戶可以通過hbase.hstore.compaction.max來配置 major合并:把所有文件壓縮成一個單獨的文件,在memstore被刷寫到磁盤后出發檢查,或shell命令major-compact后觸發,配置相關參數 hbase.hregion.majorcompaction(默認為24小時)和hbase.hregion.majorcompaction.jitter(默認為0.2)
6)HFile 注:文件長度可變,唯一固定的塊是File Info和Trailer,Trailer是指向其他快遞的指針,塊大小是由HColumnDescriptor配置的,該配置可以在創建表的時候由用戶指定,默認大小時64K,每一個塊都包含一個magic頭部和一定數量的序列化的KeyValue實例
7)WAL WAL存儲了對數據的所有更改,實現了WAL的類叫HLog類,HLog類的一個特性就是跟蹤修改,通過使用序列號來實現
3.ZooKeeper HBase使用ZooKeeper作為其協同服務組件,其主要功能包括跟蹤region服務器、保存root region的地址等 HBase建立的znode列表,默認為/hbase,這個znode的名稱由zookeeper.znode.parent屬性決定, 以下是znode的列表以及他們的作用 /hbase/hbaseid:包括clusterID,與存儲在HDFS上的hbase.id文件內容相同。 /hbase/master:包含服務器名稱 /hbase/replication:包含副本信息 /hbase/root-region-server:包含-ROOT-region所在的region服務器的機器名,這個經常在region定位中使用 /hbase/rs:所偶region服務器的根節點,集群使用它來跟蹤服務器異常 /hbase/shutdown:集群的啟動事假和關閉時間 /hbase/table:當表被禁用,信息會被添加到這個znode之下
4.復制 HBase復制可以作為一種災難恢復的方法,并且可以提供HBase層的高可用性 HBase復制中最基本的機構模式是"主推送",因為每個region服務器都有自己的WAL,所以很容易保存現在正在復制的位置 注:參與復制的集群可以不相等,主機群會通過隨機分配盡量均衡從集群的負載
1)常規處理 客戶端發送Put、Delete、或Increment到region服務器,這些請求包含的鍵值對會被region服務器轉化為WALEdit,同時WALEdit會被復制程序檢查,并以列族為單元復制數據。修改被添加到WAL中,并把實際數據添加到Memstore。 2)沒有反饋的從集群 如果從集群的region服務器沒有響應rpc請求,主集群的region服務器將會睡眠并按照配置的次數重試。如果從集群的region服務器還是不可用,主機全會重新選擇一臺其他的機器來提交修改 3)挑選要復制的目標集群 主集群的region服務器連接從集群的ZooKeeper群組,然后掃描/hbase/rs目錄來發現所有可用的并隨機選擇一部分服務器來復制數據(默認是10%)
八、高級用法 1.rowkey設計 1)高表與寬表 HBase中的表可以設計為高表和寬表,前者指表中列少兒行多,后者則正好相反。用戶應當盡量將需要查詢的維度或信息存儲在行健中,應為用它篩選的效率最高 此外,HBase只能按行分片,因此高表更有優勢
2)時間序列:當處理流式事件時,最常用的就是按時間序列組織數據,這些數據會被有序的存儲在一個特定的范圍內,到時系統產生讀寫熱點,解決這個問題的方法就是想辦法將數據分散到所有的region服務器上,有很多中方法,例如在行鍵前價格,通常情況下如下選擇
- salting方式:prefix=Long.hashCode(timestamp) % <number of regionservers>
- 字段變換/提升字段:如果用戶設計的行鍵包含多個字段則可以調整它們的位置
- 隨機化:rowkey=MD5(timestamp),隨機化很適合每次只讀取一行數據的應用,如果用戶不需要連續掃描而只需要隨機讀取,可以考慮這種策略
時間順序關系 每個列族下的列可以作為輔助索引單獨進行排序,主要內容在主要的列族下,索引放在另外一個列族下,為了編碼創建太多的列族,可以把所有輔助索引存儲在有一個單獨的列族下,同時列鍵的最左端使用索引ID這個前綴來表示不同的順序
2.輔助索引 輔助索引存儲了新坐標和現有坐標之間的映射關系,一些為可行的解決方案 由客戶端管理索引: 把責任完全轉移到應用層的典型做法是把一個數據表和一個查找/映射表結合起來,每當程序寫數據表的時候,它也同時更新映射表(輔助索引表)。讀數據時可以直接在主表進行查詢,從輔助索引表中先查找原表的行鍵,再在原表中讀取實際數據。優點:用戶可以按照需求設計映射表。缺點:Hbase不能保證跨行操作的原子性 用戶可以自由設計主索引和輔助索引之間的映射關系時,必須接受的缺點是用戶需要實現所有存儲和查找數據必需的方法
帶索引的事務型HBase 開源的ITHBase,擴展了HBase,最核心的擴展是增加了保證所有輔助索引,提供了一個IndexedTableDescriptor,提供了數據表的輔助索引操作支持,大多數類被添加了索引支持功能的類替換了
帶索引的HBase IHBase是完全在內存中維護索引,索引永遠都是同步的,不需要額外的事務控制,索引的定義由IdxIndexDescriptor類完成
3.搜索集成 使用任意關鍵字來搜索數據,滿足這種需要往往是集成一個完整的搜索引擎 Lucene:獨立于HBase使用的Lucene或其他派生類的解決方案可以通過Mapreduce建立索引。 HBasene:選擇的方法是直接在HBase內部建立搜索索引,同時為用戶提供Lucene的API,它把每個文檔的字段、詞存儲在一個單獨的行,同時包含這個詞的文檔儲存在這一行的列中
九、監控集群 1.監控框架 每個HBase進程都會提供一系列監控指標,這些監控指標可以被各種監控API和工具使用,包括JMX和Ganglia。每種服務器都有多組監控指標,這些監控指標按子系統分組并隸屬于一種服務器 HBase使用Hadoop的監控框架,并繼承了其所有類和特性,這個框架基于MetricsContext接口來處理監控數據點的生成,并使用這些數據點監控和繪圖 1)可用的實現列表: GangliaContext:用來推送監控指標到Ganglia FileContext:將監控指標寫入磁盤上一個文件中 TimeStampingFileContext:將監控指標寫入磁盤上一個文件中,但是為每個監控指標添加一個時間戳前綴 CompositeContext:允許為監控指標生成不止一個上下文 NullContext:監控指標框架的關閉選項,使用這個上下文時,不生成也不聚合監控指標 NullContextWithUpdateThread:不生成任何監控指標,但是啟動聚合統計線程。這種上下文在通過JMX檢索監控指標時使用
多重監控指標使用MetricsRecored分組,來描述一個具體的子系統。HBase使用這些組分別來保存master、region機器,以及其他服務器的統計信息,每個組都有唯一的名字:<context-name>.<record-name>.<metrics-name>。上下文有內置的定時器來觸發并將監控指標推送至目標
2)各種指標類型: 整型值:(IV) 長整型值:(LV) 速率(R):一個代表速率的浮點型值,可以是每秒操作或者消息數 字符串:存儲靜態的,基于文本的信息。并用來報告HBase版本信息和構建時間 時間變化整型(TVI):上下文會維護一個單調遞增累加計數器。框架使用這個方法對各種消息進行技術 時間變化長整型(TVL):用于增速較快的計數器 時間變化率(TVR):需要追蹤操作數或消息的數量,以及完成操作所用的時間,通常用來計算一次操作完成的平均時間 持續型時間變化率(PTVR):添加了對持續的周期性的監控指標的必要的支持。 3)master提供的監控指標
4)region服務器監控指標: 塊緩存監控指標 塊緩存用來保存底層HFile從HDFS讀取的存儲塊。count(LV)監控指標反映了當前緩存中保存的塊數目,size(LV)監控指標時占用java堆空間大小,free(LV)監控指標時堆空間為緩存保留的可用空間,evicted(LV)反映了命中緩存總數與請求緩存總數的關系 塊緩存追蹤追蹤緩存命中hit(LV)和緩存失效miss(LV)的數目,以及命中率hit radio(LV),其反映了命中緩存總數與請求緩存總數的關系。所有讀操作使用緩存,不管用戶是否制定過將使用的塊保留在緩存中。使用setCacheBlocks()僅僅影響塊的保留策略 合并監控 compaction size(PTVR)和compaction time(PTVR)分別代表需要合并的存儲文件總大小和操作花費時間 compaction queue size:用來監測一個region服務器有多少文件當前正在排隊等待合并
memstore監控指標 memstore size MB(IV):服務器上所有memstore總共占用的堆大小 flush queue zie(IV):將要被刷寫的region的數目
存儲監控指標: store files(IV):所有存儲文件的數目 store file index MB(IV):所有存儲文件的塊索引和元數據的總和大小
I/O監控指標: fs read latency(TVR):文件系統的讀延遲 fs write latency:寫延遲 fs sync latency:統計了預寫日志記錄同步到文件系統的延遲
RPC監控指標 Ganglia 組成: Ganglia監控守護進程(gmond):監控守護進程需要在每臺需要監控的機器上運行,它搜集本地數據,準備統計,然后被其他系統拉取。通過單一或組播方網絡消息傳播的主機變化情況,使用組播方式,每個監控守護進程可以獲取集群完整狀態,所有的服務器擁有同樣的組播地址 Ganglia元數據守護進程(gmetad):元數據守護進程安裝在一個中心節點上,作為整個集群的管理節點。元數據守護進程從一個或多個監控守護進程拉去數據來獲取整個集群的狀態,然后使用RDTool將這些信息存放在一個用于輪詢的時間序列數據庫中。 GangliaPHP:展示統計信息
十、性能優化 1.垃圾回收優化 垃圾回收時master通常不會產生問題,只需要添加到region服務器的啟動參數中。 用戶可以通過向hbase-env.sh配置文件中添加HBASE_OPTS或者HBASE_REGIONSERVER_OPTS變量來設置垃圾回收的相關選項。后者僅影響region服務器進程,也是推薦的修改方式 指定新生代的方式:-XX:MaxNewSize=128m -XX:NewSize=128m或-Xmn128m 注意:默認值對于多數region服務器面對的負載還是太小,所以她必須增大
建議在JRE日志中輸入垃圾回收的詳細信息,通過添加以下JRE選項: -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -Xloggc:$HBASE-HOME/logs/gc-hbase.log 該日志不會按日期定時滾動,需要手動處理(例如:使用基于crontab的每日滾動轉存任務)
通過不同的JRE參數來指定不同的垃圾回收實現策略,推薦的值是: -XX:+UseParNewGC and -XX:+UseConcMarkSweepGC UseParNewGC:停止運行java進程二期清空年輕代堆 ConcMarkSweepGC:不停止java進程的情況下異步并行的完成工作
2.預拆分region 管理接口中createTable()方法或shell中的create命令可以接受列表形式提供的拆分行健作為參數
3.負載均衡: master有一個內置的叫做均衡器的特性,在默認的情況下,均衡器每五分鐘運行一次,可以通過hbase.balancer.period屬性設置 均衡器有一個可以限制自身運行時間的上限,用戶可以通過hbase.balance.max.balancing屬性來設置,默認為均衡器間隔周期的一半
4.合并region HBase集成了一個工具能夠讓用戶在集群沒有工作時河北那個兩個相鄰的region,工具為org.apache.hadoop.hbase.util.Merge
5.客戶端API:最佳實踐 1)禁止自動刷寫:當有大量的寫入操作時,使用setAutoFlush(false)方法,確認HTable自動刷寫的特性已經關閉,如果禁用了自動刷寫,add(Put)操作指導寫緩沖區被填滿時才會被送出,可以調用HTable的flushCommits()方法顯式刷寫數據,調用HTable的close()也會隱式調用flushCommits() 2)使用掃面緩存:如果HBase被用作一個MapReduce作業的輸入源,請最好將作為MapReduce作業輸入掃描器實例的緩存用setCaching()方法設置為比默認值1大得多的值,使用默認值意味著map任務處理每條記錄都請求region服務器 3)限定掃描范圍 當Scan用來處理大量行時注意哪些屬性被選中了,從而限制掃描范圍 4)關閉ResultScanner 如果用戶忘記關閉由HTable.getScanner()返回的ResultScanner實例,則可能對服務器端造成影響,一定要在try/catche的finally塊中關閉ResultScanner 5)塊緩存用法 Scan實例通過setCacheBlock()方法來設置使用region服務器中的塊緩存,如果MapReduce作業中使用掃描,這個方法應當被設為false,對于那些頻繁訪問行的行,建議使用塊緩存 6)關閉Put上WAL 提高吞吐量方式,使用Put的writeToWAL(false)來關閉WAL,不過一旦region服務器故障就會丟失數據
6.配置 1)減少Zookeeper超時 默認在region服務器和ZooKeeper集群之間的超時時間是3分鐘,通過zookeeper.session.timeout屬性設置,在改變值之前,確認用戶服務器上JVM的垃圾回收機制是受控的 2)增加處理線程 hbase.regionserver.handler.count屬性定義了響應外部用戶訪問數據表請求的線程數,默認值10有些偏小,將這個值設置的高也有可能產生問題,并發的寫請求造成壓力 3)增加堆大小 如果用戶使用更好的服務器,可以給HBase分配8G內存或更大,用戶可以在hbase-env.sh文件中調整HBASE_HEAPSIZE的設置,master會默認1GB的堆運行,region服務器則會按照用戶單獨指定的堆空間運行 4)啟動數據壓縮 用戶應當為存儲文件啟動壓縮,尤其推薦使用Snappy或LZO壓縮 5)增加region大小 默認region大小為256M,用戶可以增加其大小,但是該參數的大小要仔細評估 6)調整塊緩存大小 控制堆中塊緩存大小的屬性是一個浮動點數類型的百分比,默認值是20%,可以通過perf.hfile.block.cache.size屬性改變這個值,看看是否存在許多塊被換出的情況,如果存在,則可以考慮增加塊緩存的大小。用戶負載大多數為讀請求是另一個增加緩存大小的原因。 7)調整memstore限制 內存存儲占用的堆大小用hbase.regionserver.global.memstore.upperLimit屬性來配置,默認值為40%,此外hbase.regionserver.global.memstore.lowerLimit屬性(默認為35%)用戶控制當服務器清空memstore之后剩余的大小,當用戶主要在處理讀請求時,可以考慮通知減少memstore的上線限來增加塊緩存的空間 8)增加阻塞時存儲文件數目 這個值通過hbase.hstore.blockingStoreFiles屬性來設置的,它決定了當存儲文件的數據達到閾值時,更新操作將會被阻塞,當應用經常遇到大負載的突發寫請求時,用戶可以稍微增加這個值來應對這種情況,其默認值是7 9)增加阻塞倍率 屬性hbase.hregion.memstore.block.multiplier的默認值是2,當memstore達到屬性multiplier乘以flush的大小限制時會阻止進一步更新 10)減少最大日志文件的限制 設置hbase.regionserver.maxlogs屬性使得用戶能夠控制基于磁盤的WAL文件數目,進而控制刷寫頻率,該參數的默認值是32
負載測試 Hbase有自己的性能評價工具,名為PE,使用命令:hbase org.apache.hadoop.hbase.PerformanceEvaluation YCSB:Yahoo的云服務基準測試系統也可用于對HBase集群進行超負荷測試
十一、集群管理 1.運維任務 1)減少節點 使用hbase-daemon.sh stop regionserver停止region服務器 如果關閉節點時負載均衡還在運行,則在復雜均衡和master恢復下線的region服務器之間可能存在競爭,要避免這種情況,使用shell命令:balance_switch false禁用負載均衡 HBase0.90.2之后引入了一種可以讓region服務器逐漸減少其負載并停止服務的方法,使用graceful_stop.sh腳本來完成 用戶也可以用graceful_stop.sh腳本來重啟服務器,并將之前屬于它的region移回原味(用戶可能選擇后者以保持數據的局部性),最簡單的滾動重啟可以使用如下命令(確認之前已經關閉負載均衡): for i in 'cat conf/regionservers|sort; do ./bin/graceful_stop.sh --restart --reload --debug $i; done $> /tmp/log.txt &
2.數據任務 1)導入/導出 HBase發布了一些有用的工具,其中兩個支持導入和導出MapReduce作業。這些工具包含在HBase的JAR文件中,用戶可以通過hadoop jar命令來獲得這些工具,使用格式:hadoop jar $HBASE_HOME/HBASE-0.91.0-SNAPSHOT.jar <command>
總結
以上是生活随笔為你收集整理的hbase权威指南学习笔记的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: 22图的遍历
- 下一篇: 【spring cloud】注解@Spr
