Hbase rowKey 設(shè)計與預(yù)分區(qū)建表

Hbase RowKey 設(shè)計

使用Spark或通過REST/API 方式存取Hbase烛卧,性能影響最大的因素在于Hbase 的結(jié)構(gòu)設(shè)計咪啡。Hbase 結(jié)構(gòu)設(shè)計包括兩個方面

  • rowKey 的設(shè)計
  • rowKey 和Hbase 表預(yù)分區(qū)

rowKey 數(shù)據(jù)盡量保持短小精悍缀辩,同時還要能與業(yè)務(wù)數(shù)據(jù)的主鍵有關(guān)聯(lián)荆残。
同時盡量散列芽唇。這樣才能保證數(shù)據(jù)均勻的存儲到Hbase 的Region里弛车。數(shù)據(jù)均勻分不到Hbase Region 中蛉鹿,檢索的速度才夠快滨砍。

rowKey 設(shè)計有以下幾種思路

  • 拼接業(yè)務(wù)主鍵,轉(zhuǎn)換為md5
  • 拼接業(yè)務(wù)主鍵妖异,按照一個Hash 算法截取前綴再拼接業(yè)務(wù)主鍵

第一種方法:數(shù)據(jù)分布比較平均惋戏,處理簡單,當(dāng)無法從rowKey 中抽取業(yè)務(wù)主鍵他膳,因此需在Hbase 數(shù)據(jù)列中額外花費額外的空間存儲响逢。
第二種方法:數(shù)據(jù)分布也比較平均,需專門實現(xiàn)Hash 算法和抽取業(yè)務(wù)主鍵的方法棕孙,當(dāng)節(jié)省了數(shù)據(jù)存成空間舔亭。

幾種構(gòu)造RowKey 的方法

// 對指定的列構(gòu)造rowKey,采用Hash前綴拼接業(yè)務(wù)主鍵的方法
def rowKeyWithHashPrefix(column: String*): Array[Byte] = {
    val rkString = column.mkString("")
    val hash_prefix = getHashCode(rkString)
    val rowKey = Bytes.add(Bytes.toBytes(hash_prefix), Bytes.toBytes(rkString))
    rowKey
  }

// 對指定的列構(gòu)造rowKey, 采用Md5 前綴拼接業(yè)務(wù)主鍵方法,主要目的是建表時采用MD5 前綴進(jìn)行預(yù)分區(qū)
def rowKeyWithMD5Prefix(separator:String,length: Int,column: String*): Array[Byte] = {
    val columns = column.mkString(separator)

    var md5_prefix = MD5Hash.getMD5AsHex(Bytes.toBytes(columns))
    if (length < 8){
      md5_prefix = md5_prefix.substring(0, 8)
    }else if (length >= 8 || length <= 32){
      md5_prefix = md5_prefix.substring(0, length)
    }
    val row = Array(md5_prefix,columns)
    val rowKey = Bytes.toBytes(row.mkString(separator))
    rowKey
  }

// 對指定的列構(gòu)造RowKey,采用MD5方法
def rowKeyByMD5(column: String*): Array[Byte] = {
    val rkString = column.mkString("")
    val md5 = MD5Hash.getMD5AsHex(Bytes.toBytes(rkString))
    val rowKey = Bytes.toBytes(md5)
    rowKey
  }
// 直接拼接業(yè)務(wù)主鍵構(gòu)造rowKey
def rowKey(column:String*):Array[Byte] = Bytes.toBytes(column.mkString(""))

// Hash 前綴的方法:指定列拼接之后與最大的Short值做 & 運算
// 目的是預(yù)分區(qū)蟀俊,盡量保證數(shù)據(jù)均勻分布  
private def getHashCode(field: String): Short ={
    (field.hashCode() & 0x7FFF).toShort
  }

Hbase RowKey 設(shè)計和Hbase 建表

為了提高Hbase 寫入速度钦铺,預(yù)分區(qū)是一種非常重要的技術(shù)手段。預(yù)分區(qū)之后肢预,數(shù)據(jù)會被均勻分散到不同的region 中职抡,這樣不會出現(xiàn)寫熱點,從而提高Hbase寫入速度误甚。

/**
    * Hbase自帶了兩種pre-split的算法,分別是 HexStringSplit 和  UniformSplit
    * 如果我們的row key是十六進(jìn)制的字符串作為前綴的,就比較適合用HexStringSplit
    * @param tablename 表名
    * @param regionNum 預(yù)分區(qū)數(shù)量
    * @param columns 列簇數(shù)組
    */
  def createHTable(connection: Connection, tablename: String,regionNum: Int, columns: Array[String]): Unit = {

    val hexsplit: HexStringSplit = new HexStringSplit()
// 預(yù)先構(gòu)建分區(qū)缚甩,指定分區(qū)的start key
    val splitkeys: Array[Array[Byte]] = hexsplit.split(regionNum)

    val admin = connection.getAdmin

    val tableName = TableName.valueOf(nameSpace + ":" + tablename)

    if (!admin.tableExists(tableName)) {

      if(!admin.getNamespaceDescriptor(nameSpace).getName.equals(nameSpace))
        admin.createNamespace(NamespaceDescriptor.create(nameSpace).build())

      val tableDescriptor = new HTableDescriptor(tableName)

      if (columns != null) {
        columns.foreach(c => {
          val hcd = new HColumnDescriptor(c.getBytes()) //設(shè)置列簇
          hcd.setMaxVersions(1)
          hcd.setCompressionType(Algorithm.GZ) //設(shè)定數(shù)據(jù)存儲的壓縮類型.默認(rèn)無壓縮(NONE)
          tableDescriptor.addFamily(hcd)
        })
      }
      admin.createTable(tableDescriptor,splitkeys)
    }

  }
/**
    * short預(yù)分區(qū)建表:0X0000~0X7FFF
    * @param connection
    * @param tablename 表名
    * @param regionNum 預(yù)分區(qū)數(shù)量
    * @param columns 列簇數(shù)組
    */
  def createHTable(connection: Connection, tablename: String,regionNum: Short, columns: Array[String]): Unit = {

    val admin = connection.getAdmin

    val tableName = TableName.valueOf(nameSpace+ ":" + tablename)

    if (!admin.tableExists(tableName)) {

      if(!admin.getNamespaceDescriptor(nameSpace).getName.equals(nameSpace))
        admin.createNamespace(NamespaceDescriptor.create(nameSpace).build())

      val tableDescriptor = new HTableDescriptor(tableName)

      if (columns != null) {
        columns.foreach(c => {
          val hcd = new HColumnDescriptor(c.getBytes()) //設(shè)置列簇
          hcd.setMaxVersions(1)
          hcd.setCompressionType(Algorithm.GZ) //設(shè)定數(shù)據(jù)存儲的壓縮類型.默認(rèn)無壓縮(NONE)
          tableDescriptor.addFamily(hcd)
        })
      }
      val start = (0x7FFF / regionNum).toShort
      val end = (0x7FFF - start).toShort
      admin.createTable(tableDescriptor,Bytes.toBytes(start),Bytes.toBytes(end),regionNum)
    }

  }

第一種建表方式,需要在存取數(shù)據(jù)時采用MD5 算法構(gòu)造rowKey, 第二種需要構(gòu)造Hash前綴的rowKey.

通過以上方式建表和查詢能大幅提高Hbase 寫入和讀取速度窑邦,并且不會出現(xiàn)熱點region擅威。
可參考我在Github 上實現(xiàn):https://github.com/Smallhi/example

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市冈钦,隨后出現(xiàn)的幾起案子郊丛,更是在濱河造成了極大的恐慌,老刑警劉巖瞧筛,帶你破解...
    沈念sama閱讀 206,839評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件厉熟,死亡現(xiàn)場離奇詭異,居然都是意外死亡较幌,警方通過查閱死者的電腦和手機揍瑟,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來乍炉,“玉大人绢片,你說我怎么就攤上這事滤馍。” “怎么了底循?”我有些...
    開封第一講書人閱讀 153,116評論 0 344
  • 文/不壞的土叔 我叫張陵巢株,是天一觀的道長。 經(jīng)常有香客問我熙涤,道長阁苞,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,371評論 1 279
  • 正文 為了忘掉前任祠挫,我火速辦了婚禮猬错,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘茸歧。我一直安慰自己,他們只是感情好显沈,可當(dāng)我...
    茶點故事閱讀 64,384評論 5 374
  • 文/花漫 我一把揭開白布软瞎。 她就那樣靜靜地躺著,像睡著了一般拉讯。 火紅的嫁衣襯著肌膚如雪涤浇。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,111評論 1 285
  • 那天魔慷,我揣著相機與錄音只锭,去河邊找鬼。 笑死院尔,一個胖子當(dāng)著我的面吹牛蜻展,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播邀摆,決...
    沈念sama閱讀 38,416評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼纵顾,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了栋盹?” 一聲冷哼從身側(cè)響起施逾,我...
    開封第一講書人閱讀 37,053評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎例获,沒想到半個月后汉额,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,558評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡榨汤,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,007評論 2 325
  • 正文 我和宋清朗相戀三年蠕搜,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片收壕。...
    茶點故事閱讀 38,117評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡讥脐,死狀恐怖遭居,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情旬渠,我是刑警寧澤俱萍,帶...
    沈念sama閱讀 33,756評論 4 324
  • 正文 年R本政府宣布,位于F島的核電站告丢,受9級特大地震影響枪蘑,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜岖免,卻給世界環(huán)境...
    茶點故事閱讀 39,324評論 3 307
  • 文/蒙蒙 一岳颇、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧颅湘,春花似錦话侧、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至鹿寨,卻和暖如春新博,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背脚草。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評論 1 262
  • 我被黑心中介騙來泰國打工赫悄, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人馏慨。 一個月前我還...
    沈念sama閱讀 45,578評論 2 355
  • 正文 我出身青樓埂淮,卻偏偏與公主長得像,于是被迫代替她去往敵國和親写隶。 傳聞我的和親對象是個殘疾皇子同诫,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,877評論 2 345

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