De fleste databaser vokser i størrelse over tid. Væksten er ikke altid hurtig nok til at påvirke databasens ydeevne, men der er helt sikkert tilfælde, hvor det sker. Når den gør det, spekulerer vi ofte på, hvad der kunne gøres for at reducere denne påvirkning, og hvordan kan vi sikre glatte databaseoperationer, når vi håndterer data i stor skala.
Først og fremmest, lad os prøve at definere, hvad betyder en "stor datamængde"? For MySQL eller MariaDB er det ukomprimeret InnoDB. InnoDB fungerer på en måde, så den drager stor fordel af tilgængelig hukommelse - primært InnoDB bufferpuljen. Så længe dataene passer der, minimeres diskadgang til kun at håndtere skrivninger - læsninger serveres ud af hukommelsen. Hvad sker der, når dataene vokser ud af hukommelsen? Flere og flere data skal læses fra disken, når der er behov for at få adgang til rækker, som i øjeblikket ikke er cachelagret. Når mængden af data stiger, skifter arbejdsbyrden fra CPU-bundet til I/O-bundet. Det betyder, at flaskehalsen ikke længere er CPU (hvilket var tilfældet, da dataene passede ind i hukommelsen - dataadgang i hukommelsen er hurtig, datatransformation og aggregering er langsommere), men det er I/O-undersystemet (CPU-operationer på data er meget hurtigere end at få adgang til data fra disk.) Med øget brug af flash er I/O-bundne arbejdsbelastninger ikke så forfærdelige, som de plejede at være i tider med roterende drev (random access er meget hurtigere med SSD), men ydeevnehittet er der stadig .
En anden ting vi skal huske på, at vi typisk kun bekymrer os om det aktive datasæt. Sikker på, du kan have terabyte data i dit skema, men hvis du kun skal have adgang til de sidste 5 GB, er dette faktisk en ganske god situation. Selvfølgelig udgør det stadig driftsmæssige udfordringer, men præstationsmæssigt burde det stadig være ok.
Lad os bare antage med henblik på denne blog, og dette er ikke en videnskabelig definition, at vi med den store datamængde mener tilfælde, hvor aktiv datastørrelse væsentligt vokser større end størrelsen af hukommelsen. Det kan være 100 GB, når du har 2 GB hukommelse, det kan være 20 TB, når du har 200 GB hukommelse. Vippepunktet er, at din arbejdsbyrde er strengt I/O bundet. Bær over med os, mens vi diskuterer nogle af de muligheder, der er tilgængelige for MySQL og MariaDB.
Partitionering
Den historiske (men fuldkommen gyldige) tilgang til håndtering af store mængder data er at implementere partitionering. Ideen bag det er at opdele tabellen i partitioner, en slags undertabeller. Opdelingen sker i henhold til reglerne defineret af brugeren. Lad os tage et kig på nogle af eksemplerne (SQL-eksemplerne er taget fra MySQL 8.0-dokumentationen)
MySQL 8.0 kommer med følgende typer partitionering:
- RANGE
- LISTE
- KOLONNER
- HASH
- NØGLE
Det kan også oprette underpartitioner. Vi vil ikke omskrive dokumentation her, men vi vil stadig gerne give dig et indblik i, hvordan partitioner fungerer. For at oprette partitioner skal du definere partitioneringsnøglen. Det kan være en kolonne eller i tilfælde af RANGE eller LIST flere kolonner, der vil blive brugt til at definere, hvordan dataene skal opdeles i partitioner.
HASH-partitionering kræver, at brugeren definerer en kolonne, som bliver hashed. Derefter vil dataene blive opdelt i brugerdefinerede antal partitioner baseret på denne hashværdi:
CREATE TABLE employees (
id INT NOT NULL,
fname VARCHAR(30),
lname VARCHAR(30),
hired DATE NOT NULL DEFAULT '1970-01-01',
separated DATE NOT NULL DEFAULT '9999-12-31',
job_code INT,
store_id INT
)
PARTITION BY HASH( YEAR(hired) )
PARTITIONS 4;
I dette tilfælde oprettes hash baseret på resultatet genereret af YEAR()-funktionen i kolonnen 'hyret'.
NØGLE-partitionering er ens med den undtagelse, at brugeren definerer, hvilken kolonne der skal hash, og resten er op til MySQL at håndtere.
Mens HASH- og KEY-partitioner tilfældigt fordelte data på tværs af antallet af partitioner, lader RANGE og LIST brugeren bestemme, hvad han skal gøre. RANGE bruges almindeligvis med tid eller dato:
CREATE TABLE quarterly_report_status (
report_id INT NOT NULL,
report_status VARCHAR(20) NOT NULL,
report_updated TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
)
PARTITION BY RANGE ( UNIX_TIMESTAMP(report_updated) ) (
PARTITION p0 VALUES LESS THAN ( UNIX_TIMESTAMP('2008-01-01 00:00:00') ),
PARTITION p1 VALUES LESS THAN ( UNIX_TIMESTAMP('2008-04-01 00:00:00') ),
PARTITION p2 VALUES LESS THAN ( UNIX_TIMESTAMP('2008-07-01 00:00:00') ),
PARTITION p3 VALUES LESS THAN ( UNIX_TIMESTAMP('2008-10-01 00:00:00') ),
PARTITION p4 VALUES LESS THAN ( UNIX_TIMESTAMP('2009-01-01 00:00:00') ),
PARTITION p5 VALUES LESS THAN ( UNIX_TIMESTAMP('2009-04-01 00:00:00') ),
PARTITION p6 VALUES LESS THAN ( UNIX_TIMESTAMP('2009-07-01 00:00:00') ),
PARTITION p7 VALUES LESS THAN ( UNIX_TIMESTAMP('2009-10-01 00:00:00') ),
PARTITION p8 VALUES LESS THAN ( UNIX_TIMESTAMP('2010-01-01 00:00:00') ),
PARTITION p9 VALUES LESS THAN (MAXVALUE)
);
Den kan også bruges med andre typer kolonner:
CREATE TABLE employees (
id INT NOT NULL,
fname VARCHAR(30),
lname VARCHAR(30),
hired DATE NOT NULL DEFAULT '1970-01-01',
separated DATE NOT NULL DEFAULT '9999-12-31',
job_code INT NOT NULL,
store_id INT NOT NULL
)
PARTITION BY RANGE (store_id) (
PARTITION p0 VALUES LESS THAN (6),
PARTITION p1 VALUES LESS THAN (11),
PARTITION p2 VALUES LESS THAN (16),
PARTITION p3 VALUES LESS THAN MAXVALUE
);
LIST-partitionerne fungerer baseret på en liste over værdier, der sorterer rækkerne på tværs af flere partitioner:
CREATE TABLE employees (
id INT NOT NULL,
fname VARCHAR(30),
lname VARCHAR(30),
hired DATE NOT NULL DEFAULT '1970-01-01',
separated DATE NOT NULL DEFAULT '9999-12-31',
job_code INT,
store_id INT
)
PARTITION BY LIST(store_id) (
PARTITION pNorth VALUES IN (3,5,6,9,17),
PARTITION pEast VALUES IN (1,2,10,11,19,20),
PARTITION pWest VALUES IN (4,12,13,14,18),
PARTITION pCentral VALUES IN (7,8,15,16)
);
Hvad er meningen med at bruge partitioner, spørger du måske? Hovedpointen er, at opslagene er væsentligt hurtigere end med en ikke-opdelt tabel. Lad os sige, at du vil søge efter de rækker, der blev oprettet i en given måned. Hvis du har flere års data gemt i tabellen, vil dette være en udfordring - et indeks skal bruges, og som vi ved, hjælper indekser med at finde rækker, men adgang til disse rækker vil resultere i en masse tilfældige læsninger fra hele bordet. Hvis du har partitioner oprettet på års-månedsbasis, kan MySQL bare læse alle rækkerne fra den pågældende partition - intet behov for at få adgang til indeks, intet behov for at lave tilfældige læsninger:bare læs alle data fra partitionen sekventielt, og vi er alt klar.
Partitioner er også meget nyttige til at håndtere datarotation. Hvis MySQL nemt kan identificere rækker, der skal slettes og tilknytte dem til en enkelt partition, i stedet for at køre DELETE FROM table WHERE …, som vil bruge indeks til at finde rækker, kan du afkorte partitionen. Dette er ekstremt nyttigt med RANGE-partitionering - for at holde os til eksemplet ovenfor, hvis vi kun vil beholde data i 2 år, kan vi nemt oprette et cron-job, som vil fjerne den gamle partition og oprette en ny, tom en til næste måned.
InnoDB-komprimering
Hvis vi har en stor mængde data (ikke nødvendigvis tænker på databaser), er det første, vi tænker på, at komprimere det. Der er adskillige værktøjer, der giver mulighed for at komprimere dine filer, hvilket reducerer deres størrelse betydeligt. Det har InnoDB også mulighed for - både MySQL og MariaDB understøtter InnoDB-komprimering. Den største fordel ved at bruge kompression er reduktionen af I/O-aktiviteten. Data, når de komprimeres, er mindre, så det er hurtigere at læse og skrive. Typisk InnoDB-side er 16KB i størrelse, for SSD er dette 4 I/O-operationer til at læse eller skrive (SSD bruger typisk 4KB-sider). Hvis vi formår at komprimere 16KB til 4KB, reducerede vi bare I/O-operationer med fire. Det hjælper ikke meget med hensyn til datasæt til hukommelsesforhold. Faktisk kan det endda gøre det værre - MySQL, for at kunne operere på dataene, er nødt til at dekomprimere siden. Alligevel læser den komprimeret side fra disk. Dette resulterer i, at InnoDB-bufferpuljen gemmer 4KB komprimerede data og 16KB ukomprimerede data. Selvfølgelig er der algoritmer på plads til at fjerne unødvendige data (ukomprimeret side vil blive fjernet, når det er muligt, og kun holde komprimeret én i hukommelsen), men du kan ikke forvente for meget af en forbedring på dette område.
Det er også vigtigt at huske på, hvordan komprimering fungerer i forhold til opbevaringen. Solid state-drev er normen for databaseservere i disse dage, og de har et par specifikke egenskaber. De er hurtige, de er ligeglade med, om trafikken er sekventiel eller tilfældig (selvom de stadig foretrækker sekventiel adgang frem for tilfældig). De er dyre for store mængder. De lider af "udslidte", da de kan klare et begrænset antal skrivecyklusser. Kompression hjælper betydeligt her - ved at reducere størrelsen af dataene på disken, reducerer vi omkostningerne til lagerlaget til database. Ved at reducere størrelsen af de data, vi skriver til disken, øger vi SSD'ens levetid.
Desværre, selvom komprimering hjælper, kan det stadig ikke være nok for større mængder data. Et andet skridt ville være at lede efter noget andet end InnoDB.
MyRocks
MyRocks er en lagermotor tilgængelig for MySQL og MariaDB, der er baseret på et andet koncept end InnoDB. Min kollega, Sebastian Insausti, har en fin blog om at bruge MyRocks med MariaDB. Essensen er, på grund af dets design (den bruger Log Structured Merge, LSM), MyRocks er væsentligt bedre med hensyn til komprimering end InnoDB (som er baseret på B+Tree-struktur). MyRocks er designet til at håndtere store mængder data og til at reducere antallet af skrivninger. Det stammer fra Facebook, hvor datamængderne er store og kravene til at få adgang til dataene er høje. Således SSD-lagring - stadig i så stor skala er hver gevinst i komprimering enorm. MyRocks kan levere endda op til 2x bedre komprimering end InnoDB (hvilket betyder, at du skærer antallet af servere ned med to). Det er også designet til at reducere skriveforstærkningen (antal skrivninger, der kræves for at håndtere en ændring af rækkeindholdet) - det kræver 10x færre skrivninger end InnoDB. Dette reducerer naturligvis I/O-belastningen, men endnu vigtigere, det vil øge levetiden for en SSD ti gange sammenlignet med at håndtere den samme belastning ved hjælp af InnoDB). Fra et præstationssynspunkt, mindre datavolumen, jo hurtigere er adgangen, og sådanne lagermotorer kan også hjælpe med at få dataene ud af databasen hurtigere (selvom det ikke var den højeste prioritet ved design af MyRocks).
Søjledatalagre
Relaterede ressourcer ClusterControl Performance Management Forstå virkningerne af høj latens i høj tilgængelighed MySQL og MariaDB Solutions MySQL Performance Cheat SheetPå et tidspunkt er alt, hvad vi kan gøre, at indrømme, at vi ikke kan håndtere en sådan mængde data ved hjælp af MySQL. Selvfølgelig kan du sønderdele det, du kan gøre forskellige ting, men til sidst giver det bare ikke mening længere. Det er tid til at lede efter yderligere løsninger. En af dem ville være at bruge søjleformede datastores - databaser, som er designet med big data analytics i tankerne. Sikker på, de hjælper ikke med OLTP-typen af trafikken, men analyser er stort set standard i dag, da virksomheder forsøger at være datadrevne og træffe beslutninger baseret på nøjagtige tal, ikke tilfældige data. Der er adskillige søjleformede datalagre, men vi vil gerne nævne to af dem her. MariaDB AX og ClickHouse. Vi har et par blogs, der forklarer, hvad MariaDB AX er, og hvordan kan MariaDB AX bruges. Hvad der er vigtigt, kan MariaDB AX skaleres op i en form af en klynge, hvilket forbedrer ydeevnen. ClickHouse er en anden mulighed for at køre analyser - ClickHouse kan nemt konfigureres til at replikere data fra MySQL, som vi diskuterede i et af vores blogindlæg. Det er hurtigt, det er gratis, og det kan også bruges til at danne en klynge og til at sønderdele data for endnu bedre ydeevne.
Konklusion
Vi håber, at dette blogindlæg gav dig indsigt i, hvor store mængder data der kan håndteres i MySQL eller MariaDB. Heldigvis er der et par muligheder til vores rådighed, og i sidste ende, hvis vi ikke rigtig kan få det til at fungere, er der gode alternativer.