HimeraSearchDB
Carding_EbayThief
triada
CrackerTuch
d-shop
HimeraSearchDB

НОВОСТИ Топ факапов Циан

Bonnie
Оффлайн
Регистрация
12.04.17
Сообщения
19.095
Реакции
107
Репутация
0
zyiu-qkcptbeezgf_c5adiagete.png


Всем добра!

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

Преамбула


Давным-давно, когда Циан состоял из монолитов, и никаких намеков на микросервисы еще не было, мы измеряли доступность ресурса проверкой 3–5 страниц.

Отвечают — все хорошо, не отвечают в течение длительного времени — алерт. Сколько времени они должны не работать для того, чтобы это считалось инцидентом, — решали люди на совещаниях. Команда инженеров всегда участвовала в расследовании инцидента. Когда расследование было закончено, писали постмортем — своеобразный отчет на почту в формате: что было, сколько длилось, что сделали в моменте, что сделаем в будущем.

Основные страницы сайта или как мы понимаем, что пробили дно


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

Допустим, мы выяснили, что есть ряд суперважных разделов сайта, которые отвечают за основной сервис — поиск и подачу объявлений. Если количество запросов, которые завершились ошибкой, превышает 1%, — это критический инцидент. Если в течение 15 минут в прайм-тайм процент ошибок превышает 0,1% — то это также считается критическим инцидентом. Эти критерии покрывают бОльшую часть инцидентов, остальные выходят за рамки этой статьи.

otmwk90qyl-jcomorjhkofebrgq.png


Топ лучших инцидентов Циан


Итак, мы точно научились определять тот факт, что инцидент случился.

Теперь каждый инцидент у нас детально описан и отражен в эпике Jira. К слову: для этого мы завели отдельный проект, назвали его FAIL — в нем можно создавать только эпики.

Если собрать все фейлы за последние несколько лет, то лидируют:

  • инциденты, связанные с mssql;
  • инциденты, вызванные внешними факторами;
  • ошибки админа.

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

Пятое место — «Наводим порядок в DNS»


Это был ненастный вторник. Решили мы навести порядок в DNS-кластере.

Захотелось перевести внутренние dns-серверы c bind на powerdns, выделив под это полностью отдельные серверы, где кроме dns ничего нет.

Разместили мы по одному dns-серверу в каждой локации наших ДЦ, и наступил момент переезда зон из bind в powerdns и переключения инфраструктуры на новые серверы.

В самый разгар переезда из всех серверов, которые были указаны в локальных кэширующих bind-ах на всех серверах, остался только один, который был в дата-центре в Санкт-Петербурге. Этот ДЦ изначально был задекларирован как некритичный для нас, но внезапно стал single point of failure.
Как раз в такой период переезда упал канал между Москвой и Санкт-Петербургом. Мы фактически остались без DNS на пять минут и поднялись, когда хостер устранил неполадки.

Выводы:

Если раньше мы пренебрегали внешними факторами во время подготовки к работам, то сейчас их тоже включили в список того, к чему готовимся. И теперь стремимся к тому, что все компоненты зарезервированы n-2, а на время работ мы можем опускать этот уровень до n-1.

  • Во время составления плана действий отмечайте пункты, где сервис может упасть, и продумывайте сценарий, где все пошло «хуже некуда», заранее.
  • Распределяйте внутренние dns-серверы по разным геолокациям/датацентрам/стойкам/коммутаторам/вводам.
  • На каждом сервере ставьте локальный кеширующий dns-сервер, который перенаправляет запросы на основные dns-серверы, а в случае его недоступности будет отвечать из кеша.

Четвертое место — «Наводим порядок в Nginx»


В один прекрасный день наша команда решила, что «хватит это терпеть», и запустился процесс рефакторинга конфигов nginx. Основная цель — привести конфиги к интуитивно понятной структуре. Раньше все было «исторически сложившимся» и логики в себе никакой не несло. Теперь каждый server_name вынесли в одноименный файл и распределили все конфиги по папкам. К слову — конфиг содержит в себе 253949 строк или 7836520 символа и занимает почти 7 мегабайт. Верхний уровень структуры:

Nginx structure

├── access
│ ├── allow.list
...
│ └── whitelist.conf
├── geobase
│ ├── exclude.conf
...
│ └── geo_ip_to_region_id.conf
├── geodb
│ ├── GeoIP.dat
│ ├── GeoIP2-Country.mmdb
│ └── GeoLiteCity.dat
├── inc
│ ├── error.inc
...
│ └── proxy.inc
├── lists.d
│ ├── bot.conf
...
│ ├── dynamic
│ └── geo.conf
├── lua
│ ├── cookie.lua
│ ├── log
│ │ └── log.lua
│ ├── logics
│ │ ├── include.lua
│ │ ├── ...
│ │ └── utils.lua
│ └── prom
│ ├── stats.lua
│ └── stats_prometheus.lua
├── map.d
│ ├── access.conf
│ ├── ..
│ └── zones.conf
├── nginx.conf
├── robots.txt
├── server.d
│ ├── cian.ru
│ │ ├── cian.ru.conf
│ │ ├── ...
│ │ └── my.cian.ru.conf
├── service.d
│ ├── ...
│ └── status.conf
└── upstream.d
├── cian-mcs.conf
├── ...
└── wafserver.conf


Стало значительно лучше, но в процессе переименования и распределения конфигов часть из них имела неправильное расширение и не попала в директиву include *.conf. Как следствие — часть хостов стала недоступна и возвращала 301 на главную. Из-за того что код ответа был не 5хх/4хх, это заметили не сразу, а лишь под утро. После этого мы начали писать тесты на проверку инфраструктурных компонентов.

Выводы:

  • Правильно структурируйте конфиги (не только nginx) и продумывайте структуру на раннем этапе проекта. Так вы сделаете их более понятными команде, что в свою очередь уменьшит ТТМ.
  • Для некоторых инфраструктурных компонентов пишите тесты. Например: проверка, что все ключевые server_name отдают правильный статус, + тело ответа. Достаточно будет иметь под рукой просто несколько скриптов, которые проверяют основные функции компонента, чтобы судорожно не вспоминать в 3 часа ночи, что же еще надо проверить.

Третье место — «Внезапно закончилось место в Cassandra»


Данные планомерно росли, и все было хорошо до того момента, когда в кластере Cassandra начали падать repair больших кейспейсов, потому что на них не может отработать compaction.

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

  • места оставалось около 20% суммарно по кластеру;
  • полноценно добавить ноды нельзя, потому что не проходит cleanup после добавления ноды из-за нехватки места на разделах;
  • производительность понемногу падает, так как не работает компакция;
  • кластер работает в аварийном режиме.

lpahie7bann64sajoibumpqbr5g.png


Выход — добавили еще 5 нод без cleanup, после чего начали планомерно выводить из кластера и снова вводить, как пустые ноды, на которых закончилось место. Времени затрачено сильно больше, чем хотелось бы. Был риск частичной или полной недоступности кластера.

Выводы:

  • На всех серверах cassandra должно быть занято не больше 60% места на каждом разделе.
  • Загружены они должны быть не более чем на 50% по cpu.
  • Не стоит забивать на capacity planning и продумывать его надо для каждого компонента, исходя из его специфики.
  • Чем больше нод в кластере — тем лучше. Серверы, содержащие небольшой объем данных, быстрее переналиваются, и такой кластер легче реанимировать.

Второе место — «Исчезли данные из consul key-value storage»


Для service discovery мы, как и многие, используем consul. Но у нас его key-value используется еще и для blue-green выкладки монолита. Там хранится информация об активных и неактивных апстримах, которые меняются местами во время деплоя. Для этого был написан сервис деплоя, который взаимодействовал с KV. В какой-то момент данные из KV пропали. Восстановили по памяти, но с рядом ошибок. Как следствие — при выкладке нагрузка на апстримы распределилась неравномерно, а мы получили много ошибок 502 из-за перегрузки бекендов по CPU. В итоге переехали с consul KV на postgres, откуда удалить их уже не так просто.

Выводы:

  • Сервисы без какой-либо авторизации не должны содержать в себе критичных для работы сайта данных. Например, если у вас нет авторизации в ES — лучше бы запретить доступ на уровне сети отовсюду, где он не нужен, оставить только необходимые, а также сделать action.destructive_requires_name: true.
  • Отрабатывайте механизм резервного копирования и восстановления заранее. Например, заранее сделайте скрипт (к примеру, на python), который умеет и бекапить и восстанавливать.

Первое место — «Капитан неочевидность»


В какой-то момент мы заметили неравномерное распределение нагрузки на апстримы nginx в случаях, когда в бекенде было 10+ серверов. Из-за того что round-robin направлял запросы с 1 по последний апстрим по порядку, и каждый релоад nginx начинал сначала, на первые апстримы всегда приходилось больше запросов, чем на остальные Как следствие — они работали медленнее и страдал весь сайт. Это становилось все более заметным по мере увеличения количества трафика. Просто обновить nginx для включения random не вышло — надо переделывать кучу lua кода, который не взлетел на версии 1.15 (в тот момент). Пришлось пропатчить наш nginx 1.14.2, внедрив в него поддержку random. Это решило проблему. Этот баг побеждает в номинации «капитан неочевидность».

Выводы:

Было очень интересно и увлекательно исследовать этот баг).

  • Выстройте мониторинг так, чтобы он помогал находить подобные флуктуации быстро. Например, можно использовать ELK для того, чтобы наблюдать за rps на каждый backend каждого upstream, следить за их временем ответа с точки зрения nginx. В данном случае это нам и помогло выявить проблему.

В результате бОльшей части фейлов можно было бы избежать при более скрупулезном подходе к тому, что делаешь. Надо всегда помнить о законе Мерфи: Anything that can go wrong will go wrong, и строить компоненты, руководствуясь им.
 
Сверху Снизу