Configurar pools de conexão

Algumas bibliotecas de cliente do Cloud Bigtable permitem configurar o número de canais gRPC em um pool de conexões do cliente, também conhecido como pool de canais. Na maioria dos casos, a configuração padrão está correta, e não é necessário alterá-la.

Os pools de conexões são redimensionados automaticamente conforme necessário quando você usa a biblioteca de cliente do Cloud Bigtable para Java versão 2.23.0 ou mais recente e quando você usa o cliente HBase do Cloud Bigtable para Java versão 2.9.1 ou mais recente.

Nesta página, descrevemos como determinar o tamanho ideal do pool de conexões para seu aplicativo e apresentamos snippets de código que mostram como configurar os pools de conexão.

Antes de ler esta página, leia a visão geral dos pools de conexão do Bigtable para saber como funcionam e se você deve alterar o seu.

As seguintes bibliotecas de cliente oferecem pool de conexões e permitem configurar o número de pools:

Determinar o melhor tamanho de pool de conexões

Para deixar espaço para flutuações de tráfego, o ideal é que um pool de conexões tenha por volta de duas vezes o número de conexões necessárias para a saturação máxima. Como uma conexão pode processar no máximo 100 solicitações simultâneas, entre 10 e 50 solicitações pendentes por conexão é o ideal. Esse conceito é descrito em mais detalhes em Pools de conexão.

Monitore seu tráfego após fazer alterações e ajuste o número de conexões no pool, se necessário.

As etapas a seguir ajudam você a calcular o número ideal de conexões no seu pool de canais usando métricas do lado do cliente, como as disponíveis no OpenCensus.

  1. Com as métricas do lado do cliente, colete as seguintes informações:
    1. O número máximo de consultas por segundo (QPS) por cliente quando o aplicativo está executando uma carga de trabalho típica.
    2. A latência média (o tempo de resposta para uma única solicitação) em ms.
  2. Determine o número de solicitações que podem ser enviadas em série por segundo dividindo 1.000 pelo valor médio da latência.
  3. Divida o QPS em segundos pelo número de solicitações seriais por segundo.
  4. Divida o resultado por 50 solicitações por canal para determinar o tamanho mínimo ideal do pool de canais. Se o cálculo for menor que 2, use pelo menos dois canais mesmo assim, para garantir redundância.
  5. Divida o mesmo resultado por 10 solicitações por canal para determinar o tamanho máximo do pool de canais.

Essas etapas são expressas nas seguintes equações:

  • (QPS ÷ (1.000 ÷ latência ms)) ÷ 50 streams = número mínimo ideal de conexões

  • ((QPS s ÷ (1.000 ÷ latência ms) ÷ 10 streams)) = número máximo ideal de conexões

Exemplo

O aplicativo normalmente envia 50.000 solicitações por segundo, e a latência média é de 10 ms. Divida 1.000 por 10 ms para determinar se é possível enviar 100 solicitações em série por segundo. Divida esse número por 50.000 para chegar ao paralelismo necessário para enviar 50.000 QPS: 500. Cada canal pode ter no máximo 100 solicitações ao mesmo tempo, e a utilização do seu canal de destino está entre 10 e 50 streams simultâneos. Portanto, para calcular o mínimo, divida 500 por 50 para chegar a 10. Para encontrar o máximo, divida 500 por 10 para chegar a 50. Isso significa que o tamanho do pool de canais para este exemplo deve estar entre 10 e 50 conexões.

Definir o tamanho do pool

Os exemplos de código a seguir demonstram como configurar o número de pools nas bibliotecas de cliente que permitem definir o tamanho do pool.

Go

import (
	"context"
	"fmt"
	"io"

	"cloud.google.com/go/bigtable"
	"google.golang.org/api/option"
)

func configureConnectionPool(w io.Writer, projectID, instanceID string) error {
	// projectID := "my-project-id"
	// instanceID := "my-instance-id"
	ctx := context.Background()

	// Set up Bigtable data operations client.
	poolSize := 10
	client, err := bigtable.NewClient(ctx, projectID, instanceID, option.WithGRPCConnectionPool(poolSize))
	defer client.Close()

	if err != nil {
		return fmt.Errorf("bigtable.NewClient: %w", err)
	}

	fmt.Fprintf(w, "Connected with pool size of %d", poolSize)

	return nil
}

HBase

Este exemplo é aplicável apenas para versões da biblioteca de cliente anteriores à 2.9.1, quando o redimensionamento automático foi introduzido.



import static com.google.cloud.bigtable.hbase.BigtableOptionsFactory.BIGTABLE_DATA_CHANNEL_COUNT_KEY;

import com.google.cloud.bigtable.hbase.BigtableConfiguration;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.client.Connection;

public class ConfigureConnectionPool {

  public static void configureConnectionPool(String projectId, String instanceId) {
    // String projectId = "my-project-id";
    // String instanceId = "my-instance-id";
    Configuration config = BigtableConfiguration.configure(projectId, instanceId);
    config.setInt(BIGTABLE_DATA_CHANNEL_COUNT_KEY, 10);
    try (Connection connection = BigtableConfiguration.connect(config)) {
      int poolSize = connection.getConfiguration().getInt(BIGTABLE_DATA_CHANNEL_COUNT_KEY, 0);

      System.out.println(String.format("Connected with pool size of %d", poolSize));
    } catch (Exception e) {
      System.out.println("Error during ConfigureConnectionPool: \n" + e.toString());
    }
  }
}

Java

Este exemplo é aplicável apenas para versões da biblioteca de cliente anteriores à 2.23.0, quando o redimensionamento automático foi introduzido.


import com.google.api.gax.grpc.InstantiatingGrpcChannelProvider;
import com.google.cloud.bigtable.data.v2.BigtableDataClient;
import com.google.cloud.bigtable.data.v2.BigtableDataSettings;
import com.google.cloud.bigtable.data.v2.stub.EnhancedBigtableStubSettings;
import java.io.IOException;

public class ConfigureConnectionPool {

  public static void configureConnectionPool(String projectId, String instanceId) {
    // String projectId = "my-project-id";
    // String instanceId = "my-instance-id";

    BigtableDataSettings.Builder settingsBuilder =
        BigtableDataSettings.newBuilder().setProjectId(projectId).setInstanceId(instanceId);

    settingsBuilder
        .stubSettings()
        .setTransportChannelProvider(
            EnhancedBigtableStubSettings.defaultGrpcTransportProviderBuilder()
                .setPoolSize(10)
                .build());

    BigtableDataSettings settings = settingsBuilder.build();
    try (BigtableDataClient dataClient = BigtableDataClient.create(settings)) {
      InstantiatingGrpcChannelProvider provider =
          (InstantiatingGrpcChannelProvider)
              settings.getStubSettings().getTransportChannelProvider();

      int poolSize = provider.toBuilder().getPoolSize();

      System.out.println(String.format("Connected with pool size of %d", poolSize));
    } catch (IOException e) {
      System.out.println("Error during ConfigureConnectionPool: \n" + e.toString());
    }
  }
}

C++

namespace cbt = ::google::cloud::bigtable;
namespace gc = ::google::cloud;
[](std::string const& project_id, std::string const& instance_id,
   std::string const& table_id) {
  auto constexpr kPoolSize = 10;
  auto options = gc::Options{}.set<gc::GrpcNumChannelsOption>(kPoolSize);
  cbt::Table table(cbt::MakeDataConnection(options),
                   cbt::TableResource(project_id, instance_id, table_id));
  std::cout << "Connected with channel pool size of " << kPoolSize << "\n";
}