MySQL Performance unter ZFS auf FreeBSD
FreeBSD hat sich zwischenzeitlich auch in einer reinen ZFS Installation im Produktiveinsatz bewährt. Zahlreiche Funktionen wie ZFS-Snapshots, zfs send/zfs receive u.v.a. erleichtern dem Administrator das tägliche Leben mit FreeBSD.
Zuletzt haben sich aber erhebliche Performanceprobleme in Kombination FreeBSD, ZFS und MySQL ergeben. Grundsätzlich haben wir mit gewissen Abstrichen gerechnet und diese erwartet, aber der Import einer ~6 MB MySQL Dump Datei (1 INSERT-Statement je Row) in 4 Minuten 42 Sekunden mit MySQL 5.5 unter FreeBSD ZFS anstatt in 4 Sekunden unter FreeBSD mit UFS2 waren uns dann doch zuviel.
Also Zeit sich einmal mit dem Thema ZFS Tuning auseinanderzusetzen. Wir wollen hier die wichtigsten ZFS Tuning Parameter zum Thema MySQL unter FreeBSD mit ZFS zusammenfassen:
/boot/loader.conf:
vfs.zfs.cache_flush_disable=1
vfs.zfs.txg.timeout=5
Der Parameter vfs.zfs.cache_flush_disable stellte sich als der wesentliche in Zusammenhang mit unserem größten Problem dar. MySQL führt bei jeder Transaktion ein Flush auf seine Datenbankdateien durch, dies führt unter ZFS dazu, dass ein Flush tatsächlich die Daten auf die Festplatte schreibt. Das bringt uns zwar erhebliche Datensicherheit, aber auch extreme Performanceverluste im Vergleich zu UFS, welches sich bei einem Flush anders verhält. Um ZFS hier überhaupt „konkurrenzfähig“ zu machen und nicht Äpfel mit Rosinen zu vergleichen, muss man den ZFS-Cache-Flush deaktivieren.
/etc/sysctl.conf:
vfs.zfs.prefetch_disable=1
kern.maxvnodes=250000
Der Parameter kern.maxvnodes muss an die eigenen Anforderungen angepasst werden. Die Zahl der aktuell benötigten VNodes kann mit sysctl vfs.numvnodes ermittelt werden. Wenn vfs.numvnodes sich in die Nähe von kern.maxvnodes bewegt, sinkt die Performance.
Beim Erstellen der Filesystem für MySQL zu beachten:
# Filesystem für MyISAM Datenbanken, Blocksize auf 8k, in unserem Fall /var/db/mysql
zfs create -o mountpoint=/var/db/mysql tank/mysql
zfs set recordsize=8k# Filesystem für InnoDB Logs, Default Blocksize
zfs create -o mountpoint=/var/db/mysql/iblog tank/iblog# Filesystem für InnoDB Tablespace, Blocksize auf 16k
zfs create -o mountpoint=/var/db/mysql/ibdata tank/ibdata
zfs set primarycache=metadata tank/ibdata
zfs set recordsize=16k
Die Änderung der Blocksize/Recordsize muss vor dem Erzeugen der Datenbankdateien erfolgen!
Anpassungen my.cnf:
innodb_data_home_dir = /var/db/mysql/ibdata
innodb_log_group_home_dir = /var/db/mysql/iblog
innodb_flush_method = O_DIRECT
skip-innodb_doublewrite
Vom Tuning des ARC wurde Abstand genommen und war in unserem Fall nicht erforderlich. Eventuell wird künftig eine SSD für den L2ARC eingesetzt.
Diese Konfiguration ist eine Zusammenfassung aus folgenden Quellen:
http://wiki.freebsd.org/ZFSTuningGuide
http://blogs.oracle.com/realneel/entry/mysql_innodb_zfs_best_practices
http://www.solarisinternals.com/wiki/index.php/ZFS_for_Databases
http://www.solarisinternals.com/wiki/index.php/ZFS_Evil_Tuning_Guide
http://assets.en.oreilly.com/1/event/21/Optimizing%20MySQL%20Performance%20with%20ZFS%20Presentation.pdf