«Nettstedet er tregt» ender nesten alltid i databasen. Kontrollen tar noen minutter hvis den gjøres i riktig rekkefølge: først det som synes mens forsinkelsen pågår, så det som har bygd seg opp over uker.

Man må se i problemets øyeblikk

Hovedregelen: den mest verdifulle informasjonen er tilgjengelig nøyaktig når alt er tregt. Første kommando for MySQL:

sudo mysqladmin processlist
mysql -e 'SHOW FULL PROCESSLIST'

For PostgreSQL:

sudo -u postgres psql -c "SELECT pid, state, wait_event, now()-query_start AS dur, query
FROM pg_stat_activity WHERE state != 'idle' ORDER BY dur DESC;"

Du ser hva som kjører akkurat nå og hvor lenge. Svaret synes som regel med en gang: én tung spørring holder de andre, eller hundre like spørringer venter på at en lås skal slippes.

Forbindelser

mysql -e "SHOW GLOBAL STATUS LIKE 'Threads_connected'"
mysql -e "SHOW GLOBAL STATUS LIKE 'Max_used_connections'"
mysql -e "SHOW VARIABLES LIKE 'max_connections'"

Ligger Max_used_connections tett opptil max_connections, får applikasjonen periodevis avslaget «for mange forbindelser». Å heve grensen er ikke det første man gjør: hver forbindelse tar minne, og en hevet grense på en server som allerede mangler minne, framskynder bare veien til swap. Først bør man forstå hvorfor forbindelsene ikke frigjøres: som regel skyldes det en lang spørring eller at applikasjonen mangler en pool.

Her er det også nyttig å se saken fra den andre siden: en kraftig økning i antall forbindelser kan skyldes at boter i mengder besøker en tung side — søket, katalogfilteret, rapportgeneratoren — og ikke økt popularitet.

Trege spørringer

Uten en logg over trege spørringer kommer man ikke videre. MySQL:

SET GLOBAL slow_query_log = 'ON';
SET GLOBAL long_query_time = 1;

Etter et døgn:

sudo mysqldumpslow -s t -t 10 /var/log/mysql/mysql-slow.log

PostgreSQL, i postgresql.conf:

log_min_duration_statement = 1000

Deretter utvidelsen pg_stat_statements, som med en gang viser den samlede tiden for hver spørring:

SELECT calls, round(total_exec_time) AS total_ms, query
FROM pg_stat_statements ORDER BY total_exec_time DESC LIMIT 10;

Merk: det viktige er ikke den lengste spørringen, men den med størst samlet tid. En spørring på 50 millisekunder som kjøres tusen ganger i minuttet, skader mer enn en tisekunders rapport én gang i døgnet.

Innstillingen man oftest glemmer

For MySQL og MariaDB er det InnoDB-bufferpoolens størrelse. Standardverdien er 128 megabyte og har ikke endret seg på tiår. På en server der databasen er flere gigabyte, betyr det stadig lesing fra disk i stedet for fra minne.

mysql -e "SHOW VARIABLES LIKE 'innodb_buffer_pool_size'"

En fornuftig målestokk for en dedikert databaseserver er halvparten av arbeidsminnet; for en server der webserveren og PHP arbeider ved siden av, er det en fjerdedel, med blikket på at swappen ikke skal starte. Den ene innstillingen gir som regel mer enn en ukes spørringsoptimalisering.

To ting som umerkelig spiser disken

MySQLs binærlogger. De trengs til replikering og gjenoppretting til et tidspunkt, vokser uavbrutt og slettes som standard iblant ikke i det hele tatt. Kontroll:

sudo du -sh /var/lib/mysql/*bin.*
mysql -e "SHOW VARIABLES LIKE 'binlog_expire_logs_seconds'"

Har du ingen replikering og bruker ikke gjenoppretting til et tidspunkt, settes lagringstiden til fornuftige noen døgn.

WAL-logger i PostgreSQL ved en glemt replikeringsslot. Et mindre kjent og farligere tilfelle: er en replikeringsslot opprettet og forbrukeren ikke lenger kobler seg til den, plikter PostgreSQL å lagre alle logger siden frakoblingen — og vil lagre dem til disken tar slutt.

sudo -u postgres psql -c "SELECT slot_name, active, restart_lsn FROM pg_replication_slots;"

En inaktiv slot ingen trenger, skal slettes. Det er en av få situasjoner der en database garantert kjører disken i bunn.

Størrelse og vekst

SELECT table_schema, round(sum(data_length+index_length)/1024/1024) AS mb
FROM information_schema.tables GROUP BY table_schema ORDER BY mb DESC;

Det nyttige er ikke så mye det aktuelle tallet som endringstakten. En database som er doblet på en måned uten tilsvarende økning i besøk, betyr som regel at en loggtabell skrives og aldri ryddes — økter, jobbhistorikk, en utvidelses hendelseslogg.

Sikkerhet på to linjer

Når du likevel har åpnet databasekonsollen, er to ting verdt å kontrollere. Det første: er databasen tilgjengelig utenfra (ss -tulpn | grep 3306) — utover skal den nesten aldri vende. Det andre: kontoer med tilgang fra hvilken som helst adresse:

mysql -e "SELECT user, host FROM mysql.user"

Oppføringer med host = '%' betyr «tilkobling tillatt hvorfra som helst». Er porten i tillegg åpen, står bare et passord mellom databasen og internett.

Sikkerhetskopier

Det siste som er verdt å si. At en sikkerhetskopifil finnes, garanterer ingenting — bare en gjennomført gjenoppretting gjør det. En dump som aldri er rullet tilbake, kan like gjerne være avkortet, tatt med en låsefeil eller inneholde feil database. Det skal kontrolleres på forhånd og på en egen maskin, ikke den dagen kopien trengs.

Til den daglige overvåkingen holder tre tall: antall forbindelser, antall trege spørringer i døgnet og databasens størrelse. Alle tre endres langsomt og forutsigbart, og enhver kraftig endring er verdt et blikk. Hvordan de ser ut på én side, viser demonstrasjonen nedenfor.