使用Spark RDD實現HBase分佈式scan

使用Spark RDD實現hbase分佈式Scan

主要思路

利用Spark RDD的分佈式計算,將一個Scan任務按照自定義的範圍切分爲小的scan,使用這些RDD實現對scan的並行查詢,提高查詢效率。核心是手動實現RDD的compute方法與getPartitions方法。

關於Spark RDD

本文中使用到的關於Spark RDD方面的知識主要集中在RDD分區計算上,查看spark源碼即可知道,spark RDD中有兩個比較重要的方法,一個是compute 用於計算一個指定的分區給當前RDD,一個是getPartitions用於獲取當前RDD的一組分區。

主要代碼實現

下面是主要的代碼實現,具體關於分區範圍的值需要自己根據實際情況和自己的需求實現

class HBaseScanRDD(sc: SparkContext, val table: Table) //此處table值不應該出現,僅用於跳過編譯錯誤
extends RDD[Result](sc, Nil) {

var ranges = Seq.empty[HRegionInfo]
var regions = new ArrayHRegionInfo

override protected def getPartitions: Array[Partition] = {
var idx = 0
val ps = regions.flatMap { _ =>
val rs = ranges
idx += 1
if (rs.nonEmpty)
Some(idx - 1, rs) //這裏的結果爲自定義的HBasePartition
else
None
}
ps.asInstanceOf[Array[Partition]]
}

@DeveloperApi
override def compute(partition: Partition, context: TaskContext): >Iterator[Result] = {
val split = partition.asInstanceOf[HBasePartition]
//繼承Partition即可
val scans = split.scanRanges //構建小的Scan,推薦按照region的>startkey endkey進行切分
.map { range =>
//(start,end)的四種情況
(range.getStartKey, range.getEndKey) match {
case (a, b) => new Scan(a, b)
case (a, None) => new Scan(a)
case (None, b) => new Scan(ArrayByte, b)
case (None, None) => new Scan()
}
}
//並行scan
scans.par.map { scan =>
table.getScanner(scan)
}.map(toResultIterator)
.fold(Iterator.empty: Iterator[Result]) { case (x, y) =>
x ++ y
}
}

//這裏用於獲取scanner的值
private def toResultIterator(scanner: ResultScanner): Iterator[Result] = {
val iterator = new Iterator[Result] {
var cur: Option[Result] = None

 override def hasNext: Boolean = {
  if (cur.isEmpty) {
     val r = scanner.next()
     if (r == null) {
     } else {
       cur = Some(r)
     }
   }
   cur.isDefined
 }

 override def next(): Result = {
  hasNext
  val ret = cur.get
 cur = None

ret
}
}
iterator
}
}

case class HBasePartition(
override val index: Int,
scanRanges: Seq[HRegionInfo]) extends Partition

以上代碼只是用於描述思路,實際使用時還需要對代碼細節進行處理

注意:由於spark源碼定義RDD爲private[spark],所以該類只能放置與名稱爲org.apache.hadoop.hbase.spark的包或子包中,否則會出現編譯錯誤。
u
非tips: 由於hbase的scan在服務端查詢時,會分爲兩類scanner,一個查詢memstore,一個查詢hfile,
其中查找hfile的scanner會根據設置參數”hbase.storescanner.parallel.seek.enable”
決定是否使用多線程對文件進行查詢,所以建議將該參數設置爲true。

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