Etikettarkiv: innodb

Så fixar du en krashad MySQL-databas

Flertalet gånger så har jag stött på problem då mysqld vägrar starta på grund av olika orsaker. Den absolut vanligaste orsaken är att hårddisken blivit full. Den näst vanligaste orsaken är att AppArmor gör DENIED då datakatalogen ligger utanför standardkatalogen för MySQL.

Men, om du nu har felsökt och stöter på problem som ger felmeddelanden såsom:

130423 13:08:09 InnoDB: Database was not shut down normally!
InnoDB: Starting crash recovery.
InnoDB: Reading tablespace information from the .ibd files...
InnoDB: Restoring possible half-written data pages from the doublewrite
InnoDB: buffer...
InnoDB: Doing recovery: scanned up to log sequence number 709 555107725
InnoDB: 1 transaction(s) which must be rolled back or cleaned up
InnoDB: in total 1 row operations to undo
InnoDB: Trx id counter is 1 3738915328
130423 13:08:09 InnoDB: Starting an apply batch of log records to the database...
InnoDB: Progress in percents: 1 2 3 4 5 InnoDB: Probable data corruption on page 14686502
InnoDB: Original record (compact record)
InnoDB: on that page.
InnoDB: Cannot find the dir slot for record (compact record)
InnoDB: on that page!
130423 13:08:09 InnoDB: Page dump in ascii and hex (16384 bytes):
InnoDB: stored checksum 1683902533, prior-to-4.0.14-form stored checksum 3027438534
InnoDB: Page lsn 709 555059595, low 4 bytes of lsn at page end 555059595
InnoDB: Page number (if stored to page already) 14686502,
InnoDB: space id (if created with >= MySQL-4.1.1 and stored already) 0
InnoDB: Page may be an index page where index id is 0 375
130423 13:08:10 InnoDB: Assertion failure in thread 139759355893504 in file ../../../storage/innobase/page/page0page.c line 133
InnoDB: We intentionally generate a memory trap.
InnoDB: Submit a detailed bug report to http://bugs.mysql.com.
InnoDB: If you get repeated assertion failures or crashes, even
InnoDB: immediately after the mysqld startup, there may be
InnoDB: corruption in the InnoDB tablespace. Please refer to
InnoDB: http://dev.mysql.com/doc/refman/5.1/en/forcing-innodb-recovery.html
InnoDB: about forcing recovery.
11:08:10 UTC - mysqld got signal 6 ;
This could be because you hit a bug. It is also possible that this binary
or one of the libraries it was linked against is corrupt, improperly built,
or misconfigured. This error can also be caused by malfunctioning hardware.
We will try our best to scrape up some info that will hopefully help
diagnose the problem, but since we have already crashed,
something is definitely wrong and this may fail.

Då rekommenderar jag att du testar InnoDB recovery tool. Som återfinnes här:  InnoDB Recovery Tool. Obs du bör ha minst lika mycket hårddisk ledigt som storleken på din databas.

Så tolkar du MySQL:s felkoder

Rätt ofta så stöter jag problem med MySQL som då spottar ur sig någon typ av felkod. Dessa felkoder och hur de uppkommer brukar jag tyvärr hinna glömma bort mellan varven så därför skriver jag ner dem här för att underlätta för mig och dig:

Följande felmeddelande:

  • ERROR 3 (HY000) at line 11619: Error writing file ‘/tmp/STUkun6Z’ (Errcode: 28)

Avkodas lättast genom att man skriver perror 28 vid en kommandotolk i Linux så bör något liknande komma fram:

  • OS error code  28:  No space left on device
Vilket är tämligen självförklarande. Slut på hårddiskutrymme på den monteringspunkten.
Om du sedemera utför någon typ av import eller dylikt som kan ta sjukt lång tid så brukar jag använda två bra trick:
  • Visa hur lång tid som är kvar av importen med följande kommandorad: pv filnamn.sql | mysql -u root -p (pv är ett användbart litet program som kan installeras via apt-get install pv)
Output blir ungefär följande då:
  • 10,9GB 1:24:51 [ 1,1kB/s] [=====>             ] 19% ETA 5:59:32
Och det andra tricket är att undersöka vad som händer genom SHOW PROCESSLIST vilket med fördel kan köras på följande sätt:
  • echo ‘show processlist’|mysql -u root -plösenord -B
Nu till nästa felmeddelande:
  • ERROR 1071 (42000) at line 11673: Specified key was too long; max key length is 1000 bytes
Det tog ett tag innan jag insåg hur detta felmeddelande uppstod och det var pga att InnoDB-motorn i min MySQL installation ej startades pga felaktiga konfigurationsvariabler i my.cnf och då gick MySQL automatiskt över till MyISAM. Denna ”bugg” har funnits i många år och upprört en hel del (se sista kommentaren här). Kan vara rätt jobbigt om man gör mysqldump på ett system för att sedan läsa in dumpen på ett annat system och det ej fungerar.
Nästa problematik är inte direkt ett felmeddelande utan någon jag stött på då en import tog sjuk lång tid. Vid undersökning så stod det ”repair by sorting” vilket är något som kan ta många timmar. Efter lite googlande så hittade jag att en snabbare repair finns och då skall följande meddelande visas vid SHOW PROCESSLIST: repair using keycache. Fixas genom att sätta myisam_max_sort_file_size=10G i my.cnf.
Om du använder dig av mysqlimport eller LOAD DATA INFILE och får något av följande felmeddelanden:
  • Error: 13, Can’t get stat of ‘/var/lib/mysql/Desktop/abc123′ (Errcode: 2)
  • File ‘/home/standage/Desktop/abc213′ not found (Errcode: 13)

Så beror det troligtvis på att du ej har behörighet eller att du ej angett hela sökvägen till filen. Brukar jag lösa genom att genomföra importen med ett mysql-root konto.

Uppdatering: Något annat som kan ställa till fel hos MySQL är nya AppArmor som standard används i senare versioner av Ubuntu. Om du ändrar exempelvis datadir så kommer det ej att fungera. Då måste du ändra i apparmor-profilen för MySQL.

Serverstrul

Denna vecka så har mer eller mindre alla mina servrar strulat. Jag fick för mig att uppgradera Redis till en lite nyare version som har buggfixar samt äter mindre CPU och passade samtidigt på att uppgardera det PHP bibliotek jag använder för att prata med Redis till owlient/phpredis. Så klart så gick något fel och cachningen i Redis ballade ut och servern dog sakta men säkert pga alla SQL-frågor som ej cachades.

Nästa problem dyker upp på Bloggy då flertalet InnoDB-databasfiler försvinner vid en hastig omstart av servern och MySQL vägrar starta så jag får manuellt använda strace till att lista ut vilken databas som strular och bygga om flertalet tabeller. Då passar jag även på att uppgradera Varnish till senaste versionen och lägger in lite kod för att ej cacha WordPress-adminsidor vilket får till följd att inloggningen på Bloggy misslyckas för alla användare.

Samt så har även den server som sköter bloggsökmotorn Bloggz strulat.. vilket lärdom kan man dra av detta då? Jo, att om du uppgraderar eller ändrar minsta lilla så testa att det verkligen fungerar, lägg till exemeplevis dold HTML-kod som berättar om sidans element verkligen cachas eller ej.

Bildkälla: http://retecool.com/post/computable-awards--fail/1/

Optimera din MySQL databas

Jag har suttit många månader och felsökt varför vissa saker går långsamt i MySQL när jag utvecklat bloggsökmotorn och i detta blogginlägg försöker jag sammanfatta de erfarenheter jag lärt mig på vägen:

  1. InnoDB är många gånger att föredra framför MyISAM. Jag fick jättemycket problem med låsningar då jag skriver och läser mycket till stora tabeller. MyISAM är generellt snabbare på INSERT’s
  2. Undvik typkonverteringar. I python exempelvis så görs detta automatiskt ibland och då kan det leda till att MySQL måste göra typkonverteringar vid varje jämförelse.
    • - ”Avoid overuse of MySQL’s automatic type conversion. MySQL will perform automatic type conversion, but if you can avoid conversions, you may get better performance” (från boken MySQL: The definitive guide to using, programming, and administering MySQL 4.1 and 5.0, Third Edition)
  3. Använd EXPLAIN före SELECT manuellt för att se var flaskhalsar kan sitta.
  4. Försök att undvika FULLTEXT indextyper, en vacker dag så sitter du där med tonvis med information och sökningarna tar flera sekunder. Snegla istället på Sphinx.
  5. Tråda så mycket som möjligt. Men var inte dum
  6. Slå på log_slow_queries i my.cnf och kolla loggen vilka frågor som går långsamt och försök optimera dessa.
  7. Bryt ner SQL-frågorna och utred vilket värde som tar lång tid att få fram.
  8. Kör SHOW FULL PROCESSLIST ibland och titta på ”Time” fältet där du ser hur lång tid frågor tar.
  9. Undvik ORDER BY RAND() då dessa frågor kopieras till en temporär tabell vilket tar tid.
  10. Ha full koll på dina INDEX så att de används på ett optimalt sätt. Inte för många och inte för få.
  11. Försök att tweaka my.cnf så att den stämmer överens med just din hårdvara gällande RAM-minne osv. Exempelvis så kan innodb_buffer_pool_size vara upp till 80% av minnesstorleken.
  12. Använd LIMIT där det är möjligt.
  13. Testa att lägg databasen på en separat hårddisk (datadir). Är standard /var/mysql på de flesta OS.
  14. Kör OPTIMIZE TABLE en gång i veckan eller en gång per månad.
  15. Ställ dig frågan att det kanske inte är databasen det är fel på utan kanske hur DU använder den.
  16. Läs mysqlperformanceblog.com samt Google är din vän.

Såja, hoppas det var allt. Fyller på om det är något som jag glömt.