Estatísticas de divisão

Este documento descreve como detectar e depurar hotspots no seu banco de dados. É possível acessar estatísticas sobre pontos de acesso em divisões com GoogleSQL e PostgreSQL.

O Spanner armazena seus dados como um espaço de chaves contíguo, ordenado pelas chaves primárias das tabelas e índices. Uma divisão é um intervalo de linhas de um conjunto de tabelas ou um índice. O início da divisão é chamado de início da divisão. O limite de divisão define o fim da divisão. A divisão inclui o início, mas não o limite.

No Spanner, pontos de acesso são situações em que muitas solicitações são enviadas para o mesmo servidor, o que satura os recursos dele e pode causar latências altas. As divisões afetadas por pontos de acesso são conhecidas como divisões ativas ou quentes.

A estatística de hotspot de uma divisão (identificada no sistema como CPU_USAGE_SCORE) é uma medição da carga em uma divisão limitada pelos recursos disponíveis no servidor. Essa medição é fornecida como uma porcentagem. Se mais de 50% da carga em uma divisão for limitada pelos recursos disponíveis, ela será considerada quente. Se 100% da carga em uma divisão for limitada, ela será considerada ativa. Essas divisões dinâmicas também podem afetar a latência das solicitações atendidas por elas.

O CPU_USAGE_SCORE de uma divisão pode permanecer constante ou variar com o tempo com base na carga de trabalho que acessa a divisão e nas mudanças nos limites dela.

Com base nas restrições de recursos de divisão quente e fria, o Spanner pode usar a divisão baseada em carga para distribuir uniformemente a carga no espaço de chaves. As divisões quente e morna podem ser movidas entre os servidores da instância para balanceamento de carga. O Spanner realiza a divisão baseada em carga em segundo plano, minimizando o impacto na latência. No entanto, o Spanner pode não conseguir equilibrar a carga, mesmo após várias tentativas de divisão, devido a antipadrões no aplicativo. A coluna UNSPLITTABLE_REASONS nas visualizações de estatísticas fornece motivos específicos para que uma divisão quente ou morna não possa ser dividida ainda mais. Portanto, divisões persistentes quentes ou muito quentes que duram pelo menos 10 minutos podem precisar de mais solução de problemas e possíveis mudanças no aplicativo, especialmente quando UNSPLITTABLE_REASONS estão presentes.

As estatísticas de divisão ativa do Spanner ajudam a identificar as divisões em que ocorrem pontos de acesso e entender por que eles podem persistir. Essas estatísticas, combinadas com códigos UNSPLITTABLE_REASONS, ajudam a diagnosticar as ações necessárias para resolver os pontos de acesso. Em seguida, faça as mudanças necessárias no aplicativo ou esquema.

Como acessar as estatísticas de divisão frequente

O Spanner fornece as estatísticas de divisão dinâmica no esquema SPANNER_SYS. Os dados do SPANNER_SYS estão disponíveis nas interfaces do GoogleSQL e do PostgreSQL. Você pode acessar esses dados das seguintes maneiras:

Os seguintes métodos de leitura única fornecidos pelo Spanner não são compatíveis com SPANNER_SYS:

  • realizar uma leitura forte de uma única linha ou de várias linhas em uma tabela;
  • realizar uma leitura desatualizada de uma única linha ou várias linhas em uma tabela;
  • ler uma única linha ou várias linhas em um índice secundário.

Estatísticas de divisões ativas

Use as seguintes visualizações para acompanhar divisões de alta demanda:

  • SPANNER_SYS.SPLIT_STATS_TOP_MINUTE: mostra divisões que estão em alta durante intervalos de um minuto.
  • SPANNER_SYS.SPLIT_STATS_TOP_10MINUTE: mostra divisões que estão em alta durante qualquer parte de um intervalo de 10 minutos.
  • SPANNER_SYS.SPLIT_STATS_TOP_HOUR: mostra divisões que estão em alta durante qualquer parte de um intervalo de uma hora.

Essas visualizações têm as seguintes propriedades:

  • Cada uma contém dados para intervalos de tempo não sobrepostos da duração que o nome da visualização especifica.
  • Os intervalos são baseados em horas:
    • Os intervalos de um minuto terminam no minuto.
    • Os intervalos de 10 minutos terminam no 10º minuto da hora, por exemplo, 11:10:00, 11:20:00.
    • Os intervalos de uma hora terminam na hora.
  • Após cada intervalo, o Spanner coleta dados de todos os servidores e disponibiliza os dados nas visualizações SPANNER_SYS pouco tempo depois. Por exemplo, às 11h59m30s, os intervalos mais recentes disponíveis para consultas SQL são:
    • 1 minuto: 11h58min00s-11h58min59s
    • 10 minutos: 11h40min00s-11h49min59s
    • 1 hora: 10:00:00-10:59:59
  • O Spanner agrupa as estatísticas por divisões.
  • Cada linha contém estatísticas, incluindo a porcentagem de CPU_USAGE_SCORE, que indica o nível de atividade de uma divisão, para cada divisão em que o Spanner captura estatísticas durante o intervalo especificado.
  • A visualização SPANNER_SYS.SPLIT_STATS_TOP_MINUTE oferece estatísticas detalhadas de divisão a cada minuto. Use esta visualização para depurar eventos recentes em detalhes.
  • As visualizações SPANNER_SYS.SPLIT_STATS_TOP_10MINUTE e SPANNER_SYS.SPLIT_STATS_TOP_HOUR oferecem uma visão agregada em intervalos de 10 minutos e de uma hora, respectivamente. Use essas visualizações para analisar tendências ou investigar problemas nos últimos dias ou semanas. Para mais informações sobre agregação, consulte Ver agregação de eventos.
  • Se o Spanner não puder armazenar todas as divisões ativas durante o intervalo, o sistema vai priorizar as divisões com a maior porcentagem de CPU_USAGE_SCORE durante o intervalo especificado. Se não houver divisões retornadas, isso indica a ausência de divisões muito usadas.

Retenção de dados

A quantidade máxima de dados que o Spanner retém para cada visualização, a qualquer momento, é a seguinte:

  • SPANNER_SYS.SPLIT_STATS_TOP_MINUTE: intervalos que abrangem as 24 horas anteriores.
  • SPANNER_SYS.SPLIT_STATS_TOP_10MINUTE: intervalos que abrangem os quatro dias anteriores.
  • SPANNER_SYS.SPLIT_STATS_TOP_HOUR: intervalos que abrangem os últimos 30 dias.

Não é possível aumentar ou diminuir esses períodos de retenção, e não é possível impedir que o Spanner colete estatísticas de divisão dinâmica.

  • Para excluir dados de estatísticas, exclua o banco de dados que está sendo rastreado ou aguarde até que os dados de estatísticas saiam da retenção.
  • Para reter dados de estatísticas por períodos mais longos, copie periodicamente os dados das visualizações de estatísticas de divisão ativa.

Mostrar esquema

A tabela a seguir mostra o esquema das estatísticas de divisão frequente:

Nome da coluna Tipo Descrição
INTERVAL_END TIMESTAMP Fim do intervalo de tempo em que a divisão estava ativa ou quente.
SPLIT_START STRING A chave inicial do intervalo de linhas na divisão. O início da divisão também pode ser <begin>, indicando o início do espaço de chaves.
SPLIT_LIMIT STRING A chave de limite do intervalo de linhas na divisão. A chave de limite também pode ser <end>, indicando o fim do espaço de chaves.
CPU_USAGE_SCORE INT64 A porcentagem de CPU_USAGE_SCORE das divisões. Uma porcentagem de CPU_USAGE_SCORE de 50% indica a presença de divisões quentes ou ativas.
AFFECTED_TABLES STRING ARRAY As tabelas com linhas que podem estar na divisão.
UNSPLITTABLE_REASONS STRING ARRAY Identifica o tipo de pontos de acesso presentes que a divisão baseada em carga não pode reduzir, geralmente devido a antipadrões. A presença de qualquer motivo indica que provavelmente é necessária uma intervenção do usuário, como ajustes de esquema ou de carga de trabalho. Uma matriz vazia significa que nenhuma condição não divisível foi detectada durante esse intervalo ou que a carga alta foi muito breve para que o Spanner determinasse se ela era não divisível. Consulte tipos de UNSPLITTABLE_REASONS para mais detalhes.

Chaves de início e limite de divisão

Uma divisão é um intervalo de linhas contíguas de um banco de dados, definido pelas chaves de início e limite. Uma divisão pode ser uma única linha, um intervalo de linhas estreito ou amplo, e pode incluir várias tabelas ou índices.

As colunas SPLIT_START e SPLIT_LIMIT identificam as chaves primárias de uma divisão quente ou fria.

Esquema de exemplo

O esquema a seguir é uma tabela de exemplo para os tópicos desta página.

GoogleSQL

CREATE TABLE Users (
  UserId INT64 NOT NULL,
  FirstName STRING(MAX),
  LastName STRING(MAX),
) PRIMARY KEY(UserId);

CREATE INDEX UsersByFirstName ON Users(FirstName DESC);

CREATE TABLE Threads (
  UserId INT64 NOT NULL,
  ThreadId INT64 NOT NULL,
  Starred BOOL,
) PRIMARY KEY(UserId, ThreadId),
  INTERLEAVE IN PARENT Users ON DELETE CASCADE;

CREATE TABLE Messages (
  UserId INT64 NOT NULL,
  ThreadId INT64 NOT NULL,
  MessageId INT64 NOT NULL,
  Subject STRING(MAX),
  Body STRING(MAX),
) PRIMARY KEY(UserId, ThreadId, MessageId),
  INTERLEAVE IN PARENT Threads ON DELETE CASCADE;

CREATE INDEX MessagesIdx ON Messages(UserId, ThreadId, Subject),
INTERLEAVE IN Threads;

PostgreSQL

CREATE TABLE users
(
   userid    BIGINT NOT NULL PRIMARY KEY,-- INT64 to BIGINT
   firstname VARCHAR(max),-- STRING(MAX) to VARCHAR(MAX)
   lastname  VARCHAR(max)
);

CREATE INDEX usersbyfirstname
  ON users(firstname DESC);

CREATE TABLE threads
  (
    userid   BIGINT NOT NULL,
    threadid BIGINT NOT NULL,
    starred  BOOLEAN, -- BOOL to BOOLEAN
    PRIMARY KEY (userid, threadid),
    CONSTRAINT fk_threads_user FOREIGN KEY (userid) REFERENCES users(userid) ON
    DELETE CASCADE -- Interleave to Foreign Key constraint
  );

CREATE TABLE messages
  (
    userid    BIGINT NOT NULL,
    threadid  BIGINT NOT NULL,
    messageid BIGINT NOT NULL PRIMARY KEY,
    subject   VARCHAR(max),
    body      VARCHAR(max),
    CONSTRAINT fk_messages_thread FOREIGN KEY (userid, threadid) REFERENCES
    threads(userid, threadid) ON DELETE CASCADE
  -- Interleave to Foreign Key constraint
  );

CREATE INDEX messagesidx ON messages(userid, threadid, subject), REFERENCES
threads(userid, threadid);

Imagine que seu espaço de chaves seja assim:

PRIMARY KEY
<begin>
Users()
Threads()
Users(2)
Users(3)
Threads(3)
Threads(3,"a")
Messages(3,"a",1)
Messages(3,"a",2)
Threads(3, "aa")
Users(9)
Users(10)
Threads(10)
UsersByFirstName("abc")
UsersByFirstName("abcd")
<end>

Exemplo de divisões

Confira a seguir alguns exemplos de divisões para ajudar você a entender como elas são.

Os valores SPLIT_START e SPLIT_LIMIT podem indicar a linha de uma tabela ou índice, ou podem ser <begin> e <end>, representando os limites do espaço de chaves do banco de dados. Os SPLIT_START e SPLIT_LIMIT também podem conter chaves truncadas, que são chaves que precedem qualquer chave completa na tabela. Por exemplo, Threads(10) é um prefixo para qualquer linha Threads intercalada em Users(10).

SPLIT_START SPLIT_LIMIT AFFECTED_TABLES EXPLICAÇÃO
Users(3) Users(10) UsersByFirstName, Users, Threads, Messages, MessagesIdx A divisão começa na linha com UserId=3 e termina na linha anterior à linha com UserId = 10. A divisão contém as linhas da tabela Users e todas as linhas das tabelas intercaladas de UserId=3 a 10.
Messages(3,"a",1) Threads(3,"aa") Threads, Messages, MessagesIdx A divisão começa na linha com UserId=3, ThreadId="a" e MessageId=1 e termina na linha anterior à linha com a chave de UserId=3 e ThreadsId = "aa". A divisão contém todas as tabelas entre Messages(3,"a",1) e Threads(3,"aa"). Como split_start e split_limit são intercalados na mesma linha da tabela de nível superior, a divisão contém as linhas das tabelas intercaladas entre o início e o limite. Consulte schemas-overview para entender como as tabelas intercaladas são colocadas juntas.
Messages(3,"a",1) <end> UsersByFirstName, Users, Threads, Messages, MessagesIdx A divisão começa na tabela de mensagens na linha com a chave UserId=3, ThreadId="a" e MessageId=1. A divisão hospeda todas as linhas de split_start a <end>, o fim do espaço de chaves do banco de dados. Todas as linhas das tabelas após o split_start, como Users(4), estão incluídas na divisão.
<begin> Users(9) UsersByFirstName, Users, Threads, Messages, MessagesIdx A divisão começa em <begin>, o início do espaço de chaves do banco de dados, e termina na linha anterior à linha Users com UserId=9. Assim, a divisão tem todas as linhas da tabela anteriores a Users e todas as linhas da tabela Users anteriores a UserId=9 e as linhas das tabelas intercaladas.
Messages(3,"a",1) Threads(10) UsersByFirstName, Users, Threads, Messages, MessagesIdx A divisão começa em Messages(3,"a", 1) intercalada em Users(3) e termina na linha anterior a Threads(10). Threads(10) é uma chave de divisão truncada que é um prefixo de qualquer chave da tabela "Threads" intercalada em Users(10).
Users() <end> UsersByFirstName, Users, Threads, Messages, MessagesIdx A divisão começa na chave truncada de Users(), que precede qualquer chave completa da tabela Users. A divisão se estende até o fim do possível espaço de chaves no banco de dados. As affected_tables abrangem a tabela Users, as tabelas e os índices intercalados e todas as tabelas que podem aparecer depois dos usuários.
Threads(10) UsersByFirstName("abc") UsersByFirstName, Users, Threads, Messages, MessagesIdx A divisão começa na linha Threads com UserId = 10 e termina no índice UsersByFirstName na chave que precede "abc".

Tipos UNSPLITTABLE_REASONS

Quando o Spanner não consegue reduzir um hotspot com a divisão baseada em carga, a coluna UNSPLITTABLE_REASONS nas visualizações SPLIT_STATS_TOP_* cita um ou mais dos seguintes motivos:

HOT_ROW

Descrição:carga alta concentrada em uma única linha. O Spanner não pode adicionar pontos de divisão em uma linha individual.

Causas comuns:

  • Operações frequentes de alto volume (leituras, gravações ou atualizações) em uma única chave.
  • Projetos de esquema que centralizam o acesso a uma única linha.

Estratégias de mitigação:

MOVING_HOT_SPOT

Descrição:o intervalo de chaves que sofre grandes mudanças de carga ao longo do tempo, geralmente de forma sequencial. A divisão com base na carga é ineficaz, já que o ponto de acesso é realocado antes que o Spanner possa dividir o intervalo afetado anteriormente.

Causas comuns:

  • Inserções com uma parte da chave principal crescente ou decrescente monotonicamente, como um carimbo de data/hora de commit.
  • Leituras de pontos sequenciais no espaço de chaves de uma tabela.

Estratégias de mitigação:

  • Evite chaves que aumentam ou diminuem monotonicamente na primeira parte da chave primária em cargas de trabalho com muitas gravações. Para estratégias detalhadas de mitigação, consulte Práticas recomendadas de design de esquema. As técnicas incluem o uso de UUIDs ou a adição de um hash da chave.

LARGE_SCAN_HOT_SPOT

Descrição:a divisão tem carga alta devido a operações frequentes ou que consomem muitos recursos e fazem verificações em um intervalo de chaves. Isso pode incluir leituras de intervalo (incluindo leituras emitidas como parte de uma transação) ou consultas. O Spanner evita dividir excessivamente os intervalos cobertos por essas operações para evitar uma possível degradação de desempenho nas verificações, que pode ocorrer se os dados ficarem muito fragmentados em muitas divisões pequenas.

Causas comuns:

  • Consultas ou operações de leitura que executam verificações de intervalo amplas em dados acessados com frequência.
  • Instruções DML (UPDATE, DELETE) com cláusulas WHERE que exigem intervalos de verificação.
  • Ausência de índices adequados, o que leva a verificações da tabela de base.

Estratégias de mitigação:

  • Otimize as instruções SQL (SELECT, UPDATE, DELETE) para reduzir o número de linhas verificadas.
  • Crie índices adequados para oferecer suporte a consultas comuns e predicados de DML, minimizando o número de linhas verificadas.

UNISOLATABLE_HOT_ROW

Descrição:o Spanner identifica uma chave estreita de alta carga, mas não consegue isolá-la inserindo novos pontos de divisão devido à indisponibilidade de um ponto de divisão adequado. Esse caso é semelhante a HOT_ROW, mas o SPLIT_START e o SPLIT_LIMIT não isolam completamente o hotspot.

Causas comuns:

  • Carga intensa e localizada em uma linha ou linhas adjacentes que compartilham um prefixo de chave.

Estratégias de mitigação:

  • Analise os padrões de acesso a aplicativos para as chaves nos SPLIT_START e SPLIT_LIMIT informados.
  • As estratégias de mitigação geralmente se sobrepõem a HOT_ROW, com foco na redução da carga operacional direta no intervalo de chaves estreito problemático.

UNSPECIFIED

Descrição: a divisão está passando por uma carga alta e não pode ser dividida, mas a causa não se enquadra nas outras categorias específicas. Isso pode acontecer em cenários de carga complexos ou devido ao comportamento interno do sistema.

Estratégias de mitigação:

  • Investigue consultas, transações ou cargas de trabalho de aplicativos que acessam as tabelas na divisão dinâmica (listadas em AFFECTED_TABLES) que apresentaram aumento na carga.
  • Use ferramentas como o Query Insights e o Transaction Insights para identificar operações caras.
  • Avalie a carga de trabalho e verifique se você está usando as práticas recomendadas de design de esquema e as práticas recomendadas de SQL.
  • Se o problema persistir por mais de 10 minutos apesar das otimizações anteriores, abra um caso de suporte.

Ver agregação de eventos

As entradas nas visualizações SPANNER_SYS.SPLIT_STATS_TOP_10MINUTE e SPANNER_SYS.SPLIT_STATS_TOP_HOUR representam uma agregação dos intervalos de um minuto nas respectivas janelas:

CPU_USAGE_SCORE: mostra o CPU_USAGE_SCORE máximo registrado para a divisão em qualquer intervalo de um minuto dentro da janela de 10 minutos ou de uma hora.

UNSPLITTABLE_REASONS: essa matriz é uma união de todos os UNSPLITTABLE_REASONS exclusivos observados para a divisão em todos os intervalos de um minuto na janela.

Uma divisão aparece nessas visualizações se o CPU_USAGE_SCORE dela foi de 50% ou mais em pelo menos um dos intervalos de um minuto.

Exemplo de agregação

Analise a divisão de Users(101) para Users(102). A tabela a seguir mostra as entradas potenciais na visualização MINUTE em um período de 10 minutos, das 10:00:00 às 10:10:00:

INTERVAL_END SPLIT_START SPLIT_LIMIT CPU_USAGE_SCORE AFFECTED_TABLES UNSPLITTABLE_REASONS
10:01:00 Usuários(101) Usuários(102) 60 [Messages,Users,Threads] []
10:02:00 Usuários(101) Usuários(102) 95 [Messages,Users,Threads] [HOT_ROW]
10:03:00 Usuários(101) Usuários(102) 80 [Messages,Users,Threads] [HOT_ROW]
10:04:00 Usuários(101) Usuários(102) 55 [Users,Threads] []
10:06:00 Usuários(101) Usuários(102) 70 [Users,Threads] [LARGE_SCAN_HOT_SPOT]
10:07:00 Usuários(101) Usuários(102) 65 [Users,Threads] [LARGE_SCAN_HOT_SPOT]
10:09:00 Usuários(101) Usuários(102) 52 [Users,Threads] []

A entrada agregada correspondente em 10MINUTE para o intervalo que termina às 10:10:00 para essa divisão seria:

INTERVAL_END SPLIT_START SPLIT_LIMIT CPU_USAGE_SCORE AFFECTED_TABLES UNSPLITTABLE_REASONS
10:10:00 Usuários(101) Usuários(102) 95 [Messages,Users,Threads] [HOT_ROW, LARGE_SCAN_HOT_SPOT]
  • CPU_USAGE_SCORE: 95 é o valor máximo da coluna CPU_USAGE_SCORE na visualização de 1 minuto para essa divisão na janela.
  • UNSPLITTABLE_REASONS: [HOT_ROW, LARGE_SCAN_HOT_SPOT] é a união de todos os motivos exclusivos presentes na coluna UNSPLITTABLE_REASONS na visualização de 1 minuto.

Este exemplo mostra como a visualização 10MINUTE resume a carga mais intensa e todos os tipos de problemas não divisíveis encontrados durante o período. A visualização HOUR segue a mesma lógica de agregação em um período de 60 minutos.

Encontrar divisões em alta

Use a seguinte instrução SQL para recuperar estatísticas de divisão dinâmica. É possível executar essas instruções SQL usando as bibliotecas de cliente, a Google Cloud CLI ou o consoleGoogle Cloud .

SELECT
  t.interval_end,
  t.split_start,
  t.split_limit,
  t.cpu_usage_score,
  t.affected_tables,
  t.unsplittable_reasons
FROM
  SPANNER_SYS.SPLIT_STATS_TOP_DURATION AS t
WHERE
  -- Optional: Filter by a specific interval end time
  -- t.interval_end = 'INTERVAL_END_TIME'
ORDER BY
  t.interval_end DESC, t.cpu_usage_score DESC;

Substitua:

  • DURATION: escolha MINUTE, 10MINUTE ou HOUR, com base no período de observação. Por exemplo, SPANNER_SYS.SPLIT_STATS_TOP_HOUR.
  • INTERVAL_END_TIME: substitua por um TIMESTAMP do horário de término do seu período de observação. Por exemplo, 2072-06-08 08:30:00Z.

Interpretar os resultados da consulta

Para uma lista completa de códigos UNSPLITTABLE_REASONS e os possíveis diagnósticos, consulte Tipos de UNSPLITTABLE_REASONS. Por exemplo, a saída da consulta pode ser assim:

SPLIT_START SPLIT_LIMIT CPU_USAGE_SCORE AFFECTED_TABLES UNSPLITTABLE_REASONS
Conversas(10) Threads(10, "aa") 100 Mensagens,Conversas [UNISOLATABLE_HOT_ROW]
Messages(631, "abc", 1) Messages(631, "abc", 3) 100 Mensagens [HOT_ROW]
Usuários(620) <end> 100 Messages,Users,Threads [MOVING_HOT_SPOT]
Usuários(101) Usuários(102) 90 Messages,Users,Threads [HOT_ROW]
Usuários(13) Usuários(76) 82 Messages,Users,Threads [LARGE_SCAN_HOT_SPOT]
Threads(12, "zebra") Usuários(14) 76 Messages,Users,Threads []

Com base nesses resultados, você pode inferir os seguintes problemas:

  • Threads(10) para Threads(10, "aa"): em alta com 100% e [UNISOLATABLE_HOT_ROW]. Uma única chave, um prefixo de intervalo de chaves na tabela Threads ou uma tabela intercalada está quente, e o Spanner não pode dividir mais o intervalo.
  • Messages(631, "abc", 1) to Messages(631, "abc", 3): Hot at 100% with [HOT_ROW]. A carga está concentrada em MessageId 1 e 2 para este usuário e thread.
  • Usuários(620) para <end>:quente a 100% com [MOVING_HOT_SPOT]. Isso geralmente indica um padrão de inserções com IDs de usuário que aumentam ou diminuem monotonicamente, fazendo com que o final do espaço de chaves fique persistentemente quente.
  • Usuários(101) a Usuários(102): quente em 90% com [HOT_ROW]. A carga é concentrada na única linha "Users" UserId = 101 e nos filhos intercalados.
  • Usuários(13) a Usuários(76): em alta com 82% e [LARGE_SCAN_HOT_SPOT]. Isso sugere verificações frequentes ou caras nesse intervalo de IDs de usuário.
  • Threads(12, "zebra") to Users(14): quente com 76% de uso. Nenhum motivo de não divisão foi detectado neste intervalo. O Spanner ainda pode dividir se a carga persistir ou aumentar.

Resolver problemas de pontos de acesso usando estatísticas de divisão ativa

Esta seção descreve como detectar e solucionar problemas de hotspots.

Selecionar um período para investigar

Verifique as métricas de latência do banco de dados do Spanner para encontrar o período em que o aplicativo apresentou alta latência e uso da CPU. Por exemplo, ele pode mostrar que um problema começou por volta das 22h50 de 18 de maio de 2072.

Verificar motivos de não divisão

Como o Spanner equilibra a carga com a divisão baseada em carga, recomendamos que você investigue pontos de acesso que continuam por mais de 10 minutos, especialmente se eles tiverem UNSPLITTABLE_REASONS. A presença de UNSPLITTABLE_REASONS indica que o Spanner não pode dividir a divisão dinâmica, e talvez seja necessário fazer mudanças no esquema ou na carga de trabalho para reduzir o ponto de acesso.

É possível consultar UNSPLITTABLE_REASONS, conforme mostrado na consulta de exemplo a seguir:

SELECT
  reason,
  COUNT(*) AS occurrences
FROM
  SPANNER_SYS.SPLIT_STATS_TOP_MINUTE AS t,
  UNNEST(t.unsplittable_reasons) AS reason
WHERE
  t.cpu_usage_score >= 50
  AND ARRAY_LENGTH(t.unsplittable_reasons) > 0
  AND t.interval_end >= "2072-05-18T17:40:00Z"  -- Start of window
  AND t.interval_end <= "2072-05-18T17:50:00Z"  -- End of window
GROUP BY
  reason
ORDER BY
  occurrences DESC;

A presença de UNSPLITTABLE_REASONS indica a necessidade de mais depuração.

Também é possível monitorar motivos não divisíveis usando o Cloud Monitoring. A métrica a ser usada é unsplittable_reason_count. Para mais informações, consulte Métricas do Spanner.

Encontre as divisões com o maior CPU_USAGE_SCORE e o UNSPLITTABLE_REASONS delas.

Neste exemplo, executamos o seguinte SQL para encontrar os intervalos de linhas com o nível CPU_USAGE_SCORE mais alto e o UNSPLITTABLE_REASONS correspondente:

GoogleSQL

SELECT t.split_start,
     t.split_limit,
     t.cpu_usage_score,
     t.affected_tables,
     t.unsplittable_reasons
FROM   SPANNER_SYS.SPLIT_STATS_TOP_MINUTE t
WHERE  t.cpu_usage_score >= 50
AND  t.interval_end = "interval_end_date_time";

Substitua interval_end_date_time pela data e hora do intervalo, usando o formato AAAA-MM-DDTHH:MM:SSZ. Por exemplo, 2072-05-18T17:40:00Z.

PostgreSQL

SELECT t.split_start,
     t.split_limit,
     t.cpu_usage_score,
     t.affected_tables,
     t.unsplittable_reasons
FROM   spanner_sys.split_stats_top_minute t
WHERE  t.cpu_usage_score >= 50
AND  t.interval_end = 'interval_end_date_time'::timestamptz;

Substitua interval_end_date_time pela data e hora do intervalo, usando o formato AAAA-MM-DDTHH:MM:SSZ. Por exemplo, 2072-05-18T17:40:00Z.

O SQL anterior gera o seguinte:

SPLIT_START SPLIT_LIMIT CPU_USAGE_SCORE AFFECTED_TABLES UNSPLITTABLE_REASONS
Users(180) <end> 85 Messages,Users,Threads [MOVING_HOT_SPOT]
Users(24) Users(76) 76 Messages,Users,Threads [HOT_ROW, LARGE_SCAN_HOT_SPOT]
Threads(10) UsersByFirstName("abc") 100 UsersByFirstName, Users, Threads, Messages, MessagesIdx []

Nessa tabela de resultados, podemos ver que há três divisões frequentes, e duas delas não podem ser divididas. É preciso investigar melhor os pontos de acesso com UNSPLITTABLE_REASONS que persistem ao longo do tempo. Para entender o que cada motivo significa e como mitigá-lo, consulte os tipos de UNSPLITTABLE_REASONS.

Práticas recomendadas para reduzir pontos de acesso

Observação:se você teve um aumento na carga e fez o escalonamento vertical da instância recentemente, o Spanner pode levar alguns minutos para realizar as operações de balanceamento de carga antes que a latência diminua.

Se o balanceamento de carga não diminuir a latência, a próxima etapa será identificar a causa dos pontos de acesso. Depois disso, as opções são reduzir a carga de trabalho do hotspot ou otimizar o esquema e a lógica do aplicativo para evitar hotspots.

Identificar a causa

  • Use os insights de bloqueio e transação para procurar transações com alto tempo de espera de bloqueio em que a chave de início do intervalo de linhas está dentro da divisão dinâmica.
  • Use os Insights de consulta para procurar consultas que leem da tabela que contém a divisão ativa e que recentemente aumentaram a latência ou têm uma proporção maior de latência para CPU.
  • Use Consultas ativas mais antigas para procurar consultas que leem da tabela que contém a divisão dinâmica e têm latência maior do que o esperado.

Alguns casos especiais a serem observados:

  • Verifique se o tempo de vida útil (TTL) foi ativado recentemente. Se houver muitas divisões de dados antigos, o TTL poderá aumentar os níveis de CPU_USAGE_SCORE durante exclusões em massa. Nesse caso, o problema será resolvido automaticamente quando as exclusões iniciais forem concluídas.

Otimizar a carga de trabalho

A seguir