В нашем проекте есть немного (~500GB) статических файлов, которые раздаются через nginx. Лежат они на одном физическом сервере и подключены по NFS к серверу, на котором запущен nginx. Скорость сети между серверами 1GBit/s. И вот мы задумались о том, чтобы как-то обезопасить проект от "потери" сервера, хранящего статические файлы. Сразу отметём вопросы выбора типа хранилища, просто примем тот факт, что мы выбрали GlusterFS, а вот почему и как, вы узнаете в статье.
У нас было только одно требование к GlusterFS - скорость должна быть не сильно ниже текущего NFS, ведь почти в каждой статье пишут, что как раз скорость у GlusterFS хромает.
Общие положения
Для тестирования скорости и "игр" с GlusterFS разворачивались виртуалки (CPU - 1, RAM - 1GB, Disk - 10GB) в облаке openstack у одного из провайдеров. Сеть между виртуалками 1GBit/s.
В качестве серверов GlusterFS используется Ubuntu 22.04 и ее пакеты glusterfs-server, nfs-ganesha-gluster из стандартного репозитория. Хоть мы и стараемся использовать на серверах RedHat base дистрибутивы (Centos, AlmaLinux), но как ни странно, нормально установить GlusterFS на AlmaLinux8 и AlmaLinux9 не вышло. Если будет интересно почему, то могу написать в комментариях.
Скорость измерялась с помощью скрипта. Да, тупо записывали на диск/nfs-папку/glusterfs-том 1GB блоками по 1MB. Потом сравнивали показатели. Ведь все познается в сравнении, не правда ли?
#!/usr/bin/env perl $s = 0; for ($i = 1; $i <= 3; $i++) { $rv = `sync; dd if=/dev/zero of=speed_test.img bs=1M count=1024 2>&1; sync`; $rv =~ /\s+(\d+)\.?\d?\s+MB\/s/; $s += $1; print $rv; } printf("speed = %0.0f\n", $s/3);
Самое замечательное в GlusterFS это то, что она очень гибкая в конфигурировании томов, которые могут плавно переходить от Distribute к Replicate и затем к Distributed‑Replicate. Да, кстати, читатель этой статьи должен знать термины GlusterFS, ну или желательно, чтобы знал, ну или не желательно, в общем, как хотите, но в статье будут встречаться термины GlusterFS без особых объяснений.
Скоростные испытания
srv1, srv2 — виртуалки в роли сервера, client — виртуалка в роли клиента, eth0 на srv1 замерялась через vnstat в момент теста скорости.
п/п | действия | скорость (MB/s) |
1 | На srv1 замеряем скорость локального диска. | 165 |
На srv1 запускаем обычный NFS сервер и расшариваем папку | ||
2 | На client монтируем расшаренную nfs-папку через eth0 на srv1 показывает | 109 |
На srv1 выключаем обычный NFS сервер, создаем GlusterFS том (далее glusterfs-том) gv0 из одного кирпичика на srv1. Тип glusterfs-тома получится Distribute. Затем расшариваем glusterfs-том gv0 через nfs-ganesha. | ||
далее тип glusterfs-тома Distribute | ||
3 | На srv1 монтируем gv0 том через eth0 на srv1 показывает | 170 |
4 | На client монтируем gv0 том через eth0 на srv1 показывает | 119 |
5 | На client монтируем gv0 том через eth0 на srv1 показывает | 111 |
К glusterfs-тому gv0 подключаем srv2 с фактором репликации 2, тип которого становится Replicate. | ||
далее тип glusterfs-тома Replicate | ||
6 | На srv1 монтируем gv0 том через eth0 на srv1 показывает | 119 |
7 | На client монтируем gv0 том через eth0 на srv1 показывает | 54 |
8 | На client монтируем gv0 том через eth0 на srv1 показывает | 84 |
Выводы по испытаниям
Удивляет то, что у glusterfs-тома с типом Distribute скорость записи по всем случаям монтирования чуток выше, чем у локального диска и обычного nfs соответсвенно. Замеры делались несколько раз и каждый раз наблюдалась такая картина. Казалось бы, должно быть наоборот. Главный вывод из этого такой: на одном сервере смело можно использовать glusterfs-том типа Distribute, не теряя в скорости. Только вот зачем, спросите вы. Ну хотя бы для того, чтобы изначально заложить вариант расширения хранилища.
Когда glusterfs-том трансформируется в тип Replicate, скорость начинает падать. Что вполне очевидно, т.к. файлы начинают зеркалироваться на двух серверах (как raid1 у mdadm). Падение происходит по разному у разных типов монтирования, что тоже вполне очевидно, если посмотреть на показатели загруженности eth0 на srv1.
При монтировании через
mount-t glusterfs
скорость упала до 54 (в два раза), при этом eth0 на srv1 загружен лишь на половину, т.к. вторая половина трафика ушла на srv2, т.е. client в момент записи пишет сразу на два сервера и eth0 у client при этом загружен на 100%.При монтировании через
mount-t nfs4
скорость упала до 84, при этом eth0 на srv1 загружен на 100%, но трафик уже идет в обоих направлениях. т.к. srv1, получая байты от client, вынужден отправлять их на srv2.Теоретически можно предположить, что если на client сделать две сетевухи и объединить (bonding) их в одну, то при монтировании через
mount-t glusterfs
скорость должна возрасти в два раза, т.е. до 108, что полностью соответствует обычному NFS.
Исходя из вышесказанного, мы решили поэтапно перенести наше хранилище статических файлов с одного сервера на другой с glusterfs-томом типа Distribute с последующим добавлением второго сервера и преобразованием glusterfs-тома в Replicate. Да, скорости в 84 для нашего типа нагрузки вполне хватает. Ну и поскольку в итоге планируется два сервера, то желательно разнести их по разным зонам доступности. Схема получилась вот такой.
+ --- nfs endpoint
/
+------/-------+
| / |
| +--------+ |
| | srv1 | |
| | 900G | | availability
| +--------+ | zone 1
| |
===|==============|==============
| |
| +--------+ | availability
| | srv2 | | zone 2
| | 900G | |
| +--------+ |
| |
| Replicated |
| volume 900G |
+--------------+
Для того чтобы можно было "потерять" один из серверов в такой схеме и продолжить нормально работать, нужно выполнить два условия: точка монтирования nfs должна быть только на одном из серверов; glusterfs-том нужно потюнить вот так:
gluster volume set gv0 network.ping-timeout 5
gluster volume set gv0 cluster.quorum-type fixed
gluster volume set gv0 cluster.quorum-count 1
Подводя общие итоги, хочется сказать
Скорость GlusterFS нифига не медленная, а очень сильно зависит от "толщины" сети и типа тома. Например, сама GlusterFS рекомендует использовать фактор репликации равный 3, но тогда скорость записи упадет не в два раза, а в три, т.к. клиент будет одновременно писать на три сервера вместо двух. И следовательно, чем выше нужна скорость, тем "толще" надо делать сеть. А вот как делать сеть "толще", надо думать - либо ставить 10GBit/s сетевухи, либо пытаться объединять сетевухи. Все очень сильно зависит от требований и финансовых возможностей проекта.
Схема из двух серверов и с монтированием glusterfs-тома по nfs вполне работоспособна. Скорость, конечно, падает по сравнению с обычным nfs, но не в два раза, как с монтированием по glusterfs. Это куда лучше, чем использовать rsync и прочее для возможности "потери" сервера.
Немного фантазий, проверенных на практике
Если нам перестанет хватать места, то можно легко добавить еще пару серверов srv3 и srv4 (добавлять нужно парами), и тогда тип glusterfs-тома станет Distributed-Replicate, а схема будет уже такой:
+-----------------------------------------+
| |
| +- vip for nfs -+ |
| / \ |
| / \ |
| +------/-------+ +-------\------+ |
| | / | | \ | |
| | +--------+ | | +--------+ | |
| | | srv1 | | | | srv3 | | |
| | | 900G | | | | 900G | | | availability
| | +--------+ | | +--------+ | | zone 1
| | | | | |
===|==|==============|=====|==============|==|==============
| | | | | |
| | +--------+ | | +--------+ | | availability
| | | srv2 | | | | srv4 | | | zone 2
| | | 900G | | | | 900G | | |
| | +--------+ | | +--------+ | |
| | | | | |
| | Replicated | | Replicated | |
| | volume 900G | | volume 900G | |
| +--------------+ +--------------+ |
| |
| Distributed volume 1800G |
+-----------------------------------------+
При такой схеме файлы будут распределяться по имени на разные пары серверов. Например, файл с именем speed_test_11.img попадет на сервера srv1 и srv2, а файл с именем speed_test_22.img попадет на сервера srv3 и srv4. Дальше представим, что client монтирует glusterfs-том через mount-t nfs4
, подлючаясь к srv1. В таком случае, если тест скорости будет делаться на файле speed_test_11.img, то скорость будет 84, ну а если на файле speed_test_22.img, то скорость будет 54 (как у монтирования через mount-t glusterfs
), т.к. в этом случае уже сам srv1 будет вынужден по сети отправлять файл на два сервера - на srv3 и srv4. Т.е. надо будет думать над тем, как и где увелиичить "толщину" сети.