В этой статье говорится о том, как настроить обратный прокси-сервер NGINX или NGINX Plus в качестве балансировщика нагрузки для хранилища объектов (object storage) на базе Minio.


Проектирование хранилища объектов


Практически любому приложению нужно хранилище, но требования к этому компоненту системы могут сильно различаться. Возьмем для примера хранилище документов: возможно, на начальных этапах работы ему не придется обслуживать большое количество запросов на чтение, но впоследствии может понадобиться масштабирование. Другое приложение (такое как, например, галерея изображений) уже с момента запуска должно уметь и быстро обслуживать большое количество запросов, и масштабироваться по мере необходимости.


Эти тонкости осложняют процесс организации хранилища. Но все не так плохо: c приходом хранилища объектов (object storage) в качестве стандартного способа хранения неструктурированных данных (во многом за счет необходимости использования HTTP) начался процесс стандартизации работы приложения с хранилищем.


Но вопрос все еще остается: как организовать заточенное под ваше приложение и в то же время гибкое хранилище объектов?


Поскольку работа с хранилищем объектов подразумевает использование HTTP-серверов и клиентов, для обслуживания HTTP-трафика необходимо выбрать подходящий веб-сервер (например, не нуждающийся в представлении NGINX). В качестве бэкэнда можно использовать легковесный и хорошо масштабируемый сервер хранилища объектов. На эту роль отлично подходит Minio. Гибкость подобной системы является ключевым фактором при создании сервиса корпоративного уровня.


С помощью NGINX Plus администраторы могут не только настроить балансировку входящего трафика, но и кэширование, дросселирование (throttling), завершение SSL/TLS и даже фильтрацию трафика на основе различных параметров. Minio, с другой стороны, предлагает легковесное хранилище объектов, совместимое с Amazon S3.


Minio создан для размещения неструктурированных данных, таких как фотографии, видеозаписи, файлы журналов, резервные копии, а также образы виртуальных машин и контейнеров. Небольшой размер позволяет включать его в состав стека приложений, аналогичного Node.js, Redis и MySQL. В minio также поддерживается распределенный режим (distributed mode), который предоставляет возможность подключения к одному серверу хранения объектов множества дисков, в том числе расположенных на разных машинах.


В этой статье мы рассмотрим несколько сценариев использования NGINX Plus в сочетании с Minio, которые позволяют настроить хорошо масштабируемое, отказоустойчивое и стабильное хранилище объектов корпоративного класса.


NGINX Plus в качестве обратного прокси и балансировщика нагрузки


NGINX Plus прежде всего известен как обратный прокси (reverse proxy). Но нужен ли обратный прокси для Minio? Давайте посмотрим на несколько сценариев использования:


  • Если перед одним или несколькими серверами Minio стоит обратный прокси NGINX Plus, появляется возможность перемещать экземпляры серверов Minio на другие машины/площадки без необходимости изменения настроек клиентов.
  • NGINX Plus может балансировать входящий трафик и равномерно раздавать его экземплярам распределенного сервера Minio.
  • Прокси-сервер NGINX Plus может входить в состав отказоустойчивого хранилища объектов, созданного с помощью команды mirror из состава Minio Client (mc).

NGINX Plus выполняет обратное проксирование трафика клиента путем передачи запросов на внутренний сервер, который задается директивой proxy_pass. В следующем фрагменте файла конфигурации единственный экземпляр Minio запущен на localhost и доступен по ссылке http://localhost:9000. Все запросы к директории верхнего уровня (/) на www.example.com, приходящие на 80-й порт, направляются Minio. NGINX Plus в явном виде устанавливает заголовок Host равным этому значению в исходном запросе.


server {
    listen 80;
    server_name www.example.com;
location / {
        proxy_set_header Host $http_host;
        proxy_pass       http://localhost:9000;
    }
}

Если серверов Minio несколько, имеет смысл настроить балансировку трафика путем перечисления этих серверов в блоке конфигурации upstream и указания этой группы в директиве proxy_pass directive:


upstream minio_servers {
    server minio-server-1:9000;
    server minio-server-2:9000;
}
server {
    listen 80;
    server_name www.example.com;
location / {
        proxy_set_header Host $http_host;
        proxy_pass       http://minio_servers;
    }
}

Для получения более подробной информации о настройке NGINX или NGINX Plus в качестве прокси для Minio см. документацию по Minio.


Завершение SSL/TLS


В последнее время HTTPS становится протоколом по умолчанию для передачи большей части веб-трафика, поэтому для Minio имеет смысл разворачивать сразу HTTPS-сервер. NGINX Plus в качестве HTTPS-сервера настроить достаточно просто. Первым делом нужен SSL/TLS-сертификат, который можно получить и интегрировать в NGINX Plus с помощью Let’s Encrypt.


Далее следует отредактировать файл конфигурации NGINX Plus, где необходимо указать параметр ssl в директиве listen, которая находится в блоке server, а затем прописать файлы с сертификатом сервера и закрытым ключом:


server {
    listen 80;
    server_name www.example.com;
    return 301 https://www.example.com$request_uri;
}
server {
    listen              443 ssl;
    server_name         www.example.com;
ssl_certificate     www.example.com.crt;
    ssl_certificate_key www.example.com.key;
    ssl_protocols       TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers         HIGH:!aNULL:!MD5;
location / {
        proxy_set_header Host $http_host;
        proxy_pass       http://localhost:9000;
    }
}

Для получения более подробной информации о завершении SSL/TLS см. NGINX Plus Admin Guide.


Кэширование


Серверы хранилищ объектов обычно не отличаются быстродействием, но это не означает, что запросы клиентов обрабатываются медленно. При включении кэширования на сервере NGINX Plus он сохраняет часто запрашиваемые данные и может сразу вернуть их клиенту, не перенаправляя запрос на внутренний сервер.


Вот как это работает. Веб-кэш сервера NGINX Plus расположен между клиентом и сервером Minio, и в нем сохраняется копия каждого запрошенного из хранилища файла. Если запрошенный файл есть в кэше, NGINX сразу возвращает его, не обращаясь к Minio. Таким образом уменьшаются время ответа клиенту и нагрузка на сервер Minio.


Чтобы настроить кэш NGINX Plus для работы с Minio, используются директивы proxy_cache_path и proxy_cache. Директива proxy_cache_path устанавливает расположение и конфигурацию кэша, а proxy_cache активирует его. Дополнительную информацию можно найти в A Guide to Caching with NGINX and NGINX Plus.


proxy_cache_path /path/to/cache levels=1:2 keys_zone=my_cache:10m max_size=10g inactive=60m
                 use_temp_path=off;
server {
...
    location / {
        proxy_cache      my_cache;
        proxy_set_header Host $http_host;
        proxy_pass       http://localhost:9000;
    }
}

Дросселирование (throttling)


Бывают случаи, когда исходя из требований бизнеса или соображений безопасности некоторых http-клиентов нужно немного «придушить». NGINX Plus позволяет ограничить доступную полосу пропускания, количество запросов и соединений.


Чтобы ограничить полосу пропускания, используйте директиву limit_rate. В следующем примере скорость загрузки ограничена 200 Кб в секунду:


server {
    ...
    location /images/ {
        limit_rate 200k;
        ...
    }
}

Чтобы ограничить количество запросов, используйте директивы limit_req и limit_req_zone, аналогично этому примеру, в котором каждый уникальный IP-адрес ограничен 10 запросами в секунду с пиками до 20 запросов.


limit_req_zone $binary_remote_addr zone=my_req_limit:10m rate=10r/s;
server {
    ...
    location /images/ {
        limit_req zone=my_req_limit burst=20;
        ...
    }
}

Чтобы ограничить количество соединений, используйте директивы limit_conn и limit_conn_zone. В следующем примере каждый уникальный IP-адрес ограничен пятью одновременными соединениями.


limit_conn_zone $binary_remote_addr zone=my_conn_limit:10m;
server {
    ...
    location /images/ {
        limit_conn my_conn_limit 5;
        ...
    }
}

Для получения более подробной информации см. NGINX Plus Admin Guide.


Заключение


В этой статье мы продемонстрировали несколько функций NGINX Plus, позволяющих организовать балансировку нагрузки (в частности, для сервера хранилища объектов Minio). Связка NGINX Plus и Minio дает возможность настроить гибкое хранилище объектов, заточенное под нужды вашего приложения.


Эта статья была изначально опубликована в блоге Nginx.


Нас можно найти в Slack: slack.minio.io

Поделиться с друзьями
-->

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


  1. motakuji
    21.03.2017 08:56
    +5

    Статья ни о чем. Директивы проксирования в nginx знает уже каждая домохозяйка.


    1. olemskoi
      21.03.2017 11:54

      А о minio знает каждая?


  1. crezd
    21.03.2017 11:39
    +7

    Почему именно Nginx Plus? Всё что вы написали можно сделать и в бесплатной версии.

    А вот реальный usecase из жизни: S3 билинг в основном состоит из исходящего трафика и количество запросов на отдачу статики, так вот перед тем как городить свой облачный S3, более разумно найти ту самую золотую середину:

    Ставим nginx прокси на свои сервера — где дешевый трафик(не амазон) и кешируем запросы к s3, благо уже есть готовые сборки под это дело.

    https://github.com/coopernurse/nginx-s3-proxy
    nginx compiled with aws-auth support, suitable for S3 reverse proxy usage.

    proxy_cache_lock on;
        proxy_cache_lock_timeout 60s;
        proxy_cache_path /data/cache levels=1:2 keys_zone=s3cache:10m max_size=30g;
    
        server {
            listen     8000;
    
            location / {
                proxy_pass https://your-bucket.s3.amazonaws.com;
    
                aws_access_key your-access-key;
                aws_secret_key your-secret-key;
                s3_bucket your-bucket;
    
                proxy_set_header Authorization $s3_auth_token;
                proxy_set_header x-amz-date $aws_date;
    
                proxy_cache        s3cache;
                proxy_cache_valid  200 302  24h;
            }
    }
    


    Работы на минуты 3, у нас счёт уменьшился раз в 5-6, если настроить кешинг более агрессивно, то можно сэкономить еще. Плюсы — продолжаем юзать облако и не обретаем головняк в виде Минио.


    1. zelenin
      21.03.2017 15:56

      интересный кейс


    1. vlaabra
      22.03.2017 01:21

      А зачем тогда S3? Только хранить?


      1. crezd
        22.03.2017 06:37

        Да


  1. nikitasius
    21.03.2017 12:03

    Маркетинг, такой маркетинг.


  1. Juralis
    21.03.2017 13:32

    А можно я вам (автору статьи) пару вопросов задам, раз уж вы тут.

    У вас в документации написано:
    «The maximum size of a single object is limited to 5TB. putObject transparently uploads objects larger than 5MiB in multiple parts. This allows failed uploads to resume safely by only uploading the missing parts. Uploaded data is carefully verified using MD5SUM signatures.».

    Вы не могли бы уточнить, что конкретно будет происходить?
    Например, вот ситуация. Приложение получает какой-то файл на 100 мегабайт. То есть, он будет разбит на несколько частей. Допустим, когда 53 мегабайта были вроде как получены, произошел внезапный обрыв соединения. Как будет осуществлено возобновление? Мне нужно будет узнать текущее число загруженных байт и начать просто записывать недостающие? Или что там должно вообще происходить? Как-то не вполне очевидно написано. Как клиент поймёт, какие части ему нужно отправить?

    И второе, как можно приблизительно оценить объёмы и количество единиц хранимой информации, которые можно будет эффективно хранить? Пара миллиардов мелких файлов вперемешку с тысячами больших — нормально лягут?

    Заранее спасибо!


    1. olemskoi
      21.03.2017 14:07
      +1

      Автор статьи где-то тут ;-)


      1. Juralis
        21.03.2017 14:15

        А, это перевод, прошу прощения.


    1. zelenin
      21.03.2017 16:17

      Например, вот ситуация. Приложение получает какой-то файл на 100 мегабайт. То есть, он будет разбит на несколько частей. Допустим, когда 53 мегабайта были вроде как получены, произошел внезапный обрыв соединения. Как будет осуществлено возобновление? Мне нужно будет узнать текущее число загруженных байт и начать просто записывать недостающие? Или что там должно вообще происходить? Как-то не вполне очевидно написано. Как клиент поймёт, какие части ему нужно отправить?

      очевидно да. запросить загруженные части, начать загружать отсутствующие.


      1. Juralis
        21.03.2017 17:26

        Что-то там совсем всё не очевидно, если честно. У меня возникло ощущение, что это работает так, что если отправить повторно файл на загрузку, то он как бы «промотает» уже полученные ранее байты и будет записывать только недостающие. По крайней мере, сейчас попробовал, выглядит это как-то так. То есть, все байты отправляются повторно, но часть из них пропускается и пишутся лишь нужные, что в теории должно быть быстрее, за счёт того, что не нужно будет повторно писать на диск то, что уже есть. Но вот повторная отправка байтов мне как-то не нравится.

        С другой стороны, в библиотеке для ноды я вижу такие методы как initiateNewMultipartUpload, что вроде как подразумевает необходимость каких-то дополнительных действий. Но это по какой-то причине не содержится в примерах и документации. То есть, похоже нельзя просто так взять и начать пихать недостающие байты. Причём, я так и не вижу, каким именно способом можно получить размер уже закачанных данных. Метод, который возвращает список незавершенных загрузок почему-то отказывается возвращать размер:

        { key: 'test.bin',
          uploadId: '648d7c8a-176b-4d01-9a16-8823edc8ab0b',
          initiated: 2017-03-21T13:43:16.134Z,
          size: NaN }
        

        Сколько смотрю на все эти файловые хранилища — везде одна проблема — переусложнённый append данных в уже имеющийся файл. Хотя, надо ещё порыться в потрохах. В крайнем случае, наверное можно попробовать подмонтировать эту штуку в виде раздела, хотя мне не очень нравится эта идея.


        1. zelenin
          21.03.2017 18:09

          Что-то там совсем всё не очевидно, если честно

          ну очевидно что так должно работать, если декларируется наличие возможности (а как по другому?). Вопрос: реализовано ли в клиентской библиотеке, которую вы смотрите.


          Вот на примере go:



  1. iPrime
    21.03.2017 18:16

    Что-то в документации не увидел, как инстансы minio взаимодействуют между собой? Отпадет винт, нода и т.п., что будет делать minio, ребалансировка? Как работает? Лучше бы про сам minio написали ))



  1. kemko
    21.03.2017 20:11

    Для получения более подробной информации о настройке NGINX или NGINX Plus в качестве прокси для Minio см. документацию по Minio.

    Я может быть туплю, но в документации виден только пример для обычного nginx, а примеров того, чем поможет Plus нет ни в документации, ни в статье.


    Быть может, Plus вы тут упоминали из-за health check и режима балансировщика least_conn. Справедливо, ведь это удобно, когда строишь целый кластер. Но если платить от $1,900 за установку не хочется, то можно обойтись другими способами.


    Например, в Ubuntu есть пакет nginx-full, в состав которого входит сторонний модуль Upstream Fair Queue. Это, конечно, не least_conn, но уже и не round-robin.


    Если этого мало, и хочется и балансировщик, который не закинет на бэкэнд больше нужного коннектов, и health check устраивать не во время обработки запросов, а отдельно, то можно посмотреть в сторону haproxy, там всё это есть. А судя по документации, Minio не ожидает какую-то nginx-магию в плане рерайтов, хитрых location с разными и прочего.