Ne vale la pena l'overhead della frequente invalidazione della cache delle query?


22

Attualmente sto lavorando su un database MySQL in cui vediamo un gran numero di invalidazioni dalla cache delle query, principalmente a causa dell'elevato numero di istruzioni INSERT, DELETE e UPDATE che vengono eseguite su molte tabelle.

Quello che sto cercando di determinare è se ci sono o meno dei vantaggi nel consentire l'utilizzo della cache delle query per le istruzioni SELECT che vengono eseguite su queste tabelle. Dato che vengono invalidati così rapidamente, mi sembra che la cosa migliore sarebbe semplicemente usare SQL_NO_CACHE su istruzioni SELECT con queste tabelle.

Ne vale la pena l'overhead di frequente invalidazione?

Modifica: su richiesta dell'utente @RolandoMySQLDBA di seguito, ecco le informazioni su MyISAM e INNODB.

InnoDB

  • Dimensione dati: 177.414 GB
  • Dimensione indice: 114.792 GB
  • Dimensione tavolo: 292.205 GB

MyISAM

  • Dimensione dati: 379.762 GB
  • Dimensione indice: 80.681 GB
  • Dimensione tavolo: 460.443 GB

Informazioni addizionali:

  • Versione: 5.0.85
  • query_cache_limit: 1048576
  • query_cache_min_res_unit: 4096
  • query_cache_size: 104857600
  • query_cache_type: ON
  • query_cache_wlock_invalidate: OFF
  • innodb_buffer_pool_size: 8841592832
  • 24 GB di RAM


Hehe, molto perspicace.
Craig Sefton,

Risposte:


16

Dovresti semplicemente disabilitare la cache delle query con

[mysqld]
query_cache_size = 0

e quindi riavviare mysql. Perché dovrei suggerirlo ???

La query cache sarà sempre testa a testa con InnoDB. Sarebbe bello se MVCC di InnoDB consentisse di eseguire query dalla cache delle query se le modifiche non influiscono sulle letture ripetibili per altre transazioni. Sfortunatamente, InnoDB non lo fa. Apparentemente, hai molte domande che vengono invalidate piuttosto rapidamente e probabilmente non vengono riutilizzate.

Per InnoDB in MySQL 4.0, la cache delle query è stata disabilitata per le transazioni. Per MySQL 4.1+, InnoDB riproduce il traffic traffic quando consente l'accesso alla cache delle query in base alla tabella.

Dal punto di vista della tua domanda, direi che la giustificazione della rimozione della cache delle query non è tanto l'overhead, ma il modo in cui InnoDB lo gestisce.

Per ulteriori informazioni su come InnoDB interagisce con la cache delle query, leggere le pagine 213-215 del libro "MySQL ad alte prestazioni (seconda edizione)" .

Se tutti o la maggior parte dei tuoi dati è MyISAM, potresti seguire l'idea originale di utilizzare SQL_NO_CACHE.

Se disponi di un mix di InnoDB e MyISAM, dovrai trovare il giusto equilibrio per la tua applicazione in base all'entità della perdita di cache. In effetti, le pagine 209-210 dello stesso libro indicano i motivi per cui mancano i cache:

  • La query non è memorizzabile nella cache, perché contiene un costrutto non deterministico (come CURRENT_DATE) o perché il set di risultati è troppo grande per essere archiviato. Entrambi i tipi di query non memorizzabili incrementano la variabile di stato Qcache_not_cached.
  • Il server non ha mai visto la query prima, quindi non ha mai avuto la possibilità di memorizzarne il risultato nella cache.
  • Il risultato della query era precedentemente memorizzato nella cache, ma il server lo ha rimosso. Questo può accadere perché non c'era memoria sufficiente per conservarlo, perché qualcuno ha incaricato il server di rimuoverlo o perché è stato invalidato

e le cause alla radice di mancati errori nella cache con poche query invariabili potrebbero essere:

  • La cache delle query non è ancora calda. Cioè il server non ha avuto la possibilità di riempire la cache con set di risultati.
  • Il server sta visualizzando query che non ha mai visto prima. Se non si hanno molte query ripetute, ciò può accadere anche dopo il riscaldamento della cache.
  • Esistono molte invalidazioni della cache.

AGGIORNAMENTO 2012-09-06 10:10 EDT

Guardando le tue ultime informazioni aggiornate, hai query_cache_limitimpostato su 1048576 (1M). Ciò limita qualsiasi risultato impostato su 1M. Se recuperi qualcosa di più grande, semplicemente non verrà memorizzato nella cache. Sebbene sia stato query_cache_sizeimpostato su 104857600 (100 M), ciò consente di impostare solo 100 risultati memorizzati nella cache in un mondo perfetto. Se esegui centinaia di query, la frammentazione avverrà piuttosto rapidamente. Hai anche 4096 (4K) come set di risultati di dimensione minima. Sfortunatamente, mysql non ha alcun meccanismo interno per deframmentare la cache delle query.

Se devi disporre della cache delle query e hai così tanta RAM, puoi eseguire quanto segue:

SET GLOBAL query_cache_size = 0;
SELECT SLEEP(60);
SET GLOBAL query_cache_size = 1024 * 1024 * 1024;

per eliminare la cache delle query. Si perdono tutti i risultati memorizzati nella cache, quindi eseguire queste righe durante le ore non di punta.

Vorrei anche assegnare quanto segue:

  • query_cache_size = 1G
  • query_cache_limit = 8M

Questo lascia 23G di RAM. Vorrei sollevare quanto segue:

  • innodb_buffer_pool_size = 12G
  • key_buffer_size = 4G

Questo lascia il 7G. Questo dovrebbe essere adeguato per connessioni OS e DB.

Tenere presente che il buffer delle chiavi memorizza nella cache solo le pagine dell'indice MyISAM, mentre il pool di buffer InnoDB memorizza nella cache dati e indici.

Un'altra raccomandazione: aggiornare a MySQL 5.5 in modo da poter configurare InnoDB per più CPU e thread multipli per I / O di lettura / scrittura.

Vedi i miei post precedenti sull'utilizzo di MySQL 5.5 in combinazione con l'accesso a più CPU per InnoDB

AGGIORNAMENTO 2012-09-06 14:56 EDT

Il mio metodo per svuotare la cache delle query è piuttosto estremo perché contiene i dati memorizzati nella cache e forma un segmento completamente diverso di RAM. Come hai sottolineato nel tuo commento, FLUSH QUERY CACHE(come hai suggerito) o addirittura RESET QUERY CACHEsarebbe meglio. Per chiarimenti, quando ho detto "nessun meccanismo interno", intendevo esattamente questo. La deframmentazione è necessaria e deve essere eseguita manualmente. Dovrebbe essere crontab'd .

Se fai DML (INSERT, UPDATE, DELETE) su InnoDB più spesso che su MyISAM, direi di rimuovere del tutto la cache delle query, che ho detto all'inizio.


Grazie per la risposta. Ho quel libro e lo uso ampiamente; sono consapevole dei motivi che descrivi per i mancati cache, ma come ho già detto, abbiamo già identificato le invalidazioni della cache come un problema chiave a causa della forte correlazione che stiamo vedendo tra Com_select e Qcache_inserts. Oh, e il DB in questione ha un mix di INNODB e MyISAM.
Craig Sefton,

Aggiornato con le informazioni aggiuntive richieste. Grazie.
Craig Sefton,

Grazie per la risposta, non vedo l'ora per il resto. Una delle cose che abbiamo identificato è che circa il 18% delle query non veniva memorizzato nella cache, quindi apprezzare sicuramente i consigli relativi alle impostazioni. Purtroppo la scatola non è dedicata, ma i tuoi consigli dovrebbero aiutarti. Anche la frammentazione è sicuramente un problema. Sono ancora molto preoccupato per il numero di invalidazioni che stiamo vedendo (al contrario delle query che non sono affatto memorizzate nella cache), quindi sono ancora incerto se ne valga la pena. Apprezzo molto la tua intuizione, grazie mille.
Craig Sefton,

Per quanto riguarda il tuo commento su "mysql non ha alcun meccanismo interno per deframmentare la cache delle query", non puoi eseguire il comando FLUSH QUERY CACHEper deframmentarlo? Vedi: dev.mysql.com/doc/refman/5.0/en/flush.html
Craig Sefton

Aggiornato la mia risposta ...
RolandoMySQLDBA

3

MALE: query_cache_size = 1G

Perché? Per quanto tempo impiegherà un flush. Cioè, quando si verifica una scrittura, l'intero 1 GB verrà scansionato per trovare eventuali riferimenti alla tabella che è stata modificata. Maggiore è il controllo qualità, più lento sarà. Raccomando una dimensione non superiore a 50 M, a meno che i tuoi dati non cambino raramente.

Il controllo qualità è sovraccarico sia per MyISAM che per InnoDB. Elimina un Mutex globale e lo elimina troppo presto. Questo mutex è uno dei motivi per cui MySQL non è in grado di utilizzare in modo efficace più di circa 8 core.

SQL_NO_CACHE non è notato fino a dopo il Mutex non viene bloccato! L'unico uso per quella bandiera è per il benchmarking.

Spesso è meglio assegnare la RAM a qualche altra cache.


2

Mi viene in mente un caso perfetto per questo, e abbiamo testato a fondo ed eseguirlo in produzione ... Lo chiamo "corsia preferenziale" strategia di clustering preferenziale :

Se si esegue la suddivisione in lettura-scrittura con un proxy come MaxScale o l'applicazione è in grado, è possibile inviare alcune letture per quelle tabelle raramente invalidate solo agli slave con la cache delle query attivata e il resto ad altri slave con esso spento.

Facciamo questo e gestiamo 4 M chiamate al minuto al cluster durante i nostri test di carico (non benchmark ... il vero affare) come risultato. L'app aspetta su master_pos_wait () per alcune cose, quindi è limitata dal thread di replica e, sebbene l'abbiamo vista con uno stato di attesa sull'invalidazione di Qcache a un throughput molto elevato, quei livelli di throughput sono più alti di quanto il cluster sia pari capace senza Qcache.

Questo funziona perché raramente c'è qualcosa di rilevante nella piccola cache delle query su quelle macchine per invalidare (quelle query sono rilevanti solo per le tabelle raramente aggiornate). Queste scatole sono la nostra "corsia preferenziale". Per il resto delle query eseguite dall'applicazione, non devono fare i conti con Qcache poiché vanno alle caselle senza che siano accese.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.