HBase簡介及應用

一、關鍵字

分佈式存儲系統、開源、基於列模式、適合非結構化

二、特性

海量存儲,數據可達PB級別

列式存儲,一種NoSql數據庫

極易擴展,分佈式數據庫

高併發,多個PC同時處理

稀疏,指HBase列的靈活性,可以指定任意多的列

三、什麼適合用HBase?

HBase不適合解決所有的問題:

數據庫量要足夠多, 如果有十億及百億行數據, 那麼HBase是一個很好的選項, 如果只有幾百萬行甚至不到的數據量,RDBMS是一個很好的選擇, 因爲數據量小的話, 真正能工作的機器少, 剩餘的機器處於空閒的狀態

不需要輔助索引,靜態類型的列,事務等特性

保證硬件資源足夠,集羣中節點數少於5個,都不能表現的很好

四、應用場景

  • 存儲業務數據:不同小區的人口信息、個人的定位信息等

  • 存儲日誌數據:登錄日誌、中間件訪問日誌、推送日誌、業務操作日誌等信息

  • 存儲業務附件:圖像、視頻、文檔等附件信息

五、HBase架構體系

  • HMaster: 集羣中的主服務器, 負責監控集羣中所有的RegionServer,並且管理着所有的元數據

  • HRegionServer: 管理Regions,每個RegionServer有多個Region, 運行在DataNode上

  • Store: Region有多個Store,每個Store對應表中一個列族

  • Memstore: 一個Store有一個Memstore和多個StoreFile(HFile)

  • StoreFile: 底層是Block

  • HFile: 真實的數據存儲文件

  • HLog: 預寫日誌文件,也叫WAL

 

六、應用開發

  1. 批量創建表

在創建表時只要指定表名、列簇就可以創建了, 當然在實際生產環境中通常會根據業務場景指定好表的預分區,這樣可以防止數據存入到一個Region上,造成熱點問題。

/* 判斷表是否存在 */
  def isExists(tableName: String): Boolean = {
    var result = false
    val tName = TableName.valueOf(tableName)
    if (admin.tableExists(tName)) {
      result = true
    }
    result
  }

  def createTable(tableName: String, columnFamilys: Array[String]) = {
    //操作的表名
    val tName = TableName.valueOf(tableName)
    //當表不存在的時候創建Hbase表
    if (!admin.tableExists(tName)) {
      //創建Hbase表模式
      val descriptor = new HTableDescriptor(tName)
      //創建列簇i
      for (columnFamily <- columnFamilys) {
        descriptor.addFamily(new HColumnDescriptor(columnFamily))
      }
      //創建表
      admin.createTable(descriptor)

      //建立分區表,使數據均勻分佈到各個服務器上
      val splitKesy = Array(2, 4, 6, 8).map(Bytes.toBytes(_))
      admin.createTable(descriptor, splitKesy)
      println("create successful!!")
    }
  }

    2. 數據寫入

數據寫入可以單條寫入也可以批量寫入, 實際環境中通常是批量寫入,這樣會提高寫入效率

//向hbase表中插入數據, 更新操作一樣
  def insertTable(tableName: String, rowkey: String, columnFamily: String, column: String, value: String) = {
    val table = connection.getTable(TableName.valueOf(tableName))

    //準備key 的數據
    val puts = new Put(rowkey.getBytes())
    //添加列簇名,字段名,字段值value
    puts.addColumn(columnFamily.getBytes(), column.getBytes(), value.getBytes())
    //把數據插入到tbale中
    table.put(puts)
    table.close()
    println("insert successful!!")
  }

   3. 數據更新

數據的更新和數據插入代碼是一樣的, 邏輯是不存在的列會創建插入, 存在則會覆蓋掉原有的數據。

//向hbase表中插入數據, 更新操作一樣
  def insertTable(tableName: String, rowkey: String, columnFamily: String, column: String, value: String) = {
    val table = connection.getTable(TableName.valueOf(tableName))

    //準備key 的數據
    val puts = new Put(rowkey.getBytes())
    //添加列簇名,字段名,字段值value
    puts.addColumn(columnFamily.getBytes(), column.getBytes(), value.getBytes())
    //把數據插入到tbale中
    table.put(puts)
    table.close()
    println("insert successful!!")
  }

  4. 數據刪除

數據刪除就是根據表名、rowKey、還有對應的列簇和列刪除即可。

//刪除某條記錄
  def deleteRecord(tableName: String, rowkey: String, columnFamily: String, column: String) = {
    val table = connection.getTable(TableName.valueOf(tableName))

    val info = new Delete(Bytes.toBytes(rowkey))
    info.addColumn(columnFamily.getBytes(), column.getBytes())
    table.delete(info)
    table.close()
    println("delete successful!!")
  }

  5. 數據查詢

數據查詢通常根據rowKey範圍進行掃描查詢,這樣效率最高

//獲取hbase表中的數據
  def scanDataFromHTable(tableName: String, columnFamily: String, column: String) = {
    val table = connection.getTable(TableName.valueOf(tableName))
    //定義scan對象
    val scan = new Scan()
    //添加列簇名稱
    scan.addFamily(columnFamily.getBytes())
    //從table中抓取數據來scan
    val scanner = table.getScanner(scan)
    var result = scanner.next()
    //數據不爲空時輸出數據
    while (result != null) {
      println(s"rowkey:${Bytes.toString(result.getRow)},列簇:${columnFamily}:${column},value:${Bytes.toString(result.getValue(Bytes.toBytes(columnFamily), Bytes.toBytes(column)))}")
      result = scanner.next()
    }
    //通過scan取完數據後,記得要關閉ResultScanner,否則RegionServer可能會出現問題(對應的Server資源無法釋放)
    scanner.close()
    table.close()
  }

查詢優化的點有

  • 設置Scan緩存, 這樣能有效提升掃描查詢性能

  • 指定要查詢的列, 這樣很大程度減少

以上就是本文的全部內容。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章