2015-12-17 1 views
2

У меня есть одна маленькая таблица (размером 100 Мб) в большой таблице с 10 экземплярами. Когда я пытаюсь сканировать/получать строку один раз в 1 минуту, латентность вызова составляет более 300 мс. Если я нахожусь с более частыми вызовами, например, каждую секунду, латентность составляет 50-60 мс. Я не уверен, как повысить производительность при использовании низкочастотных вызовов. это ожидаемое поведение. или я делаю что-то неправильно.Большое сканирование/время отклика (латентность) при низких частотных вызовах очень высокое

Вот мой тестовый код. Я создал одного исполнителя для двух клиентских подключений hbase к большой таблице. но ответ низкочастотного соединения медленнее, чем соединение, которое вызывает более частые звонки.

Любые предложения?

package com.bids; 

import java.io.IOException; 
import java.util.ArrayList; 
import java.util.LinkedHashMap; 
import java.util.List; 
import java.util.Map; 
import java.util.concurrent.ExecutorService; 
import java.util.concurrent.Executors; 

import org.apache.hadoop.conf.Configuration; 
import org.apache.hadoop.hbase.CellUtil; 
import org.apache.hadoop.hbase.HBaseConfiguration; 
import org.apache.hadoop.hbase.TableName; 
import org.apache.hadoop.hbase.client.Connection; 
import org.apache.hadoop.hbase.client.ConnectionFactory; 
import org.apache.hadoop.hbase.client.Result; 
import org.apache.hadoop.hbase.client.ResultScanner; 
import org.apache.hadoop.hbase.client.Scan; 
import org.apache.hadoop.hbase.client.Table; 
import org.apache.hadoop.hbase.filter.FilterList; 
import org.apache.hadoop.hbase.util.Bytes; 
import org.fusesource.jansi.AnsiConsole; 

public class BTConnectTest { 
    public static void main(String[] args) throws IOException, InterruptedException { 

     Configuration hBaseConfig = HBaseConfiguration.create(); 
     hBaseConfig.set("google.bigtable.project.id", "xxxxxxx"); 
     hBaseConfig.set("google.bigtable.cluster.name", "hbase-test1"); 
     hBaseConfig.set("google.bigtable.zone.name", "us-central1-b"); 
     hBaseConfig.set("hbase.client.connection.impl", "com.google.cloud.bigtable.hbase1_1.BigtableConnection"); 

     ExecutorService executor = Executors.newSingleThreadExecutor(); 

     final Connection bigTableConnection1 = ConnectionFactory.createConnection(hBaseConfig, executor); 

     final Connection bigTableConnection2 = ConnectionFactory.createConnection(hBaseConfig, executor); 

     Thread t = new Thread(new Runnable() { 

      @Override 
      public void run() { 
       while (true) { 
        try { 
         Thread.sleep(1000); 
        } catch (InterruptedException e1) { 
         // TODO Auto-generated catch block 
         e1.printStackTrace(); 
        } 
        long before = System.nanoTime(); 
        try { 
         makeACall2Bigtable(bigTableConnection2); 
        } catch (Exception e) { 
         // TODO Auto-generated catch block 
         e.printStackTrace(); 
        } 
        // bigTableConnection.close(); 
        long after = System.nanoTime(); 

        long diff = after - before; 

        System.out.println("\t\t\t\t\t\t connection: " + 1 + " diff: " + diff/(1000 * 1000)); 
       } 
      } 
     }); 
     t.start(); 

     long sum = 0; 
     int n = 0; 
     while (true) { 
      if (n > 60) { 
       Thread.sleep(60000); 
      } 

      long before = System.nanoTime(); 

      Connection bigTableConnection = bigTableConnection1; 
      int label = -1; 

      makeACall2Bigtable(bigTableConnection); 
      long after = System.nanoTime(); 

      long diff = after - before; 
      n = n + 1; 
      sum += diff; 
      long avg = sum/(n * 1000 * 1000); 
      AnsiConsole a = new AnsiConsole(); 

      System.out.println("connection: " + 0 + " diff: " + diff/(1000 * 1000) + " avg: " + avg); 

     } 
     // bigTableConnection.close(); 

    } 

    private static void makeACall2Bigtable(Connection bigTableConnection) throws IOException { 

     Table table = bigTableConnection.getTable(TableName.valueOf("customer")); 
     Scan scan = new Scan(); 
     scan.setStartRow(Bytes.toBytes("101")); 
     scan.setStopRow(Bytes.toBytes("102")); 
     List<String> cols = new ArrayList<String>(3); 
     cols.add("name"); 
     cols.add("age"); 
     cols.add("weight"); 
     String keyName = "id"; 
     final String DEFAULT_COLFAM = "z"; 
     for (String col : cols) { 
      scan.addColumn(Bytes.toBytes(DEFAULT_COLFAM), Bytes.toBytes(col)); 
     } 
     ResultScanner resultScanner = table.getScanner(scan); 

     for (Result result : resultScanner) { 
      Map<String, String> columnValueMap = new LinkedHashMap<String, String>(); 
      for (String col : cols) { 
       if (result.containsColumn(Bytes.toBytes(DEFAULT_COLFAM), Bytes.toBytes(col))) { 
        columnValueMap.put(col, new String(CellUtil.cloneValue(
          result.getColumnLatestCell(Bytes.toBytes(DEFAULT_COLFAM), Bytes.toBytes(col))))); 
       } else { 
        if (cols.contains(keyName)) { 
         columnValueMap.put(col, null); 
        } 

       } 
      } 

     } 
     resultScanner.close(); 
     table.close(); 

    } 

} 
+1

Важно отметить, что ваши подключения связаны с другим хостинг-провайдером, который имеет непредсказуемую производительность. Запросы из центра обработки данных обычно отвечают в течение 4-6 мс. –

ответ

4
  • Первые несколько звонков медленнее из-за известных проблем. Некоторая настройка , которая происходит на стороне сервера для каждого «канала», и у нас есть несколько каналов.
  • Вам не нужен finalFilterList.
  • Вы должны кэшировать свои байты семейства Scan, TableName и family. Вы можете их повторно использовать.
  • Если вы получаете одну строку, сделайте Get вместо сканирования.
  • Вам нужен исполнитель?
  • Возможно, ваше сканирование должно использовать setMaxVersions (1), чтобы быть в безопасности.
  • Возможно, попробуйте scan.setStartRow (Bytes.toBytes («101»)) и scan.setStopRow (Bytes.toBytes («102»)) вместо префикса строки, чтобы узнать, помогает ли это?
  • Убедитесь, что ваш код запущен в той же зоне, что и ваш кластер.

Я надеюсь, что это поможет.

+0

@sduskis проблема с производительностью все еще существует, несмотря на некоторые из вышеперечисленных изменений. Это выше всего лишь тестовый код для имитации проблемы. Я использую исполнителя, чтобы ограничить количество потоков во время соединения, при этом соединение по умолчанию запускается с ~ 300 потоками (я бы это внутренне использовал newCachedThreadPool). Также я не могу кэшировать имя таблицы, потому что это параметр ввода для моего сервиса. Услуга не предназначена для одной таблицы. – PraveenK

3

Если вы действительно собираетесь делать низкочастотные запросы в процессе производства, вы можете запустить фоновый поток, который делает случайный запрос в вашей таблице каждые несколько секунд.

Bigtable действительно оптимизирован для большого объема данных с частым доступом. Первый запрос через некоторое время может потребовать повторного чтения данных. Периодические запросы будут держать его в живых.

+3

Когда я запускаю один и тот же кусок кода из виртуальных машин Google, время отклика намного выше, чем 3 мс для высокочастотных вызовов и до 19 мс для низких частых звонков .. это здорово. – PraveenK

Смежные вопросы