Nesta página, descrevemos o conceito avançado de sessões no Spanner, incluindo práticas recomendadas para sessões ao criar uma biblioteca de cliente, usar as APIs REST ou RPC ou as bibliotecas de cliente do Google.
Visão geral das sessões
Uma sessão representa um canal de comunicação com o serviço de banco de dados do Spanner. Ela é usada para executar transações que leem, gravam ou modificam dados em um banco de dados do Spanner. Cada sessão aplica-se a um único banco de dados.
Com as sessões é possível executar uma ou várias transações por vez. Ao realizar várias transações, a sessão é chamada de sessão multiplexada.
Leituras, gravações e consultas independentes usam uma transação internamente.
Benefícios de desempenho de um pool de sessões
Criar uma sessão é algo caro. Para evitar o custo de desempenho sempre que uma operação de banco de dados for realizada, os clientes podem manter um pool de sessões, que é um conjunto de sessões disponíveis, prontas para serem usadas. O pool armazena as sessões existentes e retorna o tipo de sessão apropriado quando solicitado, além de lidar com a limpeza das sessões não utilizadas. Para um exemplo de como implementar um pool de sessões, consulte o código-fonte de uma das bibliotecas de cliente do Spanner, como a biblioteca de cliente Go ou a biblioteca de cliente Java.
Pretende-se que as sessões tenham duração longa. Portanto, após o uso de uma sessão em uma operação de banco de dados, o cliente deve retornar a sessão ao pool para reutilização.
Visão geral dos canais gRPC
Os canais gRPC são usados pelo cliente do Spanner para comunicação. Um canal gRPC é aproximadamente equivalente a uma conexão TCP. Um canal gRPC pode processar até 100 solicitações simultâneas. Isso significa que um aplicativo vai precisar de pelo menos tantos canais gRPC quanto o número de solicitações simultâneas que ele vai executar, dividido por 100.
O cliente do Spanner cria um pool de canais gRPC quando você o cria.
Práticas recomendadas ao usar bibliotecas de cliente do Google
Veja a seguir as práticas recomendadas ao usar as bibliotecas de cliente do Google para o Spanner.
Configurar o número de sessões e canais gRPC nos pools
As bibliotecas de cliente têm um número padrão de sessões no pool de sessões e um número padrão de canais gRPC no pool de canais. Ambos os padrões são adequados para a maioria dos casos. Confira abaixo as sessões mínimas e máximas padrão e o número padrão de canais gRPC para cada linguagem de programação.
C++
MinSessions: 100
MaxSessions: 400
NumChannels: 4
C#
MinSessions: 100
MaxSessions: 400
NumChannels: 4
Go
MinSessions: 100
MaxSessions: 400
NumChannels: 4
Java
MinSessions: 100
MaxSessions: 400
NumChannels: 4
Node.js
O cliente Node.js não é compatível com vários canais gRPC. Portanto, recomendamos criar vários clientes em vez de aumentar o tamanho do pool de sessões além de 100 sessões para um único cliente.
MinSessions: 25
MaxSessions: 100
PHP
O cliente PHP não aceita um número configurável de canais gRPC.
MinSessions: 1
MaxSessions: 500
Python
O Python é compatível com quatro tipos diferentes de tipos de pool de sessões, que podem ser usados para gerenciar sessões.
Ruby
O cliente Ruby não oferece suporte a vários canais gRPC. Portanto, recomendamos criar vários clientes em vez de aumentar o tamanho do pool de sessões além de 100 sessões para um único cliente.
MinSessions: 10
MaxSessions: 100
O número de sessões usadas pelo aplicativo é igual ao número de transações simultâneas que ele executa. Modifique as configurações padrão do pool de sessões somente se você espera que uma única instância de aplicativo execute mais transações simultâneas do que o pool de sessões padrão pode processar.
Para aplicativos de alta simultaneidade, recomendamos o seguinte:
- Defina
MinSessions
como o número esperado de transações simultâneas que um único cliente vai executar. - Defina
MaxSessions
como o número máximo de transações simultâneas que um único cliente pode executar. - Defina
MinSessions=MaxSessions
se a simultaneidade esperada não mudar muito durante a vida útil do aplicativo. Isso impede que o pool de sessões seja escalonado verticalmente. Aumentar ou diminuir o pool de sessões também consome alguns recursos. - Defina
NumChannels
comoMaxSessions / 100
. Um canal gRPC pode processar até 100 solicitações simultaneamente. Aumente esse valor se você observar uma alta latência de cauda (latência p95/p99), porque isso pode ser um indício de congestionamento do canal gRPC.
Aumentar o número de sessões ativas usa recursos adicionais no serviço de banco de dados do Spanner e na biblioteca de cliente. Aumentar o número de sessões além da necessidade real do aplicativo pode prejudicar a performance do sistema.
Aumentar o pool de sessões em vez do número de clientes
O tamanho do pool de sessões de um aplicativo determina quantas transações simultâneas uma única instância do aplicativo pode executar. Não é recomendável aumentar o tamanho do pool de sessões além da simultaneidade máxima que uma única instância de aplicativo pode processar. Se o aplicativo receber um pico de solicitações que exceda o número de sessões no pool, elas serão enfileiradas enquanto aguardam a disponibilidade de uma sessão.
Os recursos consumidos pela biblioteca de cliente são os seguintes:
- Cada canal gRPC usa uma conexão TCP.
- Cada invocação gRPC requer uma linha de execução. O número máximo de threads usados pela biblioteca de cliente é igual ao número máximo de consultas simultâneas que o aplicativo executa. Essas linhas de execução vêm acima de qualquer linha que o aplicativo use para a própria lógica de negócios.
Não é recomendável aumentar o tamanho do pool de sessões além do número máximo de linhas de execução que uma única instância de aplicativo pode processar. Em vez disso, aumente o número de instâncias do aplicativo.
Gerenciar a fração de sessões de gravação
Para algumas bibliotecas de cliente, o Spanner reserva uma parte das sessões para transações de leitura e gravação, chamada de fração de sessões de gravação. Se seu aplicativo usar todas as sessões de leitura, o Spanner usará as sessões de leitura e gravação, mesmo para transações somente leitura. As sessões de leitura e gravação exigem spanner.databases.beginOrRollbackReadWriteTransaction
. Se o usuário estiver no papel spanner.databaseReader
do IAM, a chamada vai falhar e o Spanner vai retornar esta mensagem de erro:
generic::permission_denied: Resource %resource% is missing IAM permission:
spanner.databases.beginOrRollbackReadWriteTransaction
É possível definir a fração de sessões de gravação para as bibliotecas de cliente que mantêm uma fração de sessões de gravação.
C++
Todas as sessões em C ++ são iguais. Não há sessões somente de leitura ou sessões de leitura e gravação.
C#
A fração padrão de sessões de gravação para C# é 0,2. É possível mudar a fração usando o campo WriteSessionsFraction de SessionPoolOptions
.
Go
Todas as sessões do Go são iguais. Não há sessões somente de leitura ou sessões de leitura e gravação.
Java
Todas as sessões do Java são iguais. Não há sessões somente de leitura ou sessões de leitura e gravação.
Node.js
Todas as sessões do Node.js são iguais. Não há sessões somente de leitura ou sessões de leitura e gravação.
PHP
Todas as sessões do PHP são as mesmas. Não há sessões somente de leitura ou sessões de leitura e gravação.
Python
O Python é compatível com quatro tipos diferentes de tipos de pool de sessões, que podem ser usados para gerenciar sessões de leitura e sessões de leitura e gravação.
Ruby
A fração padrão de sessões de gravação para Ruby é 0.3. Para alterar a fração, use o método de inicialização do cliente.
Práticas recomendadas ao criar uma biblioteca de cliente ou usar REST/RPC
Veja a seguir as práticas recomendadas para implementar sessões em uma biblioteca de cliente do Spanner ou para usar sessões com as APIs REST ou RPC.
Essas práticas recomendadas se aplicam somente se você estiver desenvolvendo uma biblioteca de cliente ou se estiver usando APIs REST/RPC. Se você estiver usando uma das bibliotecas de cliente do Google para o Spanner, consulte Práticas recomendadas ao usar bibliotecas de cliente do Google.
Criar e dimensionar o pool de sessões
Para determinar um tamanho ideal do pool de sessões para um processo do cliente, defina o limite inferior para o número de transações simultâneas esperadas e defina o limite superior para um número de teste inicial, como 100. Se o limite superior não for adequado, aumente-o. Aumentar o número de sessões ativas usa recursos adicionais no serviço de banco de dados do Spanner. Portanto, deixar de limpar as sessões não usadas pode prejudicar o desempenho. Para usuários que trabalham com a API RPC, recomendamos não ter mais de 100 sessões por canal gRPC.
Lidar com sessões excluídas
Há três maneiras de excluir uma sessão:
- Um cliente pode excluir uma sessão.
- O serviço de banco de dados do Spanner pode excluir uma sessão quando ela estiver inativa por mais de uma hora.
- O serviço de banco de dados do Spanner poderá excluir uma sessão se ela tiver mais de 28 dias.
As tentativas de usar uma sessão excluída resultam em NOT_FOUND
. Nesse caso, crie e use uma nova sessão, adicione-a ao pool e remova a sessão excluída dele.
Manter uma sessão inativa operante
O serviço de banco de dados do Spanner reserva-se o direito de encerrar uma sessão não utilizada. É possível impedir que a sessão seja encerrada, se você precisar mesmo manter uma sessão inativa operante, por exemplo, se for esperado um aumento significativo de curto prazo no uso do banco de dados. Realizar uma operação de baixo custo, como executar a consulta SQL SELECT 1
para manter a sessão ativa. Se você tiver uma sessão inativa que não precisará usar em curto prazo, deixe o Spanner encerrar a sessão e crie uma sessão nova na próxima vez em que ela for necessária.
Um cenário para manter as sessões ativas é lidar com a demanda de pico regular no banco de dados. Se ocorre um uso intenso do banco de dados diariamente das 9h às 18h, mantenha algumas sessões inativas disponíveis durante esse período, uma vez que elas provavelmente serão necessárias para o uso no horário de pico. Após as 18h, deixe o Spanner encerrar as sessões inativas. Todos os dias, antes das 9h, crie algumas sessões novas para que elas estejam prontas para a demanda esperada.
Outro cenário é se você tem um aplicativo que usa o Spanner, mas precisa evitar a sobrecarga de conexão. Mantenha um conjunto de sessões ativas para evitar que a sobrecarga de conexão aconteça.
Ocultar detalhes da sessão do usuário da biblioteca de cliente
Se você estiver criando uma biblioteca de cliente, não exponha sessões ao consumidor da biblioteca de cliente. Permita que o cliente faça chamadas de banco de dados sem a complexidade de criar e manter sessões. Para um exemplo de uma biblioteca de cliente que oculta os detalhes da sessão do consumidor, consulte a biblioteca de cliente do Spanner para Java.
Lidar com erros de transações de gravação que não sejam idempotentes
As transações de gravação sem proteção de repetição podem aplicar mutações mais de uma vez.
Se uma mutação não é idempotente, uma mutação que é aplicada mais de uma vez pode resultar em uma falha. Por exemplo, uma inserção pode apresentar falha com ALREADY_EXISTS
mesmo que a linha não exista antes da tentativa de gravação. Isso pode ocorrer se o servidor de back-end confirmou a mutação, mas não conseguiu comunicar o sucesso ao cliente. Nesse caso, a mutação poderia ser tentada novamente, resultando na falha ALREADY_EXISTS
.
Estas são as formas possíveis de abordar esse cenário quando você implementa sua própria biblioteca de cliente ou usa a API REST:
- Estruturar suas gravações para que sejam idempotentes.
- Usar gravações com proteção contra repetição.
- Implementar um método que execute a lógica "upsert": inserir se for novo ou atualizar se existir.
- Lidar com o erro em nome do cliente.
Manter conexões estáveis
Para melhor desempenho, a conexão utilizada para hospedar uma sessão deve permanecer estável. Quando a conexão que hospeda uma sessão é alterada, o Spanner pode anular a transação ativa na sessão e causar uma pequena carga extra no banco de dados enquanto atualiza os metadados da sessão. Não há problema se algumas conexões mudarem esporadicamente, mas devem ser evitadas situações em que um grande número de conexões mudam ao mesmo tempo. Quando você usar um proxy entre o cliente e o Spanner, a estabilidade da conexão deverá ser mantida em todas as sessões.
Monitorar sessões ativas
É possível usar o comando ListSessions
para monitorar sessões ativas no banco de dados pela linha de comando, com a API REST ou com a API RPC. ListSessions
mostra as sessões ativas de um determinado banco de dados. Isso é útil se você precisa encontrar a causa de um vazamento de sessão. (Um vazamento de sessão é um incidente em que as sessões estão sendo criadas, mas não retornadas para um pool de sessões para reutilização.)
Com ListSessions
, você visualiza metadados das sessões ativas, inclusive quando uma sessão foi criada e quando uma sessão foi usada pela última vez. Analisar esses dados vai
lhe mostrar a direção certa na hora de solucionar problemas. Se a maioria das sessões ativas não tiver um approximate_last_use_time
recente, isso pode indicar que as sessões não estão sendo reutilizadas corretamente pelo seu aplicativo. Consulte a referência da API RPC para mais informações sobre o campo approximate_last_use_time
.
Para mais informações sobre como usar ListSessions
, consulte a referência da API REST, a referência da API RPC ou a referência da ferramenta de linha de comando gcloud.
Limpeza automática de vazamentos de sessão
Quando você usa todas as sessões no pool, cada nova transação aguarda até que uma sessão seja retornada ao pool. Quando as sessões são criadas, mas não retornadas ao pool para reutilização, isso é chamado de vazamento de sessão. Quando há um vazamento de sessão, as transações que aguardam uma sessão aberta ficam presas indefinidamente e bloqueiam o aplicativo. Os vazamentos de sessão geralmente são causados por transações problemáticas que estão em execução por um período extremamente longo e não são confirmadas.
É possível configurar o pool de sessões para resolver automaticamente essas transações inativas. Quando você ativa a biblioteca de cliente para resolver automaticamente transições inativas, ela identifica transações problemáticas que podem causar um vazamento de sessão, remove essas transações do pool de sessões e as substitui por uma nova sessão.
O registro em log também pode ajudar a identificar essas transações problemáticas. Se a geração de registros estiver ativada, os registros de aviso serão compartilhados por padrão quando mais de 95% do pool de sessões estiver em uso. Se o uso da sessão for maior que 95%, aumente o número máximo de sessões permitidas no pool de sessões ou verifique se há um vazamento de sessão. Os registros de aviso contêm rastreamentos de pilha de transações que são executadas por mais tempo do que o esperado e podem ajudar a identificar a causa da alta utilização do pool de sessões. Os registros de aviso são enviados de acordo com a configuração do exportador de registros.
Permitir que a biblioteca de cliente resolva automaticamente transações inativas
É possível ativar a biblioteca de cliente para enviar registros de aviso e resolver automaticamente transações inativas ou ativar a biblioteca de cliente para receber apenas registros de aviso.
Java
Para receber registros de aviso e remover transações inativas, use setWarnAndCloseIfInactiveTransactions
.
final SessionPoolOptions sessionPoolOptions = SessionPoolOptions.newBuilder().setWarnAndCloseIfInactiveTransactions().build()
final Spanner spanner =
SpannerOptions.newBuilder()
.setSessionPoolOption(sessionPoolOptions)
.build()
.getService();
final DatabaseClient client = spanner.getDatabaseClient(databaseId);
Para receber apenas registros de aviso, use
setWarnIfInactiveTransactions
.
final SessionPoolOptions sessionPoolOptions = SessionPoolOptions.newBuilder().setWarnIfInactiveTransactions().build()
final Spanner spanner =
SpannerOptions.newBuilder()
.setSessionPoolOption(sessionPoolOptions)
.build()
.getService();
final DatabaseClient client = spanner.getDatabaseClient(databaseId);
Go
Para receber registros de aviso e remover transações inativas, use
SessionPoolConfig
com InactiveTransactionRemovalOptions
.
client, err := spanner.NewClientWithConfig(
ctx, database, spanner.ClientConfig{SessionPoolConfig: spanner.SessionPoolConfig{
InactiveTransactionRemovalOptions: spanner.InactiveTransactionRemovalOptions{
ActionOnInactiveTransaction: spanner.WarnAndClose,
}
}},
)
if err != nil {
return err
}
defer client.Close()
Para receber apenas registros de aviso, use customLogger
.
customLogger := log.New(os.Stdout, "spanner-client: ", log.Lshortfile)
// Create a logger instance using the golang log package
cfg := spanner.ClientConfig{
Logger: customLogger,
}
client, err := spanner.NewClientWithConfig(ctx, db, cfg)
Sessões multiplexadas
Com as sessões multiplexadas, é possível criar um grande número de solicitações simultâneas em uma única sessão. Uma sessão multiplexada é um identificador que você usa em vários canais gRPC. Ele não introduz gargalos adicionais. As sessões multiplexadas têm as seguintes vantagens:
- Consumo reduzido de recursos de back-end devido a um protocolo de gerenciamento de sessão mais simples. Por exemplo, eles evitam atividades de manutenção de sessão associadas à manutenção da propriedade da sessão e à coleta de lixo.
- Sessão de longa duração que não exige solicitações de manutenção quando está inativa.
As sessões multiplexadas são compatíveis com o seguinte:
- As bibliotecas de cliente Java e Go.
Ferramentas do ecossistema do Spanner que dependem das bibliotecas de cliente Java e Go, como PGAdapter, JDBC, Hibernate, driver database/sql e GORM.
Ferramentas do ecossistema do Spanner que dependem das bibliotecas de cliente Java e Go, como PGAdapter, JDBC, Hibernate, driver de banco de dados ou SQL e GORM. Use as métricas do OpenTelemetry para ver como o tráfego é dividido entre o pool de sessões atual e a sessão multiplexada. O OpenTelemetry tem um filtro de métricas,
is_multiplexed
, que mostra sessões multiplexadas quando definido comotrue
.
As sessões multiplexadas são compatíveis com todos os tipos de transações.
As bibliotecas de cliente fazem a rotação das sessões multiplexadas a cada sete dias para evitar o envio de transações em sessões desatualizadas.
As sessões multiplexadas ficam desativadas por padrão. É necessário usar variáveis de ambiente para ativar sessões multiplexadas antes de usá-las nos aplicativos cliente. Para ativar sessões multiplexadas usando Java ou Go, consulte Ativar sessões multiplexadas.
Considerações
Se você estiver tentando confirmar um corpo de transação de leitura ou gravação vazio ou uma transação em que todas as consultas ou instrução DML falharam, há alguns cenários a serem considerados com sessões multiplexadas. As sessões multiplexadas exigem
que você inclua um token de pré-commit gerado pelo servidor em cada solicitação de commit. Para transações que contêm consultas ou DML, é necessário ter pelo menos uma consulta ou transação DML anterior bem-sucedida para que o servidor envie um token válido de volta à biblioteca de cliente. Se não houver consultas ou transações DML bem-sucedidas, a biblioteca de cliente vai adicionar implicitamente SELECT 1
antes de um commit.
Em uma transação de leitura ou gravação em uma sessão multiplexada que só tem mutações, se uma das mutações for para uma tabela ou coluna que NÃO existe no esquema, o cliente poderá retornar um erro INVALID_ARGUMENT
em vez de um erro NOT_FOUND
.
Ativar sessões multiplexadas
Para usar sessões multiplexadas nos aplicativos cliente, primeiro defina uma variável de ambiente para ativar esse recurso.
Para ativar sessões multiplexadas, defina a variável de ambiente GOOGLE_CLOUD_SPANNER_MULTIPLEXED_SESSIONS
como TRUE
. Essa
flag também ativa o suporte a sessões multiplexadas para transações ReadOnly
.
export GOOGLE_CLOUD_SPANNER_MULTIPLEXED_SESSIONS=TRUE
Para ativar o suporte a operações particionadas em sessões multiplexadas, defina a variável de ambiente GOOGLE_CLOUD_SPANNER_MULTIPLEXED_SESSIONS_PARTITIONED_OPS
como TRUE
.
export GOOGLE_CLOUD_SPANNER_MULTIPLEXED_SESSIONS_PARTITIONED_OPS=TRUE
Para ativar o suporte a transações de leitura e gravação em sessões multiplexadas, defina a variável de ambiente GOOGLE_CLOUD_SPANNER_MULTIPLEXED_SESSIONS_FOR_RW
como TRUE
.
export GOOGLE_CLOUD_SPANNER_MULTIPLEXED_SESSIONS_FOR_RW=True
É necessário definir GOOGLE_CLOUD_SPANNER_MULTIPLEXED_SESSIONS
como TRUE
como pré-requisito para oferecer suporte a uma transação em uma sessão multiplexada.
Ver o tráfego de sessões regulares e multiplexadas
O Opentelemetry tem o filtro is_multiplexed
para mostrar o tráfego de sessões multiplexadas. Defina esse filtro como true to view multiplexed sessions
and
false` para ver as sessões regulares.
- Configure o OpenTelemetry para Spanner usando os procedimentos na seção Spanner OpenTelemetry Antes de começar.
Acesse o Metrics Explorer.
No menu suspenso Métrica, filtre por
generic
.Clique em Tarefa genérica e navegue até Spanner > Spanner/num_acquired_sessions.
No campo Filtro, selecione uma das seguintes opções:
a.
is_multiplexed = false
para ver as sessões regulares. b.is_multiplexed = true
para conferir as sessões multiplexadas.A imagem a seguir mostra a opção Filtrar com sessões multiplexadas selecionadas.
Para mais informações sobre o uso do OpenTelemetry com o Spanner, consulte Como aproveitar o OpenTelemetry para democratizar a capacidade de observação do Spanner e Examinar a latência em um componente do Spanner com o OpenTelemetry.