Краеугольным камнем современной вычислительной техники являются системы хранения данных - диски не поспевают за производительностью памяти, память - за процессорами. В OLTP, там где она особенно важна, инженеры вынуждены строить систему максимально оптимизированно работающую с данными, иначе простоев процессора и проблем с общей производительностью не избежать. Посмотрим, как выявить проблемы и продиагностировать их.
СХД условно делится на два слоя: дисковая подсистема и менеджер томов (если это SVM + UFS) и файловая система (включая менеджер томов, если это ZFS), и приложение его использующее. Измерить нагрузку на первый уровень довольно-таки тривиально, достаточно выполнить команду iostat в eXtended-режиме
# iostat -xtc dad1 5 5
<...>
extended device statistics tty cpu
device r/s w/s kr/s kw/s wait actv svc_t %w %b tin tout us sy wt id
dad1 24.0 279.9 956.8 29713.5 57.0 1.9 193.9 95 97 0 50 2 46 0 53
где dad1 - имя устройства (чуть подробнее об этом - в предыдущей записи в блоге), а числа - стандартные для stat-утилит интервал и количество замеров.
Как видим, в системе большое количество запросов на запись (w/s - 280 запросов, и как следствие большое время их обработки - svc_t - 180 миллисекунд). Что же делать, если проблема связана с интенсивным доступом к какому-то из файлов. Понятное дело, что это приведет к блокировкам доступа. Определить, же, какой файл является проблемным мне помогла статья
Scaling Olio Web Tier
Я написал простенький тест:
#!/bin/bash
while :
do
dd if=/meta/meta-1 of=/meta/meta-2 bs=16384 &
sleep 1
done
После этого нужно посмотреть текущие блокировки ядра с помощью lockstat:
root@blade # lockstat sleep 1
Adaptive mutex spin: 48 events in 2.273 seconds (21 events/sec)
Count indv cuml rcnt nsec Lock Caller
-------------------------------------------------------------------------------
43 90% 90% 0.00 10854 0x30000097d70 dcdintr+0x38
5 10% 100% 0.00 10150 vph_mutex+0x4630 pvn_write_done+0x120
-------------------------------------------------------------------------------
Adaptive mutex block: 48 events in 2.273 seconds (21 events/sec)
Count indv cuml rcnt nsec Lock Caller
-------------------------------------------------------------------------------
43 90% 90% 0.00 22565 0x30000097d70 dcdintr+0x38
5 10% 100% 0.00 13049 vph_mutex+0x4630 pvn_write_done+0x120
-------------------------------------------------------------------------------
R/W writer blocked by writer: 4812 events in 2.273 seconds (2117 events/sec)
Count indv cuml rcnt nsec Lock Caller
-------------------------------------------------------------------------------
4812 100% 100% 0.00 19198477 0x300040d7c48 ufs_rwlock+0x78
-------------------------------------------------------------------------------
Как видим значительная задержка наблюдается на блокировке ufs_rwlock. Выясним связанный с ней файл используя mdb.
Выберем адрес блокировки, и убедимся, что запись находится в inode кэше:
> 0x300040d7c48::whatis
300040d7c48 is 300040d7b70+d8, allocated from ufs_inode_cache
Проверим смещение поля блокировки в структуре inode:
> ::offsetof inode_t i_rwlock
offsetof (inode_t, i_rwlock) = 0xd8
Вычтем смещение и узнаем текущую vnode и связанный с ней путь:
> 0x300040d7c48-0xd8::print inode_t i_vnode
i_vnode = 0x300040db300
> 0x300040db300::vnode2path
/meta/meta-2
Как говорится, что и требовалось доказать. Очевидно, теперь нужно оптимизировать приложение на более корректный доступ к данному файлу.