Badoo corporate blog
High performance
Website development
Comments 51
+1
Хм, интересно, а почему именно C? Неужели не хватало производительности настолько?
+1
В основном это потребление памяти, нежели производительность. Но в целом производительность тоже важна.
+1
Да, Юра тоже прав. Если взять один из наших самых нагруженных сервисов, то суммарно на трех машинах он занимает в памяти около 1,3 TiB. Тщательное управление памятью в этом случае очень важно.
+3
Почему у нас больше всего демонов на Си?
Вопрос многогранный.
Во-первых, потому что мы хорошо знаем и любим Си.
Во-вторых, Badoo существует давно и 10 лет назад было такого большого выбора вкусных языков, как Go или Rust.
В третьих, у нас действительно очень высокая нагрузка. Мы, к примеру, в некоторых демонах используем JIT компиляцию для конвертации поискового запроса по битовому массиву в sse/avx/avx2 машинный код.
Сейчас же, если нам не требуется супер высокой производительности, мы предпочитаем Go.
0
О, ну поскольку тема Go на хабре очень популярна, то позволю себе спросить — насколько просадка по сравнению с С?
+5
У меня нет для вас готовых цифр и красивых графиков до\после, к сожалению.
Мы используем Go очень давно. На ранних этапах мы постоянно боролись с GC. Даже делали доклад на тему оптимизации Go на meetup, который проходил в нашем офисе. Но с каждой новой версией Go становится лучше и более приспособленным для высоких нагрузок и сервисов, которые используют много памяти.
Если говорить про Си VS Go в плане производительности, то Go, конечно, проигрывает. Но Go на порядки удобнее для программирования. Делать многопоточную систему на Go — удовольствие, а на Си — морока. Если посмотреть чуть шире, то за счет этого удобства вы сможете написать распределенную систему на Go, которая будет работать лучше, чем система на Си. Не за счет банальной скорости, а за счет того что к моменту как система на Go уже будет вовсю работать и работать отлично, на Си вы будете искать ошибки в многопоточном коде.
0
У нас в целом машины с демонами в процессор обычно не упираются. Но даже для случаев, когда CPU очень важен, никто не мешает использовать готовые библиотеки на Си, которые хорошо оптимизированы. Марко об этом не сказал, но вообще говоря у нас есть несколько демонов на го, которые именно так и делают. Например, используют RocksDB для хранения данных на диске, и при этом внутренние гошные структуры в качестве индекса и имеют много воркеров, которые с этими структурами как-то по-хитрому работают.
+1
Тоже используем ELK, правда доставляет всё logCourier, т.к. сервера в основном виндовые. А вы на riemann для алертинга не смотрели? Если не учитывать clojure и отсутствие кластерности, довольно мощная штука
+1
Нет, riemann мы пока не смотрели. Вы правы, clojure немного пугает. Но взглянуть стоит. Спасибо.
0
Мы используем Paasta для деплоя и мониторинга живости сервисов. Возможно на первый взгляд может показаться, что это слишком сложно и мутно, да оно сложно, но довольно сильно унифицирует все сервисы и принципы работы с ними.

http://engineeringblog.yelp.com/2015/11/introducing-paasta-an-open-platform-as-a-service.html
+1
Меня смущает строка «Мы выделили три сервера для кластера Elastic Search и настроили его так, чтобы каждый индекс имел одну реплику...»
Вы реплицируете индекс целиком? Один шард на индекс?
+1
Верно. Один индекс = 1 шард + 1 реплика.
Такое число мы выбрали сознательно, основываясь на документации, нашей задаче и некоторым статьям с рекомендациями в интернете.
Один шард — это один Lucene индекс, а поиск по индексу должен затронуть все шарды. Т.е. если два разных шарда находятся на двух разных нодах, поиск затронет обе ноды. Т.к. у нас один индекс на день и он не супер-пупер большой, то мы посчитали правильным ускорить поиск за счет использования одного шарда.
По вашему тону я могу судить что вы считаете это неправильным?
+1
Отнють. Просто поинтересовался этим моментом. Извините, если тон комментария показался резким.
При шардинге в ES поиск (и фильтрация) осуществляется параллельно на всех шардах, поэтому, потенциально можно получить профит в скорости, но при этом возрастёт нагрузка на узлы. Возможно использование роутинга запросов, при котором запрос отправляется лишь на определённый шард и не затрагивает другие. Но необходимо отталкиваться от специфики хранимых данных и задач их обработки.
Поэтому уверен, что вы всё сделали правильно.
0
Добавлю:
Мы тоже используем ELK, тоже ES для хранения логов развернули на 3-х серверах. Но решили, использовать 3 мастер-шарда (по одному на каждую ноду) и одну реплику, подумав, что в случае вылета узла, recover индексов займёт меньше времени за счёт меньшего размера шардов.
Спасибо за интересную статью!
0
При шардирование скорость обработки увеличивается, НО съедается место под словарь и управляющие структуры, так как он практически дублируется для каждого шарда.
А при вашем подходе у вас активен только один сервер в день, при выделенных.
Может 2 шарда на индекс + 1 реплика на шард.
А почему вы не поставите haproxy перед 2-мя logstash?
Основное отличие Graylog2 от Logstash, у него встроенный журнал Kafka, то есть сначала он пишет все в журнал, и только потом Elastic.
+1
У вас есть многострочные логи? И если да, то как вы их пишете в syslog?
0
Пока что стектрейсы не идут в syslog. В обозримом будущем мы или сделаем запись стректрейсов в виде одной строки или будем препроцессить их перед записью в сислог.
+1
если не в syslog, то logCourier и логсташ отлично справляются с многострочностью
0
Ты хочешь сказать что на Go не пишут плохих приложений? :-)
0
Да пишут, конечно. Просто среди проектов на го очень много приложений, которые позиционируют себя, как легковесные, легко интегрирующиеся со всем, чем можно, использующие стандартные механизмы… Ну ты понял :)
+1
syslog формат принимает многострочные логи, если откурывать сокет в UDP формате
+1
Нет, не рассматривали. У нас в данной задаче нет "зоопарка" разных систем, которые пишут логи. Собираются логи только наших самописных демонов, формат логов которых уже унифицирован.
Т.е., как мне кажется, для данной конкретной задачи fluentd просто не нужен.
+1
я про проблему отложенной записи в централизованное хранилище минуя syslog, это решение могло бы подойти
+1
Да, наверное. Т.е. в ту же категорию "потенциальных замен" syslog, если с syslog будут проблемы. Спасибо.
+1
Если говорить о нагрузке, то на данный момент в течение дня приходит от 600 до 2000 строчек с логами в секунду, с периодическими всплесками до 10 тысяч строчек. Данную нагрузку система переваривает без каких-либо проблем.

А можно поинтересоваться мощностью ваших машин выделенных под ELK стек?
+2
Конечно. Если кратко, то такая спецификация:
  • Intel® Xeon® CPU E5-2680 0 @ 2.70GHz — 32 ядра
  • 64 GiB памяти
  • SSD диски
0
Спасибо за статью. Тоже сейчас присматриваемся к ELK. Скажите, есть ли у вас в системе ситуации, когда один объект(запрос) проходит
обработку в нескольких сервисах?
Пример: пришел запрос от пользователя, он попадает сначала в сервис1, затем сервис1 в рамках обработки этого запроса обращается в сервис 2, сервис 2 лезет в сервис 3 и т.д.
Если да, то отслеживаете ли вы в логах историю его обработку в разных сервисах и как у вас это реализовано(можно ли вытащить все логи из всех сервисов по этому запросу и понять, допустим, какой сервис тормозил)?
0
У нас в Си отделе есть такие ситуации. Не так много, но есть. К примеру один узел кластера какого-либо сервиса может что-то спросить у другого узла или у под-сервиса. Но того, о чем вы говорите, у нас нет. Т.е. посмотреть что где тормозило можно только в большом масштабе, не по конкретному изначальному запросу. Но фича была бы классной, я согласен.
0
А почему лог за 26.03 почти на порядок больше, чем за последующие (27-29) дни?
+2
Имхо костыль на костыле:
  • не docker way для контейнеризированных демонов
  • блокирующая отправка сообщений в лог и каскадные падения
  • возможность потерять логи
  • нет стектрейсов
  • лишь слегка поднапрягшись, можно было бы сделать структурированную часть лога, которую пишет программист, и получить нормальный поиск по ней

Синхронные вызовы в event loop демона — непозволительная роскошь

Парни, ну это же азы...
Но мы не хотели тратить время на него и быстро сделали третий, т.е. начали писать в syslog по UDP

Зачем вообще нужны такие логи?


Пишите в локальные файлы или буферизирующий сервис, оттуда пробрасывайте куда хотите, таким образом развязав создание логов и их процессинг.
+2
Ваши замечания абсолютно верны, если строить всю инфраструктуру с нуля и у вас нет большого кол-ва уже существующих и работающих сервисов.
Когда вам нужно сделать что-то на летящем самолете, большую роль играет кол-во изменений которое придется сделать для достижения устраивающего всех результата.
Парни, ну это же азы...

Конечно азы. Но вы будете удивлены сколько разных подводных камней зарыто в libc. Выделение памяти в snprintf, если вы используете %f или блокировки для получения таймзоны в localtime_r(). Или как у нас, блокирующая запись в syslog(). Такие вещи не лежат на поверхности. Легко говорить "ну что же вы так" постфактум.
+1
если строить всю инфраструктуру с нуля и у вас нет большого кол-ва уже существующих и работающих сервисов.

Во многих случаях верное, это замечание сейчас вообще не релевантно.
Такие вещи не лежат на поверхности

Ничего не говорю про другие вещи, только про синхронную запись в асинхронном коде.
Как вы вообще обходились без логов, если у вас допускаются такие вещи?
0
Во многих случаях верное, это замечание сейчас вообще не релевантно.

Не согласен.
Как вы вообще обходились без логов, если у вас допускаются такие вещи?

У нас не допускаются такие вещи.
+1
Я правильно понял, что между локальными для физической машины rsyslog демоном и центральным демоном ЦОДа у вас был TCP? Ведь протокол syslog изначально подразумевает UDP.
+1
Скорее всего и сейчас между rsyslog-ами и сейчас идет tcp. На 100% не уверен. Возможно banuchka ответит.
UDP у нас только от сервиса к rsyslogd. Не потому что нам там так нужны свойства UDP или не нужен оверхед TCP, а потому что посылку по UDP проще сделать асинхронной.
+1
Я к тому, что ваша проблема с каскадным отказом возможно решалась не написанием "собственного syslog по UDP", а просто переключением связи между главным демоном цода и демоном машины в UDP режим. Да, вы бы теряли логи, но не теряли стабильность. Честно говоря я ни разу не видел случая, что кто-нибудь включал TCP на передачу syslog в сети.
+1
Эта проблема была решена чуть по-другому. Наши администраторы настроили очереди в rsyslog правильно. До какого-то момента они в памяти, потом на диске, а потом новые сообщения выкидываются.
+1
При использовании UDP в качестве транспорта для событий есть одна мелочь, на которую я нарывался. Протокол syslog предполагает необязательность поля TIMESTAMP. В этом случае метку времени обычно проставляет принимающая сторона, но UDP может задержаться в пути и так как никакого контроля очередности (как в TCP) нет, то пакеты обработаются в другом порядке, что может сильно осложнить исследование логов. Поэтому приложение должно проставлять таймстамп при генерации события, а принимающая сторона не должна эти стампы игнорить (а есть соблазн так сделать, чтоб синхронизировать логи от разных источников). Оригинальный код libc проставляет время, но сторонние реализации могут на это забить, а зря.
Вообще со временем в syslog засада. Поле таймстамп это просто текст. В этот текст должно вставляться смещение относительно GMT. Но на деле эта информация бывай кем-нибудь да дропится (особенно в собственных костылях), и в результирующий текстовый лог попадает локальное время клиента не пересчитаное во время принимающей стороны. Если у вас куча серверов работает в разных таймозонах тут вам придется походить по граблям. Ну или перевести все сервера в GMT (не всегда возможно, к сожалению).
+1
Тут нам проще. У нас есть время в оригинальном сообщении и мы везде и всегда используем UTC для времени.
0
Как я понимаю, ELK прекрасно решает задачи «показать крутой дэшборд полный графиков, чтобы сразу было видно общее здоровье систем» и «удобно и быстро посмотреть все сделанные записи по нужному критерию.» Но, скажите пожалуйста, а вот аналога классического tail -f вы на ELK не делали?
Возможно это неправильный подход, но у меня еще есть привычка что когда прилетел алерт, условно говоря, «у нас что-то с гладилкой кота, кот уже 15 минут требует, но все еще неглаженный» то первый же порыв — сделать некое tail -f /var/log/pet.log | grep -w cat | grep -vi meow (за'grep'ав до состояния когда выделено только самое важное и активность логов приемлема для глаз), посмотреть что там такое прямо сейчас творится, а затем так и оставить на соседнем мониторе, чтобы краем глаза можно было именно что вживую наблюдать происходящие процессы и изменения в них.
0
Мы так не делали и не делаем. Для tail заходим на конкретный сервер.
Но я предполагаю что такое делать нужно не в ELK, а до него. Транспорт должен такое поддерживать.
0
Спасибо за отличную статью! Скажите, есть ли планы открыть в опенсоурс вашу систему алёртинга для эластика?
0
Привет. Нет, пока нету. Мы ее встроили в наш внутренний бекофис и «вынуть» ее оттуда очень сложно.
Only those users with full accounts are able to leave comments. , please.