Bigtable время сканирования / получения ответа (задержка) при низкочастотных вызовах очень велико
У меня есть одна маленькая таблица (размером 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();
}
}
2 ответа
- Первые несколько вызовов медленнее из-за известных проблем. Некоторые настройки, которые происходят на стороне сервера для каждого "Канала", и у нас есть несколько каналов.
- Вы не должны нуждаться в finalFilterList.
- Вы должны кэшировать ваши байты Scan, TableName и семейства столбцов. Вы можете использовать их повторно.
- Если вы получаете одну строку, сделайте Get вместо сканирования.
- Вам нужен исполнитель?
- Ваше сканирование, вероятно, должно использовать setMaxVersions(1) просто для безопасности.
- Возможно, попробуйте scan.setStartRow(Bytes.toBytes("101")) и scan.setStopRow(Bytes.toBytes("102")) вместо префикса строки, чтобы увидеть, помогает ли это?
- Убедитесь, что ваш код выполняется в той же зоне, что и ваш кластер.
Надеюсь, это поможет.
Если вы действительно собираетесь выполнять низкочастотные запросы в рабочей среде, вы можете запускать фоновый поток, который каждые несколько секунд делает случайный запрос к вашей таблице.
Bigtable действительно оптимизирован для большого количества данных с частым доступом. Первый запрос через некоторое время может потребовать повторного считывания данных. Периодические запросы будут поддерживать его.