Чему мы научились, разрабатывая backend

    imageРазработка Parallels Access потребовала создания геораспределенного сервиса, позволяющего безопасно устанавливать связь между компьютерами и мобильными клиентами пользователей в различных точках земного шара. Команда, которая над ним трудится, хочет поделиться полученным опытом в форме цитат, чтобы облегчить участь тем, кто только планирует создание своего клиент/серверного продукта, и погрузить в ностальгию профессионалов, имеющих за спиной дюжину успешных проектов:

    1. Для каждого публичного адреса, который потенциально может быть прикрыт CDN, заводите второй — для прямого использования сервисами. Иначе после включения «рубильника в CDN» узнаете о себе много нового, как о явлении.
    2. Включайте опцию log slow queries на СУБД. Всегда найдется инженер, который «зарядит» запрос мимо индексов. Или администратор, неправильно настроивший резервное копирование.
    3. Виртуальные машины в облаках — расходный материал. Максимально автоматизируйте разворачивание серверов. Разрабатывайте сервис так, чтобы потеря одного сервера была безболезненна.
    4. Виртуализация как студенческое общежитие: вечеринка у одного (повышенная CPU или IO активность) может аукнуться всему этажу.
    5. Используйте проверенные технологии. Любая прикольная штука содержит массу подводных камней, которые зачастую обнаруживаются уже в продакшн.
    6. NoSql может из кареты превратиться в тыкву при первой потребности произвести join.
    7. Backend API должен быть не только простым в разработке авторами, но и удобным в использовании клиентами, которые отличаются своим многообразием (web/mobile/desktop) и имеют привычку от версии к версии показывать разные данные на одних и тех же экранах.
    8. Инженер, помни: задача выполнена, когда твой код принес пользу пользователю и прибыль заказчику. Коммит — всего лишь первый шаг на этом пути.
    9. Работа сервисов из-под root'a — дыра в безопасности. В крайнем случае, стартуй из-под root'a, переключайся с помощью setuid().
    10. Избыточное логгирование может отрицательно сказаться на производительности. Научитесь менять log level'a на лету, что позволит исследовать проблемы в момент их появления.
    11. SSL можно использовать не только для шифрования. Переход от ключей к сертификатам позволит организовать авторизацию и аутентификацию компонент в инфраструктуре.
    12. Linux-сисадмины скажут спасибо, если конфиги будут в /etc/myapp, логи в /var/log/myapp и т.д. Другими словами, храните файлы в общепринятых для OS директориях.
    13. Любой лог-файл потенциально может бесконтрольно вырасти. На стадии проектирования планируйте жизненный цикл лог-файлов и данных, которые они содержат.
    14. Настройте мониторинг всех компонентов, используя удобный сервис. Далее приготовьтесь его улучшать, чтобы не просыпаться по ночам от незначительных срабатываний.
    15. Создайте календарь с датами истечения срока использования сертификатов, подписок, ключей. Иначе «что-то перестанет работать» совершенно неожиданно.
    16. Перед тем, как улучшать производительность, изучите, как правильно выбрать метрики и что такое throughput и latency.
    17. Сервис должен выбирать тот объем данных, который он сможет корректно обработать. Иначе запрос,

      update users set halyava_end_date='2016-01-01'
      Rows matched: 300000 Changed: 300000 Warnings: 0


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

      2016-01-01 00:00:00 Mail service is trying to send 300 000 email…
      2016-01-01 00:00:01 Out of memory error


    18. Клиентские приложения должны корректно отрабатывать ситуацию, когда сервис перегружен или недоступен. Каждую последующую попытку соединиться выбирайте с увеличивающимся интервалом с элементами случайности. Иначе взлет после обновления/падения будет тяжелым.
    19. Серверу приложений история миграций ни к чему, лучше уметь надежно и быстро накатить его с чистого листа.
    20. Точно указывайте версии сторонних библиотек. Смена минорной версии может сломать все. Не используйте библиотеки из публичных репозиториев автоматически.
    21. Если не знаете, где искать ошибку, поищите ее сначала в сериализаторах, потом в десериализаторах.
    22. Пока для хранения и обработки дат можно использовать unix timestamp, лучше использовать unix timestamp.
    23. Скорость работы — это свойство продукта, которое может дорого стоить, но при этом быть не нужным.
    24. Распределенные системы хранения либо неконсистентны, либо тормозят, либо и то, и другое.
    25. Любая очередь — это инструмент мониторинга. Количество элементов в очереди, скорость их поступления и обработки могут прояснить происходящее в системе.
    26. Преждевременное избавление кода от копипасты — это преждевременная оптимизация.
    27. Если ты делаешь лишнюю операцию, то неважно, насколько быстро ты ее делаешь.


    В комментариях готовы ответить на более конкретные вопросы. Кроме того, всю эту неделю я буду вести Твиттер бэкенд-разработчиков @backendsecrethttp://bit.ly/20mJ9GP — где тоже буду рассказывать о полезном и отвечать на вопросы.
    Parallels 95,37
    Мировой лидер на рынке межплатформенных решений
    Поделиться публикацией
    Комментарии 37
    • +2
      Всё, кроме, пожалуй, 26 пункта — плюсую. Спасибо, утащил в сокровищницу!
      • +3
        Да, 26-й пункт стоит однозначно убрать.
        • +1
          Или добавить пояснение. Я могу представить такие ситуации, в которых этот пункт справедлив.
          • 0
            Единственное оправданное применение «копипасты» — это одноразовый скрипт, который перестает быть полезен и удаляется сразу после использования. Но это как-то выходит за рамки темы «Чему мы научились, разрабатывая backend»…
            • +1
              Могу добавить пример: если у вас появилась в двух местах кода копипаста, это плохо, но он неё как правило можно избавиться множеством способов, которые потом усложнят её использовать в третьем месте. А вот как только эта копипаста расползлась по 3-4 местам, тогда можно убивать её более спокойно. Обычно ведь под копипастой имеется ввиду не абсолютно идентичные копии кода, а чуть-чуть отличающиеся. Обобщить слишком рано — усложнить доделки потом.

              Аналогия: убивать копипасту слишком ранр — это как при появлении температуры тут же принимать жаропонижающее, вместо того, что бы изучить причины. Но и обратно, есть ситуации когда сбивать температуру нужно сразу, иначе пациент не доживёт до этапа анализа. (да, я только что из больницы :-( ).
              • 0
                Мне кажется, вы приравниваете копипасту к преждевременной оптимизации. Вот последняя — да, на раннем этапе ни к чему хорошему не приведёт. А копипаста — совсем другое дело. Её главное опасное свойство — неконтролируемое размножение. Где есть 3 копипасты и «всё работает», тут же возникает желание добавить еще парочку, ну работает же, подумаешь, скопирую еще разок и всё, и рабочий день на полчасика короче… А потом люди боятся рефакторить чужой код (а некоторые и свой), т.к. боятся что-то испортить. В итоге со временем рефакторинг становится практически невозможным.
                В общем, на мой взгляд преждевременная оптимизация и копипаста (или плохой дизайн) — это совсем не одно и то же.
              • 0
                Единственное оправданное применение копипасты — красные тесты.
              • +4
                Прежде, чем добавлять какой-то уровень абстракции, хорошо бы получить работающий (и покрытый тестами) Proof of Concept, а уже после, видя более-менее полную картину, избавляться от нее более осознанно, чем в самом начале.
                • +1
                  Поддерживаю, бездумное избавление от копипасты, хуже самой копипасты.
          • +1
            Какой хороший конспект, спасибо.
            • +4
              За пункты 5-6 не удержалась и вбросила ссыль на эту статью моим коллегам-разработчикам из-за которых мы уже год компостируем себе мозги изучаем на живом проекте OrientDB и Kafka. Там сейчас такое началось… :)
              • 0
                OrientDB про пятый пункт, это да.
                но кто, если не мы? )
              • +2
                Поясните п.1. Не очень понятна ситуация и пути выхода.
                • +3
                  Например: есть у вас myapp.myhost.com с которого nginx тянет статику и на котором живет backend API, используемое отображаемой страницой. Далее вы разрабатываете внутренний сервис, который использует вышеупомянутое API и из нежелания усложнять конфигурацию/пинать админов/и т.д. для вызовов используете адрес myapp.myhost.com. В час Х на перед доменом ставят CDN для ускорения загрузки страниц и все, что обращается на myapp.myhost.com начинает ходить через CDN со всеми вытекающими отсюда спецэффектами. По нашему мнению, самый простой вариант не создавать проблему — завести что-то типа origin.myapp.myhost.com и внутренние сервисы направлять на этот адрес.
                  • 0
                    Я бы всё же порекомендовал для внутренних сервисов получение адреса реализовывать через специальные тулзы для сервис дискавери вроде consul.
                    • 0
                      Мы тоже к нему присматриваемся но пока особо не пробовали.
                      • 0
                        Советую. У нас вся внутренняя инфраструктура через него работает. Единственная проблема была, когда провайдер ребутнул все наши машины с мастер нодами консула.
                  • +1
                    Сходу, пару ситуаций:
                    1. Вы хотите послать запрос к приложению, а он приходит на CDN и не доходит до бекенда.
                    2. CDN начнет обновляться с CDN. Эпичность последствий, я думаю, вы можете вообразить.
                  • +1
                    Linux-сисадмины скажут спасибо, если конфиги будут в /etc/myapp, логи в /var/log/myapp и т.д. Другими словами, храните файлы в общепринятых для OS директориях.
                    Любой лог-файл потенциально может бесконтрольно вырасти. На стадии проектирования планируйте жизненный цикл лог-файлов и данных, которые они содержат.


                    Мне кажется, в качестве еще более интересной практики можно продвигать использование уже готовых инструментов для сбора/записи/маршрутизации логов (начать можно просто с записи в syslog) — тогда сисадмины сами выберут, куда им складывать файлы (если вообще записывать логи в текстовые файлы), а разработчикам не придется в который раз изобретать ротацию и, возможно, инструменты для работы с самими логами.
                    • +4
                      Логи своих приложений — это пограничная зона ответственности. Когда удается договориться с админами — они ими рулят используя стандартные средства, когда нет — приходится познавать дзен.
                      • +1
                        Позвольте вставить свои 5 копеек как сисадмин: есть такая штуковина как FHS и PREFIX
                        FHS (Filesystem Hierarchy Standard) описывает что и куда складывать.
                        PREFIX — обычно передается configure-скрипту, чтобы указать кда положить всё дерево директорий, прописанное FHS.

                        Что это дает в сумме?
                        Вот вы ставите, скажем, nginx 1.9.5. По FHS он должен попасть в /usr/local, указываете ./configure --prefix=/usr/local и вуаля — он в /usr/local, логи в /usr/local/var/log и так далее.
                        prefix=/ только для того что ставится из пакетов (будь то deb, rpm или еще что).
                        С другой стороны, вы можете скачать свои сорцы в /usr/local/src/myapp собрать там и сделать checkinstall -D (или для rpm ключик заюзать) и ваша софтина теперь имеет право встать в /, а не в /usr/local. И сносится она легко — dpkg -r myapp

                        По логам — лично я считаю что лучше в syslog не писать. Пишите в $PREFIX/var/log/myapp/$instance.log, а админы уже прикрутят туда logcheck/logrotate, НО это лично моё мнение и я пока не рулил массово облаками, на уровне руления облаком всё может быть иначе (сбор логов, все дела).
                        • 0
                          По логам — лично я считаю что лучше в syslog не писать.
                          Почему, если не секрет?
                          Пишите в $PREFIX/var/log/myapp/$instance.log
                          Не забывайте, что access_log на 300 rps — это 300 записей на диск в секунду.
                          • 0
                            Почему, если не секрет?

                            С одной стороны, когда всё в одном месте — проще смотреть что происходило вообще.
                            На практике же syslog становится такой мусоркой, что без grep'а его смотреть невозможно.
                            Возможно с приходом systemd/journald и возможностью выбора что смотрет будет легче, но в продакшене Ubuntu 14.04, которая этого лишена напрочь.
                            Не забывайте, что access_log на 300 rps — это 300 записей на диск в секунду.

                            Опять-таки, зависит от того что вы пишете, чем и куда.
                            Например, в nginx можно не писать запросы на получение статики, а всё остальное писать через буфер — и вот 300 rps уже совсем не 300 wps.
                            С другой стороны, можно начать выдумывать костыли из разряда записи на отдельный диск (или сервер, особые извращенцы могут писать на tmpfs с ротацией лога по размеру в постоянное хранилище).
                            Да и симлинки никто не отменял — сделайте приложению симлинк в удобное вам место и пускай себе пишет.
                            • +3
                              Для nginx — да, но мы тут больше говорим про приложения собственной разработки.

                              syslog — очень гибкая система, которая не ограничивается записью логов в /var/log/messages.
                              syslog позволяет:
                              — иметь отдельные правила для каждого приложения
                              — передать логи по сети на отдельный log сервер;
                              — сохранять их по папочкам, в зависимости от имени хоста и приложения.
                              Например:
                              /$host/$service/$day.log

                              Помнится, я даже делал разделение по дням и часам:
                              /$host/$service/$year/$month/$day/$hour.log
                              В современных дистрибутивах давно стоят rsyslogd и syslog-ng, которые это умеют.
                              • 0
                                Я как-то не задумывался над этим.
                                В таком случае да, вы правы.
                                • 0
                                  Мы тоже прошли похожий путь размышлений и в итоге в некоторых компонентах сделали управляемый извне уровень логгирования. По умолчанию в логи пишем только критические ошибки, но из админки можно переключить на более детальный, что позволяет более подробно изучать проблему не забивая попусту диск. Цена вопроса — изучение в деталях log4j и 100 строк кода
                  • –2
                    Пока для хранения и обработки дат можно использовать unix timestamp, лучше использовать unix timestamp.

                    Сомнительный совет как по мне.
                    • +1
                      Если в твоём языке есть удобный тип данных с поддержкой арифметики, конверсией таймзон, форматированного вывода, то почему нужно его игнорировать?
                      С unix timestamp быстро надоест «руками» высчитывать сколько это будет «сейчас плюс один год и три месяца».
                    • 0
                      Спасибо! Отличный список. Особенно пункт 8!
                      • 0
                        > Включайте опцию log slow queries на СУБД
                        Это создаст избыточное логирование. Мне кажется, если запросы более-менее постоянны, то можно (нужно) протестировать с помощью explain, а потом пускать в прод.
                        • 0
                          Как правило постоянны те запросы, которые написаны вручную. Если общение идет через ORM + проект развивается и местами рефакторится, то за полетом фантазии в составлении SQL запросов на всех уровнях не уследишь. А проблемными как правило оказываются единицы.
                          • 0
                            Я бы сказал так: включайте все slow-log'и, пока это не приводит к существенной деградации.
                            В одном случае у нас при включении slow-log'а крашились воркеры FPM, в другой — я открыл глаза разработчику на причину необъяснимых тормозов сайта (раз из пяти TTFB >5 секунд, причем проблема явно где-то коде сайта).
                            • 0
                              Согласен, каждый инструмент — это палка о двух концах. Если бездумно применять то можно только навредить. У нас ситуации когда включение slow log чего то ломало или тормозило как-то не наблюдалось.
                            • 0
                              Как правило, log slow queries имеют настраиваемый порог срабатывания, можно добиться логирования только действительно аномально медленных запросов. А если он может устанавливаться на уровне сессии, то настраивать логирование можно хоть на уровне отдельных запросов: этот запрос логировать, если выполняется больше секунды, а этот — если больше 3-х часов.
                            • 0
                              Linux-сисадмины скажут спасибо, если конфиги будут в /etc/myapp, логи в /var/log/myapp и т.д.

                              Не факт. Некоторые предпочитают, чтобы приложение лежало в одном каталоге. Особенно когда действует принцип «один-сервер — одно приложение».

                            Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                            Самое читаемое