infra
February 21, 2022

Синхронизация файлов без регистрации и СМС - lsyncd

В одном из наших проектов появилась необходимость обеспечить высокую надежность продукта при работе со сторонним софтом. И не просто с софтом, а таким, который работает с файлами - в самом что ни на есть "файловом" виде. Далее я рассмотрю решения и подводные камни, о которые можно распороть пятку…

Начнем с закрытого / проприетарного / стороннего софта, с которым предстоит работать, но сам софт я называть не буду:

  • сторонний софт использует файлы, которые ему надо подложить;
  • этот софт нам требуется и без него никак нельзя - вариантов нет (законы, сертификаты и прочая порнокриптография);
  • изменить или как-то доработать его нельзя;
  • надо, чтоб было надёжно - поднимите руки 🤙 кто уже знает проблему!

Интеграция со сторонним ПО

Сама задача решается просто - на отдельной машине установлен лицензионный закрытый софт, мы для интеграции с ним запускаем маленький сервис. В нашем случае необходимо реализовать всего две функции - положить файл в нужную папку (1) и дёрнуть (3) конкретное локальное АПИ (для самых дотошных - ABI). И никакого S3 или другого Object Storage - только файлы, только хардкор.

Работа со сторонни ПО

Прод? Рано!

Пока всё идёт хорошо, но когда речь заходит о продуктовой эксплуатации приходит ОНА - отказоустойчивость. Если весь хост с этим ПО отхлебнёт - надо, чтоб система продолжала работать. В этом тоже нет ничего сложного - добавляем избыточности (2 или более хоста) и ставим за балансировщик (у нас обычно это traefik).

И в этот момент на первый план выходит проблема - как синхронизировать файлы между хостами?

Проблема 🔄

Just use the Force, Luke

В обычной жизни все уже привыкли использовать Object Store и мы в RNDSOFT не исключение, но тут его нельзя, потому как нужны файлы в виде… 📂 файлов! Частота изменения данных (записи нового файла) очень небольшая - 1 или 2 раза в месяц, и ради этого тащить Ceph и прочие GlusterFS очень не хочется. Что же делать?

Есть отличный инструмент lsyncd. Надёжный, быстрый и очень простой. Базируется на двух столпах - inotify (очень быстрый механизм ядра Linux) и rsync - не требует представления. Если поискать в интернетах, то можно найти много статей на тему того, как мгновенно синхронизировать миллионы файлов между 3 и более хостами. И мы не исключение - ррррраз и запустили! 🚀

Шутка конечно, но уж больно картинка понравилась

Dockerfile

Времена пакетных менеджеров потихоньку уходят, и в данном случае мы также решили запаковать lsyncd в докер и запускать его, как и все остальные сервисы - в кластере на Nomad.

FROM alpine:3.11

RUN apk --no-cache add openssh-client rsync lsyncd gettext libintl

RUN mkdir -p /syncfolder /root/.ssh

ADD ./lsyncd.in.lua /tmp/lsyncd.in.lua

ENV LSYNCD_SOURCE_DIR=/localdir
ENV LSYNCD_TARGET_DIR=/remotedir
ENV LSYNCD_REMOTE_HOST=1.1.1.1
ENV LSYNCD_DELAY=2

RUN echo 'StrictHostKeyChecking=no' >> /etc/ssh/ssh_config

CMD envsubst < /tmp/lsyncd.in.lua > /etc/lsyncd/lsyncd.lua && /usr/bin/lsyncd /etc/lsyncd/lsyncd.lua

lsyncd.in.lua

Настроек там вагон и целая тележка, но для нашего случая всё предельно просто:

settings {
  nodaemon   = true
}

sync {
  default.rsyncssh,
  source="${LSYNCD_SOURCE_DIR}",
  host = "${LSYNCD_REMOTE_HOST}",
  targetdir="${LSYNCD_TARGET_DIR}",
  delay=${LSYNCD_DELAY},
  delete=false
}

docker-compose.yml

С запуском тоже не сложно - приведу тестовый конфиг. На проде у нас работает Nomad, но job-файл на HCL менее выразительный, чем у docker-compose, поэтому пойдём по классике:

version: '3.8'

services:
  lsyncd:
    image: yourregistry.ru/lsyncd:latest
    restart: unless-stopped
    environment:
      LSYNCD_SOURCE_DIR: "/syncfolder"
      LSYNCD_TARGET_DIR: "/remotetarge"
      LSYNCD_REMOTE_HOST: "IP"
      LSYNCD_DELAY: “2”
    volumes:
      - /source:/syncfolder
      - /root/.ssh:/root/.ssh

Lsyncd умеет по-разному авторизовываться (мы используем специально созданные ssh-ключи), умеет гибко настраивать rsync, с помощью которого и происходит непосредственная синхронизация, но это уже совсем другая история.

Результат и пруфы производительности

Вот так это всё работает на проде

Поскольку, исходя из наших бизнес требований, нам не требуется молниеносность, то и тесты / бенчмарки сделали на глазок, но результаты впечатляют. Тестировали так:

  1. на одном хосте создали папочку и нагенерили в неё ~112 МБ файлов;
  2. открыли логи контейнера, в которые он пишет выполняемые действия;
  3. через mv атомарно переместили папку с тестовыми файлами в папку для синхронизации;
  4. внимательно и сосредоточенно 👀 следили за логами и их временными метками…

Результат…. ~112 МБ в секунду, не считая двухсекундной задержки, которая у нас прописана в конфиге.


Пока писал заметку, нагуглил десятки статей про lsyncd и инструменты, использующие его под капотом. В облачном мире это весьма распространённое решение, показывающее великолепные результаты. И к тому же, оно простое как противотанковый ёж - поставил и работает. Скорости ⚡ более чем достаточно, конфигурация гибкая - можно настроить на любой вкус и цвет. Пользуйтесь на здоровье! 🤝