2016-01-12 24 views
3

聲明

我們有10臺機器HBase集羣和數十億行內部。每行由一個列族和〜20列組成。我們需要執行頻繁的掃描請求,其中包含起始行前綴和結束行前綴。通常每次掃描都會返回100到10000行。在Java和Python中對HBase的並行掃描請求具有不同的性能

因爲請求可能會經常發生(每分鐘最多幾個請求),所以性能會被預先設置。由於系統的體系結構,我們希望用Python代替當前的Java代碼來實現我們的解決方案。問題出在Python上,我們得到的性能比Java差5至10倍。

什麼現在工作

我們有執行掃描請求到HBase的Java代碼。它採用ususal的HBase的Java API:

public List<String> getNumber(Number key) { 
    List<String> res = new ArrayList<>(); 

    String start_key = key.getNumber(); 
    String next_key = key.getNumber() + "1"; 
    byte[] prefix_begin = Bytes.toBytes(start_key); 
    byte[] prefix_end = Bytes.toBytes(next_key); 
    Scan scan = new Scan(prefix_begin, prefix_end); 
    ResultScanner scanner = table.getScanner(scan); 
    for (Result result : scanner) { 
     byte[] row = result.getRow(); 
     res.add(Bytes.toString(row)); 
    } 

    return res; 
} 

這些查詢Callable接口和ScheduledThreadPoolExecutor的幫助下並行。每個可調用的call()方法僅運行getNumber(Number key)

public List<String> getNumbers(List<Number> keys) { 
    List<String> res = new ArrayList<String>(); 

    List<Callables.CallingCallable> callables = new ArrayList(); 
    for (Number source : keys) { 
     callables.add(new Callables.CallingCallable(this, source)); 
    } 

    Object futures = new ArrayList(); 
    ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(24); 

    try { 
     futures = executor.invokeAll(callables); 
    } catch (InterruptedException ex) { 
    } 

    executor.shutdown(); 
} 

這工作相當好,並允許達到以下性能:

  • 1.5 - 每單次掃描2.0秒
  • 5.0 - 8.0秒每100並行掃描

我們試試

我們試圖實現與Happybase庫的幫助在Python類似的解決方案:

@staticmethod 
def execute_query(key, table_name, con_pool): 
     items = [] 
     with con_pool.connection() as connection: 
      table = happybase.Table(table_name, connection) 
      [row_start, row_end] = get_start_and_end_row(key) 
      selected_rows = table.scan(row_start=row_start, row_stop=row_end) 
      for key, data in selected_rows: 
       items.append(Item(data)) 
     return items 

@staticmethod 
def execute_in_parallel(table_name, hbase_host, hbase_port, keys): 
     pool = ThreadPool(24) 
     con_pool = happybase.ConnectionPool(size=24, host=hbase_host, port=hbase_port) 
     execute_query_partial = partial(execute_query, table_name=table_name, con_pool=con_pool) 
     result_info = pool.map_async(execute_query_partial, keys, chunksize=1) 
     result = result_info.get() 

達到的性能:

  • 2.0 - 每一次掃描3.0秒
  • 30 - 55 sec每100次並行掃描

正如我們所看到的,單次掃描的性能非常相似。但Python中的並行任務要慢得多。

任何想法爲什麼會發生?也許我們的Python/Happybase代碼存在一些問題?還是HBase Thrift服務器(HappyBase用來連接HBase)的性能?

回答

1

有一種使用Jython的方法,它允許您訪問Java JVM和Java庫。有了這個,你可以在同一個源文件中編寫python和java。然後將代碼編譯爲JVM的Java字節碼。這應該與Jython用java代碼編寫的性能相同,因此您不必使用純Java編寫代碼。

Java基準測試與Python相比要高得多。這是一個顯示java和python之間性能的網站。

http://benchmarksgame.alioth.debian.org/u64q/python.html

,這裏是Jython的網站: http://www.jython.org/