Statistiche suddivisione

Questo documento descrive come rilevare ed eseguire il debug degli hotspot nel database. Puoi accedere alle statistiche sugli hotspot nelle suddivisioni con GoogleSQL e PostgreSQL.

Spanner archivia i dati come uno spazio delle chiavi contiguo, ordinato in base alle chiavi primarie di tabelle e indici. Una suddivisione è un intervallo di righe di un insieme di tabelle o di un indice. L'inizio della suddivisione è chiamato inizio della suddivisione. Il limite di suddivisione imposta la fine della suddivisione. La suddivisione include l'inizio della suddivisione, ma non il limite della suddivisione.

In Spanner, gli hotspot sono situazioni in cui vengono inviate troppe richieste allo stesso server, il che satura le risorse del server e potenzialmente causa latenze elevate. Le suddivisioni interessate dagli hotspot sono note come suddivisioni frequenti o calde.

La statistica hotspot di una suddivisione (identificata nel sistema come CPU_USAGE_SCORE) è una misurazione del carico su una suddivisione vincolata dalle risorse disponibili sul server. Questa misurazione è espressa come percentuale. Se più del 50% del carico su una suddivisione è vincolato dalle risorse disponibili, la suddivisione viene considerata calda. Se il 100% del carico su una suddivisione è vincolato, la suddivisione è considerata calda. Queste suddivisioni attive potrebbero influire anche sulla latenza delle richieste gestite.

Il CPU_USAGE_SCORE di una suddivisione può rimanere costante o variare nel tempo in base al carico di lavoro che accede alla suddivisione e alle modifiche ai limiti della suddivisione.

In base ai vincoli delle risorse di suddivisione calda e tiepida, Spanner potrebbe utilizzare la suddivisione basata sul carico per distribuire uniformemente il carico nello spazio delle chiavi. Le suddivisioni calde e attive possono essere spostate tra i server dell'istanza per il bilanciamento del carico. Spanner esegue la suddivisione in base al carico in background, riducendo al minimo l'impatto sulla latenza. Tuttavia, Spanner potrebbe non essere in grado di bilanciare il carico, anche dopo diversi tentativi di suddivisione, a causa di anti-pattern nell'applicazione. La colonna UNSPLITTABLE_REASONS nelle visualizzazioni delle statistiche fornisce i motivi specifici per cui una suddivisione calda o tiepida non può essere ulteriormente suddivisa. Pertanto, le divisioni persistenti calde o molto calde che durano almeno 10 minuti potrebbero richiedere ulteriore risoluzione dei problemi e potenziali modifiche all'applicazione, soprattutto quando sono presenti UNSPLITTABLE_REASONS.

Le statistiche sulla suddivisione degli hotspot di Spanner ti aiutano a identificare le suddivisioni in cui si verificano gli hotspot e a capire perché potrebbero persistere. Queste statistiche, combinate con i codici UNSPLITTABLE_REASONS, possono aiutarti a diagnosticare le azioni che devi intraprendere per risolvere i problemi. Puoi quindi apportare modifiche all'applicazione o allo schema, se necessario.

Come accedere alle statistiche sulla divisione a caldo

Spanner fornisce le statistiche sulla suddivisione frequente nello schema SPANNER_SYS. I dati di SPANNER_SYS sono disponibili tramite le interfacce GoogleSQL e PostgreSQL. Puoi accedere a questi dati nei seguenti modi:

I seguenti metodi di lettura singola forniti da Spanner non supportano SPANNER_SYS:

  • Esecuzione di una lettura coerente da una o più righe di una tabella.
  • Esecuzione di una lettura obsoleta da una o più righe di una tabella.
  • Lettura da una singola riga o da più righe in un indice secondario.

Statistiche sulle suddivisioni più frequenti

Utilizza le seguenti visualizzazioni per monitorare le suddivisioni più frequenti:

  • SPANNER_SYS.SPLIT_STATS_TOP_MINUTE: mostra le frazioni più calde durante intervalli di 1 minuto.
  • SPANNER_SYS.SPLIT_STATS_TOP_10MINUTE: mostra i tempi intermedi più veloci durante qualsiasi parte di un intervallo di 10 minuti.
  • SPANNER_SYS.SPLIT_STATS_TOP_HOUR: mostra le frazioni più calde durante qualsiasi parte di un intervallo di 1 ora.

Queste visualizzazioni hanno le seguenti proprietà:

  • Ogni vista contiene dati per intervalli di tempo non sovrapposti della durata specificata dal nome della vista.
  • Gli intervalli si basano sugli orari:
    • Gli intervalli di 1 minuto terminano al minuto.
    • Gli intervalli di 10 minuti terminano al decimo minuto dell'ora, ad esempio, 11:10:00, 11:20:00.
    • Gli intervalli di un'ora terminano all'ora.
  • Dopo ogni intervallo, Spanner raccoglie i dati da tutti i server e li rende disponibili nelle visualizzazioni SPANNER_SYS poco dopo. Ad esempio, alle 11:59:30, gli intervalli più recenti disponibili per le query SQL sono:
    • 1 minuto: 11:58:00-11:58:59
    • 10 minuti: 11:40:00-11:49:59
    • 1 ora: 10:00:00-10:59:59
  • Spanner raggruppa le statistiche in base alle suddivisioni.
  • Ogni riga contiene statistiche, inclusa la percentuale CPU_USAGE_SCORE che indica il livello di calore di una divisione, per ogni divisione per cui Spanner acquisisce statistiche durante l'intervallo specificato.
  • La visualizzazione SPANNER_SYS.SPLIT_STATS_TOP_MINUTE offre statistiche dettagliate sul tempo intermedio per ogni minuto. Utilizza questa visualizzazione per il debug dettagliato degli eventi recenti.
  • Le visualizzazioni SPANNER_SYS.SPLIT_STATS_TOP_10MINUTE e SPANNER_SYS.SPLIT_STATS_TOP_HOUR forniscono una visualizzazione aggregata rispettivamente a intervalli di 10 minuti e di un'ora. Utilizza queste visualizzazioni per l'analisi delle tendenze o per esaminare i problemi riscontrati negli ultimi giorni o settimane. Per saperne di più sull'aggregazione, consulta Visualizzare l'aggregazione degli eventi.
  • Se Spanner non è in grado di archiviare tutte le suddivisioni attive durante l'intervallo, il sistema assegna la priorità alle suddivisioni con la percentuale di CPU_USAGE_SCORE più alta durante l'intervallo specificato. Se non vengono restituiti split, significa che non sono presenti hot split.

Conservazione dei dati

La quantità massima di dati conservati da Spanner per ogni visualizzazione, in qualsiasi momento, è la seguente:

  • SPANNER_SYS.SPLIT_STATS_TOP_MINUTE: intervalli che coprono le 24 ore precedenti.
  • SPANNER_SYS.SPLIT_STATS_TOP_10MINUTE: intervalli che coprono i 4 giorni precedenti.
  • SPANNER_SYS.SPLIT_STATS_TOP_HOUR: intervalli che coprono i 30 giorni precedenti.

Questi periodi di conservazione non possono essere aumentati o diminuiti e non puoi impedire a Spanner di raccogliere statistiche sulla suddivisione a caldo.

  • Per eliminare i dati delle statistiche, devi eliminare il database monitorato o attendere che i dati delle statistiche vengano eliminati dalla conservazione.
  • Per conservare i dati statistici per periodi più lunghi, copia periodicamente i dati dalle visualizzazioni delle statistiche di suddivisione a caldo.

Visualizza schema

La tabella seguente mostra lo schema per le statistiche sulla divisione a caldo:

Nome colonna Tipo Descrizione
INTERVAL_END TIMESTAMP Fine dell'intervallo di tempo durante il quale la suddivisione era tiepida o frequente.
SPLIT_START STRING La chiave iniziale dell'intervallo di righe nella suddivisione. L'inizio della suddivisione può essere anche <begin>, che indica l'inizio dello spazio delle chiavi.
SPLIT_LIMIT STRING La chiave del limite per l'intervallo di righe nella suddivisione. La chiave del limite potrebbe anche essere <end>, che indica la fine dello spazio delle chiavi.
CPU_USAGE_SCORE INT64 La percentuale CPU_USAGE_SCORE delle suddivisioni. Una percentuale di CPU_USAGE_SCORE del 50% indica la presenza di suddivisioni calde o molto calde.
AFFECTED_TABLES STRING ARRAY Le tabelle le cui righe potrebbero essere nella suddivisione.
UNSPLITTABLE_REASONS STRING ARRAY Identifica il tipo di hotspot presenti che la suddivisione basata sul carico non può mitigare, spesso a causa di antipattern. La presenza di un motivo indica che è probabilmente necessario l'intervento dell'utente, ad esempio aggiustamenti dello schema o del carico di lavoro. Un array vuoto indica che non sono state rilevate condizioni non divisibili durante questo intervallo oppure che il carico elevato è durato troppo poco tempo per consentire a Spanner di determinare se era non divisibile. Per ulteriori dettagli, consulta la sezione Tipi di UNSPLITTABLE_REASONS.

Chiavi di inizio e limite della suddivisione

Una suddivisione è un intervallo di righe contigue di un database ed è definita dalle chiavi start e limit. Una divisione può essere una singola riga, un intervallo di righe stretto o un intervallo di righe ampio e può includere più tabelle o indici.

Le colonne SPLIT_START e SPLIT_LIMIT identificano le chiavi primarie di una suddivisione tiepida o frequente.

Schema di esempio

Lo schema seguente è una tabella di esempio per gli argomenti di questa pagina.

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);

Immagina che il tuo spazio delle chiavi sia simile a questo:

CHIAVE PRIMARIA
<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>

Esempio di suddivisione

Di seguito sono riportati alcuni esempi di suddivisioni per aiutarti a capire come appaiono.

SPLIT_START e SPLIT_LIMIT potrebbero indicare la riga di una tabella o di un indice oppure possono essere <begin> e <end>, che rappresentano i limiti dello spazio delle chiavi del database. SPLIT_START e SPLIT_LIMIT potrebbero contenere anche chiavi troncate, ovvero chiavi che precedono qualsiasi chiave completa nella tabella. Ad esempio, Threads(10) è un prefisso per qualsiasi riga Threads intercalata in Users(10).

SPLIT_START SPLIT_LIMIT AFFECTED_TABLES SPIEGAZIONE
Users(3) Users(10) UsersByFirstName, Users, Threads, Messages, MessagesIdx La divisione inizia dalla riga con UserId=3 e termina alla riga precedente a quella con UserId = 10. La suddivisione contiene le righe della tabella Users e tutte le righe delle tabelle alternate per UserId=3 fino a 10.
Messages(3,"a",1) Threads(3,"aa") Threads, Messages, MessagesIdx La suddivisione inizia dalla riga con UserId=3, ThreadId="a" e MessageId=1 e termina alla riga precedente a quella con la chiave di UserId=3 e ThreadsId = "aa". La suddivisione contiene tutte le tabelle tra Messages(3,"a",1) e Threads(3,"aa"). Poiché split_start e split_limit sono intercalati nella stessa riga della tabella di primo livello, la suddivisione contiene le righe delle tabelle intercalate tra l'inizio e il limite. Consulta schemas-overview per capire come vengono collocate le tabelle con interfoliazione.
Messages(3,"a",1) <end> UsersByFirstName, Users, Threads, Messages, MessagesIdx La suddivisione inizia nella tabella dei messaggi dalla riga con chiave UserId=3, ThreadId="a" e MessageId=1. La suddivisione contiene tutte le righe da split_start a <end>, la fine dello spazio delle chiavi del database. Tutte le righe delle tabelle che seguono split_start, come Users(4), sono incluse nella suddivisione.
<begin> Users(9) UsersByFirstName, Users, Threads, Messages, MessagesIdx La suddivisione inizia da <begin>, l'inizio dello spazio delle chiavi del database, e termina alla riga precedente alla riga Users con UserId=9. Pertanto, la suddivisione contiene tutte le righe della tabella che precedono Users e tutte le righe della tabella Users che precedono UserId=9 e le righe delle relative tabelle con interfoliazione.
Messages(3,"a",1) Threads(10) UsersByFirstName, Users, Threads, Messages, MessagesIdx La suddivisione inizia a Messages(3,"a", 1) intercalata in Users(3) e termina alla riga precedente a Threads(10). Threads(10) è una chiave di suddivisione troncata che è un prefisso di qualsiasi chiave della tabella Threads intercalata in Users(10).
Users() <end> UsersByFirstName, Users, Threads, Messages, MessagesIdx La suddivisione inizia dalla chiave di suddivisione troncata di Users(), che precede qualsiasi chiave completa della tabella Users. La suddivisione si estende fino alla fine dello spazio delle chiavi possibile nel database. Le tabelle interessate coprono quindi la tabella Users, le relative tabelle e indici intercalati e tutte le tabelle che potrebbero essere visualizzate dopo gli utenti.
Threads(10) UsersByFirstName("abc") UsersByFirstName, Users, Threads, Messages, MessagesIdx La suddivisione inizia alla riga Threads con UserId = 10 e termina all'indice UsersByFirstName con la chiave precedente a "abc".

Tipi di UNSPLITTABLE_REASONS

Quando Spanner non riesce a mitigare un hotspot tramite la suddivisione basata sul carico, la colonna UNSPLITTABLE_REASONS nelle viste SPLIT_STATS_TOP_* cita uno o più dei seguenti motivi:

HOT_ROW

Descrizione: il carico elevato è concentrato su una singola riga. Spanner non può aggiungere punti di divisione all'interno di una singola riga.

Cause comuni:

  • Operazioni frequenti a volumi elevati (letture, scritture o aggiornamenti) su una singola chiave.
  • Progettazioni dello schema che centralizzano l'accesso a una singola riga.

Strategie di mitigazione:

MOVING_HOT_SPOT

Descrizione: l'intervallo di chiavi che registra un carico elevato cambia nel tempo, spesso in sequenza. La suddivisione basata sul carico è inefficace perché l'hotspot si sposta prima che Spanner possa dividere l'intervallo interessato in precedenza.

Cause comuni:

  • Inserimenti con una parte della chiave principale che aumenta o diminuisce in modo monotono, ad esempio un timestamp di commit.
  • Le letture puntuali sequenziali vengono eseguite nello spazio delle chiavi di una tabella.

Strategie di mitigazione:

  • Evita chiavi che aumentano o diminuiscono monotonicamente per la prima parte della chiave primaria nei carichi di lavoro con molte operazioni di scrittura. Per strategie di mitigazione dettagliate, consulta Best practice per la progettazione di schemi. Le tecniche includono l'utilizzo di UUID o l'anteposizione di un hash della chiave.

LARGE_SCAN_HOT_SPOT

Descrizione: la suddivisione è soggetta a un carico elevato a causa di operazioni frequenti o che richiedono molte risorse che analizzano un intervallo di chiavi. che possono includere letture di intervalli (incluse quelle emesse nell'ambito di una transazione) o query. Spanner si astiene dal dividere eccessivamente gli intervalli coperti da queste operazioni per evitare un potenziale peggioramento delle prestazioni per queste scansioni, che può verificarsi se i dati diventano troppo frammentati in molte piccole suddivisioni.

Cause comuni:

  • Query o operazioni di lettura che eseguono scansioni di ampio raggio sui dati a cui si accede di frequente.
  • Istruzioni DML (UPDATE, DELETE) con clausole WHERE che richiedono l'analisi di intervalli.
  • Assenza di indici adatti, che porta a scansioni della tabella di base.

Strategie di mitigazione:

  • Ottimizza le istruzioni SQL (SELECT, UPDATE, DELETE) per ridurre il numero di righe scansionate.
  • Crea indici appropriati per supportare i predicati comuni di query e DML, riducendo al minimo il numero di righe scansionate.

UNISOLATABLE_HOT_ROW

Descrizione: Spanner identifica una chiave ristretta e a carico elevato, ma non può isolarla inserendo nuovi punti di divisione, a causa dell'indisponibilità di un punto di divisione adatto. Questo caso è simile a HOT_ROW, ma SPLIT_START e SPLIT_LIMIT non isolano completamente l'hotspot.

Cause comuni:

  • Carico intenso e localizzato su una riga o su righe adiacenti che condividono un prefisso della chiave.

Strategie di mitigazione:

  • Analizza i pattern di accesso alle applicazioni per le chiavi all'interno di SPLIT_START e SPLIT_LIMIT segnalati.
  • Le strategie di mitigazione spesso si sovrappongono a HOT_ROW, concentrandosi sulla riduzione del carico operativo diretto sull'intervallo di chiavi ristretto problematico.

UNSPECIFIED

Descrizione: la divisione sta subendo un carico elevato e non può essere suddivisa, ma la causa non rientra nelle altre categorie specifiche. Ciò può accadere in scenari di carico complessi o a causa del comportamento interno del sistema.

Strategie di mitigazione:

  • Esamina i carichi di lavoro, le query o le transazioni delle applicazioni che accedono alle tabelle all'interno della partizione attiva (elencate in AFFECTED_TABLES) che hanno mostrato un carico maggiore.
  • Utilizza strumenti come Query Insights e Transaction Insights per identificare le operazioni costose.
  • Valuta il carico di lavoro e assicurati di utilizzare le best practice per la progettazione dello schema e le best practice per SQL.
  • Se il problema persiste per più di 10 minuti nonostante le ottimizzazioni precedenti, apri una richiesta di assistenza.

Visualizzare l'aggregazione degli eventi

Le voci nelle visualizzazioni SPANNER_SYS.SPLIT_STATS_TOP_10MINUTE e SPANNER_SYS.SPLIT_STATS_TOP_HOUR rappresentano un'aggregazione degli intervalli di 1 minuto all'interno delle rispettive finestre:

CPU_USAGE_SCORE: mostra il CPU_USAGE_SCORE massimo registrato per la divisione in qualsiasi intervallo di 1 minuto all'interno della finestra di 10 minuti o 1 ora.

UNSPLITTABLE_REASONS: questo array è l'unione di tutti i UNSPLITTABLE_REASONS unici osservati per la divisione in tutti gli intervalli di 1 minuto all'interno della finestra.

Una divisione viene visualizzata in queste visualizzazioni se il suo CPU_USAGE_SCORE era pari o superiore al 50% in almeno uno degli intervalli di 1 minuto costituenti.

Esempio di aggregazione

Esamina la suddivisione da Users(101) a Users(102). La tabella seguente mostra le potenziali voci nella visualizzazione MINUTE in un periodo di 10 minuti dalle 10:00:00 alle 10:10:00:

INTERVAL_END SPLIT_START SPLIT_LIMIT CPU_USAGE_SCORE AFFECTED_TABLES UNSPLITTABLE_REASONS
10:01:00 Utenti(101) Utenti(102) 60 [Messaggi,Utenti,Thread] []
10:02:00 Utenti(101) Utenti(102) 95 [Messaggi,Utenti,Thread] [HOT_ROW]
10:03:00 Utenti(101) Utenti(102) 80 [Messaggi,Utenti,Thread] [HOT_ROW]
10:04:00 Utenti(101) Utenti(102) 55 [Utenti,Thread] []
10:06:00 Utenti(101) Utenti(102) 70 [Utenti,Thread] [LARGE_SCAN_HOT_SPOT]
10:07:00 Utenti(101) Utenti(102) 65 [Utenti,Thread] [LARGE_SCAN_HOT_SPOT]
10:09:00 Utenti(101) Utenti(102) 52 [Utenti,Thread] []

La voce aggregata corrispondente in 10MINUTE per l'intervallo che termina alle 10:10:00 per questa suddivisione sarebbe:

INTERVAL_END SPLIT_START SPLIT_LIMIT CPU_USAGE_SCORE AFFECTED_TABLES UNSPLITTABLE_REASONS
10:10:00 Utenti(101) Utenti(102) 95 [Messaggi,Utenti,Thread] [HOT_ROW, LARGE_SCAN_HOT_SPOT]
  • CPU_USAGE_SCORE: 95 è il valore massimo della colonna CPU_USAGE_SCORE nella visualizzazione di 1 minuto per questa suddivisione all'interno della finestra.
  • UNSPLITTABLE_REASONS: [HOT_ROW, LARGE_SCAN_HOT_SPOT] è l'unione di tutti i motivi unici presenti nella colonna UNSPLITTABLE_REASONS nella visualizzazione di 1 minuto.

Questo esempio mostra come la visualizzazione 10MINUTE riepiloga il carico più intenso e tutti i tipi di problemi non divisibili riscontrati durante il periodo. La visualizzazione HOUR segue la stessa logica di aggregazione in un intervallo di 60 minuti.

Trovare le divisioni più frequenti

Puoi utilizzare la seguente istruzione SQL per recuperare le statistiche di suddivisione a caldo. Puoi eseguire queste istruzioni SQL utilizzando le librerie client, Google Cloud CLI o la 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;

Sostituisci quanto segue:

  • DURATION: scegli MINUTE, 10MINUTE o HOUR, in base al periodo di osservazione. Ad esempio, SPANNER_SYS.SPLIT_STATS_TOP_HOUR.
  • INTERVAL_END_TIME: sostituisci con un TIMESTAMP dell'ora di fine del periodo di osservazione. Ad esempio: 2072-06-08 08:30:00Z.

Interpretare i risultati delle query

Per un elenco completo dei codici UNSPLITTABLE_REASONS e delle relative possibili diagnosi, consulta Tipi di UNSPLITTABLE_REASONS. Ad esempio, l'output della query potrebbe essere simile al seguente:

SPLIT_START SPLIT_LIMIT CPU_USAGE_SCORE AFFECTED_TABLES UNSPLITTABLE_REASONS
Thread(10) Thread(10, "aa") 100 Messaggi,Thread [UNISOLATABLE_HOT_ROW]
Messaggi(631, "abc", 1) Messaggi(631, "abc", 3) 100 Messaggi [HOT_ROW]
Utenti(620) <end> 100 Messaggi,Utenti,Thread [MOVING_HOT_SPOT]
Utenti(101) Utenti(102) 90 Messaggi,Utenti,Thread [HOT_ROW]
Utenti(13) Utenti(76) 82 Messaggi,Utenti,Thread [LARGE_SCAN_HOT_SPOT]
Threads(12, "zebra") Utenti(14) 76 Messaggi,Utenti,Thread []

Da questi risultati, potresti dedurre i seguenti problemi:

  • Threads(10) to Threads(10, "aa"): Hot at 100% with [UNISOLATABLE_HOT_ROW]. Una singola chiave, un prefisso di intervallo di chiavi nella tabella Threads o una tabella con interleaving è molto utilizzata e Spanner non può dividere ulteriormente l'intervallo.
  • Messages(631, "abc", 1) to Messages(631, "abc", 3): Hot at 100% with [HOT_ROW]. Il carico è concentrato su MessageId 1 e 2 per questo utente e thread.
  • Utenti(620) a <end>: Hot al 100% con [MOVING_HOT_SPOT]. Spesso questo indica un pattern di inserimenti con ID utente in aumento o diminuzione monotonici, che fa sì che la fine dello spazio delle chiavi sia costantemente calda.
  • Utenti(101) a Utenti(102): molto caldo al 90% con [HOT_ROW]. Il carico è concentrato sulla singola riga Users UserId = 101 e sui relativi elementi secondari intercalati.
  • Utenti(13) a Utenti(76): molto richiesto all'82% con [LARGE_SCAN_HOT_SPOT]. Ciò suggerisce scansioni frequenti o costose in questo intervallo di ID utente.
  • Thread(12, "zebra") a Utenti(14): caldo al 76% di utilizzo. Non sono stati rilevati motivi di divisione in questo intervallo. Spanner potrebbe comunque essere in grado di dividere questo intervallo se il carico persiste o aumenta.

Risolvere i problemi relativi agli hotspot utilizzando le statistiche sulle suddivisioni che causano un hotspot

Questa sezione descrive come rilevare e risolvere i problemi relativi agli hotspot.

Seleziona un periodo di tempo da esaminare

Controlla le metriche di latenza per il tuo database Spanner per trovare il periodo di tempo in cui la tua applicazione ha riscontrato un'elevata latenza e un elevato utilizzo della CPU. Ad esempio, potrebbe mostrare che un problema è iniziato intorno alle 22:50 del 18 maggio 2072.

Controllare la presenza di motivi non divisibili

Poiché Spanner bilancia il carico con la divisione basata sul carico, ti consigliamo di esaminare gli hotspot che continuano per più di 10 minuti, soprattutto se hanno UNSPLITTABLE_REASONS. La presenza di UNSPLITTABLE_REASONS indica che Spanner non può dividere la suddivisione calda e potrebbero essere necessarie modifiche allo schema o al workload per mitigare l'hotspot.

Puoi eseguire query per UNSPLITTABLE_REASONS come mostrato nella seguente query di esempio:

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;

La presenza di UNSPLITTABLE_REASONS indica la necessità di un ulteriore debug.

Puoi anche monitorare i motivi di mancata suddivisione utilizzando Cloud Monitoring. La metrica da utilizzare è unsplittable_reason_count. Per saperne di più, consulta Metriche di Spanner.

Trova gli split con il CPU_USAGE_SCORE più alto e il relativo UNSPLITTABLE_REASONS

Per questo esempio, eseguiamo il seguente SQL per trovare gli intervalli di righe con il livello di CPU_USAGE_SCORE più alto e il relativo UNSPLITTABLE_REASONS:

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";

Sostituisci interval_end_date_time con la data e l'ora dell'intervallo, utilizzando il formato AAAA-MM-GGTHH:MM:SSZ. Ad esempio, 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;

Sostituisci interval_end_date_time con la data e l'ora dell'intervallo, utilizzando il formato AAAA-MM-GGTHH:MM:SSZ. Ad esempio, 2072-05-18T17:40:00Z.

L'SQL precedente restituisce il seguente output:

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 []

Da questa tabella dei risultati, possiamo vedere che ci sono tre hot split e due di questi non sono divisibili. Le aree cliccabili con UNSPLITTABLE_REASONS che persistono nel tempo richiedono ulteriori accertamenti. Per capire il significato di ogni motivo e come mitigarlo, consulta Tipi di UNSPLITTABLE_REASONS.

Best practice per mitigare gli hotspot

Nota:se il carico è aumentato e di recente hai eseguito l'upscaling dell'istanza, Spanner potrebbe impiegare alcuni minuti per eseguire le operazioni di bilanciamento del carico prima che la latenza diminuisca.

Se il bilanciamento del carico non riduce la latenza, il passaggio successivo consiste nell'identificare la causa degli hotspot. Dopodiché, le opzioni sono ridurre il carico di lavoro dell'hotspot oppure ottimizzare lo schema e la logica dell'applicazione per evitare gli hotspot.

Identificare la causa

  • Utilizza Lock & Transaction Insights per cercare transazioni con tempi di attesa del blocco elevati in cui la chiave iniziale dell'intervallo di righe si trova all'interno della suddivisione calda.
  • Utilizza Query Insights per cercare query che leggono dalla tabella che contiene la suddivisione hot e che di recente hanno aumentato la latenza o un rapporto più elevato tra latenza e CPU.
  • Utilizza Query attive meno recenti per cercare query che leggono dalla tabella contenente la suddivisione calda e che hanno una latenza superiore al previsto.

Alcuni casi particolari a cui prestare attenzione:

  • Controlla se di recente è stata attivata la durata (TTL). Se ci sono molte divisioni dai dati precedenti, il TTL può aumentare i livelli di CPU_USAGE_SCORE durante le eliminazioni collettive. In questo caso, il problema dovrebbe risolversi automaticamente una volta completate le eliminazioni iniziali.

Ottimizzare il workload

  • Segui le best practice di SQL. Prendi in considerazione letture obsolete, scritture che non eseguono prima le letture o l'aggiunta di indici.
  • Segui le best practice per lo schema. Assicurati che lo schema sia progettato per gestire il bilanciamento del carico ed evitare hotspot.

Passaggi successivi