Op woensdag 16 maart 2005 22:47 schreef Femme het volgende:Ik had ook nog even deze lijst met suggesties samengesteld (voordat ik las dat er nu op IRC gebabbeld wordt):
Ik weet niet wat jullie allemaal al geprobeerd hebben om de snelheid te verbeteren, maar hier zijn wat willekeurige suggesties:
- Als je de load op de database in de hand wilt houden, doe dat dan door het aantal connecties op de database server te limiteren en niet door maar gewoon doelbewust te weinig webservers in te zetten. Dat kan dmv max_connections in my.cnf.
- Naar mijn idee heeft het weinig nut om persistent MySQL connections in PHP te gebruiken. Door normale connecties te gebruiken blijft het geheugengebruik op de server iets lager omdat de MySQL minder threads tegelijkertijd zal draaien. Door de setting thread_cache in my.cnf redelijk hoog te houden (bijv. 12) zorg je ervoor dat MySQL altijd een ongebruikt threadje klaar heeft staan als er een connecties opgezet moet worden, zodat er geen nieuwe thread gemaakt hoeft te worden.
- Optimalisatie van de MySQL-instellingen is uiteraard erg belangrijk om MySQL optimaal te laten draaien. Op een doos met een 32-bits besturingssysteem en voldoende geheugen (3-4GB) moet je de buffers zodanig configureren dat MySQL dicht tegen de 2GB aan geheugen gaat gebruiken (maar niet meer, want dat kan niet onder een 32-bit OS). Met die EM64T Xeons kunnen jullie 64-bit Linux gaan draaien zodat er nog meer geheugen aan MySQL gegeven kan worden. De grootte van de buffers hangt o.a. af van de hoeveelheid MyISAM en InnoDB data in jullie database. GoT draait geheel op InnoDB tabellen en dus heeft onze forumdatabase-server een zeer grote InnoDB buffer pool. Op de andere dbserver van Tweakers.net heeft een meer gelijkwaardige mix van InnoDB en MyISAM tabellen en heeft daarom ongeveer gelijk geconfigureerde buffers voor beide. We kunnen jullie wel wat voorbeeldsettings sturen die in ieder geval goed zullen werken. Het is wel verstandig om wat ongebruikt geheugen te reserveren voor de disk cache. De InnoDB buffer pool cached ook data maar bij mijn weten heeft MySQL voor MyISAM-tabellen alleen een key buffer (daar worden indices in gecached).
- Ik gok dat jullie database-doos van Dell heeft een PERC4/DC SCSI RAID-adapter heeft. Dat is een gerebadge LSI MegaRAID SCSI 320-2 waar ik wel enige ervaringen mee heb. Zorg er in ieder geval voor dat de RAID arrays write-back caching gebruiken (bij voorkeur in combinatie met een battery backup unit, dat is dat witte ding rechtsonder op de RAID-kaart in
dit plaatje). Wellicht levert Dell standaard BBU's bij hun RAID-adapers. De instellingen 128K stripe size, direct I/O en normal read-ahead werken het best op LSI Logic RAID-controllers. Een RAID 1-array voor alleen het OS zal nauwelijks enige belasting krijgen, daar kunnen jullie wel wat MySQL logs op parkeren (error log, slow query log, InnoDB log files). Scheelt weer wat write I/O's op het RAID 5 data array.
- Zoals curry684 al heeft opgemerkt is het zeer verstandig om een load balancer te gaan gebruiken. Wellicht kan Kees jullie daarbij helpen. Een mooie redundant opstelling zit er voor jullie wellicht niet in, maar met één load balancer kunnen jullie al een veel betere verdeling van de load en een betere beschikbaarheid krijgen dan met houtje touwtje oplossingen zoals DNS round robin. Uiteraard moet jullie software wel geschikt zijn voor load balancing (dus bijv. geen sessies lokaal op de webservers opslaan maar dit in de database doen).
- Statische content kan het snelst geserveerd worden met Tux of een andere simpele webserver. Apache kan dan voorbehouden blijven voor het serveren van dynamische requests. Het kan helpen om hier een scheiding in aan te brengen, hoewel Apache het met vijf webservers op zich makkelijk moet kunnen trekken. Ik heb met het configureren van Apache niet zoveel ervaring dus daar kan ik verder weinig tips over geven.
- Ik weet niet waar jullie bottleneck zit, maar ik kan me voorstellen dat slecht geoptimaliseerde queries en een slecht geoptimaliseerde database structuur twee van de voornaamste problemen zijn. Het is tamelijk eenvoudig om met een veel voorkomende query een complete database-server onderuit te trekken als de query ranzig van aard is en de betrokken tabellen niet voor deze query zijn geoptimaliseerd.
- Om te achterhalen waar de problemen zitten, zouden jullie om te beginnen aan elke PHP-pagina een parsetime tellertje kunnen toevoegen. Je moet wel geweldig slechte of complexe code schrijven om alleen met PHP code hoge parsetijden (meer dan 200ms vind ik al erg hoog) te veroorzaken. De oorzaak zit 'm dan meestal in trage queries. Zoek uit welke pagina's traag zijn en achterhaal de schuldige query. De beste methode om een query sneller te maken is (simpel gezegd) om ervoor te zorgen dat op alle kolommen in de where clausule een index wordt gebruikt. Indices kunnen op verschillende manieren samengesteld worden. Zoek ergens een tutorial op waar dat goed wordt omschreven. Het herschrijven van een query, bijv. een andere manier van joinen van tabellen, kan ook helpen om de query sneller te maken.
- Bouw een scriptje waarmee je de efficiency van de key buffers kunt checken, zodat je kunt beoordelen of de server goed geconfigureerd is. Zie als voorbeelde de gegevens die wij
hier hebben. Zoals je ziet heeft Artemis een zeer hoge key cache hitrate. Op dit moment komt 99,9% van de gevraagde keys uit de buffers geserveerd worden. Mail me maar voor de code.
- Check de slow query log van MySQL (log-slow-queries moet vermeld zijn in my.cnf om sloq query logging ingeschakeld te hebben) en kijk wat daar allemaal voor smerigs wordt geregistreerd. Met de huidige traagheid hebben jullie waarschijnlijk een mega grote slow query log, dus begin bijv. bij een long_query_time setting van 10 seconden en verlaag die naar 5 of 3 seconden zodra de ergste rommel is opgeruimd.
- Check de MySQL processlist voor trage queries en probeer de trage queries sneller te maken. Het aantal draaiende processen zegt ook veel over de mate waarin de database en de database-queries geoptimaliseerd zijn. Op de dbserver van Tweakers.net is de processlist meestal leeg (afgezien van wat slapende processen en processen van een delayed insert), terwijl er toch gemiddeld 450 queries per seconde door die server worden verwerkt. Die queries zijn zo snel dat er zelden eentje draait net op het moment dat je de processlist opvraagt.
- Verplicht al jullie devvers om in de toekomst de snelheid van queries te checken voordat ze in productiecode verschijnen. Een simpele query hoort gewoon in 0,00s (< 0,5 ms, de timer in de MySQL client heeft geen hogere precisie) beantwoord te worden.
- INSERT DELAYED en UPDATE LOW PRIORITY gebruiken voor insert en update queries die geen prioriteit hebben en niet op user interactie moeten wachten. INSERT DELAYED werkt niet op InnoDB-tabellen!
- Gebruik de InnoDB storage engine voor tabellen die vaak worden gewijzigd. De standaard MyISAM storage engine van MySQL doet niet aan row-level locking maar lockt de hele tabel bij een wijziging, wat funest is voor de performance als er veel gelijktijdige queries op de betreffende tabel plaatsvinden. Denk aan tabellen waarin reacties, sessies, logs en statistieken worden opgeslagen. InnoDB is essentieel voor MySQL database-servers van forums die veel traffic genereren. Let er wel op dat sommige bestaande queries niet kunnen werken, bijv. queries die INSERT DELAYED gebruiken.
- Maak optimaal gebruik van query cache van MySQL door zoveel mogelijk 'recyclebare' queries te gebruiken. Als 1000 users "SELECT text FROM nieuws WHERE ID = 45000" doen dan kan het resultaat daarvan 999 keer uit de query cache gehaald worden. Als je where clausule erg variabel is (bijv. omdat de actuele timestamp erin gestopt is) zal de query steeds uniek zijn en kan het resultaat niet gecached worden. Het is niet altijd mogelijk om hier rekening mee te houden, maar het kan verstandig zijn om het in je achterhoofd te houden.