HBase - 總結(jié)

一、HBase簡介

1.1 定義

-- 1. HBase是什么糖荒?
    1. 分布式
    2. 可擴(kuò)展
    3. 支持海量數(shù)據(jù)的存儲
    4. NoSQL的數(shù)據(jù)庫靖苇。

-- 2. 說明:
   a席噩、NoSQL: Not only SQL,不僅僅是一個數(shù)據(jù)庫
   b贤壁、是基于谷歌的三篇論文之bigtable生成的悼枢。
   c、HBase:理解為Hadoop base
   
-- 3. 大數(shù)據(jù)框架:
   a脾拆、數(shù)據(jù)的存儲:hdfs / hive / hbase
   b馒索、數(shù)據(jù)的傳輸:flume / sqoop
   c莹妒、數(shù)據(jù)的計(jì)算:tez / mr / spark / flink

-- 4. 和傳統(tǒng)數(shù)據(jù)庫的差別:
   傳統(tǒng)數(shù)據(jù)庫的結(jié)構(gòu):數(shù)據(jù)庫 --> 表 --> 行和列
   HBase的結(jié)構(gòu) : namespace(命名空間) --> table --> 列族 --> 行和列 --> orgion --> store
   HBase可以理解為多維的map,嵌套的map結(jié)構(gòu)绰上。

1.2 HBase數(shù)據(jù)模型

1.2.1 HBase邏輯結(jié)構(gòu)

1.2.2 HBase的物理結(jié)構(gòu)

1.2.3 數(shù)據(jù)模型

--1. HBase表的幾個概念
    1. 'namespace':命名空間旨怠,類似mysql的數(shù)據(jù)庫,在HBase中默認(rèn)有兩個namespace:default/HBase
    2. '列族'     :
    3. 'column'   :列蜈块,在使用時鉴腻,格式為:'列族名:列名'
    4. 'row'      :行,在HBase中百揭,行是邏輯概念上的爽哎,在物理內(nèi)存中,同一行的數(shù)據(jù)很可能不在一起的器一。
                    "那么我們通過什么參數(shù)來判斷兩個數(shù)據(jù)是不是屬于同一行呢"课锌?
                    就是下面的rowkey,rowkey相同祈秕,就表示是同一行的數(shù)據(jù)渺贤。
    5. 'rowKey'   :行的標(biāo)簽,唯一定位行的標(biāo)識             
    6. 'region'   :區(qū)域请毛,表示多行數(shù)據(jù)志鞍,在HBase中,一個table默認(rèn)是一個region
    7. 'store'    :在同一個region中获印,列族的個數(shù) = store的個數(shù),store有兩種:memstore/storefile
    8. 'timeStemp':時間戳述雾,表示數(shù)據(jù)執(zhí)行的時間,
每執(zhí)行一次操作就會生成一個版本兼丰。
    9. 'table'    :表玻孟,可以理解為多維的map,在創(chuàng)建表的時候鳍征,
只需要聲明表名和列族就可以.
                    "非常適用于非結(jié)構(gòu)化數(shù)據(jù)黍翎,不需要指定數(shù)據(jù)的格式"
    10. 'cell'    : 單元格,在表中的同一個位置'某一行的某一列位置'艳丛,會有多個cell匣掸,相同的位置每修改一次,就會生成一個cell氮双。
                    由{rowkey,列族:列名碰酝,time stamp},進(jìn)行唯一標(biāo)識戴差。

-- 2. HBase集群的幾個概念
    1. 'master':可以理解為hadoop的NM送爸,專門負(fù)責(zé)管理小弟'regionServer',實(shí)現(xiàn)類為:Hmaster
    2. 'regionServer':可以理解為hadoop的DM,專門負(fù)責(zé)管理region中的數(shù)據(jù)袭厂,還有兩個組件:WAL'可理解為NM的內(nèi)存區(qū)域的元數(shù)
                       據(jù)'和balckcache墨吓,至于具體是干嘛的,后面寫操作的時候講纹磺,實(shí)現(xiàn)類為:HRegionServer
    3. 'meta'  : 元數(shù)據(jù)帖烘,zookeeper有它的地址,某一個regionServer保存著這個數(shù)據(jù)橄杨。主要有table和region所在的位置秘症。 
    4. 'zookeeper':① master的高可用 ② RegionServer的監(jiān)控 ③ Region的元數(shù)據(jù)管理。

-- 3. 說明:
   在底層存儲時讥珍,數(shù)據(jù)按照rowkey的字典順序從小到大進(jìn)行排列历极。

二、 HBase的安裝

2.1 部署zookeeper和Hadoop

2.2 解壓HBase到指定的位置

[atguigu@hadoop105 software]$ tar -zxvf hbase-2.0.5-bin.tar.gz -C /opt/module

2.3 配置環(huán)境變量

[atguigu@hadoop105 ~]$ sudo vim /etc/profile.d/my_env.sh
  • 添加
#HBASE_HOME
export HBASE_HOME=/opt/module/hbase-2.0.5
export PATH=$PATH:$HBASE_HOME/bin

2.4 配置HBase的文件

  • 修改HBase對應(yīng)的配置文件
#export HBASE_MANAGES_ZK=true 
修改至:
export HBASE_MANAGES_ZK=false
  • hbase-site.xml增加如下配置內(nèi)容:
<configuration>
    <property>
        <name>hbase.rootdir</name>
        <value>hdfs://hadoop105:8020/hbase</value>
    </property>

    <property>
        <name>hbase.cluster.distributed</name>
        <value>true</value>
    </property>

    <property>
        <name>hbase.zookeeper.quorum</name>
        <value>hadoop105,hadoop106,hadoop107</value>
    </property>

    <property>
        <name>hbase.unsafe.stream.capability.enforce</name>
        <value>false</value>
    </property>
    
    <property>
        <name>hbase.wal.provider</name>
        <value>filesystem</value>
    </property>
</configuration>
  • 配置regionservers
hadoop105
hadoop106
hadoop107

2.5 分發(fā)HBase

[atguigu@hadoop105 module]$ xsync hbase-2.0.5

2.6 啟動HBase

先啟動hadoop集群衷佃,再啟動zk,然后啟動HBase

  • 單點(diǎn)啟動
hbase-daemon.sh start master
hbase-daemon.sh start regionserver

-daemon是指后臺啟動蹄葱。
  • 群起
[atguigu@hadoop105 hbase-2.0.5]$ start-hbase.sh

-- 說明:
   a氏义、會啟動當(dāng)前節(jié)點(diǎn)的master
   b、在所有節(jié)點(diǎn)啟動regionServer
   c图云、Hmaster和regionServer都是一個進(jìn)程惯悠。

2.7 查看HBase的頁面

網(wǎng)址:hadoop105:16010

2.8 master的高可用(可選)

  • 關(guān)閉HBase的集群
stop-hbase.sh
  • 在conf目錄下創(chuàng)建backup-masters文件
touch conf/backup-masters
  • 在backup-masters文件中配置高可用HMaster節(jié)點(diǎn)
echo hadoop106 > conf/backup-masters
  • 將整個conf目錄scp到其他節(jié)點(diǎn)
xsync conf

三、 HBase的操作

3.1 基本操作

  1. 進(jìn)入hbase的客戶端
[atguigu@hadoop105 conf]$ hbase shell
  1. 查看所有namespace中所有的表
hbase(main):001:0> list

TABLE   
test:user  #test是一個namespace
user       #沒有寫命名空間的竣况,則默認(rèn)是default
2 row(s)
Took 0.4410 seconds 
=> ["test:user", "user"]

3.2 表的操作

  1. 創(chuàng)建表
--1.語法: create 'namespace:tablename','列族1'克婶,'列族2',...
    如果是namespace是default丹泉,則可以省略
--2.實(shí)例1:hbase(main):002:0> create 'test','info','info1' 
    實(shí)例2:hbase(main):004:0> create 'test:lianzp','info'
  1. 添加數(shù)據(jù)
-- 1. 語法: put 'tablename','rowkey','列族1:列名'情萤,'value'
      說明:shell操作每次只能添加一個值
-- 2. 實(shí)例: hbase(main):008:0> put 'user','1001','info1:age',20
  1. 全局掃描數(shù)據(jù)
-- 1. 語法: scan 'tablename'
-- 2. 實(shí)例: hbase(main):009:0> scan 'user'
-- 3. 打印結(jié)果:#如下是顯示了4行數(shù)據(jù),實(shí)際上數(shù)據(jù)在表中屬于3行
     ROW                          COLUMN+CELL                                                   
     1000                        column=info2:sex, timestamp=1592894945017, value=woman                            
     1001                        column=info1:age, timestamp=1592911858092, value=20                               
     1001                        column=info1:name, timestamp=1592894905511, value=lianzp                          
     1003                        column=info1:age, timestamp=1592894925226, value=50 
  1. 掃描指定行的數(shù)據(jù)
-- 1. 語法:scan 'tablename',{STARTROW=>'rowkey',STOPROW=>'rowkey'}
-- 2. 說明:
           a摹恨、區(qū)間為左閉右開
           b筋岛、如果STARTROW沒有寫,則表示開始的rowkey為負(fù)無窮晒哄,即沒有下限睁宰,只有上限
              如果STOPROW沒有寫,則表示結(jié)束的rowkey為正無窮寝凌,即沒有上限柒傻,只有下限
           
-- 3. 實(shí)例:hbase(main):012:0> scan 'user',{STARTROW=>'1000',STOPROW=>'1003'}
            hbase(main):014:0> scan 'user',{STARTROW=>'1000'}
            hbase(main):015:0> scan 'user',{STOPROW=>'1001'}
-- 4. 結(jié)果:
         ROW                          COLUMN+CELL         
         1000                        column=info2:sex, timestamp=1592894945017, value=woman
         1001                        column=info1:age, timestamp=1592911858092, value=20         
         1001                        column=info1:name, timestamp=1592894905511, value=lianzp   
        2 row(s)
  1. 獲取某一行的數(shù)據(jù)
-- 1. 語法: get 'tablename','rowkey'
-- 2. 實(shí)例: get 'user','1001'
  1. 獲取某一行指定列的數(shù)據(jù)
-- 1. 語法: get 'tablename','rowkey','列族1:列名'
-- 2. 實(shí)例: get 'user','1001','info1:age'
  1. 獲取行的數(shù)量
-- 1. 語法: count 'tablename'
-- 2. 實(shí)例: hbase(main):001:0> count 'user'
  1. 查詢表的結(jié)構(gòu)
-- 1. 語法: describe 'tablename'
-- 2. 實(shí)例: hbase(main):002:0> describe 'user'
  1. 刪除某一行某一列的值
-- 1. 語法: delete 'tablename','rowkey'较木,'列族1:列名'
-- 2. 實(shí)例: hbase(main):002:0> hbase(main):005:0> delete 'user','1001','info1:age'
-- 3. 說明:
      a红符、一個位置默認(rèn)保留一個版本,如果一個位置被多次修改時,刪除當(dāng)前的數(shù)據(jù)违孝,再進(jìn)行查詢時刹前,在未flush的情況下,上一個版本的數(shù)據(jù)
         可以被查詢出來雌桑。
      b喇喉、此處的刪除并不是真正的刪除,只是給這個刪除的數(shù)據(jù)打上了一個標(biāo)記校坑,只有當(dāng)落盤flush的時候拣技,才會真正的被清理掉。

10 . 刪除某一行的全部數(shù)據(jù)

-- 1. 語法: deleteall 'tablename','rowkey'
-- 2. 實(shí)例: hbase(main):020:0> deleteall 'user','1001'
  1. 清除表數(shù)據(jù)
-- 1. 語法: truncate 'tablename'
-- 2. 實(shí)例:hbase(main):020:0> truncate 'user'
-- 3. 說明:
      a耍目、在執(zhí)行的過程中膏斤,首先會自動disable 'user'
      b、然后再清空表數(shù)據(jù),truncate 'user'
 -- 4. 打印結(jié)果
        Truncating 'user' table (it may take a while):
        Disabling table...
        Truncating table...
        Took 1.5164 seconds
  1. 刪除表
-- 1. 語法: drop 'tablename'
-- 2. 實(shí)例: hbase(main):020:0> drop 'user'
-- 3. 說明:
     如果直接drop表邪驮,會報(bào)錯:ERROR: Table student is enabled. Disable it first
      a莫辨、在刪除表時,需要手動將表設(shè)置為:disable 'tablename'
      b毅访、然后再刪除,drop 'tablename'
  1. 多版本
-- 1.設(shè)置多版本
   alter 'student' ,{NAME => 'info',VERSIONS => 3}
-- 2.查詢多版本
   get 'student','1001',{COLUMN => 'info:age' ,VERSIONS => 3 }

3.3 namespace操作

  1. 創(chuàng)建namespace
hbase(main):037:0> create_namespace 'lianzp'
  1. 查詢namespace
hbase(main):039:0> list_namespace
  1. 創(chuàng)建自定的namespace的表
hbase(main):042:0> create 'lianzp:test','info'
  1. 查詢指定namespace的所有表
hbase(main):044:0> list_namespace_tables 'lianzp'
  1. 刪除namespace
hbase(main):049:0> drop_namespace 'lianzp'

-- 說明:在刪除namespace之前沮榜,需要先刪除namespace的表,刪除表時喻粹,需要先將表置于不可用的狀態(tài)蟆融。

四、HBase進(jìn)階

4.1 Region Server的架構(gòu)

image.png
--1. 說明:
  a守呜、1個Region Server =  1個WAL + 1個 Block Cache + N個regoin 
  b型酥、1個Region =  1個MemStore + N個StoreFile 
  
-- 2. Region Server
  a、是一個進(jìn)程查乒,是HBase分布式的一個節(jié)點(diǎn)弥喉。
  
-- 3. WAL
  a、預(yù)防日志侣颂,存儲在hdfs上档桃,向RegionServer發(fā)送請求時,首先會經(jīng)過WAL憔晒,將具體的操作保存下來藻肄,然后再進(jìn)行具體的操作;
  b拒担、作用:當(dāng)regionServer出現(xiàn)故障時嘹屯,因?yàn)閃AL保留了具體的操作,所以數(shù)據(jù)不會丟失从撼。
  
-- 4. Block Cache
   a州弟、讀緩存钧栖,每次查詢出的數(shù)據(jù)會緩存在BlockCache中较性,方便下次查詢
 
-- 5. Region
   a甚淡、是一張表中的多行數(shù)據(jù)却汉,默認(rèn)是一個Region妓雾。
   
-- 6. Store
   a、對應(yīng)一張表中的列族的個數(shù)梢褐。
   b套么、有兩種蟹漓,分別是MemStore 和StoreFile
   
-- 7. memstore
   a最蕾、數(shù)據(jù)是先存儲在MemStore中依溯,排好序后,等到達(dá)刷寫時機(jī)才會刷寫到HFile瘟则,每次刷寫都會形成一個新的HFile

-- 8. StoreFile
   a黎炉、StoreFile以Hfile的形式存儲在HDFS上
   b、數(shù)據(jù)在每個StoreFile中都是有序的

4.2 寫流程

image.png
--1. 具體流程:
    1. Client先訪問zookeeper醋拧,請求hbase:meta元數(shù)據(jù)位于哪個Region Server中慷嗜。
    2. zookeeper返回hbase:meta所在的Region Server地址
    3. client訪問對應(yīng)的Region Server,請求hbase:meta元數(shù)據(jù)信息
    4. Region Server返回meta元數(shù)據(jù)信息
    5. client根據(jù)寫請求的namespace:table/rowkey趁仙,查詢出目標(biāo)數(shù)據(jù)位于哪個Region Server中的哪個Region中洪添。
       并將該table的region信息以及meta表的位置信息緩存在客戶端的meta cache,方便下次訪問雀费。
    6. 與目標(biāo)Region Server進(jìn)行通訊;
    7. 將數(shù)據(jù)順序?qū)懭耄ㄗ芳樱┑絎AL痊焊;
    8. WAL將數(shù)據(jù)寫入對應(yīng)的MemStore盏袄,數(shù)據(jù)會在MemStore進(jìn)行排序;
    9. 完成寫數(shù)據(jù)操作以后薄啥,向客戶端發(fā)送ack辕羽;
    10. 等達(dá)到MemStore的刷寫時機(jī)后,將數(shù)據(jù)刷寫到HFile垄惧。

-- 2. hbase:meta包含哪些信息呢刁愿?
   命令:scan ‘hbase:meta’
   a、rowkey: test,,1592911245995.c42a3b247c7ed78f071
               1) test:namespace,命名空間
               2) ,,:startkey endkey到逊,起止的rowkey
               3) 1592911245995:time stamp 铣口,時間戳
               4) .c42a3b247c7ed78f071:前面3個參數(shù)的MD5值。
   b觉壶、column=info:regioninfo : region的信息脑题,
                               value={ENCODED => c42a3b247c7ed78f071f60721bad78ad, NAME => 'test,,
 f60721bad78ad.1592911245995.c42a3b247c7ed78f071f60721bad78ad.', STARTKEY => '', ENDKEY => ''}
   c、column=info:seqnumDuringOpen :序列號铜靶,value=\x00\x00\x00\x00\x00\x00\x00\x02 
   d叔遂、column=info:server : 該region所在的server,value=hadoop106:16020
   e、column=info:serverstartcode : 該region所在的server創(chuàng)建的時間戳已艰,value=1592887276902
   f痊末、column=info:sn    : value=hadoop106,16020,1592887276902
   g、column=info:state :該region的狀態(tài)哩掺,value=OPEN 

4.3 MemStore flush時機(jī)

-- MemStore刷寫時機(jī):
    如下一共有4種刷寫實(shí)時機(jī)凿叠,任何一個時機(jī)點(diǎn)到達(dá)后均會進(jìn)行刷寫,刷寫分為:
    a疮丛、刷寫:memStore向storeFile中寫數(shù)據(jù)幔嫂。
    b、阻止寫:阻止客戶端往region中寫數(shù)據(jù)誊薄。
-- 時機(jī)1:region級別履恩,刷寫方式:當(dāng)前region中所有memstore都刷寫
    a、'刷寫':當(dāng)某個memstroe的大小達(dá)到了'hbase.hregion.memstore.flush.size'(默認(rèn)值128M)呢蔫,
               時切心,該region中所有memstore都會刷寫。
               '每一個region有多個store片吊,一個store包含了一個memStore和多個storeFile'
    b绽昏、'阻止寫':當(dāng)memstore的大小達(dá)到了'hbase.hregion.memstore.flush.size(默認(rèn)值128M)
                                    * hbase.hregion.memstore.block.multiplier(默認(rèn)值4)'
               時512MB,會阻止繼續(xù)往該memstore寫數(shù)據(jù)俏脊。
-- 時機(jī)2: regionServer級別全谤,刷寫方式:按照所有memstore的數(shù)據(jù)大小順序(由大到小)依次進(jìn)行刷寫
    a爷贫、'刷寫':當(dāng)regionserver中memstore的總大小達(dá)到
              'java_heapsize*hbase.regionserver.global.memstore.size(默認(rèn)值0.4)
              *hbase.regionserver.global.memstore.size.lower.limit(默認(rèn)值0.95)'认然,
              即 0.38 * JVM堆內(nèi)存
              region會按照其所有memstore的大小順序(由大到小)依次進(jìn)行刷寫漫萄。
              直到region server中所有memstore的總大小減小到上述值以下卷员。
    b、'阻止寫':當(dāng)region server中memstore的總大小達(dá)到'java_heapsize*hbase.regionserver.global.memstore.size'
               (默認(rèn)值0.4)時腾务,會阻止繼續(xù)往所有的memstore寫數(shù)據(jù)毕骡。
-- 時機(jī)3:時間級別:刷寫方式:默認(rèn)1H進(jìn)行刷寫               
    a、'刷寫':到達(dá)自動刷寫的時間岩瘦,也會觸發(fā)memstore flush未巫。自動刷新的時間間隔由該屬性進(jìn)行配置
            'hbase.regionserver.optionalcacheflushinterval(默認(rèn)1小時)。'
 
 -- 時機(jī)4:關(guān)閉hbase時担钮,刷寫方式:進(jìn)行刷寫
    a橱赠、'刷寫':關(guān)閉hbase即進(jìn)行刷寫。

4.4 讀流程

image.png

image.png
-- 整體的流程和寫的流程大致一致箫津,主要的區(qū)別在于:
1. 讀的位置有很多位置
      a狭姨、block cache
      b宰啦、memStore
      c、StoreFile
2. 不同的位置饼拍,均會有數(shù)據(jù)赡模,但是數(shù)據(jù)的版本可能不一樣,所以當(dāng)客戶端讀取多個版本數(shù)據(jù)時师抄,可能每個位置都需要讀取漓柑。
3. 讀取到每個位置的數(shù)據(jù)以后,然后進(jìn)行merge叨吮,將數(shù)據(jù)進(jìn)行合并辆布,最后發(fā)送給客戶端。
4. 客戶端每次讀取到的數(shù)據(jù)最后會緩存到block cache中茶鉴,緩沖內(nèi)存的大小'默認(rèn)大小為64kb'

4.5 StoreFile Compaction

image.png
--1. StoreFile文件合并的原因
  1. memstore每次刷寫都會生成一個新的HFile锋玲。--小文件
  2. 同一個字段的不同版本(timestamp)和不同類型(Put/Delete)有可能會分布在不同的HFile中
  3. 為了減少HFile的個數(shù)
  4. 清理掉過期和刪除的數(shù)據(jù)
--2. 說明:
  a、什么是過期的數(shù)據(jù)涵叮?
     table中每一個位置有保留的版本數(shù)惭蹂,同一位置進(jìn)行多次數(shù)據(jù)修改時,就會有多個版本割粮,在flush之前盾碗,數(shù)據(jù)不會丟失,在落盤時舀瓢,只會
     保留對應(yīng)版本數(shù)量的最新的數(shù)據(jù)廷雅,超過版本數(shù)量的數(shù)據(jù)就屬于過期數(shù)據(jù)。
  b京髓、什么是刪除的數(shù)據(jù)榜轿?
     使用delete刪除數(shù)據(jù)時,數(shù)據(jù)并不是真正的刪除朵锣,而是給數(shù)據(jù)打一個標(biāo)識,當(dāng)落盤時甸私,這些數(shù)據(jù)就會被過濾和刪除诚些。
  
--3. 合并分類:
  a、Minor Compaction皇型,小合并诬烹,臨近的若干個較小的HFile合并成一個較大的HFile,并清理掉部分過期和刪除的數(shù)據(jù)弃鸦。默認(rèn)是3個文件
  b绞吁、Major Compaction,大合并唬格,將一個Store下的所有的HFile合并成一個大HFile家破,并且會清理掉所有過期和刪除的數(shù)據(jù)颜说。

4.6 多版本

#創(chuàng)建一個列族的版本數(shù)為2
create 't1' ,{NAME=>'f1,VERSIONS=>2}
#獲取兩個2個版本
get 't1','1002',{CLOUMN => 'f1:age',VERSIONS => 2}

4.7 Region Split

--1. Region基本介紹
    1. 默認(rèn)一個Table汰聋,只有一個Region
    2. 隨著數(shù)據(jù)的不斷寫入门粪,Region會自動進(jìn)行拆分,'如果設(shè)定了region分區(qū)的規(guī)則烹困,那么這個默認(rèn)切分規(guī)則不會有效'
    3. 拆分以后玄妈,HMaster有可能會將某個Region轉(zhuǎn)移到其他的Region Server,涉及到數(shù)據(jù)的遷移髓梅,IO

--2. Region切分的時機(jī)
   '情況1':0.94版本之前
   當(dāng)1個region中的某個Store下所有StoreFile的總大小超過hbase.hregion.max.filesize拟蜻,該Region就會進(jìn)行拆分。
   '情況2':0.94版本之后
    2.當(dāng)1個region中的某個Store下所有StoreFile的總大小超過Min(initialSize*R^3 ,hbase.hregion.max.filesize)枯饿,該Region就會進(jìn)行拆分酝锅。其中initialSize的默認(rèn)值為2*hbase.hregion.memstore.flush.size鸭你,R為當(dāng)前Region Server中屬于該Table的Region個數(shù)
    -- 10G以前屈张,按照取最小值進(jìn)行切分,10G以后袱巨,就每10G切分一次阁谆。
    具體的切分策略為:
    第一次split:1^3 * 256 = 256MB 
    第二次split:2^3 * 256 = 2048MB 
    第三次split:3^3 * 256 = 6912MB 
    第四次split:4^3 * 256 = 16384MB > 10GB,因此取較小的值10GB 
    后面每次split的size都是10GB了愉老。
    '情況3':Hbase 2.0
    如果當(dāng)前RegionServer上該表只有一個Region场绿,按照2 * hbase.hregion.memstore.flush.size('默認(rèn)是128M')分裂,否則按照
    hbase.hregion.max.filesize('默認(rèn)是10G')分裂

4.8 一些命令

--1. 刷寫: flush 'tableName'
--2. 防止退出hbase客戶端:q
--3. 大合并:major_compact 'tableName'
--4. 小合并:compact 'tableName'
--5. scan查詢的時候:scan 'student',{COLUMNS => 'info:age:toLong'}
     ROW                             COLUMN+CELL                                                                          1002                           column=info:age, timestamp=1593192755078, value=10  

五 嫉入、 HBase API

--1.DML(Data Manipulation Language)數(shù)據(jù)操縱語言:使用conn進(jìn)行操作
適用范圍:對數(shù)據(jù)庫中的數(shù)據(jù)進(jìn)行一些簡單操作焰盗,如insert,delete,update,select等.

--2.DDL(Data Definition Language)數(shù)據(jù)定義語言:使用admin對象進(jìn)行操作
適用范圍:對數(shù)據(jù)庫中的某些對象(例如,database,table)進(jìn)行管理咒林,如Create,Alter和Drop.

5.1 環(huán)境準(zhǔn)備

  • 添加依賴
<dependency>
    <groupId>org.apache.hbase</groupId>
    <artifactId>hbase-server</artifactId>
    <version>2.0.5</version>
</dependency>

<dependency>
    <groupId>org.apache.hbase</groupId>
    <artifactId>hbase-client</artifactId>
    <version>2.0.5</version>
</dependency>

5.2 DDL

package com.atguigui.lianzp

import org.apache.hadoop.conf.Configuration
import org.apache.hadoop.hbase.{HBaseConfiguration, NamespaceDescriptor, TableName}
import org.apache.hadoop.hbase.client._
import org.apache.hadoop.hbase.util.Bytes


/**
  * @Description
  * *
  * @author lianzhipeng
  * @create 2020-06-24 9:59:55
  */
object HBase_DDL {
  // 1. 獲取zookeeper的連接
  val conf: Configuration = HBaseConfiguration.create()
  conf.set("hbase.zookeeper.quorum", "hadoop105,hadoop106,hadoop107")
  val conn: Connection = ConnectionFactory.createConnection(conf)
  // 2. 獲取hbase的對象
  val admin: Admin = conn.getAdmin

  def main(args: Array[String]): Unit = {

    val result: Boolean = tableExists("user")
//    println(result)
//    createTable("emp","cf1","cf2")
//    deleteTable("user")


//    val bool: Boolean = nsExists("lianzp")
//    println(bool)
    createNS("lianzp")

    connclose()
  }

  def createNS (namespace:String) ={

    if (!nsExists(namespace)){

      val ns: NamespaceDescriptor.Builder = NamespaceDescriptor.create(namespace)

      admin.createNamespace(ns.build())
      println(s"namespace:{$namespace}創(chuàng)建成功")

    }else {
      println(s"namespace:{$namespace}已存在熬拒,創(chuàng)建失敗")
    }

  }

  def nsExists(namespace : String) ={
    // 獲取當(dāng)前所有的namespace的描述,是一個數(shù)組
    val nss: Array[NamespaceDescriptor] = admin.listNamespaceDescriptors()
    // 進(jìn)行格式轉(zhuǎn)換垫竞,獲取namespace的名字澎粟,然后確定namespace是否存在
    nss.map(_.getName).contains(namespace)

  }

  def deleteTable (table : String) ={
    // 獲取當(dāng)前表
    val tn: TableName = TableName.valueOf(table)
    if (tableExists(table)){
     // 刪除表,首先需要將表置于不可用的狀態(tài)才能進(jìn)行刪除

      admin.disableTable(tn)
      admin.deleteTable(tn)

      println(s"{$table}表刪除成功")
    }else {
      println(s"{$table}表不存在欢瞪,刪除失敗")
    }


  }

  /**
    * 判斷表是否存在
    *
    * @param name
    * @return
    */

  def tableExists(name: String) = {
    val tableName: TableName = TableName.valueOf(name)
    val bool: Boolean = admin.tableExists(tableName)
    bool

  }


  /**
    * 創(chuàng)建表
    * @param tableName
    * @param columns
    */
  def createTable (tableName :String , columns: String*) ={


    //TableDescriptor desc
    val tn: TableName = TableName.valueOf(tableName)
    val tb: TableDescriptorBuilder = TableDescriptorBuilder.newBuilder(tn)

    if (!tableExists(tableName)) {

      columns.foreach(cf => {
        val descriptor: ColumnFamilyDescriptor = ColumnFamilyDescriptorBuilder
          .newBuilder(Bytes.toBytes(cf))
          .build()
        tb.setColumnFamily(descriptor)

      })
      admin.createTable(tb.build())

      println(s"{$tableName}表創(chuàng)建成功")
    }else {
      println(s"當(dāng)前的表{$tableName}已存在")
    }


  }

  def connclose() = {
    // 4. 關(guān)閉對象
    admin.close()

    // 5. 關(guān)閉連接
    conn.close()

  }
}

5.3 DML

package com.atguigui.lianzp

import java.util

import org.apache.hadoop.conf.Configuration
import org.apache.hadoop.hbase.{Cell, CellUtil, HBaseConfiguration, TableName}
import org.apache.hadoop.hbase.client._
import org.apache.hadoop.hbase.util.Bytes

/**
  * @Description
  * *
  * @author lianzhipeng
  * @create 2020-06-24 14:16:48
  */
object HBase_DML {
  // 1. 獲取連接
  private var conf: Configuration = HBaseConfiguration.create()
  conf.set("hbase.zookeeper.quorum", "hadoop105,hadoop106,hadoop107")
  private val conn: Connection = ConnectionFactory.createConnection(conf)

  // 2. 創(chuàng)建hbase的master的對象
  private val admin: Admin = conn.getAdmin
  def main(args: Array[String]): Unit = {

    // 1. 增加數(shù)據(jù)
    //    putData("test", "1002", "info", "age", "2")
    // 2. 掃描數(shù)據(jù)
    //    scanData("test")
    // 3. 刪除數(shù)據(jù)
    deleteData("test","1001","info","name")
    // 4. 獲取數(shù)據(jù)
    //    getData("test", "1002", "info", "age")
    closeConn
  }

  /**
    * 刪除數(shù)據(jù)
    *
    * @param tableName
    * @param rowKey
    * @param columnFamily
    * @param column
    */
  def deleteData(tableName: String, rowKey: String, columnFamily: String, column: String) = {
    // 1. 獲取表
    // 封裝表
    val tn: TableName = TableName.valueOf(tableName)
    // 獲取表
    val table: Table = conn.getTable(tn)

    // 2. 判斷表是否存在
    if (tableExists(tableName)) {
      // 封裝一個delete
      val delete = new Delete(Bytes.toBytes(rowKey))
      val dl: Delete = delete.addColumn(Bytes.toBytes(columnFamily), Bytes.toBytes(column))
      // 對表進(jìn)行刪除
      table.delete(dl)
    }
  }

  def scanData(tableName: String) = {
    // 1. 獲取表
    val tn: TableName = TableName.valueOf(tableName)
    val table: Table = conn.getTable(tn)
    // 2.判斷表是否存在
    if (tableExists(tableName)) {
      // 獲取一個scan對象
      val scan = new Scan()
      // 獲取表的全局掃描
      val scanner: ResultScanner = table.getScanner(scan)
      // 這個是用來在java的集合和scala的集合之間互轉(zhuǎn)  (隱式轉(zhuǎn)換)
      import scala.collection.JavaConversions._
      // 使用迭代器活烙,獲取所有數(shù)據(jù)的集合
      val results: util.Iterator[Result] = scanner.iterator()
      // 遍歷每一行的數(shù)據(jù)
      for (result <- results) {
        // 獲取每一行數(shù)據(jù)中所有的單元格
        val cells: util.List[Cell] = result.listCells()
        if (cells != null) {
          // 遍歷所有的單元格,只能獲取最新的版本
          for (cell <- cells) {
            println(
              s"""
                 |rowKey= ${Bytes.toString(CellUtil.cloneRow(cell))}
                 |columnFamily = ${Bytes.toString(CellUtil.cloneFamily(cell))}
                 |column = ${Bytes.toString(CellUtil.cloneQualifier(cell))}
                 |value = ${Bytes.toString(CellUtil.cloneValue(cell))}
            """.stripMargin)

            println("=======================================")
          }
        }
      }
    }
  }

  def getData(tableName: String, rowKey: String, columnFamily: String, column: String) = {
    // 1. 獲取表
    val tn: TableName = TableName.valueOf(tableName)
    val table: Table = conn.getTable(tn)
    // 2. 判斷表是否存在遣鼓,如果存在則進(jìn)行查詢啸盏,如果不存在,則直接退出方法骑祟,并提示client查詢的表不存在
    if (tableExists(tableName)) {
      val get = new Get(Bytes.toBytes(rowKey))
      get.addColumn(Bytes.toBytes(columnFamily), Bytes.toBytes(column))

      val result: Result = table.get(get)
      import scala.collection.JavaConversions._

      val cells: util.List[Cell] = result.listCells()
      for (cell <- cells) {
        println(
          s"""
             |columnFamliy = ${Bytes.toString(CellUtil.cloneFamily(cell))}
             |column = ${Bytes.toString(CellUtil.cloneQualifier(cell))}
             |value = ${Bytes.toString(CellUtil.cloneValue(cell))}
             |rowKey = ${Bytes.toString(CellUtil.cloneRow(cell))}
           """.stripMargin)
      }
    } else {

      println(s"{$tableName}表不存在")
    }
  }

  /**
    * 增加數(shù)據(jù)
    *
    * @param tableName
    * @param rowKey
    * @param columnFamily
    * @param column
    * @param value
    */

  def putData(tableName: String, rowKey: String, columnFamily: String, column: String, value: String) = {
    // 1. 獲取表
    val tn: TableName = TableName.valueOf(tableName)

    val table: Table = conn.getTable(tn)
    // 2. 判斷表是否存在回懦,如果存在气笙,則添加數(shù)據(jù),如果不存在粉怕,則通知client
    if (tableExists(tableName)) {
      // 封裝插入的數(shù)據(jù)
      val put = new Put(Bytes.toBytes(rowKey))
      put.addColumn(Bytes.toBytes(columnFamily), Bytes.toBytes(column), Bytes.toBytes(value))
      // 將數(shù)據(jù)插入
      table.put(put)
      // 關(guān)閉連接
      table.close()
      println("插入數(shù)據(jù)操作執(zhí)行成功")
    } else {
      println(s"當(dāng)前表{$tableName}不存在")
    }

  }


  def tableExists(tableName: String) = {
    val tn: TableName = TableName.valueOf(tableName)
    admin.tableExists(tn)
  }

  /**
    * 關(guān)閉連接
    */
  def closeConn = {

    // 3. 關(guān)閉對象
    admin.close()

    // 4. 關(guān)閉連接
    conn.close()

  }

}

六健民、HBase的優(yōu)化

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

1. 通過預(yù)分區(qū)的方式,使添加的數(shù)據(jù)進(jìn)入指定的region中贫贝,提前進(jìn)行數(shù)據(jù)分區(qū)秉犹。

2. 當(dāng)指定預(yù)分區(qū)的規(guī)則以后,那么默認(rèn)的region split分區(qū)原則則不會有效稚晚。

3. 每一個region維護(hù)著一個startkey和endkey崇堵,新增的數(shù)據(jù),根據(jù)數(shù)據(jù)的rowkey判斷進(jìn)入哪個region客燕,比較的方式:按照字典的順序鸳劳。

4. 在實(shí)際開發(fā)中,基本上所有的表都會進(jìn)行預(yù)分區(qū)也搓,且經(jīng)常是第一個或者是最后一個region中是沒有數(shù)據(jù)赏廓。

6.1.1 手動設(shè)定預(yù)分區(qū)

hbase> create 'staff1','info','partition1',SPLITS => ['1000','2000','3000','4000']

6.1.2 生成16進(jìn)制序列預(yù)分區(qū)

create 'staff2','info','partition2',{NUMREGIONS => 15, SPLITALGO => 'HexStringSplit'}

6.1.3 按照文件設(shè)置預(yù)分區(qū)

#文件內(nèi)容
aaaa
bbbb
cccc
dddd
create 'staff3','partition3',SPLITS_FILE => 'splits.txt'

6.1.4 使用API設(shè)置

//自定義算法,產(chǎn)生一系列Hash散列值存儲在二維數(shù)組中
byte[][] splitKeys = 某個散列值函數(shù)
//創(chuàng)建HbaseAdmin實(shí)例
HBaseAdmin hAdmin = new HBaseAdmin(HbaseConfiguration.create());
//創(chuàng)建HTableDescriptor實(shí)例
HTableDescriptor tableDesc = new HTableDescriptor(tableName);
//通過HTableDescriptor實(shí)例和散列值二維數(shù)組創(chuàng)建帶有預(yù)分區(qū)的Hbase表
hAdmin.createTable(tableDesc, splitKeys);

6.2 RowKey設(shè)計(jì)

-- 1. 現(xiàn)狀
    在hbase中傍妒,rowkey是唯一區(qū)分?jǐn)?shù)據(jù)進(jìn)入哪個region中幔摸,如果region設(shè)計(jì)合理,那么有可能導(dǎo)致數(shù)據(jù)冗余和數(shù)據(jù)傾斜颤练。

-- 2. 設(shè)計(jì)規(guī)則
    1. 長度:
        a既忆、rowkey理論字節(jié)數(shù)在10-100字節(jié)之間最好,一是可以表述較多的數(shù)據(jù)內(nèi)容嗦玖,其次是數(shù)據(jù)不會過多患雇;
        b、數(shù)據(jù)長度最好是2的n次冪宇挫;
        c苛吱、rowkey的數(shù)據(jù)長度最好相同;
    2. 散列:
        a器瘪、對rowkey進(jìn)行散列又谋,采用md5,hash等方式娱局,以防止數(shù)據(jù)傾斜继阻;
    3. 唯一性:防止rowkey相同。
    
-- 3. 實(shí)現(xiàn)方式:
      a、字符串反轉(zhuǎn)奏赘。如:
      20170524000001轉(zhuǎn)成10000042507102
      20170524000002轉(zhuǎn)成20000042507102
      b缚柳、字符串連接:將本來放進(jìn)列的數(shù)據(jù),放到rowkey中抡谐,主要是將經(jīng)常需要使用到的字段/不發(fā)生改變的數(shù)據(jù)拼接到rowkey中音五。
       如:rowkey:id_name_age
   

6.3 內(nèi)存優(yōu)化

HBase操作過程中需要大量的內(nèi)存開銷,畢竟Table是可以緩存在內(nèi)存中的碟绑,但是不建議分配非常大的堆內(nèi)存,因?yàn)镚C過程持續(xù)太久會導(dǎo)致RegionServer處于長期不可用狀態(tài)苗桂,一般16~36G內(nèi)存就可以了放案,如果因?yàn)榭蚣苷加脙?nèi)存過高導(dǎo)致系統(tǒng)內(nèi)存不足稿湿,框架一樣會被系統(tǒng)服務(wù)拖死

6.4 基礎(chǔ)優(yōu)化

-- 1.Zookeeper會話超時時間
    '配置文件':hbase-site.xml
    '屬性':zookeeper.session.timeout
    '解釋':默認(rèn)值為90000毫秒(90s)。當(dāng)某個RegionServer掛掉缎罢,90s之后Master才能察覺到萎坷。可適當(dāng)減小此值瓜浸,以加快Master響應(yīng)杠巡,可調(diào)整至600000毫秒。
--2.設(shè)置RPC監(jiān)聽數(shù)量
    '配置文件':hbase-site.xml
    '屬性':hbase.regionserver.handler.count
    '解釋':默認(rèn)值為30雇寇,用于指定RPC監(jiān)聽的數(shù)量氢拥,可以根據(jù)客戶端的請求數(shù)進(jìn)行調(diào)整,讀寫請求較多時锨侯,增加此值嫩海。
--3.手動控制Major Compaction
    '配置文件':hbase-site.xml
    '屬性':hbase.hregion.majorcompaction
    '解釋':默認(rèn)值:604800000秒(7天), Major Compaction的周期识腿,若關(guān)閉自動Major Compaction出革,可將其設(shè)為0
    在實(shí)際開發(fā)中,我們一般設(shè)置為0渡讼,然后通過azkaban進(jìn)行調(diào)度骂束。
--4.優(yōu)化HStore文件大小
    '配置文件':hbase-site.xml
    '屬性':hbase.hregion.max.filesize
    '解釋':默認(rèn)值10737418240(10GB),如果需要運(yùn)行HBase的MR任務(wù)成箫,可以減小此值展箱,因?yàn)橐粋€region對應(yīng)一個map任務(wù),如果單個region過大蹬昌,會導(dǎo)致map任務(wù)執(zhí)行時間過長混驰。該值的意思就是,如果HFile的大小達(dá)到這個數(shù)值,則這個region會被切分為兩個Hfile栖榨。
--5.優(yōu)化HBase客戶端緩存
    '配置文件':hbase-site.xml
    '屬性':hbase.client.write.buffer
    '解釋':默認(rèn)值2097152bytes(2M)用于指定HBase客戶端緩存昆汹,增大該值可以減少RPC調(diào)用次數(shù),但是會消耗更多內(nèi)存婴栽,反之則反之满粗。一般我們需要設(shè)定一定的緩存大小,以達(dá)到減少RPC次數(shù)的目的愚争。
--6.指定scan.next掃描HBase所獲取的行數(shù)
    '配置文件':hbase-site.xml
    '屬性':hbase.client.scanner.caching
    '解釋':用于指定scan.next方法獲取的默認(rèn)行數(shù)映皆,值越大,消耗內(nèi)存越大轰枝。
--7.BlockCache占用RegionServer堆內(nèi)存的比例
    '配置文件':hbase-site.xml
    '屬性':hfile.block.cache.size
    '解釋':默認(rèn)0.4捅彻,讀請求比較多的情況下,可適當(dāng)調(diào)大
--8.MemStore占用RegionServer堆內(nèi)存的比例
    '配置文件':hbase-site.xml
    '屬性':hbase.regionserver.global.memstore.size
    '解釋':默認(rèn)0.4鞍陨,寫請求較多的情況下步淹,可適當(dāng)調(diào)大

七、與Hive的集成

7.1 HBase與Hive的對比

--1. Hive
   1. 是一個數(shù)據(jù)倉庫:Hive的本質(zhì)其實(shí)就是相當(dāng)于將HDFS中已經(jīng)存儲的文件在Mysql中做一個雙射關(guān)系湾戳,以方便使用HQL去管理查詢贤旷;
   2. 用于數(shù)據(jù)分析、清洗
   3. 基于HDFS 砾脑、 MapReduce: Hive存儲的數(shù)據(jù)依舊在DataNode上幼驶,編寫的HQL語句終將轉(zhuǎn)換為MapReduce代碼執(zhí)行;
   
--2. HBase
    1. 是數(shù)據(jù)庫
    2. 用于存儲結(jié)構(gòu)化和非結(jié)構(gòu)化數(shù)據(jù)
    3. 基于HDFS
    4. 延遲低韧衣。接入在線業(yè)務(wù)使用     

7.2 HBase 與 Hive集成使用

  • 在hive-site.xml中添加zookeeper的屬性盅藻,如下:
 <property>
        <name>hive.zookeeper.quorum</name>
        <value>hadoop105,hadoop106,hadoop107</value>
    </property>

    <property>
        <name>hive.zookeeper.client.port</name>
        <value>2181</value>
    </property>

7.3 案例一

-- 需求:在Hive中創(chuàng)建的表,在HBase中可以查詢到畅铭。
  1. 在Hive中創(chuàng)建表同時關(guān)聯(lián)HBase
CREATE TABLE hive_hbase_emp_table(
empno int,
ename string,
job string,
mgr int,
hiredate string,
sal double,
comm double,
deptno int)
STORED BY 'org.apache.hadoop.hive.hbase.HBaseStorageHandler'
WITH SERDEPROPERTIES ("hbase.columns.mapping" = ":key,info:ename,info:job,info:mgr,info:hiredate,info:sal,info:comm,info:deptno")
TBLPROPERTIES ("hbase.table.name" = "hbase_emp_table");

完成之后氏淑,可以分別進(jìn)入Hive和HBase查看,都生成了對應(yīng)的表

  1. 在Hive中創(chuàng)建臨時中間表硕噩,用于load文件中的數(shù)據(jù)

建立上訴的表假残,不能直接通過load的方式加載數(shù)據(jù),需要通過查詢其他表的數(shù)據(jù)進(jìn)行插入

CREATE TABLE emp(
empno int,
ename string,
job string,
mgr int,
hiredate string,
sal double,
comm double,
deptno int)
row format delimited fields terminated by '\t';
  1. 向Hive中間表中l(wèi)oad數(shù)據(jù)
load data local inpath '/opt/module/hive/datas/emp' into table emp;
  1. 通過insert命令將中間表中的數(shù)據(jù)導(dǎo)入到Hive關(guān)聯(lián)Hbase的那張表中
insert into table hive_hbase_emp_table select * from emp;
  1. 查看Hive以及關(guān)聯(lián)的HBase表中是否已經(jīng)成功的同步插入了數(shù)據(jù)
-- Hive
hive> select * from hive_hbase_emp_table;
-- HBase
Hbase> scan 'hbase_emp_table'

7.4 案例二

-- 需求:在HBase中已經(jīng)存儲了某一張表hbase_emp_table炉擅,然后在Hive中創(chuàng)建一個外部表來關(guān)聯(lián)HBase中的hbase_emp_table這張表
   
在案例1的基礎(chǔ)上進(jìn)行完成辉懒。
  1. 在Hive中創(chuàng)建外部表
CREATE EXTERNAL TABLE relevance_hbase_emp(
empno int,
ename string,
job string,
mgr int,
hiredate string,
sal double,
comm double,
deptno int)
STORED BY 
'org.apache.hadoop.hive.hbase.HBaseStorageHandler'
WITH SERDEPROPERTIES ("hbase.columns.mapping" = 
":key,info:ename,info:job,info:mgr,info:hiredate,info:sal,info:comm,info:deptno") 
TBLPROPERTIES ("hbase.table.name" = "hbase_emp_table");
  1. 關(guān)聯(lián)后就可以使用Hive函數(shù)進(jìn)行一些分析操作了
hive (default)> select * from relevance_hbase_emp;

八、Phoenix

8.1 Phoenix簡介

-- 1. Phoenix是什么谍失?
   可以理解是HBase的開源SQL皮膚眶俩,可以使用標(biāo)準(zhǔn)的JDBC API代替HBase客戶端API來創(chuàng)建表,插入數(shù)據(jù)和查詢HBase數(shù)據(jù)快鱼。
   
-- 2. Phoenix中創(chuàng)建的表存儲在HBase中颠印。

8.2 Phoenix特點(diǎn)

1. 容易集成:如Spark 纲岭、 Hive 、 Pig 线罕、 Flume 止潮、 MAPReduce
2. 操作容易:DML命令以及通過DDL命令來對表進(jìn)行操作
3. 支持HBase的二級索引創(chuàng)建。

8.3 Phoenix架構(gòu)

image.png

8.4 Phoenix安裝

8.4.1 官網(wǎng)地址

http://phoenix.apache.org/

8.4.2 Phoenix部署

  1. 上傳并解壓tar包并修改名字
[atguigu@hadoop105 module]$ tar -zxvf apache-phoenix-5.0.0-HBase-2.0-bin.tar.gz -C /opt/module/

[atguigu@hadoop102 module]$ mv apache-phoenix-5.0.0-HBase-2.0-bin phoenix
  1. 復(fù)制server包并拷貝到各個節(jié)點(diǎn)的hbase/lib
[atguigu@hadoop102 module]$ cd /opt/module/phoenix/

[atguigu@hadoop102 phoenix]$ cp /opt/module/phoenix/phoenix-5.0.0-HBase-2.0-server.jar /opt/module/hbase/lib/

[atguigu@hadoop102 phoenix]$ xsync /opt/module/hbase/lib/phoenix-5.0.0-HBase-2.0-server.jar
  1. 配置環(huán)境變量
#phoenix
export PHOENIX_HOME=/opt/module/phoenix
export PHOENIX_CLASSPATH=$PHOENIX_HOME
export PATH=$PATH:$PHOENIX_HOME/bin
  1. 重啟HBase
[atguigu@hadoop102 ~]$ stop-hbase.sh
[atguigu@hadoop102 ~]$ start-hbase.sh
  1. 連接Phoenix
[atguigu@hadoop101 phoenix]$ /opt/module/phoenix/bin/sqlline.py hadoop102,hadoop103,hadoop104:2181

8.5 Phoenix Shell 操作

--說明:
  1钞楼、 在Phoenix創(chuàng)建的表沽翔,都是存儲在hbase中;
  2窿凤、 Phoenix表的主鍵,在hbase表中跨蟹,相當(dāng)于rowkey雳殊,所以在Phoenix建表時,至少設(shè)置一個主鍵窗轩,且數(shù)據(jù)類型最好設(shè)置為varchar夯秃;
  3、 在Phoenix創(chuàng)建表時痢艺,表名和字段自動會變成大寫仓洼,如果想要設(shè)置為小寫,那么需要使用'雙引號'堤舒;
  4色建、 '單引號'表示字符串;
  5舌缤、 在HBase創(chuàng)建的表箕戳,默認(rèn)在Phoenix是查詢不到的,需要通過映射的方式可以查詢国撵。
  6陵吸、 Phoenix中不支持insert語法,使用了'upsert'代替;
  7介牙、 Phoenix的shell操作壮虫,很多和sql語法相似,但是也有些語法時不支持的环础;
  8囚似、 Phoenix創(chuàng)建的表,在hbase默認(rèn)只有一個列族'0'喳整;

8.5.1 顯示所有表

!table 或 !tables

8.5.2 創(chuàng)建表

create table lianzp (id varchar primary key , age varchar )
  • 聯(lián)合主鍵
指定多個列的聯(lián)合作為RowKey

CREATE TABLE IF NOT EXISTS us_population (
State CHAR(2) NOT NULL,
City VARCHAR NOT NULL,
Population BIGINT
CONSTRAINT my_pk PRIMARY KEY (state, city));

8.5.3 插入數(shù)據(jù)

upsert into student values('1001','zhangsan','beijing');

8.5.4 查詢記錄

select * from student;
select * from student where id='1001';

8.5.5 刪除記錄

delete from student where id='1001';

8.5.6 刪除表

drop table student;

8.5.7 退出命令行

!quit

8.6 Phoenix與hbase表映射

-- 1. 說明:
       a. 在Phoenix創(chuàng)建的表可以在hbase中直接查詢到谆构,因?yàn)镻hoenix創(chuàng)建的表就是在hbase上;
       b. 在hbase的表框都,Phoenix默認(rèn)不能直接看到搬素,需要使用映射的方式才能看到呵晨。 

-- 2. 序列化問題:
      a、Phoenix數(shù)據(jù)的序列化器和hbase數(shù)據(jù)序列化器不一致熬尺;
      b摸屠、Phoenix使用自身的序列化器,而hbase使用的是bytes.toBtes()對數(shù)據(jù)進(jìn)行序列化粱哼,則導(dǎo)致從Phoenix讀取hbase和從hbase讀取Phoenix數(shù)據(jù)時季二,會出現(xiàn)讀出的數(shù)據(jù)和原表中的數(shù)據(jù)不一致。現(xiàn)象為:
      -- 1). Hbase讀取Phoenix表
      a揭措、'列名格式問題':列名將Phoenix的字段轉(zhuǎn)換為16進(jìn)制顯示
      b胯舷、'value格式問題':值類型數(shù)據(jù)也被轉(zhuǎn)換成了16進(jìn)制顯示
      
      -- 2). Phoenix讀取hbase表
      a、'列名格式問題':在Phoenix創(chuàng)建的字段和hbase表中的字段一樣绊含,但是沒有數(shù)據(jù)
      b桑嘶、'value格式問題':查詢的數(shù)據(jù)和hbase的數(shù)據(jù)完全不等,描述見下圖:
-- 3. 解決方案如下:

8.6.1 Phoenix創(chuàng)建的表

-- 1. 在Phoenix創(chuàng)建的表躬充,在hbase中可以查詢到逃顶,但是會發(fā)現(xiàn)多了每行數(shù)據(jù)中,會多如下一列數(shù)據(jù)充甚,'稱之為空/虛的keyvalue':
      1001     column=0:_0, timestamp=1593071947795, value=x  
-- 2. 為什么Phoenix在進(jìn)行upsert時會添加一個空/虛擬KeyValue以政?
   在hbase表中,rowkey對應(yīng)Phoenix表中的主鍵伴找,如果Phoenix中表只有主鍵盈蛮,沒有其他列,那么在habse的表中疆瑰,就只有rowkey眉反,沒有列族了。所有通過增加這樣一列空的列穆役,確保這行數(shù)據(jù)即有rowkey寸五,也有列族.
-- 3. 官網(wǎng)說明:

8.6.2 HBase創(chuàng)建的表

-- 1. 在HBase表映射方式有兩種:視圖映射和表映射
-- 2. 在Phoenix實(shí)現(xiàn)映射的方式:
      a、創(chuàng)建的表名和hbase的表名相同耿币,注意大小寫梳杏;
      b、創(chuàng)建一個主鍵淹接,用來接收hbase表中的rowkey十性;
      c、其余的字段塑悼,聲明方式為:hbase表中的:列族.列名
      d劲适、最后需要加上:column_encoded_bytes=0,使的Phoenix反序列器為bytes.toBytes()厢蒜,與hbase序列化器一致霞势,則Phoenix可以
         找到hbase表中的列烹植。
 -- 3. 說明:
      a、創(chuàng)建時表名和字段名一定要相同愕贡;
      b草雕、如果創(chuàng)建的字段在hbase表不存在,也是可以的固以。相當(dāng)于空列
8.6.2.1 視圖映射
-- 1. 創(chuàng)建的視圖是只讀墩虹,只能用來進(jìn)行查詢,無法通過視圖對原數(shù)據(jù)進(jìn)行修改等操作憨琳。
  1. 在hbase準(zhǔn)備數(shù)據(jù)
create 'lianzp' ,'info'诫钓,'info1'

put 'lianzp','1001','info:name','zs'
  1. Phoenix端操操作
-- 創(chuàng)建視圖
create view "lianzp" (id varchar primary key , "info"."name" varchar , "info1"."address" varchar ) column_encoded_bytes=0;

-- 刪除視圖
drop view "lianzp";
8.6.2.2 表映射
-- 只需要將將create view 改成create table 即可。

8.7 二級索引

8.7.1 修改配置

  • 添加如下配置到HBase的HRegionserver節(jié)點(diǎn)的hbase-site.xml
  <!-- phoenix regionserver 配置參數(shù)-->
    <property>
        <name>hbase.regionserver.wal.codec</name>
        <value>org.apache.hadoop.hbase.regionserver.wal.IndexedWALEditCodec</value>
    </property>

    <property>
        <name>hbase.region.server.rpc.scheduler.factory.class</name>
        <value>org.apache.hadoop.hbase.ipc.PhoenixRpcSchedulerFactory</value>
        <description>Factory to create the Phoenix RPC Scheduler that uses separate queues for index and metadata updates</description>
    </property>

    <property>
        <name>hbase.rpc.controllerfactory.class</name>
        <value>org.apache.hadoop.hbase.ipc.controller.ServerRpcControllerFactory</value>
        <description>Factory to create the Phoenix RPC Scheduler that uses separate queues for index and metadata updates</description>
    </property>

8.7.2 全局二級索引

-- 1. 創(chuàng)建全局索引時篙螟,會在HBase中建立一張新表
  1. 創(chuàng)建單個字段的全局索引
CREATE INDEX my_index ON my_table (my_col);

'如果想查詢的字段不是索引字段的話,索引表不會被使用尖坤,也就是說不會帶來查詢速度的提升
  1. 創(chuàng)建攜帶其他字段的全局索引
CREATE INDEX my_index ON my_table (v1) INCLUDE (v2);
image-20200629011141184

8.7.3 局部二級索引

-- 1. 索引數(shù)據(jù)和數(shù)據(jù)表的數(shù)據(jù)是存放在同一張表中(且是同一個Region)
  • 創(chuàng)建局部索引
CREATE LOCAL INDEX my_index ON my_table (my_column);

8.7.4 局部和全局的選擇

-- 1. 兩種索引的介紹
全局索引:會單獨(dú)創(chuàng)建一個新的文件,默認(rèn)是一個region闲擦,同時會采用默認(rèn)的region split的切分規(guī)則;
局部索引:在原數(shù)據(jù)表的插入數(shù)據(jù)场梆,索引數(shù)據(jù)和數(shù)據(jù)表的數(shù)據(jù)是存放在同一張表中(且是同一個Region)墅冷。

-- 2. 在需要創(chuàng)建索引時,我們是選擇創(chuàng)建哪種索引呢或油?
創(chuàng)建索引以后寞忿,每次數(shù)據(jù)的改動都需要更新索引表。
兩種索引選擇的規(guī)則如下:
'情況1':寫操作頻繁顶岸,則選擇局部索引腔彰,因?yàn)閿?shù)據(jù)和索引在同一張表的同一個region中,所以更新索引的數(shù)據(jù)就不需要跨節(jié)點(diǎn)辖佣,
        避免了在寫操作的時候往不同服務(wù)器的索引表中寫索引帶來的額外開銷;
'情況2': 讀操作頻繁時霹抛,則選擇全局索引,因?yàn)槿炙饕锌梢灾苯佣ㄎ坏綌?shù)據(jù)卷谈,效率高杯拐。

8.8 Phoenix JDBC操作

8.8.1 啟動query server

queryserver.py start

8.8.2 創(chuàng)建項(xiàng)目并導(dǎo)入依賴

   <dependencies>
        <!-- https://mvnrepository.com/artifact/org.apache.phoenix/phoenix-queryserver-client -->
        <dependency>
            <groupId>org.apache.phoenix</groupId>
            <artifactId>phoenix-queryserver-client</artifactId>
            <version>5.0.0-HBase-2.0</version>
        </dependency>
    </dependencies>

8.8.3 編寫代碼

package com.atguigu;

import java.sql.*;
import org.apache.phoenix.queryserver.client.ThinClientUtil;

public class PhoenixTest {
public static void main(String[] args) throws SQLException {

        String connectionUrl = ThinClientUtil.getConnectionUrl("hadoop105", 8765);
        System.out.println(connectionUrl);
        Connection connection = DriverManager.getConnection(connectionUrl);
        PreparedStatement preparedStatement = connection.prepareStatement("select * from student");

        ResultSet resultSet = preparedStatement.executeQuery();

        while (resultSet.next()) {
            System.out.println(resultSet.getString(1) + "\t" + resultSet.getString(2));
        }

        //關(guān)閉
        connection.close();

        }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市世蔗,隨后出現(xiàn)的幾起案子端逼,更是在濱河造成了極大的恐慌,老刑警劉巖污淋,帶你破解...
    沈念sama閱讀 217,509評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件顶滩,死亡現(xiàn)場離奇詭異,居然都是意外死亡寸爆,警方通過查閱死者的電腦和手機(jī)礁鲁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評論 3 394
  • 文/潘曉璐 我一進(jìn)店門盐欺,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人救氯,你說我怎么就攤上這事找田。” “怎么了着憨?”我有些...
    開封第一講書人閱讀 163,875評論 0 354
  • 文/不壞的土叔 我叫張陵墩衙,是天一觀的道長。 經(jīng)常有香客問我甲抖,道長漆改,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,441評論 1 293
  • 正文 為了忘掉前任准谚,我火速辦了婚禮挫剑,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘柱衔。我一直安慰自己樊破,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,488評論 6 392
  • 文/花漫 我一把揭開白布唆铐。 她就那樣靜靜地躺著哲戚,像睡著了一般顺少。 火紅的嫁衣襯著肌膚如雪秒裕。 梳的紋絲不亂的頭發(fā)上爽撒,一...
    開封第一講書人閱讀 51,365評論 1 302
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛嗅定,可吹牛的內(nèi)容都是我干的碎乃。 我是一名探鬼主播动漾,決...
    沈念sama閱讀 40,190評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼共虑!你這毒婦竟也來了猜惋?” 一聲冷哼從身側(cè)響起谍咆,我...
    開封第一講書人閱讀 39,062評論 0 276
  • 序言:老撾萬榮一對情侶失蹤摹察,失蹤者是張志新(化名)和其女友劉穎恩掷,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體供嚎,經(jīng)...
    沈念sama閱讀 45,500評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡黄娘,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,706評論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了查坪。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片寸宏。...
    茶點(diǎn)故事閱讀 39,834評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖偿曙,靈堂內(nèi)的尸體忽然破棺而出氮凝,到底是詐尸還是另有隱情,我是刑警寧澤望忆,帶...
    沈念sama閱讀 35,559評論 5 345
  • 正文 年R本政府宣布罩阵,位于F島的核電站,受9級特大地震影響启摄,放射性物質(zhì)發(fā)生泄漏稿壁。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,167評論 3 328
  • 文/蒙蒙 一歉备、第九天 我趴在偏房一處隱蔽的房頂上張望傅是。 院中可真熱鬧,春花似錦蕾羊、人聲如沸喧笔。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽书闸。三九已至,卻和暖如春利凑,著一層夾襖步出監(jiān)牢的瞬間浆劲,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評論 1 269
  • 我被黑心中介騙來泰國打工哀澈, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留牌借,地道東北人。 一個月前我還...
    沈念sama閱讀 47,958評論 2 370
  • 正文 我出身青樓割按,卻偏偏與公主長得像走哺,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,779評論 2 354

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

  • HBase總結(jié) 一丙躏、數(shù)據(jù)模型 1.數(shù)據(jù)模型例子 2.數(shù)據(jù)模型解析 1)存儲(keyvalue) HBase什么樣...
    農(nóng)民2019閱讀 967評論 0 0
  • 1择示、HBase的定義:面向列、可伸縮 HBase數(shù)據(jù)庫與關(guān)系型數(shù)據(jù)庫的區(qū)別 為什么會出現(xiàn)HBase晒旅? 什么場景下使...
    夙夜M閱讀 247評論 0 1
  • 一.HBase特點(diǎn): 1.弱視圖栅盲,HBase是一種高效的映射嵌套,用戶可以在運(yùn)行時定義列废恋,每一行都有屬于自己的列谈秫。...
    helloworld1214閱讀 2,996評論 0 4
  • 一、介紹 1.hbase是一個高緯度鱼鼓,面向列拟烫,高性能,高可靠的分布式實(shí)時數(shù)據(jù)庫 2.hbase是一個nosql數(shù)據(jù)...
    AlexDawson閱讀 1,179評論 0 0
  • 1、Hbase簡介 1、是什么? Hbase是分布式的存儲海量數(shù)據(jù)的NoSql數(shù)據(jù)庫 2竹椒、場景: 實(shí)時場景 3、H...
    cc708754edc4閱讀 549評論 0 0