В нашем проекте есть немного (~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 сервер и расшариваем папку /mnt/nfs *(rw,sync,no_subtree_check,no_root_squash,no_all_squash)

2

На client монтируем расшаренную nfs-папку через mount -t nfs4 srv1: и замеряем скорость.

eth0 на srv1 показывает rx: 940.61 Mbit/s tx: 7.95 Mbit/s

109

На srv1 выключаем обычный NFS сервер, создаем GlusterFS том (далее glusterfs-том) gv0 из одного кирпичика на srv1. Тип glusterfs-тома получится Distribute. Затем расшариваем glusterfs-том gv0 через nfs-ganesha.

далее тип glusterfs-тома Distribute

3

На srv1 монтируем gv0 том через mount -t glusterfs localhost: и замеряем скорость.

eth0 на srv1 показывает rx: 1.94 kbit/s tx: 3.00 kbit/s

170

4

На client монтируем gv0 том через mount -t glusterfs srv1: и замеряем скорость.

eth0 на srv1 показывает rx: 961.47 Mbit/s tx: 6.45 Mbit/s

119

5

На client монтируем gv0 том через mount -t nfs4 srv1: и замеряем скорость.

eth0 на srv1 показывает rx: 921.94 Mbit/s tx: 2.67 Mbit/s

111

К glusterfs-тому gv0 подключаем srv2 с фактором репликации 2, тип которого становится Replicate.

далее тип glusterfs-тома Replicate

6

На srv1 монтируем gv0 том через mount -t glusterfs localhost: и замеряем скорость.

eth0 на srv1 показывает rx: 4.57 Mbit/s tx: 968.52 Mbit/s

119

7

На client монтируем gv0 том через mount -t glusterfs srv1: и замеряем скорость.

eth0 на srv1 показывает rx: 422.84 Mbit/s tx: 2.44 Mbit/s

54

8

На client монтируем gv0 том через mount -t nfs4 srv1: и замеряем скорость.

eth0 на srv1 показывает rx: 604.81 Mbit/s tx: 682.26 Mbit/s

84

Выводы по испытаниям

  1. Удивляет то, что у glusterfs-тома с типом Distribute скорость записи по всем случаям монтирования чуток выше, чем у локального диска и обычного nfs соответсвенно. Замеры делались несколько раз и каждый раз наблюдалась такая картина. Казалось бы, должно быть наоборот. Главный вывод из этого такой: на одном сервере смело можно использовать glusterfs-том типа Distribute, не теряя в скорости. Только вот зачем, спросите вы. Ну хотя бы для того, чтобы изначально заложить вариант расширения хранилища.

  2. Когда 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.

  3. Теоретически можно предположить, что если на 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. Т.е. надо будет думать над тем, как и где увелиичить "толщину" сети.

Комментарии (21)


  1. borovinskiy
    03.02.2023 13:46
    +1

    Ну я бы поостерегся тестировать скорость dd. Это тест в лучшем случае только скорости последовательной записи, а вовсе не "много случайного чтения большого количества мелких статических файлов nginx".

    Посмотрите на fio. Там много настроек как протестировать и последовательно и случайно и чтение и запись.

    А конкретно в вашем случае и тест следует проводить именно на nginx, например сняв логи с реального сервера и запустив по ним бенчмарк JMeter, чтобы повторить реальную нагрузку веб-сервера.


    1. krpsh Автор
      03.02.2023 13:55

      Конечно вы правы, что мерить скорость дисков надо именно fio. Но в данном случае мы просто мерием скорости и СРАВНИВАЕМ их, а не пытаемся узнать скорость записи и чтения реальных дисков. И самое главное, что при нашей нагрузки нам с запасом хватает скорости обыного NFS, от этого мы и отталкивались. Поэтому считаю, что в данном случает достаочно dd.


      1. borovinskiy
        03.02.2023 17:19

        HDD может быть быстрее SSD для линейной записи кусками по 1М.
        Следует ли из этого, что для чтения большого количества мелких файлов стоит выбрать HDD?


  1. Dmitry2019
    03.02.2023 14:49

    Я настраивал Glusterfs для одного проекта, где сервера поочерёдно раз в 5 минут записывали на Glusterfs порядка 10к файлов (MRTG). И скорости сети и диска хватало с запасом, но Gluster периодически терял синхронизацию между нодами. Пришлось откатиться на NFS


    1. krpsh Автор
      03.02.2023 14:52

      Хм... А вот это ценный факт. В описаниях к Glusterfs всегда говорят, что она надежная. Не ожидал такого. А можете чуток по подробней сказать о типе тома(ов) в том проекте?


      1. Dmitry2019
        03.02.2023 15:10
        +1

        glusterfs 7.9
        2 пира симметрично реплицируемые по отдельному интефейсу

        gluster peer status
        Number of Peers: 1

        Hostname: cfs2
        Uuid: 0cf321d6-315b-416c-bdc4-7f9372aecdeb
        State: Peer in Cluster (Connected)
        Other names:
        cfs2-back

        Volume Name: mrtg
        Type: Replicate
        Volume ID: e5dff098-c7c6-4f33-baef-ad99f66150e4
        Status: Started
        Snapshot Count: 0
        Number of Bricks: 1 x 2 = 2
        Transport-type: tcp
        Bricks:
        Brick1: cfs1:/home/mrtg
        Brick2: cfs2:/home/mrtg
        Options Reconfigured:
        transport.address-family: inet
        storage.fips-mode-rchecksum: on
        nfs.disable: on
        performance.client-io-threads: off

        /etc/hosts

        10.10.20.5 cfs1-back
        10.10.20.6 cfs2-back
        10.10.22.1 cfs1
        10.10.22.2 cfs2


        1. krpsh Автор
          03.02.2023 15:22

          Правильно ли я понимаю, что изначально вы монтировали том mrtg как glasterfs, но после потерь синхронизации между нодами вы откатились на обычный nfs, не nfs-ganesha?


          1. Dmitry2019
            03.02.2023 16:20

            Мы настроили NFS на реплицируемых нодах VMWare. И, если одна нода упадёт, то сервис будет недоступен только на время, пока вторая нода не поднимется с тем же IP. А это пара секунд


          1. Dmitry2019
            03.02.2023 16:23

            Мы также рассматривали поставить rsync между двумя нодами NFS и подключаться к ним через HAProxy. Но не дошли руки


  1. Demacr
    03.02.2023 16:52

    А ceph не рассматривали для своего случая?


    1. krpsh Автор
      03.02.2023 17:06

      Нет не рассматривали, т.к. не для таких масштабов она, думается мне.


  1. Firz
    03.02.2023 17:39

    А вот как делать сеть «толще», надо думать — либо ставить 10GBit/s сетевухи, либо пытаться объединять сетевухи. Все очень сильно зависит от требований и финансовых возможностей проекта.

    Просто мысли вслух, к разговору о объединении сетевух:
    В свое время изучал как и чем можно «ускорить» сеть для домашнего хранилища и был удивлен случайно узнав что Samba/SMB умеет «multichannel»(включается отдельно в настройках сервера и иногда нужно и у клиентов) — просто подключаешь к сервер несколько сетевух, к клиенту несколько сетевух и все, при копировании файлов он использует все доступные интерфейсы. То есть, к примеру, можно к свичу подключить 2 сетевухи сервера и 2 сетевухи клиента и он сам будет использовать оба интерфейса, при этом что у сервера что у клиента это будут два обычных интерфейса, без всякого агрегирования каналов. Тестировал даже варианты когда только 1 интерфейс сервера и один интерфейс клиента подключен к общей сети(свичу), а остальные сетевые интерфейсы подключены напрямую от клиента к серверу, и при подключении к сетевому ресурсу в общей сети(через свитч) он все равно определяет и использует напрямую подключенные интерфейсы для увеличения скорости передачи данных.


    1. select26
      03.02.2023 18:31

      LACP работает на L2 и совершенно прозрачно. Обычно можно собрать до 8 интерфейсов в группу.


    1. krpsh Автор
      03.02.2023 20:26

      Да, я как-то давно слышал о таком режиме у SMB/CIFS, но сам не пробовал, не было необходимости.

      Я сегодня попробовал объединить (bonding) две сетевухи в разных местах.

      Сначала сделал две сетевухи у client, объединил их в режиме balance-rr и смонтировал glusterfs-том gv0 через mount-t glusterfs . Как я и предполагал в статье, скорость увеличилась в два раза - с 54 до 108.

      Затем я убрал дополнительную сетевуху на client (осталась одна) и добавил по одной на srv1 и srv2, объединил их в режиме balance-rr на каждом из srv. На client cмонтировал glusterfs-том gv0 через mount-t nfs4 и скорость стала 98.

      При факторе репликации 2 (как у нас) монтировать лучше через nfs, т.к. в таком случае возникновения split brain менее вероятно, чем при монтировании через glusterfs. Это объясняется тем, что при glusterfs клиент пишет сразу на два сервера, а при nfs только на один сервер.


      1. Firz
        03.02.2023 21:07
        +1

        Я тоже в свое время баловался всякими LACP и multichannel и в итоге оказалось лучше и проще купить по 40-50$ SFP+ сетевух, за 150$ 4-портовый SPF+ свитч и сделать дома 10-гигабитную сеть.


        1. krpsh Автор
          03.02.2023 21:38

          Хорашая мысль, но у нас весь проект в дата-центре и цены там на 10-гигабитную сеть не особо радуют. А вот вариант с объединением сетевух вполне реален с нашим бюджетом.


      1. VASYL_MELNYK
        04.02.2023 14:27

        Я пробовал, самба работает согласно документации, но оказалось , что скорость реально падает очень сильно и когда в шаре много файлов это очень грустно становится, а когда попробовал монтировать саму шару гластера в папку и уже на самбе расшаривать просто эту шару, то оказалось что в случае такого монтирования для обновления списка файлов в шаре надо обновить через ф5, тогда как если файлы лежат просто локально такого поведения нет.

        Но гластер отлично подходит для синхронизации шар между нодами кластера виртуализации, например я в проксмоксе разливаю бекапы на ноды - большие файлы и мало гластер справляется без проблем.

        для мелких файлов лучше подходит riak, правда из нюансов надо следить за загрузкой дисков и количеством потоков репликации, мы как то пробовали на одном жестком диске держать две ноды репликации - оно фактически умерло


        1. krpsh Автор
          04.02.2023 14:48

          Про riak не слышал. Бегло сейчас читанул - нам не подходит, т.к. нам нужен доступ к файлам на файловой системе. Да и файлы у нас разные, от 10kb до 100Mb.


          1. VASYL_MELNYK
            04.02.2023 15:08

            мы тоже не хотели уходить с обычной файловой системы, но пришлось - не смогли ничего найти, пришлось переписывать апи хранилища, но там было проще - там был все таки веб-портал.


    1. borovinskiy
      03.02.2023 22:39

      По Ceph были бенчи и переход с 1Г на 10Г увеличивает скорость в Ceph примерно в 2 раза.
      В Gluster прирост может будет другой, но в 10 раз он наверняка не будет )


      1. krpsh Автор
        04.02.2023 08:09

        Если перевести нашу схему на 10GBit/s, то мы упремся в диски на srv{1,2}, т.е. в 165. Для двух серверов с томом Replicate сеть в 10GBit/s излишне,а вот для фактора репликации 3 и с быстрыми дисками на серверах это уже вполне годится )