HBase學(xué)習(xí)筆記

在對HBase進(jìn)行操作之前帽氓,首先學(xué)習(xí)一下HBase的基礎(chǔ)架構(gòu)和運行原理。這里講解了

  • HBase 在大數(shù)據(jù)生態(tài)圈中的位置
  • HBase 與傳統(tǒng)關(guān)系數(shù)據(jù)庫的區(qū)別
  • HBase 相關(guān)的模塊以及 HBase 表格的特性
  • row-key,hfile,cloumn-family,Master,Region Server相關(guān)概念
  • zookeeper在其中的作用
  • HBase存數(shù)據(jù)的原理
  • row-key設(shè)計方案

1鱼响、Row Key
與nosql數(shù)據(jù)庫們一樣,row key是用來檢索記錄的主鍵玷室。訪問hbase table中的行嗽交,只有三種方式:

  • 通過單個row key訪問
  • 通過row key的range
  • 全表掃描

Row key行鍵 (Row key)可以是任意字符串(最大長度是 64KB醋拧,實際應(yīng)用中長度一般為 10-100bytes)慷嗜,在hbase內(nèi)部淀弹,row key保存為字節(jié)數(shù)組。
存儲時庆械,數(shù)據(jù)按照Row key的字典序(byte order)排序存儲薇溃。設(shè)計key時,要充分排序存儲這個特性干奢,將經(jīng)常一起讀取的行存儲放到一起痊焊。(位置相關(guān)性)

字典序?qū)nt排序的結(jié)果是1,10,100,11,12,13,14,15,16,17,18,19,2,20,21,…,9,91,92,93,94,95,96,97,98,99。要保持整形的自然序忿峻,行鍵必須用0作左填充。
行的一次讀寫是原子操作 (不論一次讀寫多少列)辕羽。這個設(shè)計決策能夠使用戶很容易的理解程序在對同一個行進(jìn)行并發(fā)更新操作時的行為逛尚。

2、列族 column family
hbase表中的每個列刁愿,都?xì)w屬與某個列族绰寞。列族是表的chema的一部分(而列不是),必須在使用表之前定義铣口。列名都以列族作為前綴滤钱。例如courses:history,courses:math都屬于courses這個列族脑题。
訪問控制件缸、磁盤和內(nèi)存的使用統(tǒng)計都是在列族層面進(jìn)行的。實際應(yīng)用中叔遂,列族上的控制權(quán)限能幫助我們管理不同類型的應(yīng)用:我們允許一些應(yīng)用可以添加新的基本數(shù)據(jù)他炊、一些應(yīng)用可以讀取基本數(shù)據(jù)并創(chuàng)建繼承的列族、一些應(yīng)用則只允許瀏覽數(shù)據(jù)(甚至可能因為隱私的原因不能瀏覽所有數(shù)據(jù))已艰。

3痊末、單元 Cell
HBase中通過row和columns確定的為一個存貯單元稱為cell。由{row key, column( =<family> + <label>), version} 唯一確定的單元哩掺。cell中的數(shù)據(jù)是沒有類型的凿叠,全部是字節(jié)碼形式存貯。

4嚼吞、時間戳 timestamp
每個cell都保存著同一份數(shù)據(jù)的多個版本盒件。版本通過時間戳來索引。時間戳的類型是 64位整型誊薄。時間戳可以由hbase(在數(shù)據(jù)寫入時自動 )賦值履恩,此時時間戳是精確到毫秒的當(dāng)前系統(tǒng)時間。時間戳也可以由客戶顯式賦值呢蔫。如果應(yīng)用程序要避免數(shù)據(jù)版本沖突切心,就必須自己生成具有唯一性的時間戳飒筑。每個cell中,不同版本的數(shù)據(jù)按照時間倒序排序绽昏,即最新的數(shù)據(jù)排在最前面协屡。

為了避免數(shù)據(jù)存在過多版本造成的的管理 (包括存貯和索引)負(fù)擔(dān),hbase提供了兩種數(shù)據(jù)版本回收方式全谤。一是保存數(shù)據(jù)的最后n個版本肤晓,二是保存最近一段時間內(nèi)的版本(比如最近七天)。用戶可以針對每個列族進(jìn)行設(shè)置认然。


hbase命令

安裝HBase

HBase是Google Bigtable的開源實現(xiàn)补憾,它利用Hadoop HDFS作為其文件存儲系統(tǒng),利用Hadoop MapReduce來處理HBase中的海量數(shù)據(jù)卷员,利用Zookeeper作為協(xié)同服務(wù)盈匾。所以安裝HBase之前還需要安裝zookeeper和hdfs。

如果是Apache hadoop就下載相應(yīng)文件并修改配置文件安裝毕骡。我用的是cloudera hadoo就直接在集群管理界面添加服務(wù)削饵。

HBase shell命令使用

HBase shell是HBase的一套命令行工具,類似傳統(tǒng)數(shù)據(jù)中的sql概念未巫,可以使用shell命令來查詢HBase中數(shù)據(jù)的詳細(xì)情況窿撬。安裝完HBase之后,如果配置了HBase的環(huán)境變量叙凡,只要在shell中執(zhí)行hbase shell就可以進(jìn)入命令行界面劈伴。需要注意的是HBase的交互界面刪除鍵改為了Ctrl + Backspace組合

用status命令看一下集群是否正常

查看HBase版本

  • 創(chuàng)建數(shù)據(jù)庫(命名空間)
    在HBase中,namespace命名空間指對一組表的邏輯分組狭姨,類似RDBMS中的database宰啦,方便對表在業(yè)務(wù)上劃分。HBase系統(tǒng)默認(rèn)定義了兩個缺省的namespace
    1.hbase:系統(tǒng)內(nèi)建表饼拍,包括namespace和meta表
    2.default:用戶建表時未指定namespace的表都創(chuàng)建在此
    使用名list_namespace列出所有的namespace


    使用命令create_namespace 'my_test'創(chuàng)建數(shù)據(jù)庫(命名空間)

  • 刪除數(shù)據(jù)庫
    使用命令drop_namespace 'my_test'創(chuàng)建數(shù)據(jù)庫(命名空間)

  • 創(chuàng)建學(xué)生信息表
    rowkey要求是學(xué)號赡模,一個列簇,包含姓名师抄、性別漓柑、年齡、地址叨吮。
    語法:create ‘<table name>’,’<column family>’通過list命令查看所有表辆布。

  • 刪除表
    首先使用命令disable '表名'禁用表,禁用表之后茶鉴,仍然可以通過 list 和exists命令查看到锋玲。
    然后使用命令drop '表名'刪除表

  • 插入記錄
    命令put 'student','2016211883','info:name','stu1'表示插入表名為student,rowkey為2016211880(沒有則創(chuàng)建)的行涵叮,列簇info下面的列name的值為stu1.
    按照此格式依次添加10個學(xué)生惭蹂,rowkey依次為2016211880-2016211889伞插,并同時添加姓名、性別盾碗、年齡媚污、地址。

  • 刪除記錄
    刪除某個屬性的記錄delete ‘<table name>’, ‘<row>’, ‘<column name >’, ‘<time stamp>’
    刪除行deleteall 'table_name','row'

  • 修改記錄
    命令put ‘table name’,’row ’,'Column family:column name',’new value’
    將rowkey為2016211880的info簇的name屬性修改為stu1

  • 查詢記錄
    使用命令get 'student','2016211883'查看是否成功插入記錄廷雅。
    其中第一個字段填寫查詢記錄的表耗美,第二字段填寫記錄的rowkey


    也可以使用命令get 'student','2016211883','info'獲取指定rowkey和列簇的信息

  • 掃描
    scan 命令用于查看HTable數(shù)據(jù)。使用 scan 命令可以得到表中的數(shù)據(jù)航缀。它的語法如下:
    scan ‘<table name>’

  • 統(tǒng)計表的行數(shù)
    count 'table_name'

  • 清空表
    truncate 'table_name'

Python對HBase的操作

啟動thrift

thrift是用于可伸縮的跨語言服務(wù)開發(fā)框架商架。
首先需要安裝thrift,而安裝thrift之前還需要安裝thrift的很多依賴芥玉,詳見這里甸私。
但是很多情況下已經(jīng)幫你安裝好了thrift(可能是安裝操作系統(tǒng)或者安裝hadoop的時候),所以你只需要去開啟就是了飞傀,不能開啟再去安裝。


第一次開啟報了個這個錯诬烹,原因是JAVA_HOME沒有配置或者低于1.7砸烦,所以去/etc/profile或者h(yuǎn)base的conf下hbase-env.sh加上JAVA_HOME就可以了。


就成功啟動了thrift绞吁。

編寫python程序

這里需要用pip導(dǎo)入需要的包

pip install thrift
pip install hbase-thrift

編寫好后運行說語法錯誤幢痘,但是自己的語法并沒有錯,跟著錯誤點進(jìn)了hbase包的源碼家破,發(fā)現(xiàn)是python2版本的語法颜说,在網(wǎng)上搜了一下,說是把hbase里的Hbase.py和ttypes.py換成python3的即可汰聋,于是去python存放第三方包的地方換了门粪,隨后就可以了。

from thrift.transport import TSocket,TTransport
from thrift.protocol import TBinaryProtocol
from hbase import Hbase

# thrift默認(rèn)端口是9090
socket = TSocket.TSocket('192.168.233.100',9090)
socket.setTimeout(5000)

transport = TTransport.TBufferedTransport(socket)
protocol = TBinaryProtocol.TBinaryProtocol(transport)

client = Hbase.Client(protocol)
socket.open()

print(client.getTableNames())
print(client.get('student','2016211880','info:name'))


其他的操作和HBase shell差不多烹困,只要拿到了client = Hbase.Client(protocol)中的client玄妈,其它的操作只是換成了函數(shù)調(diào)用形式而已。

  • 獲取所有表
    getTableNames()可以獲取所有表

  • 創(chuàng)建表
    createTable(tbaleName,columnFamilies):創(chuàng)建表髓梅,無返回值
    tableName:表名
    columnFamilies:列族信息拟蜻,為一個ColumnDescriptor列表

column = ColumnDescriptor(name='row1')
client.createTable('tb1',[column])

這里需要注意,不能直接像HBase shell一樣傳入字符串作為列簇枯饿,而是要先用函數(shù)ColumnDescriptor(需要導(dǎo)入from hbase.ttypes import ColumnDescriptor)生成列簇對象酝锅,然后作為參數(shù)傳入進(jìn)去。

  • 刪除表
    disableTable(tbaleName)首先禁用表
    deleteTable(tbaleName)刪除指定表
print('before',client.getTableNames())
client.disableTable('tb1')
client.deleteTable('tb1')
print('after',client.getTableNames())
  • 插入記錄
    mutateRow(tableName,row,mutations):在表中指定行執(zhí)行一系列的變化操作奢方。如果拋出異常搔扁,則事務(wù)被中止爸舒。使用默認(rèn)的當(dāng)前時間戳,所有條目將具有相同的時間戳阁谆。無返回值
    tableName:表名
    row:行
    mutations:變化,list
print('before',client.get('student','2016000','info:name'))
mutation = Mutation(column='info:name',value='inset_name') 這里需要注意碳抄,以前的參數(shù)是name和value,現(xiàn)在改為了column和value
client.mutateRow('student','2016000',[mutation])
print('after',client.get('student','2016000','info:name'))

先把需要插入的列簇信息封裝為Mutation對象(需要導(dǎo)入from hbase.ttypes import Mutation)场绿,再插入表student剖效,2016000行。

  • 修改記錄
    修改記錄和剛剛上面的插入記錄一樣焰盗,只是把需要修改的信息封裝在Mutation即可璧尸。
print('before',client.get('student','2016000','info:name'))
mutation = Mutation(column='info:name',value='update_name')
client.mutateRow('student','2016000',[mutation])
print('after',client.get('student','2016000','info:name'))
  • 查詢記錄
    getRow(tableName,row):獲取表中指定行在最新時間戳上的數(shù)據(jù)。返回一個hbase.ttypes.TRowResult對象列表熬拒,如果行號不存在返回一個空列表
    tableName:表名
    row:行
    print(client.getRow('student','2016211880'))
    [TRowResult(row='2016211880', columns={'info:add': TCell(value='xxx', timestamp=1534856603503), 'info:age': TCell(value='20', timestamp=1534856521857), 'info:gender': TCell(value='m', timestamp=1534856178334), 'info:name': TCell(value='stu0', timestamp=1534860070457)})]
    這樣可以獲取一個列的所有信息爷光,也可以獲取指定信息。
    print(client.get('student','2016211880','info:name'))
    [TCell(value='stu0', timestamp=1534860070457)]
    還可以獲取所有信息后一個一個取出來
# 行
row = '2016211880'
# 查詢結(jié)果
result = client.getRow('student',row)      # result為一個列表
for item in result:                     # item為hbase.ttypes.TRowResult對象
    print(item.row)
    print(item.columns.get('info:name').value )       # 獲取值澎粟。item.columns.get('cf:a')為一個hbase.ttypes.TCell對象
    print(item.columns.get('info:name').timestamp )   # 獲取時間戳蛀序。item.columns.get('cf:a')為一個hbase.ttypes.TCell對象
  • 掃描
    scannerOpen(tableName,startRow,columns):在指定表中,從指定行開始掃描活烙,到表中最后一行結(jié)束徐裸,掃描指定列的數(shù)據(jù)。返回一個ScannerID啸盏,int類型
    tableName:表名
    startRow:起始行
    columns:列名列表,list類型
    scannerId = client.scannerOpen('student','2016211880',["info:name","info:age"])
    獲取ScannerID后重贺,根據(jù)ScannerID來獲取結(jié)果,scannerGet(id):返回一個hbase.ttypes.TRowResult對象列表
scannerId = client.scannerOpen('student','2016211880',["info:name","info:age"])
while True:
    result = client.scannerGet(scannerId)
    if not result:
        break
    print(result)

結(jié)果

[TRowResult(row='2016211880', columns={'info:age': TCell(value='20', timestamp=1534856521857), 'info:name': TCell(value='stu0', timestamp=1534860070457)})]
[TRowResult(row='2016211881', columns={'info:age': TCell(value='18', timestamp=1534856521887), 'info:name': TCell(value='stu1', timestamp=1534855473518)})]
[TRowResult(row='2016211882', columns={'info:age': TCell(value='18', timestamp=1534856521912), 'info:name': TCell(value='stu2', timestamp=1534855311597)})]
[TRowResult(row='2016211883', columns={'info:age': TCell(value='18', timestamp=1534856521940), 'info:name': TCell(value='stu3', timestamp=1534855469567)})]
[TRowResult(row='2016211884', columns={'info:age': TCell(value='18', timestamp=1534856521969), 'info:name': TCell(value='stu4', timestamp=1534855469670)})]
[TRowResult(row='2016211885', columns={'info:age': TCell(value='18', timestamp=1534856521993), 'info:name': TCell(value='stu5', timestamp=1534855469700)})]
[TRowResult(row='2016211886', columns={'info:age': TCell(value='19', timestamp=1534856522018), 'info:name': TCell(value='stu6', timestamp=1534855469732)})]
[TRowResult(row='2016211887', columns={'info:age': TCell(value='21', timestamp=1534856522042), 'info:name': TCell(value='stu7', timestamp=1534855469761)})]
[TRowResult(row='2016211888', columns={'info:age': TCell(value='22', timestamp=1534856522191), 'info:name': TCell(value='stu8', timestamp=1534855469791)})]
[TRowResult(row='2016211889', columns={'info:age': TCell(value='21', timestamp=1534856523296), 'info:name': TCell(value='stu9', timestamp=1534855469828)})]

其它的操作都和shell差不多回懦,只是換成了函數(shù)形式气笙,使用時可以查閱API文檔。

HBase預(yù)分區(qū)

HBase中怯晕,表會被劃分為1…n個Region潜圃,被托管在RegionServer中。Region二個重要的屬性:StartKey與 EndKey表示這個Region維護(hù)的rowKey范圍贫贝,當(dāng)我們要讀/寫數(shù)據(jù)時秉犹,如果rowKey落在某個start-end key范圍內(nèi),那么就會定位到目標(biāo)region并且讀/寫到相關(guān)的數(shù)據(jù)稚晚。
HBase默認(rèn)建表時有一個region崇堵,這個region的rowkey是沒有邊界的,即沒有startkey和endkey客燕,在數(shù)據(jù)寫入時鸳劳,所有數(shù)據(jù)都會寫入這個默認(rèn)的region,隨著數(shù)據(jù)量的不斷 增加也搓,此region已經(jīng)不能承受不斷增長的數(shù)據(jù)量赏廓,會進(jìn)行split涵紊,分成2個region。在此過程中幔摸,會產(chǎn)生兩個問題:1.數(shù)據(jù)往一個region上寫,會有寫熱點問題摸柄。2.region split會消耗寶貴的集群I/O資源〖纫洌基于此我們可以控制在建表的時候驱负,創(chuàng)建多個空region,并確定每個region的起始和終止rowky患雇,這樣只要我們的rowkey設(shè)計能均勻的命中各個region跃脊,就不會存在寫熱點問題。自然split的幾率也會大大降低苛吱。當(dāng)然隨著數(shù)據(jù)量的不斷增長酪术,該split的還是要進(jìn)行split。像這樣預(yù)先創(chuàng)建hbase表分區(qū)的方式翠储,稱之為預(yù)分區(qū)绘雁。

預(yù)分區(qū)步驟

  1. 規(guī)劃hbase預(yù)分區(qū)
    首先就是要想明白數(shù)據(jù)的key是如何分布的,然后規(guī)劃一下要分成多少region援所,每個region的startkey和endkey是多少咧七,然后將規(guī)劃的key寫到一個文件中。比如任斋,key的前幾位字符串都是從2016211880~2016211889的數(shù)字,這樣可以分成4個region耻涛,劃分key的文件如下:
#只是在分區(qū)比較多的時候需要這么做废酷。分區(qū)少的情況下可以直接在生成表的時候直接用SPLITS分區(qū)
2016211882|
2016211884|
2016211886|
2016211888|

因為在ASCII碼中,"|"的值是124抹缕,大于所有的數(shù)字和字母等符號澈蟆,當(dāng)然也可以用“~”(ASCII-126)。分隔文件的第一行為第一個region的stopkey卓研,每行依次類推趴俘,最后一行不僅是倒數(shù)第二個region的stopkey,同時也是最后一個region的startkey奏赘。也就是說分區(qū)文件中填的都是key取值范圍的分隔點寥闪。

  1. HBase中建分區(qū)表,指定分區(qū)文件
    和以前創(chuàng)建普通表一樣磨淌,只是創(chuàng)建的時候多了一個參數(shù)疲憋,指明了分區(qū)的信息。
    create 'sort_table','info',SPLITS=>['2016211882','2016211884','2016211886','2016211888']
    這里的分區(qū)表示方法也可以換成文件替代梁只。
    create 'split_table_test', 'cf', {SPLITS_FILE => 'region_split_info.txt'}
    去主節(jié)點60010端口下查看分區(qū)成功缚柳。

    接著插入一條數(shù)據(jù)試一試
    put 'sort_table','2016211885','info:add','xxx'

    數(shù)據(jù)插入到了指定的分區(qū)當(dāng)中埃脏。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市秋忙,隨后出現(xiàn)的幾起案子彩掐,更是在濱河造成了極大的恐慌,老刑警劉巖灰追,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件堵幽,死亡現(xiàn)場離奇詭異,居然都是意外死亡监嗜,警方通過查閱死者的電腦和手機(jī)谐檀,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來裁奇,“玉大人桐猬,你說我怎么就攤上這事」舫Γ” “怎么了溃肪?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長音五。 經(jīng)常有香客問我惫撰,道長,這世上最難降的妖魔是什么躺涝? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任厨钻,我火速辦了婚禮,結(jié)果婚禮上坚嗜,老公的妹妹穿的比我還像新娘夯膀。我一直安慰自己,他們只是感情好苍蔬,可當(dāng)我...
    茶點故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布诱建。 她就那樣靜靜地躺著,像睡著了一般碟绑。 火紅的嫁衣襯著肌膚如雪俺猿。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天格仲,我揣著相機(jī)與錄音押袍,去河邊找鬼。 笑死凯肋,一個胖子當(dāng)著我的面吹牛伯病,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼午笛,長吁一口氣:“原來是場噩夢啊……” “哼惭蟋!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起药磺,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤告组,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后癌佩,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體木缝,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年围辙,在試婚紗的時候發(fā)現(xiàn)自己被綠了我碟。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡姚建,死狀恐怖矫俺,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情掸冤,我是刑警寧澤厘托,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站稿湿,受9級特大地震影響铅匹,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜饺藤,卻給世界環(huán)境...
    茶點故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一包斑、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧涕俗,春花似錦舰始、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽枕稀。三九已至询刹,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間萎坷,已是汗流浹背凹联。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留哆档,地道東北人蔽挠。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親澳淑。 傳聞我的和親對象是個殘疾皇子比原,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,786評論 2 345

推薦閱讀更多精彩內(nèi)容