Questa pagina 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 viene fornita
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 viene considerata calda.
Spanner utilizza la divisione basata sul carico per distribuire uniformemente il carico di dati sui server dell'istanza. Le divisioni calde e molto calde possono essere spostate tra i server per il bilanciamento del carico o possono essere suddivise in divisioni più piccole. Tuttavia, Spanner potrebbe non essere in grado di bilanciare il carico, anche dopo diversi tentativi di suddivisione, a causa di anti-pattern nell'applicazione. Pertanto, gli hotspot persistenti che durano almeno 10 minuti potrebbero richiedere ulteriori risoluzioni dei problemi e potenziali modifiche all'applicazione.
Le statistiche sulla suddivisione frequente di Spanner ti aiutano a identificare le suddivisioni
in cui si verificano gli 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 le istruzioni SQL.
Accedere alle statistiche della divisione a caldo
Spanner fornisce le statistiche sulla suddivisione frequente nello schema SPANNER_SYS
. I dati di SPANNER_SYS
sono disponibili solo tramite le interfacce GoogleSQL e PostgreSQL. Puoi
utilizzare i seguenti modi per accedere a questi dati:
- La pagina Spanner Studio di un database nella console Google Cloud .
- Il comando
gcloud spanner databases execute-sql
. - Il metodo
executeSql
oexecuteStreamingSql
.
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 la seguente tabella per monitorare le suddivisioni più frequenti:
SPANNER_SYS.SPLIT_STATS_TOP_MINUTE
: mostra le frazioni più calde durante intervalli di 1 minuto.
Queste tabelle hanno le seguenti proprietà:
- Ogni tabella contiene dati per intervalli di tempo non sovrapposti della durata specificata dal nome della tabella.
Gli intervalli si basano sugli orari:
- Gli intervalli di 1 minuto terminano al minuto.
Dopo ogni intervallo, Spanner raccoglie i dati da tutti i server e li rende disponibili nelle tabelle
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
Spanner raggruppa le statistiche in base alle suddivisioni.
Ogni riga contiene una percentuale che indica il livello di frequenza di una suddivisione, per ogni suddivisione per cui 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 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 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 può anche essere <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 può anche essere <end> , che indica la fine dello spazio delle chiavi. |
CPU_USAGE_SCORE
|
INT64
|
La percentuale CPU_USAGE_SCORE delle suddivisioni. Una percentuale
CPU_USAGE_SCORE del 50% indica la presenza di |
suddivisioni | calde o frequenti. |
AFFECTED_TABLES |
STRING ARRAY |
Le tabelle le cui righe potrebbero essere nella suddivisione. |
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
calda 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 suddivisione 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 interleaved 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 alla 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 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 interleaved 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" . |
Esempi di query per trovare le suddivisioni più frequenti
L'esempio seguente mostra un'istruzione SQL che puoi utilizzare per recuperare le statistiche di suddivisione a caldo. Puoi eseguire queste istruzioni SQL utilizzando le librerie client, gcloud o la Google Cloud console.
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 è simile al 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 sulla suddivisione a caldo
Come minimo, Spanner conserva i dati per 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 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 2024.
Trovare hotspot persistenti
Poiché Spanner bilancia il carico con la divisione basata sul carico,
ti consigliamo di verificare se l'hotspotting è continuato per più di 10
minuti. Puoi farlo eseguendo una query sulla
tabella SPANNER_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.cpu_usage_score >= 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.cpu_usage_score >= 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 hotspotting che potrebbe richiedere un ulteriore debug.
Trova le divisioni con il livello di CPU_USAGE_SCORE
più alto
Per questo esempio, eseguiamo il seguente 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
.
L'SQL precedente restituisce il seguente output:
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 si sono verificati hotspot in due split. La divisione basata sul carico di Spanner potrebbe provare a risolvere gli hotspot in queste divisioni. Tuttavia, potrebbe non essere in grado di farlo se ci sono pattern problematici nello schema o nel carico di lavoro. Per rilevare se sono presenti divisioni che richiedono il tuo intervento, ti consigliamo di monitorare le divisioni per almeno 10 minuti. Ad esempio, il seguente SQL monitora la prima divisione negli ultimi 10 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
.
L'SQL precedente restituisce il seguente output:
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 |
La divisione sembra essere stata molto combattuta negli ultimi minuti. Potresti osservare la divisione più a lungo per determinare che la divisione basata sul carico di Spanner mitiga l'hotspot. Potrebbero verificarsi casi in cui Spanner non può bilanciare ulteriormente il carico.
Ad esempio, esegui una query sulla tabella SPANNER_SYS.SPLIT_STATS_TOP_MINUTE
. Vedi gli scenari di esempio riportati di seguito.
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
singola fila divisa che è rimasta calda per più di 10 minuti. Ciò può accadere quando
c'è un carico persistente su una riga popolare.
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 ulteriormente suddivisa.
Hotspot mobile
Nell'esempio seguente, il carico si sposta attraverso suddivisioni contigue nel tempo, passando a una nuova suddivisione negli 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 chiavi in ordine crescente monotono. 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 spostando le suddivisioni. L'esempio seguente mostra come potrebbe apparire.
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 giorno 2024-05-16T17: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
riflettono il workload che causa la statistica CPU_USAGE_SCORE
elevata.
Se hai notato una divisione calda 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é, le opzioni sono ridurre il carico di lavoro di hotspotting o ottimizzare lo schema e la logica dell'applicazione per evitare gli hotspot.
Identificare la causa
Utilizza Statistiche su blocchi e transazioni per cercare transazioni con tempi di attesa 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 calda 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 che contiene la suddivisione attiva e che hanno una latenza superiore al previsto.
Alcuni casi particolari a cui prestare attenzione:
- Controlla se la durata (TTL) è stata attivata di recente. Se ci sono
molte suddivisioni di 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 per SQL. Prendi in considerazione letture non aggiornate, 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
- Scopri di più sulle best practice per la progettazione dello schema.
- Scopri di più su Key Visualizer.
- Consulta gli esempi di progettazione dello schema.
- Scopri come utilizzare la dashboard delle statistiche suddivise per rilevare i punti di interesse.