Network Attached Storage
Для обеспечения отказоустойчивости мы развертываем CI/CD в Highly Available кластере Kubernetes. Приложения CI/CD стека хранят свои данные в сетевых NAS, расположенных в нескольких дата центрах. NAS реплицируют данные между собой в реальном времени с помощью DRBD9. Ниже мы выполним тесты производительности подобной системы хранения данных и выясним, насколько она подходит для CI/CD
1. Введение
Мы написали отдельную статью в нашем блоге на Хабр о том, как создаем реплицируемый NAS для Highly Available кластера Kubernetes и сняли видеопрезентацию о работе этой системы хранения данных в контексте отказоустойчивого CI/CD. Чтобы не перегружать данную статью мы не будем тут останавливаться на реализации и сосредоточимся на тестах производительности
2. Схема стенда
Смема стенда для испытаний производительности системы хранения данных выглядит так:
На схеме Highly Available кластер Kubernetes развернут в трех дата центрах. В дата центре N2 на Worker-ноде Kubernetes запущен GitLab. Модуль GitLab подключен по NFS к NAS, на котором хранит свои данные. Данные GitLab реплицируются в реальном времени с помощью DRBD9 на аналогичный NAS в датацентре N1. DRBD9 для репликации использует "protocol C" - самый надежный режим, при котором операция записи считается завершенной, когда данные записаны на SSD в датацентре N2, переданы по сети между дата центрами и записаны на SSD в дата центре N1
Worker-нода Kubernetes подключается к NAS, расположенному на том же хосте Proxmox и iperf показал 20Gbps между ними:
user@dc2-worker1:~$ iperf -c dc2-nas
------------------------------------------------------------
Client connecting to dc2-nas, TCP port 5001
TCP window size: 16.0 KByte (default)
------------------------------------------------------------
[ 1] local 89.104.65.66 port 53130 connected with 89.104.65.68 port 5001 (icwnd/mss/irtt=11/1228/322)
[ ID] Interval Transfer Bandwidth
[ 1] 0.0000-10.0043 sec 24.5 GBytes 21.0 Gbits/sec
Мы построили оба NAS на базе SSD Samsung 870 EVO скорость линейной записи на которые составила 350MB/s
user@dc2:~$ dd if=/dev/random of=/tmp/1000.bin bs=4K count=256000
256000+0 records in
256000+0 records out
1048576000 bytes (1.0 GB, 1000 MiB) copied, 2.99359 s, 350 MB/s
Как правило, узким местом для подобных систем является канал между дата центрами. Именно он и лимитирует производительность реплицируемых систем хранения данных
3. Скорость линейной записи на раздел DRBD9
Выясним зависимость скорости записи на раздел DRBD9 от пропускной способности канала, для репликации DRBD9 между дата центрами. Для этого, мы будем искусственно ограничивать пропускную способность канала между дата центрами до 1000Mbps, 800Mbps, 600Mbps, 400Mbps, 200Mbps и 100Mbps. И для каждого ограничения записывать файл размером 5Gb на Primary раздел DRBD9 с помощью команды dd:
root@dc2-nas:/home/user# dd if=/dev/random of=/mnt/disk1/5Gb.bin bs=4k count=1280000
График загрузки сети и скорости записи на раздел DRBD9 для NAS, на котором производилась запись:
График загрузки сети и скорости записи на раздел DRBD9 для NAS, на который реплицировались данные:
Результаты замеров сведем в таблицу:
| Лимит | Скорость dd | Репликация | % |
|---|---|---|---|
| 1000Mb/s | 80.7 MB/s | 575 Mb/s (71.9 MB/s) | 112 |
| 800 Mb/s | 73.2 MB/s | 479 Mb/s (59.9 MB/s) | 121 |
| 600 Mb/s | 55.4 MB/s | 390 Mb/s (48.9 MB/s) | 113 |
| 400 Mb/s | 45.4 MB/s | 327 Mb/s (40.9 MB/s) | 110 |
| 200 Mb/s | 28.1 MB/s | 195 Mb/s (24.4 MB/s) | 115 |
| 100 Mb/s | 13.2 MB/s | 96 Mbp/s (12.0 MB/s) | 110 |
Первый столбец - лимит пропускной способности канала между дата центрами. Второй столбец - скорость записи на раздел DRBD9, которую выдала команда dd. Третий столбец - фактическая скорость репликации данных DRBD9 между дата центрами. В четвертом столбце мы подсчитали сколько процентов составила скорость записи на раздел DRBD9 от скорости репликации
Вывод: скорость записи на раздел DRBD9 составляет 110% от скорости репликации DRBD9 между дата центрами
4. Характеристика нагрузки CI/CD стека на систему хранения данных
Приложения оптимизированного CI/CD стека не записывают файлы большого размера на диск. Основная нагрузка на систему хранения данных - это запись Docker-образов и кэша сборки Doсker-образов в приватный реестр. Если используются базовые Docker-образы минимального размера, multi-stage сборка и кэш сборки Docker-образов, то все сводится к записи на диск слоев (blob) Docker-образов небольшого размера
Для понимания, о каких размерах идет речь, мы выполнили в GitLab сборку Docker-образа фронтенда на Next.js. В качестве базового Docker-образа мы использовали node:24.6.0-alpine3.22 размером 55.77 MB. После сборки Docker-образа, в реестр Docker-образов были записаны несколько файлов, самые крупные из которых имели размер 21 и 24 MB:
21M /mnt/disk1/registry/docker/registry/v2/blobs/sha256/e2/e22c7dc265fd103f2f4a8e4fbe5d8e0cdb06693016d8b977dfdb265b44b094f8/data
24M /mnt/disk1/registry/docker/registry/v2/blobs/sha256/3f/3f8192d39534b1b0516a03c774cdee4ac2cfe3f9497621cc759562a479395783/data
В логе пайплайна видим, что это GitLab записал кэш сборки Docker-образа в приватный реестр:
#29 exporting cache to registry
#29 preparing build cache for export
#29 writing layer sha256:06ef6551fb661c0ad18fdd3475ee9a644262a1ba0189049dc3e7d494dfe8fd0d
#29 writing layer sha256:06ef6551fb661c0ad18fdd3475ee9a644262a1ba0189049dc3e7d494dfe8fd0d done
#29 writing layer sha256:0e254d606f0dc0dcf912b05bb4e73a4f70d5a75cd3d70772185f39b5cffb784e done
#29 writing layer sha256:30e0b7c1f7c14d53aff64626e25cf297a0189301ce5be2d9a2099e53280ea5ac
#29 writing layer sha256:30e0b7c1f7c14d53aff64626e25cf297a0189301ce5be2d9a2099e53280ea5ac 0.7s done
#29 writing layer sha256:3126b83620d1a5019251eebd5dd51b9429c4b08898ccb458203215a8ea0c634a
#29 writing layer sha256:3126b83620d1a5019251eebd5dd51b9429c4b08898ccb458203215a8ea0c634a done
#29 writing layer sha256:3896391fbd35576c1f2184143f0caa9ff88181b6cb28ff50f33d960b9865e824 done
#29 writing layer sha256:39bfcbc6896ba4dc7d105dcdc3bdf82e9b086dfdbbe49c77efc1734a0d797eae done
#29 writing layer sha256:3f8192d39534b1b0516a03c774cdee4ac2cfe3f9497621cc759562a479395783
#29 writing layer sha256:3f8192d39534b1b0516a03c774cdee4ac2cfe3f9497621cc759562a479395783 3.0s done
#29 writing layer sha256:43ca6a3a4a3868c9672d59d7d405696a9982afc4b9d49f9eaf63357c5f4b9ed4
#29 writing layer sha256:43ca6a3a4a3868c9672d59d7d405696a9982afc4b9d49f9eaf63357c5f4b9ed4 done
#29 writing layer sha256:5d47ac81c6378d7341b5423020651acfd2fed577ddad89f23bf6f7bd75b55f9b done
#29 writing layer sha256:625a2805a9e151702ac48f9290a81ccf89bac25ca844ee0198aca14ae2772608 done
#29 writing layer sha256:781a4d74d3eba0fee674ca2dd9c3ee4c0b656729749edd668decb0b37b3eb4c7 done
#29 writing layer sha256:7d00bc2f654f664ff8ef853eb4e4f0cc6256afff1d4fd8bbf64b8d146b37268a done
#29 writing layer sha256:9824c27679d3b27c5e1cb00a73adb6f4f8d556994111c12db3c5d61a0c843df8 done
#29 writing layer sha256:9fb99cb9752737a13ca27302fade11fabdc1c60ba4a59b6bfc13e0d2db7bd274 done
#29 writing layer sha256:b9ce3f47d403d44eeb342a21627d6707d7d66463bfdb9aa282c6196ff3a172c2 done
#29 writing layer sha256:d933dbf6d2743095c5de52e55158a9ecc8b0d43f8944b8dc956096c65f729ab9 done
#29 writing layer sha256:e22c7dc265fd103f2f4a8e4fbe5d8e0cdb06693016d8b977dfdb265b44b094f8 done
#29 writing layer sha256:ec6f89d2f752488acd8f37dd30e757f349a416e0f7537bc8cfca8ba539a1c1fa done
#29 writing config sha256:687c86323486ae9d90365e4ec943bec3027c770af4530c8c172ecea2433d37ca
#29 writing config sha256:687c86323486ae9d90365e4ec943bec3027c770af4530c8c172ecea2433d37ca 0.7s done
#29 writing cache image manifest sha256:5e860d99c8b57d8e3bc3c508e3b823bfc2e6dfd7d9f8c9777073e889c08b9db7
#29 preparing build cache for export 7.9s done
#29 writing cache image manifest sha256:5e860d99c8b57d8e3bc3c508e3b823bfc2e6dfd7d9f8c9777073e889c08b9db7 0.3s done
#29 DONE 7.9s
Каждый пайплайн GitLab после сборки Docker-образа записывает кэш сборки в приватный реестр. При повторной сборке, GitLab уже не будет собирать слои Docker-образа не претерпевшие изменения, а просто возьмет их из кэша, что существенно сокращает время выполнения пайплайна.
Как правило CI/CD используют для командной разработки и сразу несколько программистов могут одновременно запускать свои пайплайны, поэтому ниже мы протестируем конкурентную запись файлов в приватный реестр Docker-образов
5. Тест производительности NAS для CI/CD
Чтобы нагрузить систему хранения данных, мы одновременно запустим в GitLab 10 пайплайнов сборки Docker-образа фронтенда на Node.js из предыдущего пункта
Каждый пайплайн собирает Docker-образ для отдельной git-ветки проекта фронтенда и сохраняет кэш сборки в приватный реестр Docker-образов, физически расположенном на разделе DRBD9
Перед каждым одновременным запуском 10 пайплайнов мы будем ограничивать пропускную способность канала между дата центрами до 1000Mbps, 800Mbps, 600Mbps, 400Mbps, 200Mbps и 100Mbps. И выявим как влияет скорость репликации DRBD9 на конкурентную запись кэшей сборки Docker-образов. За эталонное время примем 7.9s из предыдущего пункта - в этом случае работал единственный пайплайн, а пропускная способность канала между дата центрами была не ограничена и составляла 1Gbps
График загрузки сети и скорости записи на раздел DRBD9 для NAS на котором GitLab записывал кэши в приватный реестр:
График загрузки сети и скорости записи на раздел DRBD9 для NAS, на который реплицировались данные:
Результаты замеров сведем в таблицу:
| Лимит | Репликация | Скорость записи кэша | Время записи кэша |
|---|---|---|---|
| 1000Mb/s | 157 Mb/s | 20.6 MB/s | 17 сек |
| 800 Mb/s | 199 Mb/s | 21.4 MB/s | 23 сек |
| 600 Mb/s | 158 Mb/s | 24.5 MB/s | 20 сек |
| 400 Mb/s | 150 Mb/s | 17.7 MB/s | 26 сек |
| 200 Mb/s | 103 Mb/s | 14.9 MB/s | 34 сек |
| 100 Mb/s | 72 Mb/s | 10.0 MB/s | 60 сек |
Первый столбец - лимит на канал между дата центрами. Второй столбец - фактическая скорость репликации DRBD9 между дата центрами. Третий столбец - скорость записи кэшей сборки Docker-образов на раздел DRBD9. Четвертый столбце - среднее время записи кэшей для всех десяти пайплайнов
Вывод: из графиков и таблицы видно, что 10 одновременно запущенных пайплайнов записывали кэши сборок Docker-образов на раздел DRBD9 со скоростью в районе 20MB/s, а DRBD9 в это время реплицировал данные со скоростью в районе 160Mbps и ограничение канала не оказывало никакого влияния. И только начиная с ограничения канала в 200Mbps начинает увеличиваться время записи кэшей сборки Docker-образов в приватный реестр, а скорость записи уменьшатся
6. Накладные расходы шифрования DRBD9
Все тесты выше проходили без шифрования трафика. Теперь рассмотрим случай, когда клиенту требуется шифровать данные при передаче между датацентрами. Включим шифрование репликации DRBD9
Выполним тесты линейной записи на раздел DRBD9 и выясним какие накладные расходы даст шифрование репликации DRBD9
График загрузки сети и скорости записи на раздел DRBD9 для NAS на котором производилась запись:
График загрузки сети и скорости записи на раздел DRBD9 для NAS на который реплицировались данные:
Результаты замеров представим в таблице:
| Лимит | Скорость dd | Репликация | % |
|---|---|---|---|
| 1000Mb/s | 80.4 MB/s | 612 Mb/s (76.5 MB/s) | 105 |
| 800 Mb/s | 65.5 MB/s | 482 Mb/s (60.3 MB/s) | 108 |
| 600 Mb/s | 61.3 MB/s | 450 Mb/s (56.3 MB/s) | 108 |
| 400 Mb/s | 44.6 MB/s | 350 Mb/s (43.8 MB/s) | 101 |
| 200 Mb/s | 25.3 MB/s | 195 Mb/s (24.4 MB/s) | 103 |
| 100 Mb/s | 12.7 MB/s | 96 Mbp/s (12.0 MB/s) | 105 |
Первый столбец - лимит пропускной способности канала между дата центрами. Второй столбец - скорость записи на раздел DRBD9 командой dd. Третий столбец - фактическая скорость репликации данных DRBD9. В четвертом столбце мы подсчитали сколько процентов составила скорость записи на раздел DRBD9 от скорости репликации DRBD9
Вывод: скорость записи на раздел DRBD9 составляет 105% от скорости репликации DRBD9 с шифрованием. Результаты замеров в п.3 показали, что скорость записи на раздел DRBD9 составила 110% от скорость репликации DRBD9 без шифрования. Следовательно, шифрование репликации DRBD9 дает оверхед в районе 5%
7. Накладные расходы шифрования NFS
Теперь разберем ситуацию, когда клиенту нужно шифровать трафик при подключении нод Kubernetes к NAS. Модули запущенные на Worker-нодах Kubernetes подключаются к NAS по протоколу NFS, для шифрования которого мы используем RPC-with-TLS
Подключимся к модулю Minio из состава GitLab и выясним к какой директории модуля подмонтирован по NFS сетевой Persistent Volume:
user@dc2-plane:~$ kubectl exec -it gitlab-minio-55f6595cd5-88pvj -n gitlab -- /bin/sh
Defaulted container "minio" out of: minio, configure (init)
/ $ mount | grep nfs
nas.gitorion.ru:/mnt/disk1 on /export type nfs4 (rw,relatime,vers=4.1,rsize=1048576,wsize=1048576,namlen=255,hard,proto=tcp,timeo=600,retrans=2,sec=sys,clientaddr=89.104.65.66,local_lock=none,addr=89.104.65.68)
Далее, будем искусственно ограничивать канал между Worker-нодой Kubernetes и NAS до 1000Mbps, 800Mbps, 600Mbps, 400Mbps, 200Mbps и 100Mbps и выполнять линейную запись в директорию /export командой dd:
/ $ dd if=/dev/random of=/export/3Gb.bin bs=4k count=768000
768000+0 records in
768000+0 records out
Сначала выполним тесты с отключеным шифрованием NFS
График загрузки сети Worker-ноды Kubernetes, на котором запущен модуль Minio:
График загрузки сети и скорости записи на сетевой диск NAS, к которому подключен Minio:
Теперь подключимся к NAS и включим шифрование на NFS-сервере
/mnt/disk1 *(rw,sync,no_subtree_check,all_squash,xprtsec=mtls)
Включим шифрование для NFS-клиента в спецификации сетевого NFS PersistentVolume, подключенного к модулю Minio
apiVersion: v1
kind: PersistentVolume
metadata:
name: disk1
spec:
accessModes:
- ReadWriteOnce
capacity:
storage: 10Gi
mountOptions:
- nfsvers=4.1
- xprtsec=mtls
nfs:
path: /mnt/disk1
server: nas.gitorion.ru
persistentVolumeReclaimPolicy: Retain
storageClassName: net-disks
Перезапустим модуль Mino, чтобы он переподключился к тому NFS с новыми параметрами. Зайдем в модуль Minio и убедимcя, что среди параметров монтированния тома NFS появился параметр шифрования
user@dc2-plane:~$ kubectl exec -it gitlab-minio-55f6595cd5-vbd6l -n gitlab -- /bin/sh
Defaulted container "minio" out of: minio, configure (init)
/ $ mount | grep disk1
nas.gitorion.ru:/mnt/disk1 on /export type nfs4 (rw,xprtsec=mtls,relatime,vers=4.1,rsize=1048576,wsize=1048576,namlen=255,hard,proto=tcp,timeo=600,retrans=2,sec=sys,clientaddr=89.104.65.66,local_lock=none,addr=89.104.65.68)
Еще раз выполним тесты линейной записи в директорию /export с включенным шифрованием NFS. Убедимся, что трафик NFS шифруется с помощью команды:
root@dc2-nas:/home/user# tshark -i ens18 -f 'tcp and port 2049'
15805 0.494156721 89.104.65.68 → 89.104.65.66 TCP 66 2049 → 839 [ACK] Seq=10261 Ack=50087199 Win=22036 Len=0 TSval=3741559549 TSecr=1427335950
15806 0.494438602 89.104.65.66 → 89.104.65.68 TLSv1.2 35678 Application Data, Application Data
15807 0.494502420 89.104.65.66 → 89.104.65.68 TLSv1.2 11118 Application Data
15808 0.494542310 89.104.65.68 → 89.104.65.66 TCP 66 2049 → 839 [ACK] Seq=10261 Ack=50133863 Win=21859 Len=0 TSval=3741559550 TSecr=1427335950
15809 0.495139863 89.104.65.66 → 89.104.65.68 TLSv1.2 54098 Application Data, Application Data, Application Data
15810 0.495339764 89.104.65.66 → 89.104.65.68 TLSv1.2 43046 Application Data, Application Data, Application Data
График загрузки сети Worker-ноды Kubernetes, на котором запущен модуль Minio:
График загрузки сети и скорости записи на диск для NAS, к которому подключен модуль Minio:
Результаты замеров сведем в таблицу:
| Лимит | dd и NFS без TLS | dd и NFS с TLS | % |
|---|---|---|---|
| 1000Mb/s | 63.0 MB/s | 65.7 MB/s | 104 |
| 800 Mb/s | 63.8 MB/s | 64.6 MB/s | 101 |
| 600 Mb/s | 44.6 MB/s | 46.1 Mb/s | 103 |
| 400 Mb/s | 45.4 MB/s | 41.4 MB/s | 91 |
| 200 Mb/s | 24.2 MB/s | 23.0 MB/s | 95 |
| 100 Mb/s | 11.2 MB/s | 12.1 MB/s | 108 |
Первый столбец - лимит канала между Worker-нодой Kubernetes и NAS. Второй столбец - скорость записи на DRBD9 раздел, подмонтированный к модулю Mino по NFS без шифрования. Третий столбец - скорость записи на DRBD9 раздел c шифрованием NFS. Четвертый столбец - сколько процентов составила запись на DRBD9 с включенным шифрованием NFS от записи без шифрования NFS
В таблице есть позиции, в которых скорость с шифрованием превосходит скорость без шифрования. Это связано с тем что NFS использует файловые кэши. Для тестов мы уменьшили кэши c 20% до 1% но не смогли нивелировать данную особенность
vm.dirty_ratio = 1
Вывод: синтетический тест не позволил выявить абсолютное значение накладных расходов при шифровании NFS с помощью RPC-with-TLS. Однако видно, что RPC-with-TLS дает минимальные накладные расходы, в среднем менее 1%
8. CI/CD при одновременном шифрование NFS и DRBD9
В заключение выясним, как влияет на производительность CI/CD одновременное шифрование NFS и DRBD9. Аналогично п.5 мы будем запускать одновременно 10 пайплайнов GitLab и оценивать скорость и время записи кэшей сборки Docker-образов в приватный реестр Docker образов
Только на этот раз мы будем выставлять одинаковое ограничение на пропускную способность канала, как для репликации DRBD9, так и для подключения Worker-нод Kubernetes к NAS по NFS
Ниже приведем результаты работы пайплайнов GitLab без шифрования трафика
График загрузки сети и скорости записи на раздел DRBD9 для NAS на котором GitLab записывал кэши в приватный реестр:
График загрузки сети и скорости записи на раздел DRBD9 для NAS на который реплицировались данные:
Результаты замеров сведем в таблицу:
| Лимит | Репликация | Скорость записи кэша | Время записи кэша |
|---|---|---|---|
| 1000Mb/s | 141 Mb/s | 17.3 MB/s | 22 сек |
| 800 Mb/s | 175 Mb/s | 21.5 MB/s | 23 сек |
| 600 Mb/s | 132 Mb/s | 17.5 MB/s | 26 сек |
| 400 Mb/s | 117 Mb/s | 14.4 MB/s | 26 сек |
| 200 Mb/s | 84 Mb/s | 12.3 MB/s | 55 сек |
| 100 Mb/s | 48 Mb/s | 6.2 MB/s | 79 сек |
Далее приведем результаты работы пайплайнов GitLab при одновременно работающем шифровании DRBD9 и NFS.
График загрузки сети и скорости записи на раздел DRBD9 для NAS на котором GitLab записывал кэши в приватный реестр:
График загрузки сети и скорости записи на раздел DRBD9 для NAS на который реплицировались данные:
Результаты замеров сведем в таблицу:
| Лимит | Репликация | Скорость записи кэша | Время записи кэша |
|---|---|---|---|
| 1000Mb/s | 151 Mb/s | 18.7 MB/s | 20 сек |
| 800 Mb/s | 186 Mb/s | 16.6 MB/s | 21 сек |
| 600 Mb/s | 162 Mb/s | 19.8 MB/s | 28 сек |
| 400 Mb/s | 116 Mb/s | 14.3 MB/s | 29 сек |
| 200 Mb/s | 90 Mb/s | 11.5 MB/s | 45 сек |
| 100 Mb/s | 52 Mb/s | 6.4 MB/s | 75 сек |
Вывод: из графиков и таблиц видно, что одновременное шифрование репликации DRBD9 и NFS не повлияло существенно на скорость работы пайплайнов GitLab с системой хранения данных