RAID1 vs RAID0 en replicación MySQL

3 abril 2013 at 21:06 by Adrián Pérez

MySQL RAIDHoy vamos a intentar mejorar la replicación de un slave MySQL, cuyo master recibe demasiadas modificaciones como para que el slave sea capaz de seguirle el ritmo. El problema que tienen los slaves, es que con versiones anteriores a MySQL 5.6, la replicación usa un único thread, y por tanto, las sentencias a replicar se ejecutan de forma secuencial. En realidad, si usamos una única base de datos, con MySQL 5.6 y su replicación con múltiples threads, no ganamos nada, puesto que MySQL 5.6 aporta un thread por base de datos.

El testeo se ha realizado con servidores CentOS 6.3 a 64 bits, con dos discos SATA 7200rpm.

Identificando el problema

En cualquier caso, el primer paso es identificar el problema, lo cual de forma natural haríamos con un "top". A continuación veremos como el único proceso del server consumiendo algo de recursos es el proceso mysqld, que a pesar de eso, no llega ni mucho menos a provocar un problema de CPU ni de RAM. Sin embargo, si que vemos un 9.6% de %iowait lo cual indica que podríamos tener ahí el cuello de botella.

[root@slave]$ top
top - 12:28:38 up 23:10,  1 user,  load average: 2.76, 2.72, 2.69
Tasks: 211 total,   3 running, 208 sleeping,   0 stopped,   0 zombie
Cpu(s):  2.7%us,  1.6%sy,  0.0%ni, 85.8%id,  9.6%wa,  0.0%hi,  0.2%si,  0.0%st
Mem:  32776052k total, 32519856k used,   256196k free,   156192k buffers
Swap: 16777136k total,   122344k used, 16654792k free,  9163420k cached

PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
4450 mysql     20   0 29.0g  21g 4628 S 37.7 68.0 394:26.55 mysqld 
584 root      20   0     0    0    0 S  6.0  0.0  70:17.46 md4_raid1

Con "iostat" podemos ver el %iowait en intervalos de por ejemplo, 5 segundos. Así si tenemos un %iowait que nunca baja a valores cercanos a cero, tenemos un cuello de botella ocasionado por las operaciones de entrada salida.

[root@slave]$ iostat -t 5
27/03/13 12:30:45
avg-cpu:  %user   %nice %system %iowait  %steal   %idle
2,70    0,00    1,87    9,63    0,00   85,80
27/03/13 12:30:50
avg-cpu:  %user   %nice %system %iowait  %steal   %idle
3,45    0,00    1,77    9,28    0,00   85,50
27/03/13 12:30:55
avg-cpu:  %user   %nice %system %iowait  %steal   %idle
3,43    0,00    1,92    9,39    0,00   85,26

Con "iotop" podemos confirmar como el mysqld es el causante de la mayoría de operaciones de i/o:

[root@slave]$ iotop
Total DISK READ: 0.00 B/s | Total DISK WRITE: 12.24 M/s
TID  PRIO  USER     DISK READ  DISK WRITE  SWAPIN     IO>    COMMAND
4497 be/4 mysql       0.00 B/s    3.97 M/s  0.00 % 59.72 % mysqld --basedir=/usr --datadir=/data/mysql/ --plugin-dir=/usr/lib64~535 --pid-file=/data/mysql/mysql.pid --socket=/data/mysql/mysql.sock
1149 be/3 root        0.00 B/s    3.96 K/s  0.00 % 57.87 % [jbd2/md4-8]
4498 be/4 mysql       0.00 B/s 1389.55 K/s  0.00 % 32.11 % mysqld --basedir=/usr --datadir=/data/mysql/ --plugin-dir=/usr/lib64~535 --pid-file=/data/mysql/mysql.pid --socket=/data/mysql/mysql.sock
1140 be/3 root        0.00 B/s    3.96 K/s  0.00 % 21.02 % [jbd2/md3-8]
4475 be/4 mysql       0.00 B/s   63.34 K/s  0.00 %  0.12 % mysqld --basedir=/usr --datadir=/data/mysql/ --plugin-dir=/usr/lib64~535 --pid-file=/data/mysql/mysql.pid --socket=/data/mysql/mysql.sock
4463 be/4 mysql       0.00 B/s    0.00 B/s  0.00 %  0.02 % mysqld --basedir=/usr --datadir=/data/mysql/ --plugin-dir=/usr/lib64~535 --pid-file=/data/mysql/mysql.pid --socket=/data/mysql/mysql.sock

Mejora de la i/o

Si ya hemos realizado las optimizaciones necesarias al my.cnf, y al disco duro, y no podemos adquirir discos de mayor rendimiento, como serían los discos SAS a 15Krpm o discos SSD, podríamos pensar en usar un RAID0, idealmente por hardware. Para este testeo, he modificado el RAID1 software del server, para usar un RAID0 software, con los mismos discos duros, dos SATA 7200rpm.

Volúmenes de replicación altos en ambos servidores

Por ejemplo, a continuación hay un ejemplo de la i/o de dos servers idénticos, uno con RAID1 software y otro con RAID0 software, ambos replicando del mismo master, justo al acabar de montar ambos servers (es decir, justo en un momento de replicación alta, pues ambos servidores han de sincronizarse con el master).

RAID1 software, ejecutado sobre la partición que tiene el dbpath del MySQL, cada 5 segundos:

[root@slave]$ iostat -xtc 5 -p md4
Device:         rrqm/s   wrqm/s     r/s     w/s   rsec/s   wsec/s avgrq-sz avgqu-sz   await  svctm  %util
md4               0,00     0,00   24,18 2245,79  3114,59 19555,23     9,99     0,00    0,00   0,00   0,00
md4               0,00     0,00    0,00 1317,60     0,00 10627,20     8,07     0,00    0,00   0,00   0,00
md4               0,00     0,00    0,80 3491,60    16,00 30590,40     8,76     0,00    0,00   0,00   0,00
md4               0,00     0,00    0,00 3973,80     0,00 32028,80     8,06     0,00    0,00   0,00   0,00
md4               0,00     0,00    0,00 3959,20     0,00 32056,00     8,10     0,00    0,00   0,00   0,00
md4               0,00     0,00    0,20 4326,20     6,40 34803,20     8,05     0,00    0,00   0,00   0,00

RAID0 software, ejecutado sobre la partición que tiene el dbpath del MySQL, cada 5 segundos:

[root@slave]$ iostat -xtc 5 -p md4
Device:         rrqm/s   wrqm/s     r/s     w/s   rsec/s   wsec/s avgrq-sz avgqu-sz   await  svctm  %util
md4               0,00     0,00   10,59 3839,54   258,55 30813,68     8,07     0,00    0,00   0,00   0,00
md4               0,00     0,00    8,20 4923,80   180,80 39612,80     8,07     0,00    0,00   0,00   0,00
md4               0,00     0,00    7,80 5363,00   134,40 42904,00     8,01     0,00    0,00   0,00   0,00
md4               0,00     0,00   12,40 5409,60   281,60 43510,40     8,08     0,00    0,00   0,00   0,00
md4               0,00     0,00   11,80 5398,60   195,20 43188,80     8,02     0,00    0,00   0,00   0,00
md4               0,00     0,00   14,80 5345,20   296,00 42984,00     8,07     0,00    0,00   0,00   0,00
md4               0,00     0,00   14,20 5918,60   272,00 47348,80     8,03     0,00    0,00   0,00   0,00

A primera vista, vemos como el número de escrituras por segundo en RAID1 está en torno a los 3900 - 4300 w/s, mientras que en RAID0 sube a los 5300 - 5900 w/s.

Servidor con RAID0 atrapa al master

Con el tiempo, el servidor con RAID0 ha llegado a atrapar al master (gracias a su mejor ratio de escrituras por segundo), mientras que el servidor con RAID1, debido al elevado volumen de sentencias a replicar, no es capaz de atrapar al master. Ésto se ve cláramente mirando el iowait de ambos servidores, una vez el servidor con RAID0 ya ha atrapado al master:

RAID1 software, ejecutado sobre la partición que tiene el dbpath del MySQL, cada 5 segundos:

[root@slave]$ iostat -xtc 5 -p md4
avg-cpu: %user %nice %system %iowait %steal %idle
3,91 0,00 1,97 9,81 0,00 84,31
Device: rrqm/s wrqm/s r/s w/s rsec/s wsec/s avgrq-sz avgqu-sz await svctm %util
md4 0,00 0,00 5,40 3929,60 172,80 31668,80 8,09 0,00 0,00 0,00 0,00

avg-cpu: %user %nice %system %iowait %steal %idle
4,39 0,00 2,12 9,57 0,00 83,92
Device: rrqm/s wrqm/s r/s w/s rsec/s wsec/s avgrq-sz avgqu-sz await svctm %util
md4 0,00 0,00 0,20 4327,00 6,40 34635,20 8,01 0,00 0,00 0,00 0,00

avg-cpu: %user %nice %system %iowait %steal %idle
3,91 0,00 2,04 10,14 0,00 83,91
Device: rrqm/s wrqm/s r/s w/s rsec/s wsec/s avgrq-sz avgqu-sz await svctm %util
md4 0,00 0,00 2,60 3863,80 83,20 33371,20 8,65 0,00 0,00 0,00 0,00

avg-cpu: %user %nice %system %iowait %steal %idle
3,55 0,00 1,64 10,13 0,00 84,68
Device: rrqm/s wrqm/s r/s w/s rsec/s wsec/s avgrq-sz avgqu-sz await svctm %util
md4 0,00 0,00 0,20 3455,00 6,40 27668,80 8,01 0,00 0,00 0,00 0,00

avg-cpu: %user %nice %system %iowait %steal %idle
3,43 0,00 1,71 10,28 0,00 84,58
Device: rrqm/s wrqm/s r/s w/s rsec/s wsec/s avgrq-sz avgqu-sz await svctm %util
md4 0,00 0,00 2,60 3545,20 83,20 30844,80 8,72 0,00 0,00 0,00 0,00

RAID0 software, ejecutado sobre la partición que tiene el dbpath del MySQL, cada 5 segundos:

[root@slave]$ iostat -xtc 5 -p md4
avg-cpu: %user %nice %system %iowait %steal %idle
0,55 0,00 0,50 2,03 0,00 96,92
Device: rrqm/s wrqm/s r/s w/s rsec/s wsec/s avgrq-sz avgqu-sz await svctm %util
md4 0,00 0,00 3,20 1399,80 102,40 12006,40 8,63 0,00 0,00 0,00 0,00

avg-cpu: %user %nice %system %iowait %steal %idle
3,36 0,00 0,60 3,23 0,00 92,80
Device: rrqm/s wrqm/s r/s w/s rsec/s wsec/s avgrq-sz avgqu-sz await svctm %util
md4 0,00 0,00 0,80 2072,20 25,60 17073,60 8,25 0,00 0,00 0,00 0,00

avg-cpu: %user %nice %system %iowait %steal %idle
0,33 0,00 0,35 1,40 0,00 97,92
Device: rrqm/s wrqm/s r/s w/s rsec/s wsec/s avgrq-sz avgqu-sz await svctm %util
md4 0,00 0,00 2,80 935,20 84,80 8088,00 8,71 0,00 0,00 0,00 0,00

avg-cpu: %user %nice %system %iowait %steal %idle
0,35 0,00 0,38 1,78 0,00 97,50
Device: rrqm/s wrqm/s r/s w/s rsec/s wsec/s avgrq-sz avgqu-sz await svctm %util
md4 0,00 0,00 1,60 1147,00 51,20 9683,20 8,48 0,00 0,00 0,00 0,00

avg-cpu: %user %nice %system %iowait %steal %idle
0,30 0,00 0,35 1,68 0,00 97,67
Device: rrqm/s wrqm/s r/s w/s rsec/s wsec/s avgrq-sz avgqu-sz await svctm %util
md4 0,00 0,00 3,80 1065,40 121,60 9118,40 8,64 0,00 0,00 0,00 0,00

En esta ocación, vemos como el iowait del servidor con RAID0 es mucho mejor que el del RAID1, puesto que el RAID1 tiene el cuello de botella en la i/o, que no es suficiente como para llegar a atrapar al master. El servidor con RAID0, sin embargo, al haber atrapado al master, ya únicamente replica en en vivo los cambios que le suceden al master, y por tanto, no tiene una gran cola de sentencias a replicar, si no que replica directamente los cambios en tiempo real. Esta es la razón de que el número de w/s sea menor, y de que por tanto el iowait también haya disminuido.

Así pues, parece que en este ejemplo, como era de esperar, el RAID0 ayuda a mejorar la i/o, y ésto, en entornos de replicación MySQL con una muy elevada carga de cambios, puede ser una solución al elevado delay de los slaves.

Flickr!Foto por Disco-Dan