Как стать автором
Обновить

Комментарии 82

Используется ли собственная система статистики посещений, если да, то как она организована, как осуществлен сбор информации, аналитика. Используется Hadoop или иной инструмент анализа. Как организовано хранение данных статистики посещений?

Судя по трафику, GA должна вылететь в копеечку.
Вот, недавно смотрел.
DevConf 2014. Валерий Старынин, Badoo. StatsColle…: youtu.be/iO0rDdqB3pU
Как устроена система мониторинга работоспособности всех частей проекта? Как вы узнаёте, что что-то сломалось и кто должен это чинить?
Ни знаю как в Badoo. Но в нашей компании используют Sentry для того что-бы узнать что что-то сломалось, довольна удобная штука, сейчас даже не знаю как мы без нее раньше обходились.

getsentry.com/welcome/
github.com/getsentry/raven-php

Zabbix, Pinba, сбор разных метрик и анализ аномалий поверх. Проблема «кто должен чинить» как правило из-за того, что у нас недостаточно данных, чтобы определить точно, в каком компоненте проблема и привлечь к работе конкретных людей. У нас почти никогда такой проблемы не стоит — этим и отличается хороший мониторинг от плохого. Хуже, когда замечена аномалия в продуктовых показателях — но тут всегда копает команда, которая отвечает за соответствующий продуктовый компонент.
Интересный вопрос как, вы реализуете нагрузочное тестирование и тестирование крупных кейсов

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

нагрузочное тестирование:
На днях был случай, программист написал sql запрос, все работает хорошо… вакатили задачу на прод, прошло несколько дней (было затишье не было народу на сайте), тут набежал народ… и из-за этого sql запроса у нас все порушилось, 504 ошибка, mysql полностью сожрал всю память.

Собственно вопрос: какими инструментами лучше проводить нагрузочное тестирование, когда тебе нужно проверять разные случаи (когда пользователь авторизован, когда пользователь авторизован но не имеет подписок, когда куча подписок, у пользователя куча постов....)

Нагрузочное тестирование — это миф. Лучше выкатывать на части аудитории и использовать мониторинг, чтобы обнаружить проблемы — latency на серверной или клиентской стороне, slow queries, запросы не по индексам и тд. А кривая архитектура не должна проходить ревью.
я правильно понял, вы выкатываете серверный код на разные аудитории? так сказать А/В тестирование backend?
да, но не для всех задач, конечно.
Динамическое добавление/удаление нод при плавающей нагрузке. За и против? Спасибо.
Плавающая нагрузка в смысле новостной сайт и выборы президента США? Это единственный сегмент, где вопрос действительно стоит остро, причем здесь весь выбор идет между стоимостью владения своей инфраструктурой и удобством аренды чужого облака: чем сложнее приложение тем выгоднее иметь его на своем кластере с точки зрения operations. Простой формулы нет, надо просто садиться и считать, что выгоднее по деньгам.
Добрый день. Вопрос по моему сервису, который сейчас переписывается «с нуля». Основной язык — PHP. Ниже я опишу свой велосипед, хотелось бы получить совет по архитектуре.

(Чую, отправите меня гуглить «очереди заданий на PHP», но как-то пока ничего нравящегося не нагуглилось, почему и решил спросить.)

Длинно получилось
Я занимаюсь обработкой текстов. Этапов обработки очень много: получить текст (если он в формате pdf, ps, doc, docx, rtf, html и ещё куча — преобразовать в текст); проверить кодировку, перегнать в UTF-8; убрать мусор (двойные пробелы, множественные переносы итп); сделать нормальную разбивку по абзацам; тегирование; лемматизация; куча статистики на выходе в разных форматах — от числа символов и слов до отдельных файлов с данными. Часть алгоритмов обработки сделана на PHP, часть — внешние утилиты, выдачу которых ещё часто приходится обрабатывать, часть — сервисы (демоны), висящие на сервере.

Сейчас у меня для каждой мелкой задачки сделан класс («процессор»), который ожидает определённый файл на входе и выдаёт файл(ы) на выходе, либо модифицирует данные в БД. Например, принимает текст, приводит его к UTF-8 и записывает обратно. Либо принимает EPUB, вызывает внешнюю утилиту и преобразует его в текст, записывает на ФС. Либо принимает текст и пишет в БД число символов. Управляет всем этим отдельный «диспетчер». Очевидно, что если на каком-то этапе мы фейлимся, то следующий обработчик не запускается, в БД пишется код и описание ошибки.

Прямо сейчас (в непубличной dev-версии) каждый новый файл, поступающий на обработку, сразу начинает обрабатываться. Очевидно, это плохо, так как можно элементарно перегрузить сервер уже 5-10 одновременными файлами. В ближайших планах сделать так, чтобы всё работало в один поток. Т. е. если обработка какого-то файла уже начата, то просто не отправляем следующий, а завершаем работу. Тот скрипт, который занимается обработкой, по завершении проверит, что в очереди есть новый файл и начнёт обрабатывать его. (Правильно организовать локи и всякие защиты от вылетания скриптов я в состоянии.)

В общем, суть вопроса в том, что всё это потребует дополнительных усилий для разбиения обработки на 2+ потока (по числу свободных ядер, например). Ну и есть ощущение, что я делаю работу, которую кто-то уже должен был сделать. Посоветуйте, что можно использовать для управления такими очередями задач.
Amazon SQS
RabbitMQ
любая другая очередь вам подойдет
Скорее всего, RabbitMQ — то, что надо. В идеале, хотелось бы немного попроще, конечно. Если сравнивать, RabbitMQ — это многофункциональный трактор, а я хотел бы просто тяпку :-)

В идеале хочется демон, который умеет принимать новое задание в очередь (например, просто строку текста). И по факту принятия задания запускать внешнюю программу, передавая ей задание как параметр. Ну и потом надо отслеживать, конечно, что процесс не умер, убивать его, если он «завис», запускать обработку в N потоков. По идее, то, что мне надо, должно иметь 2 настройки: внешняя программа-обработчик и число потоков. RabbitMQ — хорошая штука, но писался он для более сложных решений, поэтому я немного боюсь его использовать. Может, конечно, «фатальный недостаток» сказывается.

Но за ответ всё равно спасибо.
Работал с SQS. Имел демона который ждал сообщение с очереди, если нет — sleep(5), если есть — работал с сообщением. Каждую минуту крон вызывал скрипт который проверял живой ли еще мой демон или нет. На самом деле когда немного с таким поработаешь, то уже все не выглядит таким сложным, страшно начать разрабатывать такую систему :)
Ну, у меня сейчас даже немного лучше работает в продакшене — нет sleep(), есть отслеживание изменений в директории (соответственно, процесс «спит», пока в директорию не пришёл новый файл). В итоге, после поступления задания обработка начинается мгновенно. Иногда даже бывает, что после загрузки (мелкого) файла человек возвращается на список файлов, а он уже обработан, пока http-редирект шёл. Писалось на java+bash, с отслеживанием состояния задачи, «гашением» зависших задач и проч. Но — один поток. По идее, для N потоков переписать — дело пары дней. Вот почему и интересуюсь, может, кто уже написал что-то такое на си. Сложным оно не выглядит, но самому делать такое немного странно.
Велосипед работает :) Но лично мне кажеться что очереди именно для этого и делались.
beanstalkd, gearman? Сам использую beanstalkd для очереди обработки видео, по сути очень близко к тому что вы описали. А также в зависимости от того в какую очередь кинули событие, запускает парсеры/перелопачивание базы.
Вот за этот комментарий большое спасибо. По описанию beanstalkd очень нравится. Буду пробовать.
Этот класс продуктов называется «сервера очередей».
В badoo традиционно для transaction-based событий используются mysql-based очереди, потому что они очень просты в отладке и заворачиваются в транзакцию на шардах, т.е. событие или несколько событий либо проходят вместе с изменениями, либо так же вместе откатываются — то есть никогда не происходит не-целостных состояний. В противном случае куча граблей. Если кролик слишком сложен, вы можете использовать очереди через списки в Redis.
Есть ли в Badoo кодревью? Как он организован?
да, реализован через gitphp, со своими доработками и оптимизациями habrahabr.ru/company/badoo/blog/200946/, организован через кастомный jira-flow.
картинка выше — толстенный троллинг для тех, кто в танке.
Используется ли в Badoo виртуализация окружения для разработчиков?
Что-нибудь типа Vagrant или Docker. Если да, то хотелось бы подробностей.
Вы же не используете Denwer, верно? :)
Денвер не используется. Виртуализация используется (docker), но не для девелоперского окружения. Девелоперы работают на специализированной прощадке, где вся инфраструктура продакшена повторена в миниатюре (включая и шардированные базы, и несколько виртуальных датацентров). Касательно отправки контейнера прям с машины девелопера последовательно на стейджинг, а потом в прод — этот проект для нас не актуален, посколько даже при двух релизах в день в релизную ветку попадает код от очень многих девелоперов.
Можно уточнить про «специализиованную площадку»? Она общая для всех девелоперов или для каждого своя? Если общая, то как построен процесс выкладки кода, проверки кода перед комитом?
для всех девелоперов
вот тут мини-дц за ресепшеном img-fotki.yandex.ru/get/6511/2438272.13/0_7a2c2_d052677f_XL

чтобы рассказать про процесс коммнтария мало, да и очень много уже рассказывали — смотрите посты в корпоративном блоге и доклады с sqadays, рит, loveQA
например
habrahabr.ru/company/badoo/blog/190572/
или тут profyclub.ru/docs/220
Вы могли бы проконсультировать по хранению данных мониторинга с привязкой к объектам учета, формирующихся ежедневно с тысяч устройств?

За сутки с одного объекта учета приходит порядка 5-6Мб. данных. Сервисом они обрабатываются и превращаются в временные промежутки использования каждого показателя. Данные накапливаются и превращаются в историю использования объектов учета, где состояние доступно за промежуток времени по выбору пользователя.

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

Вопрос по адресу?
Вопрос по адресу, но не до конца понятно, в чём конкретно у вас проблема: не влезают данные? Это странно — одного терабайта (стандартный диск) должно хватить на годы. Не нравится делать специальные аналитические таблички? Не бойтесь, это нормально. Короче, поясните, пожалуйста, вопрос.
Как в Badoo мониторят доступность для посетителей? Не секрет, что даже если на сервере все в порядке, клиенты могут быть недовольны из-за проблем с каналами. Мониторите ли вы время отклика (загрузки) сайта и какими методами?

И более практический вопрос — а как бы вы организовали мониторинг не одного сложного сервиса (Badoo), а множества простых сайтов (скажем, мониторить реальную доступность для постителей клиентских сайтов на хостинге). Если просто «пинговать» сайты из нескольких ДЦ — это не слишком отражает картину для пользователей.
У нас есть продукт называется jinba — это клиент-сайд агент для pinba (сервер статистики), который собирает client-side статистику. Мониторим всё — в каких странах, какие страницы/сервисы. У Паши Довбуша есть доклады, например вот совсем старенький www.slideshare.net/dppsu/pavel-dovbush-toster. Сеть небольших сайтов — со стороны сервера мониторинг понятно как, а клиента — да так же ониторил бы либо готовые стат-счетчики либо через что-то подобное своё с аггрегацией.
Есть ли у вас инструмент для автоматического разворачивания полноценного тестового окружения?(например для тестирования системы целиком). Как при этом наполняется данными тестовая БД? Будет ли приложение работать с тестовой БД, созданной из схемы? (без данных)
У нас несколько ДЦ и три тысячи серверов. Того, что вы спрашиваете, для нас просто не нужно, выгоднее иметь свой мини-дц. в котором повторен продакшен в миниатюре.
А как Вы используете свой продукт в daily жизни? Какие задачи решает ваш сервис лично для Вас? Назовите причину — почему люди пользуются вашим сервисом?)
Имеется ли защита от качальщиков/парсеров/грабберов и тому подобных скриптов для выкачивания контента. Если да, то как она устроена?
Как автоматически забанить «плохой IP», но при этом не навредить новым поисковым роботам.
К сожалению, по понятным причинам мы не раскрываем логику анти-бот и анти-спам систем. Они, разумеется, есть ;)
В нашем сервисе, у нас есть необходимость добавлять/убирать сервера занимающиеся кодированием видео в зависимости от нагрузки. Сейчас мы это делаем практически вручную.
Есть А как происходит подбор мощностей в Badoo? Есть ли в Badoo фоновые задачи, объем которых не всегда предсказуем?
Мы считаем, что лучше что-то сделать руками, но полностью прогнозируемо, чем автоматически, но хз как. В самой автоматизации нет ценности, вопрос в том, какие риски и трудности она снимает. Нужно ли вам уходить от ручных перераспределений — решать вам, я вашего процесса и характера годовой нагрузки не знаю. Мы в какой-то момент всё-таки решили, что нам ужно перераспределение нагрузки для оффлайн-скриптов — мы сделали облачное решеное (потратили кучу времени, к сожалению, но получилось вроде бы полезно и удобно). Каждая группа разработки получает часть облака в пользование (чтобы не мешать другим группам), внутри рапределение нагрузки и «перетекание» скриптов с ноды на ноду при отказах происходит автоматически.
Очень интересно узнать про проектирование, конкретно — высоконагруженных backend-сервисов.

Как организована архитектура и процесс проектирования? Ведете ли проектную документацию? Насколько она детализирована — что в ней раскрывается, что остается за бортом, насколько подробно все это описывается (речь про структурные схемы/блок-схемы с описанием/описание протоколов и форматов взаимодействия внутренних и внешних компонентов)? Как определялись эти стандарты? Какие средства используются, как ведется версионирование?

Вопрос не на пустом месте, есть вполне реальные проблемы. Например, разработка/тестирование/маркетинг рвут на части в надежде получить одно универсальное техническое решение на всех в виде объемного документа, вполне вероятно — избыточного. В итоге у нас получается так, что описание простого сервиса, где смысла конкретно для разработчиков где-то на пару страниц, разрастается до двадцати — зато из-за долгой подготовки документов возникают проблемы со скоростью передачи техрешений в разработку. Поэтому послушать о том, как построен этот процесс у других, было бы очень полезно.

Ну и небольшой вопросик вдогонку — как там на сегодняшний день обстоят дела с Go? Появился ли в продакшне, удалось ли «забороть» все проблемы с garbage collectorом?
Процесс разработки и подходы давно устоялись, нужды описывать архитектуру именно с точки зрения реализации до начала работ по самой реализации часто просто нет, это адовые затраты. Перед передачей задачи в разработку пишется только PRD — как всё должно работать с продуктовой точки зрения, с макетами и тд — это позволяет не только убрать проблемы при переключении ответственности на разработку, но пораньше подключать фронтенд, BI, тестирование, переводчиков. Для внутренних и инфраструктурных задач часто даже PRD не пишется, таким образом программист становится продуктовым совладельцем (в этом есть и плюсы и минусы, но надо понимать что здесь продукт — это не сайт, а наши инструменты по мониторингу, анализу проблем, веб-интерфейсы к облачной инфраструктуре и тд). Go в продакшене есть, причем уже в некоторых очень важных местах, с GC у него всё так же («нам норм»), но тут наверное лучше ответят сишники.
Go есть в продакшене, в том числе в «критичных» для продукта моментах.
Наличие проблем с GC сильно зависит от самого приложения, т.е. от того, что вы выбираете писать на Go.

Мы выбираем Go там, где есть существенные преимущества перед event based callback hell подходом, например в сетевых сервисах типа «сходи в 10 источников параллельно, обработай данные, сходи еще в 5 и выдай ответ клиенту» (в нашем случае клиент, чаще всего, php). Или там где есть достаточно сложная логика, которую муторно писать на C, но нехватает производительности php.

В качестве анекдота — написали свой sort --merge на Go и обгоняем его в ~5 раз на наших текстовых данных и объемах (за счет простой параллелизации обработки).

С другой стороны если нужен «контроль памяти» (a-la memcached — есть X гигабайт, надо их максимально эффективно использовать), или «нужно обрабатывать 200 миллионов сравнительно короткоживущих объектов» — имеет смысл аккуратно тестировать, прежде чем пускать это в продакшен.

У нас нет «серебрянной пули» борьбы с GC, стандартные вещи — поменьше указателей, иногда отказываемся от «красоты» взаимодействия через каналы (улучшения грядут в 1.4 правда) и профайлим, профайлим, профайлим.
Например gogoprotobuf вместо goprotobuf, linked lists «ручками», хотим попробовать что-то типа bouk.co/blog/idiomatic-generics-in-go/.
Какие минимальные требования по железу, под какие задачи? Во что упираетесь?
Патчите ли ядро Linux, какие используете настройки под высокие нагрузки? Что отключаете?
Какие наиболее частые рекомендации на больших масштабах бесполезны или вредны?
Упираемся в проц и кое-где в память, реже в диск. Отсюда требования по железу — зависит от того, в какой кластер оно пападает, но если грубо, то обычные тачки делятся на «база» и «не-база». Базам просто идут в нагрузку хорошие диски. Ядро, кажется, патчили патчами от гугла (сетевой стек, лучше сишники ответят). Бесполезна рекомендация использовать одинарные кавычки вместо двойных (простите, какой вопрос — такой и ответ).
Не хотите запустить полноценный Highload AMA (Ask Me Anything)? :)
хочу! :)
Фиш, ты же вроде уже запустил его?
www.facebook.com/groups/feedme.ru/
Или в группу пускают по талонам?
Вопрос к Алексею Рыбаку.
Вопрос по организации универсальной части слоя модели.

Вот на вашем сервисе бизнеслогика оперирует какими-то объектами — юзерами, связями, сообщениями, комментариями, оценками и т.д. У каждого объекта есть свойства. И всё это должно быть защищено транзакционно.

Типовые задачи: вытащить объект из хранилища (mysql+memcache, полагаю) — 98% запросов, скажем.
И изменить одно или несколько свойств объекта — 2%.
При чём есть ещё ряд правил вида «если свойство a1 объекта класса A изменилось с <0 на >0, то найти объект класса B с ид-ром равным значению a2 нашего объекта, и, скажем, инкрементировать его свойство b1».
При чём в БД мы триггерами такое реализовать не можем, т.к. об этих изменениях тогда не узнает кеш. Т.е. это должно быть в коде.

Мы делаем так (пример):
[Слой универсальной части модели]
1. При изменении объекта сначала происходит SELECT… FOR UPDATE, чтобы застолбить строку нашего объекта в транзакции и точно знать, с каких значений мы меняем.
2. Делаем UPDATE, если он вернул, что изменения были (т.е. это не дублирующее изменение значения с 1 на 2), то на них нужно отреагировать.
[/Слой универсальной части модели]
[Слой конкретной реализации модели объекта конкретного класса]
3. Получаем данные об объекте класса B.
4. Инкрементируем в нём поле b1 (этим занимается универсальная часть):
[/Слой конкретной реализации модели объекта конкретного класса]
[Слой универсальной части модели]
5. SELECT… FOR UPDATE.
6. UPDATE.
[/Слой универсальной части модели].

Это что касается работы с mysql. Но ещё нужно держать актуальным значения в memcache, а он ничего не знает про транзакции в mysql. Поэтому, когда изменяются данные в какой-то транзакции, мы создаём в memcache для конкурирующих потоков для нашего объекта ещё один ключ, наличие которого означает, что кеш этого объекта пока невалиден, и за данными объекта надо сходить в БД. И по окончании транзакции мы этот ключ убиваем. Если транзакция зафейлилась, то убивается и сам кеш, т.к. в нём получатся неправильные данные, которые в mysql уже откатились.
Т.о. при чтении из кеша мы читаем всегда заодно и этот ключ.

Короче, я хочу спросить не столько про конкретную реализацию, сколько про подход. Наш подход мне кажется слишком переусложнённым. Поэтому я хочу, например, попробовать вместо мемкеша использовать чтение через handler socket, чтобы избавиться от проблемы синхронизации данных в мемкеше и базе.
Но интуитивно я чувствую, что можно как-то совсем просто всё это делать. На уровне вот того универсального слоя сделать как-то так, чтобы его контракт остался тем же, но он стал простым как топор и быстрым как лань.

Как это делаете вы?
Как нормально красиво синхронизировать данные в БД и мемкеше с учётом того, что мемкеш ничего не знает про транзакции БД?
В идеале ещё и не делать ниодного лишнего запроса в БД и кеш =).

P.S.: извиняюсь за сумбурное изложение проблемы =).
Поэтому, когда изменяются данные в какой-то транзакции, мы создаём в memcache для конкурирующих потоков для нашего объекта ещё один ключ, наличие которого означает, что кеш этого объекта пока невалиден, и за данными объекта надо сходить в БД

Поясните пожалуйста, что Вы делаете, когда несколько процессов изменяют один объект. Одному удастся создать дополнительный ключ в кеше о невалидности основного ключа, а остальные ждут и периодически проверяют не исчез ли дополнительный ключ? И зачем этот ключ, если в БД то же самое что и в кеше пока транзакция незакоммичена?

Мечтаю об энджине для MySQL сбрасывающем кеш при коммите.
Одному удастся создать дополнительный ключ в кеше о невалидности основного ключа, а остальные ждут и периодически проверяют не исчез ли дополнительный ключ?

Нет, конкуренты не ждут, а сразу идут в БД, которая отдаёт им данные, валидные на момент до начала транзакции.

И зачем этот ключ, если в БД то же самое что и в кеше пока транзакция незакоммичена?

Чтобы не прочитать из кеша данные, которые ещё не закоммичены в БД.

Вот пример, который затрагивает интересные кейсы:

Поток 3: прочитал основной кеш и кеш-флаг. Оба пусты.
Поток 3: прочитал данные из БД.
Поток 1: выставил кеш-флаг в положение «кеш занят».
Поток 1: записал новые данные в БД и в основной кеш (транзакция в БД не закрыта).
Поток 2: прочитал основной кеш и ключ-флаг.
Поток 2: видит, что ключ-флаг в значении «кеш занят», поэтому игнорит основной кеш.
Поток 2: читает значение из БД.
Поток 2: не пишет основной кеш, т.к. помнит, что там был флаг.
Поток 3: хочет закешировать то, что он прочитал из БД. Для этого ему нужен основной кеш в эксклюзивный доступ.
Поток 3: пытается поднять ключ-флаг, но у него не выходит. Поэтому он вздыхает и отказывается от идеи закешировать данные из БД.

Теперь два варианта исхода:
Вариант А:
Поток 5: когда-то давно прочитал данные из БД, т.к. кеша не было.
Поток 1: транзакция успешно коммитится.
Поток 1: после коммита удаляет кеш-флаг.
Поток 4: читает из кеша свежие данные.
Поток 5: решает закешировать то, что он когда-то прочитал из БД. Пишет, но его запись в мемкеш не проходит по cas'у, т.к. туда уже писал другой поток (№1).

Вариант Б:
Поток 1: транзакция откатывается.
Поток 1: удаляет сначала основной кеш, а потом кеш-флаг.
Остальные потоки: не видят данных, которые существовали во время транзакции, которая откатилась.

Мечтаю об энджине для MySQL сбрасывающем кеш при коммите.

А если вообще не использовать мемкеш, а читать данные из БД с помощью mysql handler socket, можно добиться ведь примерно той же скорости, что и с использованием мемкеша. И при этом не нужно заморачиваться синхронизацией транзакций мускла в мемкеш.
Все проблемы решаются удалением кеша при любом изменении в базе + в ряде случаев нужны-таки блокировки или операции, содержащие блокировку неявно, или lock-free подходы, но таких ситуаций вообще меньшинство, поэтому делать эти операции по умолчанию — зло, так как этот метод по-моему «заумен» и чреват ошибками, тяжелой отладкой, делает каждую транзакцию более «тяжелой». Ещё здесь есть ньюансы для нескольких ДЦ (инвалидация закешированных данных со слейвов в «чужом» дц), но это уже такие частности, на которые наступает 0%. Спасибо за вопрос!
Все проблемы решаются удалением кеша при любом изменении в базе

Но если данные меняются часто, кеш будет работать неэффективно же.

+ в ряде случаев нужны-таки блокировки или операции, содержащие блокировку неявно

Это вы в каждом случае отдельно пишете, или есть какой-то базовый поход, например, вида «тут у нас началась транзакция, поэтому все затрагиваемые объекты получают блокировку до конца транзакции»?
Если объект изменяется часто — кеш неэффективен независимо от того, как вы сделали кеширование. Если нужна псевдо-консистентность, есть достаточно стандартные паттерны — через тот же cas, блокировки на базах, как Вы написали выше. Не уверен, что есть какой-то стандартный «метод», но таких паттернов всего ничего.
Ок, принято. Спасибо.
Извините, а можете пояснить? «Мы создаём в memcache для конкурирующих потоков для нашего объекта ещё один ключ» — для какого объекта, A или B? Собственно, непонятно, как вы решаете проблему того, что вытянутые из кеша A и B будут из разных транзакций (версий).

Мы подобное решаем «тегами» в мемкеше (но проблема, озвученная выше, остаётся). Решение, похожее на ваше, но чуть более похожее на «слой абстракции». Каждый ключ в мемкеше может зависеть от произвольного числа тегов. В вашем случае оба объекта: a[id=123, a2=456] (ключ в мемкеше a#123) и b[id=456] (ключ в мемкеше b#456) будут зависеть от тега a#123 (ключ в мемкеше %a#123). Когда вы обновляете тег (а делается это сразу после коммита в БД), значение ключа %a#123 выставляется в текущее время. Каждый раз, когда вы читаете a#123 и b#456, читается и проверяется также значение тега %a#123. И если если кеш был записан раньше, чем обновился тег, значит, кеш устарел. Разумеется, в мемкеше живёт время записи каждого ключа. Но в нашем решении мы не защищены от того, что после чтения a#123 мы прочитаем b#456 из другой транзакции.

PS Не имею отношение к Badoo.
для какого объекта, A или B?

Вообще для каждого кеша, который мы собираемся менять, создаётся такой второй ключ.
В моём примере мы меняли оба объекта, поэтому создаётся по ключу для каждого.
Т.е. как только мы записали в базу в транзакции изменения (но ещё не коммитили), но перед тем, как записать эти изменения в мемкеш, выставляем в мемкеше этот флаг, чтобы никто этим кешом пока не пользовался. Потом пишем в мемкеш инфу, которую записали в базу, но которую из-за транзакции никто другой пока не видит. И чтобы и в мемкеше никто её не видел, этим флагом запрещаем принимать во внимание содержимое этого кеша.
Мне кажется, в вашей реализации в мемкеше болтается куча неактуальных данных. Они ж память занимают.
ОК, спасибо за ответ. У вас всё действительно транзакционно защищено. Но, если я правильно понимаю, требует большого внимания разработчиков — т. е. есть много ручной работы, которую надо не забыть сделать. Суть вопроса понятна, решения также нет.

Я бы, если смотреть «навскидку», делал архитектуру, привязанную к событию обновления данных — чтобы разработчик сразу и в одном месте указывал, каков запрос обновления (UPDATE) и какие ключи в кеше отвечают за этот объект. При коммите вся информация об обновлённых данных сводится воедино, и перед выполнением commit/rollback прослойка, отвечающая за работу БД, разбирается с мемкешем. Т. о. класс БД начинает отвечать за инвалидацию кеширования. Может быть, конечно, я не учитываю чего-то. За вопрос спасибо, вопрос хороший, заставляет задуматься :-)

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

Нет, всё описанное выполняет базовый слой модели, а разработчик только говорит этому слою, какие поля каких моделей каких объектов на что менять, и как реагировать на изменения для сохранения консистентности состояния объектов друг относительно друга.
Но это всё равно громоздко всё. И медленно.
Если данные сравнительно легко изолировать от остальной части системы (грубо — вытащить из базы), то вполне можно попробовать класть это дело в tarantool тот же и написать lua процедур, которые будут управлять этим делом. Все будет персистентно, но «база» и «кеш» в одном месте, так что не надо заботиться о синхронизации.

Минусы понятные — усложнение инфраструктуры, отдельный код (у вас сайт не на lua наверняка? :)) которым надо рулить/ревьюить/выкладывать.

Второй момент, в вашей сложной логике обновления данных с зависимостями от других данных — нужна ли полная синхронность обновления зависимых объектов вместе с основным?
Если нет — то очереди выглядят хорошим решением, обновляем только основной объект, вместе с этим обновлением — кидаем событие в очередь и уже отдельно применяем зависимые обновления.
нужна ли полная синхронность обновления зависимых объектов вместе с основным?

Во многих местах пока нужна. Асинхронность сильно всё усложняет, поэтому по-дефолту у нас всё синхронно меняется. Но тяжёлые куски откладываются в очередь, да.
С откладываением в очередь, кстати, ещё есть одна проблема, уже с отладкой: мы никогда не увидим полностью консистентную базу.
Извечный вопрос о мелкой статике,
Представим диск на много терабайт, с большим количеством мелких файлов, 1-50 КБ, со средним размером 4 КБ.
Как правильно организовать собственно раздачу этой статики.
Под словом «правильно» понимается наибольшее значение отношения (эффективность / затраты).
В свою очередь применял следующие техники.
1) Поскольку как правило все упирается как правило в IOPS, придумывал методы хранение популярных файлов на SSD (таким образом получаем трехуровневое кэширование, память, ссд, хдд). Тут возникают вопросы о том как эффективно определять популярные файлы, и обновлять кэш.
2) Разработка такой структуры, при которой файлы равномерно расположены по папкам (не более 255 файлов в папке), при этом возникали проблемы что если делать глубокие папки, то это занимает достаточно большое число inode, тут возникает вопрос, о том как рассчитывать количество файлов в папке, и глубину папок.
3) Форматирование диска таким образом, чтобы весь файл попадал в один блок (при среднем размере файла 5 кб)
4) Естественно по максимуму отключение различных использующих IO сервисов.
5) Возникают вопросы отказоустойчивости, в т.ч… горизонтального масштабирования и дублирования информации, как организовать дублирование многих миллиардов файлов, ибо копирование и синхронизация может занимать недели и месяцы (как правило из за низкого IOPS hdd). Мной использовался метод, похожий на работу кэширующего CDN.
6) Разбивка на большее количество независимых RAID массивов с зеркалированием. (Собственно зеркалирование для отказоустойчивости, независимых для повышения IOPS)

На этот вопрос, сотрудник яндекса мне ответил, что все решается просто, покупкой новых серверов. Это конечно верно, но оптимизация может помочь хорошо сэкономить.
Понравилась идея файсбук, где на блочном уровне используется кэширование в SSD.
Мне кажетчя, что у Вас в кучу смешано несколько вещей, и я не смогу ответить сразу на всё. Фейсбучный патч ядра для кеша на SSD вообще нужен для операций записи, это не про статику. Со статикой надо определиться, какая у неё природа, это UGC или нет? Ну и влезает она в память или нет? Если влезает — там нет дисковой нагрузки и вопрос просто снят. Если не влезает — либо сделать так, чтобы влезало, либо делать слой кешей с проксированием, всё остальное вокруг дисков без кеш-проксей не будет толком работать в промысленных масштабах.
Вопрос: как устроена система хранения и анализа логов в Badoo?

Насколько я знаю, для сбора информации по времени выполнения запросов вы используете Pinba, но это скорее к мониторингу и профилированию. Меня больше интересуют такие кейсы: например у некоторого юзера проблемы с тем, что он выполнил такие-то такие-то действия, а в итоге получил не то, что хотел, и надо разобраться, почему так получилось. Собственно, если вы ведете логи пользовательских действий, то как вы их храните и как осуществляете поиск по ним? Может быть используете какие-то специализированные решения или же просто пишете текстовые логи и потом grep-ете по ним?

У нас на проекте мы используем связку logstash + elasticsearch + kibana. Каждый из API backend-ов пишет логи в формате JSON в rsyslog, который переправляет их на специализированный сервер, где они парсятся logstash-ем и пишутся в индекс поискового движка elasticsearch. Проблемы большого количества логов решаются встроенным механизмом автоматического шардирования индексов. Для каждого запроса на nginx-е генерится некий уникальный идентификатор запроса, который затем проталкивается на API backend (если backend создает какую-то отложенную background задачу — то проталкиваем этот идентификатор в эту задачу), и потом через интерфейс kibana собираем все реакции системы на некий запрос по его идентификатору.
Почти везде транспорт скрайб с продакшн-нод, а дальше свои обработчики — где-то в базу со своей системой анализа поверх, где-то в splunk, а аналитика, пользовательские действия в hadoop. Там несколько миллиардов событий в сутки, грепать — это будет сильно :)
Какие средства Business Intelligence вы используете? Есть ли у вас собственные разработки в области BI? Есть ли у вас собственный web-client для работы с аналитикой, или же это просто Excel + SSAS (как пример)
Если говорить о системах Business Intelligence, то у них есть грубо три компонента: (1) собственно сбор данных и ETL (extract-transform-load), (2) хранилища данных и (3) аналитические инструменты и отчеты. Какие-то области перекрываются, но по сути, это три разных сегмента со своей жизнью, своими продуктами и рынками. У нас есть свои разработки, недавно мы внедрили собственный ETL-фреймворк, который позволил значительно упростить разработку рутинных компонент (фактически, язык сценариев). Но стратегически мы выступаем как пользователи, которые хотят построить систему и хотя бы года три ничего не менять, на наших объёмах это правда очень затратно по всем статьям. Могу сказать, что в Badoo сейчас второе поколение BI-системы за 4 года, сейчас: транспорт построен через Scribe + множественные утилиты собственного производства для (1), Hadoop и колоночная база Exasol для (2), MicroStrategy для (3). Где-то используется не MicroStrategy, а собственная визуализация поверх D3 (и производных от D3).
Интересует следующее.
Проект у вас сложный. Документации, кода и используемых технологий думаю много. Вместе с тем (не знаю какая у вас текучка), но как обстоит дела с преемственностью и вводом в курс дела нового пополнения.
По моему опыту заканчивалось столом, стулом компьютером и доступом к коду. За частую, это приводит к сильному увеличению времени “вливания” в новый проект. Редко кто объяснял или рассказывал, иногда в общих чертах. На многие вещи не было документации. При чем многие части ПО разрабатывал не один, многие уже уволившиеся программисты.
Часто ли сталкиваетесь с проблемой – “а, проще переписать с нуля”? В том числе из опыта доработок вашего фрейворка.
Как построены процессы взаимодействия с техническими писателями?
Далее.
Как вы относитесь к новым версия серверного ПО?
Как часто обновляете и используете ли последние версии (PHP, MySQL, Nginx и прочее)?
Как организуете тестируете новых окружений?
Присоединяюсь к вопросом о нагрузочном тестировании и окружениях для разработки. Применяете ли боевые базы при разработке для выявления поведения “кривых” запросов и т.д.
очень много вопросов, кратко:
— «переписать с нуля» — это нереально, к тому же мы проектировали всё после опыта мамбы, где мы наступили на кучу граблей, в результате сделали всё достаточно грамотно и у нас ядреные компоненты не меняются уже 8 лет, при росте с 0 до более 200 миллионов юзеров
— писателей нет
— относимся хорошо, стараемся не отставать и мигрировать, но не чаще n раз в год (для базы — 1 раз в пару-тройку лет, для php и nginx — может и 5 раз в год, статистики под рукой нет).
— про тест уже отвечал — см. ссылки
— нагрузочное тестирование отвечал, считаю, что это миф, какие-то базовые вещи можно проверить в кластере на коленке (натравить бота в кучу потоков), остальное лучше смотреть в продакшене
Добрый день, я хотел бы получить консультацию по следующему вопросу

Перед нами стоит задача построения отказостойчивой и масштабируемой системы хранения данных от системы обнаружения инцидентов. Система производит постоянный мониторинг большого кол-ва точек и в случае обнаружения инцидента заносит информацию по нему в хранилище. У инцидентов примерно следующие х-ки:
— Каждый инцидент привязан к определенному клиенту и характеризуется помимо времени обнаружения небольшим кол-вом целочисленных аттрибутов;
— Среднее кол-во инцидентов, собираемых в рамках одной итерации проверки системы мониторинга, составляет на текущий момент порядка 30 млн (эта величина может быть увеличена в разы при добавлении новых типов инцидентов или увеличении кол-ва точек, для которых производится мониторинг). За сутки система мониторинга может проводить несколько итераций проверки;
— Кол-во клиентов, для которых собирается статистика по инцидентам, порядка 50 тыс. Распределение кол-ва инцидентов по клиентам очень неравномерное (но есть возможность сделать грубый прогноз по ожидаемому порядку кол-ва инцидентов для каждого нового клиента).

Операции с данными:
OLTP (кол-во конкурентных запросов к данным невелико, до 100 запросов в секунду, запись до 5-10 тыс. транзакций в секунду):
— Вывод данных по собранным инцидентам с детализацией по каждому конкретному инциденту для каждого конкретного клиента. Вывод общих данных по всем клиентам не требуется, достаточно только данных по конкретному клиенту. Вывод данных нужен как по всем типам инцидентов, так и по конкретному типу. Сортировка по времени и по одному из целочисленных полей.
— Данные делятся на горячие (зафиксированные за последние сутки-двое), холодные (до года) и архивные. Информация по всем типам должна храниться в полном объеме. Время доступа к горячим и холодным данным должно быть одинаково быстрым, к архивным — быстрый доступ к аггрегированным данным;
— Выборка аггрегированных по временным промежуткам данным по разным типам инцидентов для конкретного клиента. Для построения временных графиков кол-ва инцидентов с шагом сутки, неделя, месяц.

OLAP (достаточно редко, как правило к конференциям или пресс-релизами):
— Подсчет аггрегированных (по различным временным интервалам) данных по всем клиентам в разрезе типов инцидентов, гео-привязки клиентов и пр. за промежуток вплоть до 1-2 лет.

Как это иногда бывает, на начальном этапе не планировалось хранить большое кол-во данных (на тот момент было до 5 млн. записей и динамика роста этого кол-ва была невелика), и хранение осуществлялось в одной таблице в MySQL. Т.к. инциденты обычно являются достаточно продолжительными по времени, в базе хранились не результаты каждой проверки системы мониторинга, а инциденты с полями 'время первого обнаружения', 'время последнего обнаружения'. На каждой итерации проверки поле 'время последнего обнаружения' обновлялось текущим временем проверки. Это позволило ограничить рост данных в таблице на порядок ценой некоторого усложнения выборок и гибкости при изменении определенных изменениях логики приложения.
Тем не менее, за последний год кол-во данных выросло до 900 млн. записей. В текущей реализации мы сделали партицирование таблицы по разным типам инцидентов, чтобы ограничить объемы обрабатываемых данных при выборках с фильтрацией по типам инцидентов. С текущими объемами данных данное решение укладывается на выборках данных в допустимое время, но есть пока несущественные проблемы с обновлением данных, которое может иногда затягиваться по времени.

В связи с постоянным ростом объема хранимых данных в настоящий момент я провожу исследование по выбору оптимального хранилища данных для нашего случая. В кандидатах сейчас следующие решения:

1. Развитие схемы хранения в реляционной базе с возможным добавлением шардинга по клиентам и партицирования по горячим/холодным/архивным данным. Здесь есть некоторые сложности с равномерным размазыванием клиентов по шардам, но при использовании виртуальных шардов можно реализовать такую кластеризацию клиентов по шардам, при которой кол-во данных в рамках шарда будет +- равномерным. Кроме того, усложнится логика приложения, адаптированная для работы с шардингом (что упрощается, если вводить прослойку вида MySQL Fabric или собственные решения на базе mysqlnd в случае PHP). Плюсы: отлаженная технология, много инструментов и юзкейсов;

2. Использование специализированных хранилищ временных рядов (хороший обзор дал Макс Лапшин levgem.livejournal.com/460103.html). У нас есть положительный опыт продолжительного использования influxdb, правда на значительно меньшем объеме данных (несколько десятков млн. точек). Другой кандидат — решение на базе Elliptics.
В данном случае есть проблема, вызванная тем, что данные системы хранения требуют хранения каждой точки проверки, а не пары 'время первого обнаружения', 'время последнего обнаружения' (можно правда обойти усложнением логики, но ценой возможных ограничений функционала хранилища), что в нашем случае увеличивает кол-во хранимых данных с 900 млн. до 5-10 млрд. точек. Плюсы (в случае influxdb): возможность автоматической пред-аггрегации данных (downsampling), шардирование и партицирование (настраиваемые движки хранения), фан и что-то новое. Недостатки: новые технологии, мало инструментов.

3. Использование колоночных БД (например, HP Vertica или InfiniDB). В данном случае можно добиться хороших показателей сжатия данных и производительности аггрегированных выборок, но есть некоторые сомнения в эффективности этих решений в OLTP режиме, учитывая их заточенность под OLAP.

В связи с этим я хотел бы просить совета по следующим вопросам:
— Зная ваш богатый опыт использования перечисленных мной технологий, на какие подводные камни стоит обратить внимание в первую очередь при оценке систем хранения того или иного типа;
— Можете ли вы со своей стороны на основе своего опыта дать рекомендации по выбору того или иного решения, возможно расширить список решений для оценки;
— Для оценки/выбора того или иного решения мы будем проводить объемное тестирование (Volume testing) каждого из них на объемах данных вплоть до тех, которые планируем достичь через год-два, а также тестирование на отказоустойчивость. Какие сценарии тестирования стоит предусмотреть и на какие метрики при тестировании на ваш взгляд стоит обратить пристальное внимание.
Это хороший вопрос, но я не смогу на него ответить в рамках комментария — слишком много всего надо уточнять. Если Вы окажетесь на Хайлоаде — найдите меня, обсудим.
Вопросы к Павлу Довбушу:

1) Часто слышал от колег такое утверждение. Что пользователи подсознательно тянутся именно к самым быстрым и отзывчивым сервисам. Даже если две страницы выглядят одинаково — пользователь выбирет самую отзывчивую. Согласны ли вы с этим утверждением?

2) Что вы думаете о Vanilla.js? Стоит ли отказаться от использования фреймворков? Спрашиваю не просто так ибо на одном из проектов успешно уничтожил все фреймворки ( ну почти — в качестве View использовал D3.js ) и в результате получили огромное кол-во плюсов ( включая что-то похожее на Virtual DOM еще до того как родился React ).

3) Есть утверждение что в JavaScript мы платим за каждую строчку кода. Платим трафиком, CPU, памятью. Согласны ли вы с таким утверждением?
я не Павел, но по 1 и 2 вопросу с вами совершенно согласен. Отзывчивость и скорость стаёт первым, вместо удобности.
1) Согласен, пользователь становится все более нетерпелив, мониторинг UX и его аналитика очень важная вещь.

2) Большие компании пишут что-то свое — Angular, Flight, React и т.п. Баду не исключение — когда кода много и проекты нужно поддерживать годами — появляется что-то свое. Наше чем-то похоже сейчас на YouTube SPF идеологически (но в таком виде появилось на 2 года раньше). В ближайшее время будем переходить к более толстому клиенту и скорее всего к M,V,VC,C разбиению. Брать готовый фреймворк бессмысленно, адаптация к нашим задачам и ограничениям будет дороже дизайна архитектуры с нуля. А если речь о базовых фреймворках (починка расхождений в браузерах) то на большом проекте все равно должны быть свои обертки вокруг таких операций для большей управляемости и возможности воткнуть измерения (RUM) и перехватчики ошибок — а что внутри — по большей части привычки и вкусовщина.

3) Важен баланс. С одной стороны полифил querySelectorAll это write-only код — непонятный, дико оптимизированный, загружаешь целиком в мозг, правишь, выгружаешь — тут по-моему по-другому не получится. А какой-нибудь демультиплексор разнотипных реквестов должен быть понятным — возможно много правок потребуется со временем.
Таким образом низкоуровневое ядро может быть набором адцких черных ящиков, само ядро сбалансированным, но лучше читаемым, а код приложения — максимально понятным и экономия на спичках только вредна.
Если есть детальный мониторинг UX, то можно понять когда и где сесть вооружившись профайлером, а где накладные расходы в пределах погрешности.
Не избыточна ли для вас RabbitMQ, почему не ZeroMQ?
у нас нет RabbitMQ
Здравствуйте,

Вопросов будет несколько, так как у вас наверняка много внутренних api и систем. то с помощью чего и как генерируете документацию? Присутствуют ли в оной если она есть примеры использования, какие то комментарии. Писать примеры в phpdoc оказалось неудобно, опять же js апи, в итоге получается какая то смесь из написанного вручную, и сформированного автоматически. Что выливается иногда в неактуальность, и часто в сложность поддержки всего этого зоопарка.

Бывает ли у вас так что системы разрабатываемые отдельно, потом оказались так тесно связаны что по логике вещей их надо совмещать, но написаны они на разных языках/платформах. и получается какая то лапша из внешних вызовов?

Знаете ли какое нибудь средство для автоматического тестирование авторизации через внешние сервисы?

Важный вопрос, резервное копирование, так как у вас вероятно настроена какая-нибудь система CI, то вопрос резервного копирования кода/структуры базы не слишком стоит, но что делать с данными? используете snapshot'ы файловой системы? По бекапам на хабре было сломано много копий, и интересно было бы узнать про то как это сделано у вас?

И еще один вопрос, как то так получилось, что я для своих проектов по сути пропустил облачную стадию, для некоторых клиентов облако сначала было слишком дорогим, а потом хлоп, и оно уже опять слишком дорогое, но не относительно shared хостинга, а относительно выделенного сервера. То есть я использую по сути разве что s3 для бекапов. Как было выше написано про новостные сайты, мало кому нужна динамическая балансировка нагрузки, она более менее прогнозируется. (digitalocean и прочее облаком можно считать поскольку постольку, ибо постоянно запущенные виртуалки, это немного не то), интересны именно приблизительные критерии, по которым можно понять, когда будет выгодно использовать облачную инфраструктуру.
У нас есть стандарт для внутренних апи — это google protobuf, документация генерится автоматом. Но это не покрывает 100% логики приложения, естественно. Лапши из вызовов нет. Автоматическое тестирование авторизации не нужно (перед деплоем selenium ну и в проде меряем просто число авторизаций). Резервное копирование делаем через xtrabackup вроде (надо DBA плдключать). Вопросы про облако я не очень понял, если можно — сформулируйте его поконкретнее, пожалуйста.
а чем именно генерируете документацию?
Мы выбрали 2 победителей: ai_boy и filatov_andrey
Напишите Ваши контакты на почту: daria@corp.badoo.com
И ждем вас завтра на конференции!
Уже писал личным сообщением но все-равно продублирую тут. Искренне и от всей души спасибо огромное за предоставленную возможность посетить эту замечательную конференцию! ( конечно с точки зрения докладов много «маркетинга» проскакивает — но общее впечатление очень позитивное :), много интересного )

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