Questa pagina descrive come rilevare e eseguire il debug degli hotspot nel database. Puoi accedere alle statistiche relative agli hotspot nelle suddivisioni sia con GoogleSQL sia con PostgreSQL.
Spanner archivia i dati come uno spazio di chiavi contiguo, ordinato in base alle chiavi principali delle tabelle e degli indici. Una suddivisione è un intervallo di righe di un insieme di tabelle o di un indice. L'inizio della suddivisione è chiamato inizio suddivisione. Il limite di suddivisione imposta la fine della suddivisione. La suddivisione include l'inizio della suddivisione, ma non il limite.
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 moderate.
La statistica dell'hotspot di una suddivisione (identificata nel sistema come
CPU_USAGE_SCORE
) è una misura del carico su una suddivisione vincolata dalle risorse disponibili sul server. Questa misurazione viene fornita come percentuale. Se più del 50% del carico di una suddivisione è vincolato dalle risorse disponibili, la suddivisione è considerata tiepida. Se il 100% del carico su una suddivisione è vincolato, la suddivisione viene considerata calda.
Spanner utilizza la suddivisione in base al carico per distribuire uniformemente il carico dei dati sui server dell'istanza. Le suddivisioni warm e hot possono essere spostate tra i server per il bilanciamento del carico o possono essere suddivise in suddivisioni più piccole. Tuttavia, Spanner potrebbe non essere in grado di bilanciare il carico, anche dopo diversi tentativi di suddivisione, a causa di antipattern nell'applicazione. Pertanto, gli hotspot persistenti che durano almeno 10 minuti potrebbero richiedere ulteriore risoluzione dei problemi e potenziali modifiche all'applicazione.
Le statistiche sulle suddivisioni frequenti di Spanner ti aiutano a identificare le suddivisioni
dove si verificano hotspot. Puoi quindi apportare modifiche all'applicazione o allo schema,
se necessario. Puoi recuperare queste statistiche dalle tabelle di sistema SPANNER_SYS.SPLIT_STATS_TOP_MINUTE
utilizzando istruzioni SQL.
Disponibilità delle statistiche sulle suddivisioni calde
Spanner fornisce le statistiche sulle suddivisioni frequenti nello schemaSPANNER_SYS
. I dati di SPANNER_SYS
sono disponibili solo tramite le interfacce GoogleSQL e PostgreSQL. Puoi
utilizzare i seguenti metodi per accedere a questi dati:
- Pagina Spanner Studio di un database nella console Google Cloud
- Il comando
gcloud spanner databases execute-sql
- L'API
executeQuery
Le API di lettura singola di Spanner non supportano SPANNER_SYS
.
Statistiche sulle suddivisioni più frequenti
Utilizza la seguente tabella per monitorare le suddivisioni più frequenti:
SPANNER_SYS.SPLIT_STATS_TOP_MINUTE
: mostra le suddivisioni più utilizzate durante intervalli di 1 minuto.
Queste tabelle hanno le seguenti proprietà:
- Ogni tabella contiene i dati relativi a intervalli di tempo non sovrapposti della durata specificata dal nome della tabella.
Gli intervalli si basano sull'ora dell'orologio:
- Gli intervalli di 1 minuto terminano al minuto.
Dopo ogni intervallo, Spanner raccoglie i dati da tutti i server e poi li rende disponibili nelle tabelle
SPANNER_SYS
poco dopo.Ad esempio, alle 00:59:30, gli intervalli più recenti disponibili per le query SQL sono:
- 1 minuto: 11:58:00-11:58:59
Spanner raggruppa le statistiche per suddivisioni.
Ogni riga contiene una percentuale che indica quanto è frequente o meno una suddivisione per ogni suddivisione per la quale Spanner acquisisce statistiche durante l'intervallo specificato.
Se meno del 50% del carico su una suddivisione è vincolato dalle risorse disponibili, Spanner non acquisisce la statistica. Se Spanner non è in grado di memorizzare tutte le suddivisioni calde durante l'intervallo, il sistema dà la priorità alle suddivisioni con la percentuale di
CPU_USAGE_SCORE
più elevata durante l'intervallo specificato. Se non vengono riportate suddivisioni, significa che non sono presenti hotspot.
Schema tabella
La tabella seguente mostra lo schema della tabella per le seguenti statistiche:
SPANNER_SYS.SPLIT_STATS_TOP_MINUTE
Nome colonna | Tipo | Descrizione |
---|---|---|
INTERVAL_END |
TIMESTAMP |
Fine dell'intervallo di tempo durante il quale la suddivisione era frequente |
SPLIT_START |
STRING |
La chiave iniziale dell'intervallo di righe nella suddivisione. L'inizio della suddivisione potrebbe 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 limit:
potrebbe anche essere <end> , che indica la fine dello spazio delle chiavi| |
CPU_USAGE_SCORE
|
INT64
|
La percentuale CPU_USAGE_SCORE delle suddivisioni. Una percentualeCPU_USAGE_SCORE del 50% indica la presenza di suddivisioni calde o tiepide. |
AFFECTED_TABLES |
STRING ARRAY |
Le tabelle le cui righe potrebbero essere nella suddivisione |
Chiave di inizio e chiave di limite della suddivisione
Una suddivisione è un intervallo di righe contigue di un database ed è definita dalle chiavi start e limit. Una suddivisione può essere una singola riga, un intervallo di righe ristretto o un intervallo di righe ampio e può includere più tabelle o indici.
Le colonne SPLIT_START
e SPLIT_LIMIT
identificano le chiavi principali di una suddivisione calda o intermedia.
Schema di esempio
Lo schema seguente è una tabella di esempio per gli argomenti trattati in 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 lo spazio delle chiavi sia simile al seguente:
CHIAVE PRINCIPALE |
---|
<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 suddivisioni
Di seguito sono riportati alcuni esempi di suddivisioni per aiutarti a capire come funzionano.
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 confini dello spazio delle chiavi del database. SPLIT_START
e SPLIT_LIMIT
possono contenere anche chiavi troncate, ovvero chiavi che precedono qualsiasi chiave completa nella tabella. Ad esempio,
Threads(10)
è un prefisso per qualsiasi riga Threads
interlacciata in Users(10)
.
SPLIT_START | SPLIT_LIMIT | AFFECTED_TABLES | SPIEGAZIONE |
---|---|---|---|
Users(3) |
Users(10) |
UsersByFirstName , Users , Threads , Messages , MessagesIdx |
La suddivisione inizia nella riga con UserId=3 e termina nella riga precedente a quella con UserId = 10 . La suddivisione contiene le righe della tabella Users e tutte le righe delle tabelle interlacciate da UserId=3 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 con la riga precedente a quella con la chiave 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 interlacciati nella stessa riga della tabella di primo livello, la suddivisione contiene le righe delle tabelle interlacciate tra start e limit. Consulta schemas-overview per capire come le tabelle con interfoliazione sono colocate. |
Messages(3,"a",1) |
<end> |
UsersByFirstName , Users , Threads , Messages , MessagesIdx |
La suddivisione inizia nella tabella dei messaggi nella riga con chiave UserId=3 , ThreadId="a" e MessageId=1 . La suddivisione ospita tutte le righe da split_start a <end> , la fine dello spazio delle chiavi del database. Tutte le righe delle tabelle successive a split_start , come Users(4) , sono incluse nella suddivisione. |
<begin> |
Users(9) |
UsersByFirstName , Users , Threads , Messages , MessagesIdx |
La suddivisione inizia a <begin> , l'inizio dello spazio delle chiavi del database e termina con la riga precedente alla riga Users con UserId=9 . Pertanto, la suddivisione contiene tutte le righe della tabella precedenti a Users e tutte le righe della tabella Users precedenti a UserId=9 , nonché le righe delle tabelle con interfoliazione. |
Messages(3,"a",1) |
Threads(10) |
UsersByFirstName , Users , Threads , Messages , MessagesIdx |
La suddivisione inizia a Messages(3,"a", 1) interlacciata in Users(3) e termina nella riga precedente a Threads(10) . Threads(10) è una chiave di suddivisione troncata che è un prefisso di qualsiasi chiave della tabella Thread interlacciata 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 possibili nel database. Pertanto, affected_tables copre la tabella Users , le relative tabelle e gli indici interlacciati e tutte le tabelle che potrebbero apparire dopo gli utenti. |
Threads(10) |
UsersByFirstName("abc") |
UsersByFirstName , Users , Threads , Messages , MessagesIdx |
La suddivisione inizia nella riga Threads con UserId = 10 e termina nell'indice UsersByFirstName nella chiave precedente a "abc" . |
Esempi di query per trovare le suddivisioni più frequenti
L'esempio seguente mostra un'istruzione SQL che puoi utilizzare per recuperare le statistiche relative alle suddivisioni calde. Puoi eseguire queste istruzioni SQL utilizzando le librerie client, gcloud o la console Google Cloud.
GoogleSQL
SELECT t.split_start,
t.split_limit,
t.cpu_usage_score,
t.affected_tables,
FROM SPANNER_SYS.SPLIT_STATS_TOP_MINUTE t
WHERE t.interval_end =
(SELECT MAX(interval_end)
FROM SPANNER_SYS.SPLIT_STATS_TOP_MINUTE)
ORDER BY t.cpu_usage_score DESC;
PostgreSQL
SELECT t.split_start,
t.split_limit,
t.cpu_usage_score,
t.affected_tables
FROM SPANNER_SYS.SPLIT_STATS_TOP_MINUTE t
WHERE t.interval_end = (
SELECT MAX(interval_end)
FROM SPANNER_SYS.SPLIT_STATS_TOP_MINUTE
)
ORDER BY t.cpu_usage_score DESC;
L'output della query è il seguente:
SPLIT_START |
SPLIT_LIMIT |
CPU_USAGE_SCORE |
AFFECTED_TABLES |
---|---|---|---|
Users(13) |
Users(76) |
82 |
Messages,Users,Threads |
Users(101) |
Users(102) |
90 |
Messages,Users,Threads |
Threads(10, "a") |
Threads(10, "aa") |
100 |
Messages,Threads |
Messages(631, "abc", 1) |
Messages(631, "abc", 3) |
100 |
Messages |
Threads(12, "zebra") |
Users(14) |
76 |
Messages,Users,Threads |
Users(620) |
<end> |
100 |
Messages,Users,Threads |
Conservazione dei dati per le statistiche relative alla suddivisione calda
Come minimo, Spanner conserva i dati di ogni tabella per il seguente periodo di tempo:
SPANNER_SYS.SPLIT_STATS_TOP_MINUTE
: intervalli che coprono le 6 ore precedenti.
Risolvere i problemi relativi agli hotspot utilizzando le statistiche sulle suddivisioni calde
Questa sezione descrive come rilevare e risolvere i problemi relativi agli hotspot.
Seleziona un periodo di tempo da esaminare
Controlla le metriche sulla latenza per il tuo database Spanner per trovare il periodo di tempo in cui la tua applicazione ha registrato una latenza e un utilizzo della CPU elevati. Ad esempio, potrebbe essere indicato che un problema è iniziato intorno alle 22:50 del 18 maggio 2024.
Trovare hotspot permanenti
Poiché Spanner bilancia il carico con la suddivisione in base al carico,
ti consigliamo di verificare se l'hotspot è continuato per più di 10
minuti. Puoi farlo eseguendo una query sulla tabellaSPANNER_SYS.SPLIT_STATS_TOP_MINUTE
, come mostrato nell'esempio seguente:
GoogleSQL
SELECT Count(DISTINCT t.interval_end)
FROM SPANNER_SYS.SPLIT_STATS_TOP_MINUTE t
WHERE t.utilization >= 50
AND t.interval_end >= "interval_end_date_time"
AND t.interval_end <= "interval_end_date_time";
Sostituisci interval_end_date_time con la data e l'ora dell'intervallo, utilizzando il formato 2024-05-18T17:40:00Z
.
PostgreSQL
SELECT COUNT(DISTINCT t.interval_end)
FROM SPLIT_STATS_TOP_MINUTE t
WHERE t.utilization >= 50
AND t.interval_end >= 'interval_end_date_time'::timestamptz
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 2024-05-18T17:40:00Z
.
Se il risultato della query precedente è uguale a 10, significa che il tuo database sta riscontrando un hotspot che potrebbe richiedere ulteriore debug.
Trova le suddivisioni con il livello CPU_USAGE_SCORE
più alto
Per questo esempio, eseguiamo il seguente comando SQL per trovare gli intervalli di righe con il livello CPU_USAGE_SCORE
più alto:
GoogleSQL
SELECT t.split_start,
t.split_limit,
t.affected_tables,
t.cpu_usage_score
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 2024-05-18T17:40:00Z
.
PostgreSQL
SELECT t.split_start,
t.split_limit,
t.affected_tables,
t.cpu_usage_score
FROM SPLIT_STATS_TOP_MINUTE t
WHERE t.cpu_usage_score = 100
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 2024-05-18T17:40:00Z
.
Il codice SQL precedente genera quanto segue:
SPLIT_START |
SPLIT_LIMIT |
CPU_USAGE_SCORE |
AFFECTED_TABLES |
---|---|---|---|
Users(180) |
<end> |
85 |
Messages,Users,Threads |
Users(24) |
Users(76) |
76 |
Messages,Users,Threads |
Da questa tabella dei risultati, possiamo vedere che gli hotspot si sono verificati in due suddivisioni. La suddivisione in base al carico di Spanner potrebbe provare a risolvere gli hotspot su queste suddivisioni. Tuttavia, potrebbe non essere in grado di farlo se sono presenti pattern problematici nello schema o nel carico di lavoro. Per rilevare se sono presenti suddivisioni che richiedono il tuo intervento, ti consigliamo di monitorarle per almeno 10 minuti. Ad esempio, il seguente codice SQL monitora la prima suddivisione negli ultimi dieci minuti.
GoogleSQL
SELECT t.interval_end,
t.split_start,
t.split_limit,
t.cpu_usage_score
FROM SPANNER_SYS.SPLIT_STATS_TOP_MINUTE t
WHERE t.split_start = "users(180)"
AND t.split_limit = "<end>"
AND t.interval_end >= "interval_end_date_time"
AND t.interval_end <= "interval_end_date_time";
Sostituisci interval_end_date_time con la data e l'ora dell'intervallo, utilizzando il formato 2024-05-18T17:40:00Z
.
PostgreSQL
SELECT t.interval_end,
t.split_start,
t.split_limit,
t.cpu_usage_score
FROM SPANNER_SYS.SPLIT_STATS_TOP_MINUTE t
WHERE t.split_start = 'users(180)'
AND t.split_limit = ''
AND t.interval_end >= 'interval_end_date_time'::timestamptz
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 2024-05-18T17:40:00Z
.
Il codice SQL precedente genera quanto segue:
INTERVAL_END |
SPLIT_START |
SPLIT_LIMIT |
CPU_USAGE_SCORE |
---|---|---|---|
2024-05-18T17:46:00Z |
Users(180) |
<end> |
85 |
2024-05-18T17:47:00Z |
Users(180) |
<end> |
85 |
2024-05-18T17:48:00Z |
Users(180) |
<end> |
85 |
2024-05-18T17:49:00Z |
Users(180) |
<end> |
85 |
2024-05-18T17:50:00Z |
Users(180) |
<end> |
85 |
Sembra che la suddivisione sia stata attiva negli ultimi minuti. Potresti osservare la suddivisione per un periodo di tempo più lungo per determinare che la suddivisione in base al carico di Spanner riduce l'hotspot. Potrebbero verificarsi casi in cui Spanner non può più eseguire il bilanciamento del carico.
Ad esempio, esegui una query sulla tabella SPANNER_SYS.SPLIT_STATS_TOP_MINUTE
. Consulta gli scenari di esempio che seguono.
GoogleSQL
SELECT t.interval_end,
t.split_start,
t.split_limit,
t.cpu_usage_score
FROM SPANNER_SYS.SPLIT_STATS_TOP_MINUTE t
WHERE t.interval_end >= "interval_end_date_time"
AND t.interval_end <= "interval_end_date_time";
Sostituisci interval_end_date_time con la data e l'ora dell'intervallo, utilizzando il formato 2024-05-18T17:40:00Z
.
PostgreSQL
SELECT t.interval_end,
t.split_start,
t.split_limit,
t._cpu_usage
FROM SPANNER_SYS.SPLIT_STATS_TOP_MINUTE t
WHERE t.interval_end >= 'interval_end_date_time'::timestamptz
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 2024-05-18T17:40:00Z
.
Singola riga calda
Nell'esempio seguente, sembra che Threads(10,"spanner")
si trovi in una suddivisione in una singola riga che è rimasta attiva per oltre 10 minuti. Ciò può accadere quando c'è un caricamento persistente su una riga molto utilizzata.
INTERVAL_END |
SPLIT_START |
SPLIT_LIMIT |
CPU_USAGE_SCORE |
---|---|---|---|
2024-05-16T20:40:00Z |
Threads(10,"spanner") |
Threads(10,"spanner1") |
62 |
2024-05-16T20:41:00Z |
Threads(10,"spanner") |
Threads(10,"spanner1") |
62 |
2024-05-16T20:42:00Z |
Threads(10,"spanner") |
Threads(10,"spanner1") |
62 |
2024-05-16T20:43:00Z |
Threads(10,"spanner") |
Threads(10,"spanner1") |
62 |
2024-05-16T20:44:00Z |
Threads(10,"spanner") |
Threads(10,"spanner1") |
62 |
2024-05-16T20:45:00Z |
Threads(10,"spanner") |
Threads(10,"spanner1") |
62 |
2024-05-16T20:46:00Z |
Threads(10,"spanner") |
Threads(10,"spanner1") |
80 |
2024-05-16T20:47:00Z |
Threads(10,"spanner") |
Threads(10,"spanner1") |
80 |
2024-05-16T20:48:00Z |
Threads(10,"spanner") |
Threads(10,"spanner1") |
80 |
2024-05-16T20:49:00Z |
Threads(10,"spanner") |
Threads(10,"spanner1") |
100 |
2024-05-16T20:50:00Z |
Threads(10,"spanner") |
Threads(10,"spanner1") |
100 |
Spanner non può bilanciare il carico per questa singola chiave perché non può essere suddivisa ulteriormente.
Hotspot in movimento
Nell'esempio seguente, il carico passa da suddivisioni contigue nel tempo, passando a una nuova suddivisione in intervalli di tempo.
INTERVAL_END |
SPLIT_START |
SPLIT_LIMIT |
CPU_USAGE_SCORE |
---|---|---|---|
2024-05-16T20:40:00Z |
Threads(1,"a") |
Threads(1,"aa") |
100 |
2024-05-16T20:41:00Z |
Threads(1,"aa") |
Threads(1,"ab") |
100 |
2024-05-16T20:42:00Z |
Threads(1,"ab") |
Threads(1,"c") |
100 |
2024-05-16T20:43:00Z |
Threads(1,"c") |
Threads(1,"ca") |
100 |
Ciò potrebbe verificarsi, ad esempio, a causa di un carico di lavoro che legge o scrive le chiavi in ordine crescente. Spanner non può bilanciare il carico per mitigare gli effetti di questo comportamento dell'applicazione.
Bilanciamento del carico normale
Spanner tenta di bilanciare il carico aggiungendo altre suddivisioni o muovendole. L'esempio seguente mostra un possibile caso.
INTERVAL_END |
SPLIT_START |
SPLIT_LIMIT |
CPU_USAGE_SCORE |
---|---|---|---|
2024-05-16T20:40:00Z |
Threads(1000,"zebra") |
<end> |
82 |
2024-05-16T20:41:00Z |
Threads(1000,"zebra") |
<end> |
90 |
2024-05-16T20:42:00Z |
Threads(1000,"zebra") |
<end> |
100 |
2024-05-16T20:43:00Z |
Threads(1000,"zebra") |
Threads(2000,"spanner") |
100 |
2024-05-16T20:44:00Z |
Threads(1200,"c") |
Threads(2000) |
92 |
2024-05-16T20:45:00Z |
Threads(1500,"c") |
Threads(1700,"zach") |
76 |
2024-05-16T20:46:00Z |
Threads(1700) |
Threads(1700,"c") |
76 |
2024-05-16T20:47:00Z |
Threads(1700) |
Threads(1700,"c") |
50 |
2024-05-16T20:48:00Z |
Threads(1700) |
Threads(1700,"c") |
39 |
In questo caso, la suddivisione più grande del 16-05-2024 alle 17:40:00Z è stata ulteriormente suddivisa in una suddivisione più piccola e, di conseguenza, la statistica CPU_USAGE_SCORE
è diminuita.
Spanner potrebbe non creare suddivisioni in singole righe. Le suddivisioni rispecchiano il carico di lavoro che causa la statistica CPU_USAGE_SCORE
elevata.
Se hai osservato una suddivisione in hot spot persistente per più di 10 minuti, consulta Best practice per mitigare gli hotspot.
Best practice per mitigare gli hotspot
Se il bilanciamento del carico non riduce la latenza, il passaggio successivo consiste nell'identificare la causa degli hotspot. Dopodiché, puoi ridurre il carico di lavoro degli hotspot o ottimizzare lo schema e la logica dell'applicazione per evitare gli hotspot.
Identificare la causa
Utilizza Approfondimenti su blocchi e transazioni per cercare transazioni con tempi di attesa del blocco elevati in cui la chiave di inizio dell'intervallo di righe rientra nella suddivisione calda.
Utilizza Approfondimenti sulle query per cercare le query che leggono dalla tabella contenente la suddivisione calda e che hanno recentemente aumentato la latenza o un rapporto di latenza più elevato rispetto alla CPU.
Utilizza Query attive meno recenti per cercare le query che leggono dalla tabella contenente la suddivisione attiva e che hanno una latenza superiore a quella prevista.
Alcuni casi speciali da tenere presenti:
- Controlla se la durata (TTL) è stata attivata di recente. Se esistono molti split dai dati precedenti, il TTL può aumentare i livelli di
CPU_USAGE_SCORE
durante le eliminazioni collettive. In questo caso, il problema dovrebbe risolversi da solo al termine delle eliminazioni iniziali.
Ottimizza il carico di lavoro
- Segui le best practice di SQL. Valuta la possibilità di eliminare le letture non aggiornate, le scritture che non eseguono prima le letture o l'aggiunta di indici.
- Segui le best practice di Schema. Assicurati che lo schema sia progettato per gestire il bilanciamento del carico ed evitare hotspot.
Passaggi successivi
- Scopri le best practice per la progettazione dello schema.
- Scopri di più su Key Visualizer.
- Consulta gli esempi di design dello schema.
- Scopri come utilizzare la dashboard Statistiche sulle suddivisioni per rilevare gli hotspot.