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 — где тоже буду рассказывать о полезном и отвечать на вопросы.

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


  1. xenohunter
    02.11.2015 11:46
    +2

    Всё, кроме, пожалуй, 26 пункта — плюсую. Спасибо, утащил в сокровищницу!


    1. Funbit
      02.11.2015 11:52
      +3

      Да, 26-й пункт стоит однозначно убрать.


      1. kolyaflash
        02.11.2015 13:51
        +1

        Или добавить пояснение. Я могу представить такие ситуации, в которых этот пункт справедлив.


        1. Funbit
          02.11.2015 14:20

          Единственное оправданное применение «копипасты» — это одноразовый скрипт, который перестает быть полезен и удаляется сразу после использования. Но это как-то выходит за рамки темы «Чему мы научились, разрабатывая backend»…


          1. Newbilius
            02.11.2015 14:46
            +1

            Могу добавить пример: если у вас появилась в двух местах кода копипаста, это плохо, но он неё как правило можно избавиться множеством способов, которые потом усложнят её использовать в третьем месте. А вот как только эта копипаста расползлась по 3-4 местам, тогда можно убивать её более спокойно. Обычно ведь под копипастой имеется ввиду не абсолютно идентичные копии кода, а чуть-чуть отличающиеся. Обобщить слишком рано — усложнить доделки потом.

            Аналогия: убивать копипасту слишком ранр — это как при появлении температуры тут же принимать жаропонижающее, вместо того, что бы изучить причины. Но и обратно, есть ситуации когда сбивать температуру нужно сразу, иначе пациент не доживёт до этапа анализа. (да, я только что из больницы :-( ).


            1. Funbit
              02.11.2015 15:16

              Мне кажется, вы приравниваете копипасту к преждевременной оптимизации. Вот последняя — да, на раннем этапе ни к чему хорошему не приведёт. А копипаста — совсем другое дело. Её главное опасное свойство — неконтролируемое размножение. Где есть 3 копипасты и «всё работает», тут же возникает желание добавить еще парочку, ну работает же, подумаешь, скопирую еще разок и всё, и рабочий день на полчасика короче… А потом люди боятся рефакторить чужой код (а некоторые и свой), т.к. боятся что-то испортить. В итоге со временем рефакторинг становится практически невозможным.
              В общем, на мой взгляд преждевременная оптимизация и копипаста (или плохой дизайн) — это совсем не одно и то же.


          1. VolCh
            02.11.2015 22:09

            Единственное оправданное применение копипасты — красные тесты.


        1. kamazee
          02.11.2015 14:58
          +4

          Прежде, чем добавлять какой-то уровень абстракции, хорошо бы получить работающий (и покрытый тестами) Proof of Concept, а уже после, видя более-менее полную картину, избавляться от нее более осознанно, чем в самом начале.


          1. kmmbvnr
            04.11.2015 09:43
            +1

            Поддерживаю, бездумное избавление от копипасты, хуже самой копипасты.


  1. BloodJohn
    02.11.2015 11:49
    +1

    Какой хороший конспект, спасибо.


  1. Musia17
    02.11.2015 11:55
    +4

    За пункты 5-6 не удержалась и вбросила ссыль на эту статью моим коллегам-разработчикам из-за которых мы уже год компостируем себе мозги изучаем на живом проекте OrientDB и Kafka. Там сейчас такое началось… :)


    1. africaunite
      02.11.2015 20:32

      OrientDB про пятый пункт, это да.
      но кто, если не мы? )


  1. alekciy
    02.11.2015 12:02
    +2

    Поясните п.1. Не очень понятна ситуация и пути выхода.


    1. yamschik
      02.11.2015 12:17
      +3

      Например: есть у вас myapp.myhost.com с которого nginx тянет статику и на котором живет backend API, используемое отображаемой страницой. Далее вы разрабатываете внутренний сервис, который использует вышеупомянутое API и из нежелания усложнять конфигурацию/пинать админов/и т.д. для вызовов используете адрес myapp.myhost.com. В час Х на перед доменом ставят CDN для ускорения загрузки страниц и все, что обращается на myapp.myhost.com начинает ходить через CDN со всеми вытекающими отсюда спецэффектами. По нашему мнению, самый простой вариант не создавать проблему — завести что-то типа origin.myapp.myhost.com и внутренние сервисы направлять на этот адрес.


      1. Suvitruf
        02.11.2015 12:21

        Я бы всё же порекомендовал для внутренних сервисов получение адреса реализовывать через специальные тулзы для сервис дискавери вроде consul.


        1. yamschik
          02.11.2015 12:56

          Мы тоже к нему присматриваемся но пока особо не пробовали.


          1. Suvitruf
            02.11.2015 13:06

            Советую. У нас вся внутренняя инфраструктура через него работает. Единственная проблема была, когда провайдер ребутнул все наши машины с мастер нодами консула.


    1. lexore
      02.11.2015 18:47
      +1

      Сходу, пару ситуаций:
      1. Вы хотите послать запрос к приложению, а он приходит на CDN и не доходит до бекенда.
      2. CDN начнет обновляться с CDN. Эпичность последствий, я думаю, вы можете вообразить.


  1. kamazee
    02.11.2015 13:05
    +1

    Linux-сисадмины скажут спасибо, если конфиги будут в /etc/myapp, логи в /var/log/myapp и т.д. Другими словами, храните файлы в общепринятых для OS директориях.
    Любой лог-файл потенциально может бесконтрольно вырасти. На стадии проектирования планируйте жизненный цикл лог-файлов и данных, которые они содержат.


    Мне кажется, в качестве еще более интересной практики можно продвигать использование уже готовых инструментов для сбора/записи/маршрутизации логов (начать можно просто с записи в syslog) — тогда сисадмины сами выберут, куда им складывать файлы (если вообще записывать логи в текстовые файлы), а разработчикам не придется в который раз изобретать ротацию и, возможно, инструменты для работы с самими логами.


    1. yamschik
      02.11.2015 13:12
      +4

      Логи своих приложений — это пограничная зона ответственности. Когда удается договориться с админами — они ими рулят используя стандартные средства, когда нет — приходится познавать дзен.


      1. Gendalph
        02.11.2015 15:27
        +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, НО это лично моё мнение и я пока не рулил массово облаками, на уровне руления облаком всё может быть иначе (сбор логов, все дела).


        1. lexore
          02.11.2015 18:43

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


          1. Gendalph
            02.11.2015 18:53

            Почему, если не секрет?

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

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


            1. lexore
              02.11.2015 19:00
              +3

              Для nginx — да, но мы тут больше говорим про приложения собственной разработки.

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

              Помнится, я даже делал разделение по дням и часам:
              /$host/$service/$year/$month/$day/$hour.log
              В современных дистрибутивах давно стоят rsyslogd и syslog-ng, которые это умеют.


              1. Gendalph
                02.11.2015 19:13

                Я как-то не задумывался над этим.
                В таком случае да, вы правы.


                1. yamschik
                  02.11.2015 20:47

                  Мы тоже прошли похожий путь размышлений и в итоге в некоторых компонентах сделали управляемый извне уровень логгирования. По умолчанию в логи пишем только критические ошибки, но из админки можно переключить на более детальный, что позволяет более подробно изучать проблему не забивая попусту диск. Цена вопроса — изучение в деталях log4j и 100 строк кода


                  1. Jimilian
                    03.11.2015 23:40

                    Log4j2 умеет это из коробки через JMX.


  1. seriyPS
    02.11.2015 15:28
    -2

    Пока для хранения и обработки дат можно использовать unix timestamp, лучше использовать unix timestamp.

    Сомнительный совет как по мне.


  1. alarin
    02.11.2015 18:25

    Спасибо! Отличный список. Особенно пункт 8!


  1. ReklatsMasters
    02.11.2015 21:45

    > Включайте опцию log slow queries на СУБД
    Это создаст избыточное логирование. Мне кажется, если запросы более-менее постоянны, то можно (нужно) протестировать с помощью explain, а потом пускать в прод.


    1. yamschik
      02.11.2015 22:14

      Как правило постоянны те запросы, которые написаны вручную. Если общение идет через ORM + проект развивается и местами рефакторится, то за полетом фантазии в составлении SQL запросов на всех уровнях не уследишь. А проблемными как правило оказываются единицы.


    1. Gendalph
      03.11.2015 01:14

      Я бы сказал так: включайте все slow-log'и, пока это не приводит к существенной деградации.
      В одном случае у нас при включении slow-log'а крашились воркеры FPM, в другой — я открыл глаза разработчику на причину необъяснимых тормозов сайта (раз из пяти TTFB >5 секунд, причем проблема явно где-то коде сайта).


      1. yamschik
        03.11.2015 10:20

        Согласен, каждый инструмент — это палка о двух концах. Если бездумно применять то можно только навредить. У нас ситуации когда включение slow log чего то ломало или тормозило как-то не наблюдалось.


    1. VolCh
      05.11.2015 10:42

      Как правило, log slow queries имеют настраиваемый порог срабатывания, можно добиться логирования только действительно аномально медленных запросов. А если он может устанавливаться на уровне сессии, то настраивать логирование можно хоть на уровне отдельных запросов: этот запрос логировать, если выполняется больше секунды, а этот — если больше 3-х часов.


  1. VolCh
    02.11.2015 23:03

    Linux-сисадмины скажут спасибо, если конфиги будут в /etc/myapp, логи в /var/log/myapp и т.д.

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


    1. Gendalph
      03.11.2015 01:15

      Это уже обсуждалось, выше: habrahabr.ru/company/parallels/blog/269927/#comment_8637989