Нам очень нравится формат AMA (ask me anything) на Reddit, когда кто-нибудь (в нашем случае – команда разработчиков) приходит в сабреддит AMA и говорит, что готов отвечать на заданные вопросы. Из самых запоминающихся сессий Ask Me Anything, например, команда инженеров Space X, или инженеры из Google, и даже действующий президент США Барак Обама четыре года назад отвечал на вопросы на Реддите. Недавно наша Android-команда проводила AMA и в онлайн-режиме отвечала на вопросы разработчиков.

Но в России нет своего Реддита. Зато есть свой Хабр. Поэтому мы решили прийти с форматом «задай нам вопрос» сюда. И не с пустыми руками, как велят правила AMA. Чтобы вам было проще понять тему, мы выбрали одну из наших команд – «Платформу» – и попросили ребят рассказать, чем они занимаются, на чём программируют и чего добились за время существования команды. И подвели небольшие итоги уходящего 2016 года. Поехали!

Оглавление


1. Чем занимается «Платформа»
2. Сервисы: Pinba, SoftMocks и другие
3. Системное программирование. Как мы начали использовать Go и к чему это привело
4. Фотографии
5. Скриптовое облако
6. LSD: Live Streaming Daemon
7. Cassandra Time Series: что это и как работает
8. Badoo AMA: задай вопрос разработчикам «Платформы»

Пруф, что это действительно мы.


Чем занимается «Платформа»



Антон Поваров, einstein_man, руководитель «Платформы»
Михаил Курмаев, demi_urg, руководитель команды A-Team

«Платформа» – это инфраструктурная команда, которая помогает другим подразделениям. Наша основная цель – сделать так, чтобы всем было хорошо, чтобы всё работало, программисты были довольны и могли спокойно писать код без оглядки на всякие сложные штуки. Мы – backend для backend.

«Платформа» состоит из двух команд: команда С-программистов (пишут на С, но в последнее время – и на Go) и А-Team (пишут на PHP и местами тоже на Go). Сишники пишут сервисы, делают PHP extensions. A-Team занимается PHP и database-инфраструктурой, а также разработкой и поддержкой инструментов для других команд.

Если говорить о конкретных проектах с точки зрения того, что видит пользователь (то, что он использует), то мы занимаемся:

  • фотографиями: вся инфраструктура хранения и отдачи лежит на нас;
  • у нас есть своё скриптовое облако (это «распределённый крон», который позволяет нам запускать офлайн-обработчики на облаке машин);
  • отвечаем за все «обертки» к сервисам (предоставляем остальным командам Badoo удобные доступы к сервисам, потому что у нас есть шардинг, есть самописные способы репликации).

За «обертки» мы отвечаем, потому что хочется скрыть все эти внутренности от backend-разработчиков других команд, чтобы упростить их работу и не допускать непредвиденных ситуаций, когда всё, чем мы занимаемся из основных задач, внезапно сломалось.


Сервисы: Pinba, SoftMocks и другие


Некоторые из наших внутренних сервисов со временем выросли в полноценные продукты и даже стали стандартом де-факто в экосистеме PHP. Самые известные из них – это PHP-FPM (сейчас он стал частью стандартной поставки PHP для веба), его написал Андрей Нигматулин (доклад на эту тему можно посмотреть здесь), и Pinba (http://pinba.org/), сервис для получения realtime-статистики от работающих приложений без накладных расходов на её сбор (UDP), с помощью которого легко понимать, что происходит с производительностью вашего приложения в любой момент времени.

Pinba удобна тем, что позволяет нам всё время собирать данные. И эти данные будут под рукой всегда, когда нужно разобраться в причине проблемы. Это удобно и значительно сокращает время, затрачиваемое на поиск и устранение проблемы. Не менее важно и то, что Pinba помогает увидеть проблему заранее, когда она ещё не затронула юзеров.

Ещё мы придумали и сделали SoftMocks, это наш собственный фреймворк, облегчающий unit-тестирование, который позволяет подменять классы и функции в тестах. Нам пришлось создать его в связи с переходом на PHP7, в котором была сильно переработана внутренняя архитектура интерпретатора, и наш старый Runkit просто перестал работать. На тот момент у нас было около 50к юнит-тестов, большинство из которых так или иначе используют моки для изоляции внешнего окружения, и мы решили попробовать другой подход, потенциально более мощный, чем Runkit/ Uopz.

Одними из основных преимуществ SoftMocks являются независимость от внутренней структуры интерпретатора и отсутствие необходимости в каких-либо сторонних расширениях PHP. Это достигается за счёт выбранного нами подхода – переписывание исходного кода программы на лету, а не динамическая подмена внутри интерпретатора. На данный момент проект выложен в open-source, и им может воспользоваться любой желающий.

Вы, возможно, знаете о том, у нас в Badoo очень сильная команда PHP-разработчиков. Поэтому нет ничего удивительного в том, что мы оказались в числе первых компаний, которые перевели проект такого масштаба (как Badoo) на PHP 7 в этом, 2016-м, году. Прочитать о том, как мы пришли к этому, с чем столкнулись и что получили, можно в этом посте.


Системное программирование. Как мы начали использовать Go и к чему это привело



Марко Кевац, mkevac, программист в отделе C/C++

В отделе C/C++ мы разрабатываем высокопроизводительные in-memory демоны, которые обрабатывают сотни тысяч запросов в секунду и хранят сотни гигабайт данных в памяти. Среди них можно найти такие вещи, как поисковые демоны, использующие bitmap-индексы и осуществляющие поиск по ним с использованием самописного JIT, или умный прокси, который обрабатывает соединения и запросы всех наших мобильных клиентов. При необходимости мы расширяем язык PHP под наши нужды. Какие-то патчи отправляются в апстрим, какие-то – слишком специфичны для нас, а какие-то вещи удаётся сделать в виде загружаемых модулей. Мы пишем и поддерживаем модули для NGINX, занимающиеся такими вещами, как шифрование урлов и данных и быстрая обработка фотографий «на лету».

Мы – хардкорные системные программисты, но при этом прекрасно понимаем все недостатки программирования на С/C++: медленная разработка, потенциальные ошибки, сложность программирования с использованием потоков.

С самого появления Go, новомодного, молодёжного и многообещающего языка от Google, мы им заинтересовались. И почти сразу же после выхода первой стабильной версии в 2012 году мы начали рассматривать возможность его применения в production.

Go обещал быть близким по духу и производительности нашему любимому С, но позволял делать прототипы и даже конечные продукты заметно быстрее и с меньшим количеством ошибок. И тот факт, что Go являлся синонимом конкурентности с его каналами и горутинами, особенно возбуждал нашу фантазию.

В тот момент у нас появилась новая крутая и очень срочная задача по поиску пересечений между людьми в реальном мире. Послушав требования, мы чуть ли не хором воскликнули: «Это задача для Go!» Требовалось потоково обработать большое количество координат пользователей, правильно их пересечь в нескольких «координатах», включая время, и выдать какой-то результат. Очень много взаимодействий между частями, очень много параллельных вычислений. Словом, именно то, что является базовой задачей для Go.

Прототип был сделан тремя людьми за неделю. Он работал. Он работал хорошо. И мы поняли, что Go у нас приживётся. В 2015 году Антон Поваров подробно рассказал в своём выступлении о Go в Badoo.

Но нельзя сказать, что наш роман был идеальным. Go на тот момент был совсем молодым языком с кучей проблем, а мы сразу же начали писать продукты, которые обрабатывали десятки тысяч запросов в секунду и потребляли почти 100 гигабайт памяти.

Нам приходилось оптимизировать наши сервисы, чтобы не делать лишних аллокаций памяти напрямую и чтобы компилятор Go не решал делать эти аллокации за нас. И здесь красота и удобство Go снова проявили себя. С самого начала Go обладал отменными средствами для профилирования производительности, потребления памяти, для того, чтобы видеть, когда компилятор решает выделить какой-то кусок на куче, а не на стеке. Наличие этих средств сделало оптимизацию интересным и познавательным приключением, а не мукой.

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

Поскольку Go стал инициативой «снизу», нам нужно было постараться, чтобы наши коллеги и менеджеры не отвергли нашу идею сразу. Мы понимали, что нужно сделать так, чтобы со стороны эксплуатации проект на Go никак не отличался от проекта на C: такие же конфиги в JSON, те же протоколы взаимодействия (основной protobuf и дополнительный на JSON), та же стандартная статистика, которая уходит в RRD. Нам надо было сделать так, чтобы со стороны релиз инжиниринга проекта на Go никак не отличался от проекта на C: тот же самый Git + TeamCity Flow, та же сборка в TeamCity, тот же процесс выкладки. И у нас это получилось.

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

Мы не создавали ничего с нуля – мы встраивали Go в существующую много лет инфраструктуру. Этот факт ограничивал нас в использовании каких-то вещей, которые для Go являются стандартными. Но именно этот факт вкупе с тем, что мы сразу начали писать серьёзный высоконагруженный проект, позволил нам окунуться в язык по уши. Мы знатно испачкались, скажу я вам, но эта близость помогла нам «срастись» с этим прекрасным языком.

Интересно было наблюдать, как с каждой выходящей версией Go рос, как ребёнок, превращающийся во взрослого человека. Мы видели, как паузы GC на наших демонах таяли с каждой новой версией, и это без изменения кода с нашей стороны!

Сейчас, спустя четыре года работы с этим языком, у нас около десятка самых разноплановых сервисов на Go в трёх командах и ещё несколько новых в планах. Go прочно вошёл в наш арсенал. Мы знаем, как его «готовить» и когда его стоит применять. Спустя столько лет интересно слышать, как программистами регулярно говорятся такие вещи, как «да набросай быстренько прототип на Go» или «тут столько параллельности и взаимодействий, это работа для Go».


Фотографии



Артём Денисов, bo0rsh201, старший PHP-программист

Фотографии являются одним из ключевых компонентов Badoo с точки зрения продукта, и мы просто обязаны уделять инфраструктуре их хранения и показа много внимания. На данный момент мы храним около 3 ПБ фотографий, каждый день пользователи заливают около 3,5 млн новых снимков, а нагрузка на чтение составляет около 80k req/sec на каждой площадке.

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

Первый слой инфраструктуры – это кэширующие серверы с быстрыми SSD дисками, которые обрабатывают 98% входящего трафика, на них работает наш собственный мини-CDN – это кэширующий прокси, оптимизированный под наш характер нагрузки, на котором также работает много утилитарной/ продуктовой логики (ACL, resize, наложение фильтров и watermark’ов на лету, circuit breaker и т. д.).

Следующий слой – кластер из пар серверов, ответственных за долговременное хранение,
часть из которых имеет локальные диски, на которых непосредственно хранятся фотографии, а часть подключена по оптике к третьему слою – Storage Area Network.

Эти пары машин обслуживают одинаковые диапазоны пользователей и работают в режиме master – master, полностью реплицируя и резервируя друг друга через асинхронную очередь. Наличие таких пар позволяет нам иметь отказоустойчивость не только на уровне жёстких дисков, но и на уровне физических хостов (kernel panic, reboot, blackout и т. д.), а также легко проводить плановые работы и без деградации сервиса переживать сбои, которые при больших масштабах не являются редкостью.

Более подробно о нашей работе с фотографиями Артём Денисов рассказал в этом году на Highload++.


Скриптовое облако


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

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

Работает это примерно следующим образом:

1) Разработчик описывает job в виде PHP-класса, который реализует один из нескольких интерфейсов (крон-скрипт, разборщик очереди, обходчик баз и т.д…

2) Добавляет его через веб-интерфейс в облако, выбирает параметры для частоты запуска, тайм-ауты и ограничения по ресурсам.

3) Далее система сама запускает этот job на распределённой инфраструктуре, которая выделена под облако, следит за его выполнением и балансирует нагрузку на кластер. Девелоперу остаётся лишь следить за статусом работы своего job’а и смотреть логи через Web UI (сколько инстансов запущено, какие настройки, какие запуски как завершились).

На данный момент в облаке у нас порядка 2000 хостов в двух ДЦ ~ 48k CPU cores/ 84Tb memory. 1800 пользовательских заданий генерируют около 4 000 запусков в секунду.

Об облаке мы рассказывали тут и тут.


LSD: Live Streaming Daemon


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

1) Нашу собственную реализацию сервера очередей для доставки событий, связанных с логикой продукта/ приложения.

2) Более простой механизм для стриминга различных логов, статистических метрик и просто больших объёмов данных со множества нод, которые надо централизованно агрегировать и обрабатывать большими пачками в одном месте.

Для второй задачи мы долгое время использовали Scribe от Facebook, но с увеличением количества прокачиваемых через него данных он становился всё менее и менее предсказуемым и уже давно предан забвению.

В итоге в какой-то момент нам стало выгоднее написать своё решение (благо эта задача не выглядит очень сложной), которое было бы легче поддерживать.

Собственную стримилку событий мы назвали LSD: Live Streaming Daemon.

Ключевые особенности LSD:

  • транспорт в виде строк из plain файлов (для клиента нет ничего надёжнее, чем запись данных в файл локальной FS);
  • клиенты не блокируются при записи, даже если все серверы-приёмники недоступны (буфер скапливается в локальной FS);
  • прозрачный контроль/ настройка лимитов на потребление сетевых/ дисковых ресурсов;
  • совместимый со scribe формат записи/ способ агрегации файлов на приёмнике.


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


Cassandra Time Series: что это и как работает



Евгений Гугучкин, che, старший PHP-программист

Badoo – сложная система, состоящая из множества связанных компонентов. Оценить состояние этой системы – непростая задача. Для того чтобы это сделать, мы собираем более 250 миллионов метрик со скоростью около 200 000 значений в секунду, и эти данные занимают примерно 10 ТБ.

Исторически для хранения и визуализации временных рядов мы использовали известную утилиту RRDtool, «обернувши» её своим фреймфорком для удобства работы.

Что нам нравилось в RRDtool, так это скорость чтения. Однако существуют и серьёзные недостатки:

  • высокая нагрузка на диски, порождаемая большим количеством операций ввода/ вывода с произвольным доступом (эту проблему мы решили использованием SSD и RRDcached);
  • отсутствие возможности записи задним числом: то есть если мы записали значение на момент времени 2016-01-01 00:00:00, то записать следом значение за 2015-12-31 23:59:59 уже не получится);
  • довольно расточительное использование места на диске для разреженных данных;
  • доступ к данным осуществляется локально: невозможно из коробки построить распределённую систему с горизонтальным масштабированием.

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

В итоге мы провели подробнейший анализ существующих решений в области time series баз данных, убедились, что ни одно нам не подходит, и написали своё решение на основе Cassandra.

На данный момент половина наших реальных данных дублируется в новое хранилище. В цифрах это выглядит так:

  • девять серверов;
  • 10 Тб данных;
  • 100 000 значений в секунду;
  • 140 миллионов метрик.

При этом мы решили практически все задачи, которые перед нами стояли:

  • выход из строя одной ноды в кластере не блокирует ни чтение, ни запись;
  • есть возможность дописывать, а также переписывать «сырые» данные, если они не старше недели (окно, в котором можно менять данные, можно настраивать и менять в процессе эксплуатации);
  • простое масштабирование кластера;
  • нет необходимости использовать дорогие SSD диски;
  • более того, можно не использовать RAID-массивы из HDD с резервированием, поскольку при замене диска нода способна восстанавливать данные с соседних реплик.

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


Badoo AMA: задай вопрос разработчикам «Платформы»


И теперь, собственно, то, зачем мы публикуем этот пост. Сегодня с 12:00 и до 19:00 (по московскому времени), команда «Платформы», будем отвечать на ваши вопросы. Мы много всего пережили за время существования команды: мы расширялись, менялись, учились, сталкиваясь с какими-то проблемами, приходили к новым языкам программирования. И мы готовы поделиться с вами нашим опытом (в том числе рассказать про фейлы, факапы и нашу боль).

Например, спрашивайте про:

  • устройство наших внутренних проектов (как устроен наш шардинг, как мы собираем и рисуем статистику, как общаемся с сервисами);
  • то, на какие грабли мы наступали, почему принимали те или иные решения (что мы делали, когда перестали умещаться на одном сервере, в одном ДЦ);
  • настройку работы сильной команды PHP/ С-программистов;
  • переход на PHP 7 (с какими проблемами можно столкнуться);
  • особенности работы с высоконагруженным проектом;
  • рекомендации PHP- и Go-программистам;
  • всё, что описано выше в посте.

Но не ограничивайтесь этим!

UPD: Спасибо всем за вопросы, мы заканчиваем нашу сессию AMA, но будем продолжать отвечать, только не так оперативно. Поэтому – спрашивайте еще.
Поделиться с друзьями
-->

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


  1. nogoody
    13.12.2016 11:43
    +3

    Добрый день. Вопрос по тестам в php. Используете вы приемочные и функциональные тесты. Я так понимаю SoftMocks только для Unit-тестов? Ну и с таким большим кол-вом unit-тестов, можете ли что порекомендовать по структуре тестов. Как их правильно разложить. И второй вопрос по тестированию базы. Вы используете фикстуры? Или накатывается какая-то тестовая база через миграции?


    1. eloin
      13.12.2016 12:45
      +6

      Это сразу пяток хороших, больших вопросов :) Попробую ответить.

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

      — Если на тестирование приходит новая фича: проверяем ее руками (возможно, выкладываем на прод с несколькими а/б тестами) -> фича дорабатывается, устаканивается описание, выбирается лучший дизайн/набор функций/текст из а/б тестов -> создаем задачу на написание к ней селениум-тестов -> собственно, пишем тесты
      — Если на тестирование приходит улучшение старого функционала/изменение существующей страницы (дизайн, расположение элементов, whatever): проверяем задачу руками, параллельно в этой же git-ветке правятся/дорабатываются селениум-тесты. Либо, если задача срочная, то проверяем только руками, а параллельно ставим задачу на правку/доработку селениум-тестов; такая задача также получает максимальный приоритет.

      2. Функциональными тестами у нас являются и юнит-тесты, и интеграционные тесты. В интеграционных проверяем взаимодействие кода с БД и различными внутренними сервисами (демонами) на C/C++/Go. Там же — проверяем взаимодействие серверной части кода с клиентами (клиенты при этом тоже мокаются).

      3. SoftMocks используются только для юнит-тестов, да. В других местах они могут быть вредны.

      4. С таким количеством юнит-тестов по структуре можно порекомендовать только одно: пишите тестируемый код :) Тогда и огромное количество тестов будет пробегать за считанные минуты. У нас ситуация чуть сложнее — юнит-тесты стали массово писать, когда кодовая база уже успела сильно разрастись. Приходится ухищряться :)

      Например, в некоторых не совсем юнит-тестах у нас есть запросы к БД. Но! В тестах реализована заглушка: если из теста идет запрос к реальной БД, то вместо настоящей запрашиваемой таблички создается временная с такой же структурой, которая наполняется тестовыми данными и по окончании теста удаляется. Таблицы такие создаются в tmpfs, поэтому на скорость выполнения тестов влияют меньше, чем могли бы (хотя это тоже сильно сказывается на времени их прохождения).

      Еще тесты у нас разбиваются на микросьюты и запускаются в облаке (подробнее, почему так, можно почитать тут: Переход на PHP 5.5 и юнит-тесты).

      5. Про тестирование баз не совсем понял. Если имеется ввиду проверка взаимодействия кода с базой, то у нас есть и фикстуры, и обращения к «реальным» (на самом деле тоже замоканым временным) базам. Например, фикстуру для самого популярного объекта User мы генерим автоматически на основе текущей эталонной структуры БД, складываем ее в файл на всех серваках, где гоняются тесты, и подключаем инклюдом.

      Если вопрос понял не правильно, то предлагаю продолжить дискуссию ниже :)


      1. nogoody
        13.12.2016 13:14
        +2

        Вы все правильно поняли, спасибо за развернутый ответ. Еще такой вопрос, вы метрики используете по тестированию, условно чтобы coverage был >90%? Я так понял вы не сразу стали писать тесты, каков сейчас процент покрытия?


        1. eloin
          13.12.2016 13:32
          +4

          Метрики используем, стараемся держать покрытие всего проекта не ниже 50%. Какие-то части кода (например, биллинг или критичные части платформы) покрыты тестами практически полностью, какие-то — (старые скрипты, страницы, всякие геттеры/сеттеры) могут быть не покрыты вообще. Цель «повысить coverage до заветных 50%» ставилась перед руководителями команд разработки, coverage повышался постепенно. Добились такого результата примерно за год-полтора.


          1. nogoody
            13.12.2016 13:53
            +1

            У вас была отдельная команда, которая этим занималась в течении полутора лет? Может у вас есть отдел чисто под написание тестов?


            1. eloin
              13.12.2016 14:08
              +4

              Лучше разработчика, написавшего какой-то код, этот код может знать только разработчик, который его поддерживает :) Поэтому и юнит-тесты к проекту писались силами самих разработчиков. Конечно, проект поделен на условные «подпроекты» (или области ответственности), каждый файл в проекте закреплен за одним или несколькими maintainer'ами, а также за определенной командой.

              Статистика по coverage'у, помимо прочего, показывает код какой команды в какой степени покрыт юнит-тестами. Ну а так как задача на покрытие проекта тестами ставилась непосредственно руководителям различных команд разработчиков (и прогресс в достижении цели оценивался каджый квартал), то в их интересах было сделать так, чтобы у разработчиков было и время, и желание эти тесты писать. Поэтому 1) coverage поднимали плавно, не ломая сильно основного процесса разработки, но и не останавливая покрытие; 2) отдельной команды автоматизаторов не было.

              Из полезных рецептов: сначала завели практику покрывать юнит-тестами все новые фичи (без этого задача не проходит code review). Если задача срочнаая, то, как и в случае с селениум-тестами, код выезжает на прод, но параллельно в баг-трекере создается задача на написание юнит-тестов к новому коду (которая также имеет высший приоритет). Потом потихонечку ставились отдельные задачи на покрытие тестами (и местами попутный рефакторинг для возможности покрытия тестами) старого кода.


  1. vyants
    13.12.2016 11:51
    +3

    Привет! У меня вопросы по Cassandra. Будет ли ваше решение в opensource? Сравнивали с новомодным ClickHouse? Кластер Cassandra внутри одного ДЦ? Если нет то как решали проблему линка между ДЦ?
    Спасибо.


    1. che
      13.12.2016 12:01
      +4

      В текущем виде решение в opensource не готово, но мы планируем прийти к этому.
      С ClickHouse не сравнивали, он вышел после того как мы запустили наш прототип.
      Кластер Cassandra у нас в одном ДЦ.


    1. einstein_man
      13.12.2016 12:49
      +4

      Насчет opensource: пока не готовы, т.к. чувствуем, что надо бы огрести побольше боли и накопить опыта эксплуатации в разных сценариях. Например у нас в CTS сейчас едут в основном около-продуктовые данные. Хотим построить второй кластер — для технических метрик (времена ответов сервисов/баз/etc, потребление ресурсов, и т.п.). Там будет примерно столько же данных.
      Плюс — java мир для нас не совсем пока родной и мы только учимся, например, понимать и тюнить JVM, развиваем/изучаем инструменты.

      Clickhouse выглядит интересно, но нас довольно мало и мы пока не готовы быть «early adopters”, хотим подождать пока вырастет community, чтобы потом прильнуть к знанию великого all.


    1. einstein_man
      13.12.2016 12:53
      +1

      Данные, которые сейчас в CTS, едут из двух DC в один, у нас есть «гарантированный» линк между ними (сколько-то сотен мегабит), плюс — естественно — публичный интернет (ну трафик шифрованный, да :) ).

      О проблеме линка между DC — что вы имеете в виду?


      1. vyants
        13.12.2016 12:59
        +2

        Я имел ввиду не клиентов кластера, а непосредственно сами машинки кластера. Обычно кластер размазанный по разным ДЦ начинает лагать от сетевых задержек между нодами из разных ДЦ. Не скажу про Cassandra, но на мускуле весьма острая проблема. Было собственно интересно, есть ли у вас проблемы и как вы их решали.


        1. einstein_man
          13.12.2016 13:03
          +1

          Понял. Кластер в одном DC с RF = 2 на данный момент, в разных стойках, вот это все.


          1. tru_pablo
            13.12.2016 14:16
            +1

            А пишете/читаете с кворумом или как?

            > выход из строя одной ноды в кластере не блокирует ни чтение, ни запись
            Как это работает при RF=2?

            Ну и вот это уж тоже как всё-таки на самом деле, то
            > около 200 000 значений в секунду
            или
            > 100 000 значений в секунду; 140 миллионов метрик.


            1. che
              13.12.2016 14:30

              > А пишете/читаете с кворумом или как?
              — сырые данные пишем с кворумом, но с DowngradingConsistency RetryPolicy
              — ролапы пишем с CL = ALL
              — читаем с CL = ONE

              >> выход из строя одной ноды в кластере не блокирует ни чтение, ни запись
              > Как это работает при RF=2?
              Сырые данные пытаемся записать во все живые ноды, но если не получается, то в одну. Для time series мы сочли это приемлемым.

              >Ну и вот это уж тоже как всё-таки на самом деле, то
              >> около 200 000 значений в секунду
              >или
              >> 100 000 значений в секунду; 140 миллионов метрик.
              Текущий поток данных 100к в секунду но справляемся и с более чем 200к


  1. d3bu99er
    13.12.2016 12:05
    -2

    День добрый! Возможно вопрос не в тему, но я всё таки спрошу:
    Почему после удаления платёжной карты из аккаунта — система продолжает проводить списания с (уже удалённой) карты?


    1. yeah_boss
      13.12.2016 12:50
      +9

      С этим вопросом тебе поможет саппорт: https://eu1.badoo.com/help/, а не разработчики Платформы.


  1. v8_jupiter
    13.12.2016 13:13

    Добрый день.
    1. Почему go а не nodejs? Ведь nodejs ближе должен быть так как все php разработчики сталкивались с javascript
    2. Видите ли вы в перспективе полную замену php на go?


    1. mkevac
      13.12.2016 13:46
      +7

      Привет!

      Go появился в Badoo из C/C++ команды, а не PHP команды. А нам сишникам как раз ближе Go. Уже после этого Go начали использовать и те люди, которые большую часть времени используют PHP.

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

      Go, например, в отличие от nodejs или PHP, дает строгую типизацию. Для тех кто всю жизнь использовал не строгую, строгая может оказаться тем самым, что им всегда не хватало.

      А вообще стыдно вам должно быть за такой вопрос! :-)

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

      A great way to end the conversation early and avoid learning anything is to ask questions like:
      — Why aren't you using Y?
      — You should be using Z! (this isn't a question)


      Go классный, няшный, интересный. Он активно развивается, но развивается с осторожность, не распыляясь налево и направо. И он позволяет нам быстро и эффективно решать наши задачи.
      Быстро и качественно решенные задачи — плюс для бизнеса, няшность и интересность — плюс для разработчика.

      Что касается полного ухода с PHP на Go, то ответ однозначный — нет.

      Те задачи что решаются на ПХП решаются им прекрасно. Да, многие ворочают нос от ПХП, но это инструмент, который очень долгое время нас не подводил. Мы знаем как его готовить, у нас десятки и десятки людей, которые пишут на нем и миллионы и миллионы строк кода, написанных на нем.

      Бонусы полного перехода на что-то иное (даже на Го) слишком призрачны.

      Но, с другой стороны, я думаю что кол-во Go кода будет однозначно расти. И какие-то ПХП-шные части могут быть на нем переписаны.


    1. einstein_man
      13.12.2016 13:53
      +2

      Ну мы уже умеем писать single-threaded софт поверх event loop с callback hell :) (хотя, насколько я знаю, с promise и подобными техниками — все уже не так больно).

      Киллер фича Go — она ведь в «нормальной» concurrency, встроенной в язык.

      В nodejs можно, полагаю, нарожать много процессов и таким образом заюзать все ресурсы железа, но возникает вопрос — а как хранить состояние, которое нужно всем? (например, в одной из наших задач — полтора миллиарда координат пользователей для near-realtime обработки и фильтрации).


      1. Tatikoma
        13.12.2016 14:35
        -3

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


      1. imgen
        13.12.2016 21:00
        +1

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


        1. einstein_man
          14.12.2016 10:56
          +2

          ну в данном случае имелись в виду os-level процессы, как средство одним nodejs приложением заюзать много cpu.

          насколько я знаком с erlang elixir — тамошние процессы скорее ближе как раз к goroutines, в том смысле, что ими управляет рантайм и каким-то образом их выполняет на os-level threads/processes.


    1. einstein_man
      13.12.2016 13:56
      +3

      И насчет полной замены PHP на Go.

      В вакууме — это вполне возможно, и насколько я знаю, в некоторых компаниях «Go микросервисы» смотрят во внешний мир, делают бизнес логику и отдают «странички» клиентам.
      Был, например, доклад, упоминавший об этом на недавнем Highload.

      В случае же Badoo — это не думаю, что нужно (@mkevac об этом тоже писал), работает же хорошо :)
      Да и мало реально — миллионы строк уже написаны и работают, крутые и умные коллеги работают, инструменты и тестирование построены. Было бы контрпродуктивно это менять.


  1. Slach
    13.12.2016 13:25
    +3

    Доброго времени суток

    планируете ли вы опенсорсить вашу систему интеграции между git, youtrack и билд системами с фичебранчами??


    1. brozen_zwork
      13.12.2016 14:07
      +2

      Привет. Я так понял речь про AIDA. Как вы правильно заметили эта система осуществляет интеграцию между многими компонентами в Badoo и она сильно завязана на наших процессах. Поэтому, к сожалению, в текущей её реализации, AIDA не универсальна и мы не можем опубликовать код в Open source.


      1. Slach
        13.12.2016 14:59

        да, я имею ввиду именно AIDA
        На чем это написано на Go или на PHP?
        я правильно понимаю что AIDA это какой то монолитный инструмент, который через web-hooks интегрирован с остальными системами (JIRA, GIT, TeamCity) через их стандартный API и невозможность вытащить это в Open-source обсуловлена тем что там всякие пароли и настройки с ключами чуть ли не в коде прописаны??


        1. brozen_zwork
          13.12.2016 15:57

          На чем это написано на Go или на PHP?

          PHP
          я правильно понимаю что AIDA это какой то монолитный инструмент

          Скорее да, чем нет. Код находится в одном репозитории и деплоится он везде одинаково.
          который через web-hooks интегрирован с остальными системами (JIRA, GIT, TeamCity) через их стандартный API

          Если говорить именно про взаимодействие с вышеупомянутыми инструментами, то да. Но кроме этого в AIDA есть еще много логики поддерживающей наш процесс разработки, автоматизации и т.д. ?
          и невозможность вытащить это в Open-source обсуловлена тем что там всякие пароли и настройки с ключами чуть ли не в коде прописаны??

          Дело не в приватности настроек, а том, что, повторюсь, AIDA завязана на наши процессы и не универсальна.


          1. Slach
            13.12.2016 20:43

            Дело не в приватности настроек, а том, что, повторюсь, AIDA завязана на наши процессы и не универсальна.


            ну вот мне нравится именно ВАШ процесс =)
            скажем если бы можно было настроить свой запуск тестов, свои вебхуки с jira и gitlab
            и вместо teamcity

            ну я так понимаю что просто куча модулей есть которые конкретно на инфраструктуру завязаны (типа выкатки .shot и т.п.)

            эххх… жаль


  1. Sherman81
    13.12.2016 13:27
    +3

    Несколько вопросов.

    0. А чего схему не показали?
    1. Вы храните преагрегаты (min, max, mean и т.д.), типа ролапов или сырые данные? Если сырые, где и чем вычисляете агрегаты?
    2. Что является ключом партишина? Сколько строк в партишине?
    3. Какие запросы делаете? Если ли функционала, который комбинирует результаты нескольких партишинов?
    4. Какая compaction strategy используется? DateTieredCompactionStrategy?
    5. Используете ли SASI-индексы?


    1. che
      13.12.2016 13:57
      +4

      Подробное описание не уместилось бы в текущий формат, поэтому мы готовим полноценную статью на эту тему.

      Если кратко по вашим вопросам:

      1. Храним последнюю неделю сырых данных, остальные перекладываем в ролапы. Поддерживаются разные агрегирующие функции, но используем пока только AVG. Все вычисляется на php.

      2. Сырые данные партицируются по идентификатору метрики и левой границе периода (сутки). Данные для разных метрик поступают с разной периодичностью, минимальная — раз в минуту. Так что, по факту, размер партиции от 1440 строк и меньше. Но есть и сильно разреженные метрики.

      Если говорить про ролапы, то сейчас одна партиция — один архив. У метрики может быть несколько архивов. Размер зависит от retention и детализации.

      3. Все верно, при запросе данных возвращается результат объединения партиций. А именно, данные из подходящего ролапа + сырые данные свернутые с такой же детализацией и агрегирующей функцией как и выбранный архив.

      4. DateTieredCompactionStrategy — сейчас является depricated. Он заменен на TWCS. Но и от него мы отказались в пользу обычного STCS, в первую очередь потому что данные мы удаляем при перекладывании в ролапы, а не при помощи TTL. Да, требуется еженедельный major compaction.

      5. Не используем, есть мнение что SASI-индексы пока не достаточно стабильные.


  1. nizsheanez
    13.12.2016 13:48
    +3

    Расскажите про юнит тестирование Go демонов.
    Если мокаете то чем, на сколько заморачиваетесь распараллеливанием тестов, какие соглашиения по наименованию и оформлению тестов, используете ли какие сторониие пакеты для тестов, и все такое.

    Ну и если что онтересное останется — расскажите про интеграционные тесты Go.


    1. mkevac
      13.12.2016 14:00
      +2

      Мне немного стыдно, но у нас для Go практически нет юнит тестов.

      Мы, команда сишников, привыкли к тому что писать на Си юнит тесты сложно. Возможно, но требует настолько много усилий, что мы не видим в этом профита. Мы привыкли полагаться на свои небольшие функциональные/smoke тесты, написанные на Python и на полноценные подробные функциональные тесты, которые пишет наш отдел тестирования на PHP.

      И вот эта вот привычка перешла на Go и мы пока не уделили этому должного внимания, чтобы ее перебороть. Все так же полагаемся на функциональные тесты, написанные отделом тестирования.

      Хочу заметить что в Go довольно развиты инструменты для рефакторинга. И вот эти инструменты вместе с строгой типизацией позволяют вам быть более уверенными в правильности кода при рефакторинге. А ведь именно для этого часто пишут юнит тесты, так ведь?..

      Интеграционные\функциональные тесты, как я уже написал, пишет отдел тестирования. Мы постарались сделать так, что демон на Go извне никак не отличается от демона на Си. Те же протоколы, те же конфиги, все то же самое. Так что отдел тестирования зачастую даже не задумывается о том, на чем написана система.


    1. einstein_man
      13.12.2016 14:09
      +2

      Возможно немного не формат :)
      Порекомендуете инструменты / пакеты / подходы к unit-тестированию в Go, чтобы у вас научиться, когда этим плотно займемся?


      1. nizsheanez
        13.12.2016 19:56

        Спасибо.
        Мы сейчас утаскиваем много кишочков PHP в GO, в PHP тестов почти небыло.
        Но немного приложив силу воли мы заимели довольно хорошее покрытие в GO.

        Про юниты:
        Начиная с 1.7 страндартная библиотека научилась всему что было в сторонних библиотеках и похоже что кроме нее ничего и не нужно, за исключением моков.
        библиотеки для моков плохи все — но победил https://github.com/golang/mock как наименьшее зло — наименее увеличивающее размер каждого теста
        для интерфейса типа Reader можно и ручками сделать stub, но как-то в реальных приложениях интерфейсы жирнеют сколько не дроби.

        Мы используем http://labix.org/gocheck, но похоже теперь можно и на стандартную либу съезжать.

        Бывает полезно гонять параллельно(t.Parallel) один тест много раз — чтобы понять что код thread-safe
        За variable shadowing следит gometalinter, поэтому на эти проблемы тестов не делаем.


        1. einstein_man
          13.12.2016 20:10

          спасибо :)


        1. nizsheanez
          13.12.2016 20:20

          Файлики юнитов ложим прям рядом с файликами кода — и я считаю это абсолютно гениальным и удобным.

          В Файлике с тестами можно использовать специальное название пакета my_package_test — тогда тесты будут думать что находятся в другом пакете от кода и тестировать его извне, хотя файлики тестов продолжат лежать рядом с кодом. Это редко нужно, но бывает + есть любители писать тесты не имея доступа к привату.


        1. einstein_man
          14.12.2016 14:07

          — удалено — промахнулся тредиком


      1. ewgRa
        21.12.2016 14:07

        Вот тут есть хороший доклад по тестированию в Go https://www.youtube.com/watch?v=yszygk1cpEc


    1. tr0mb
      13.12.2016 14:14
      +1

      Отвечу про интеграционные тесты.
      У нас есть devel окружение, на котором постоянно гоняются функциональные (веб, мобайл) тесты. Новые версии демонов заливаются на devel и становится сразу понятно сломана интеграция или нет — в случае чего начнут падать тесты.
      Если интересен процесс «разработка\тестирование», то он ничем не отличается от любого другого демона — можно подсмотреть в статье https://habrahabr.ru/company/badoo/blog/254087/.


  1. gtbear
    13.12.2016 14:32
    +2

    Может уже где то было, но я все таки уточню:
    1. Та часть что на PHP у вас оформлена как мегаприложение или вы дробите все на части? По какому принципу дробите, есть ли какие то общие правила
    2. Есть ли у вас какие то процедуры по борьбе с техническим долгом? ну например субботники чистки кода раз в месяц.


    1. demi_urg
      13.12.2016 14:52
      +4

      Привет!
      1. Довольно большая часть нашего кода — это обертки над сервисами и базами, API для работы с очередями или фотографиями и тому подобное. Все это используется другими отделами и поэтому не может быть отдельным приложением. Практически весь PHP код находится в общем репозитории и использует некоторые общие куски кода. Поэтому, наверно можно сказать, что все оформлено как мегоприложение.

      2. Мы стараемся планировать работы по техдолгу в общем пуле задач. Каких то конкретных критериев нет. Просто в какой то момент понемаем, что сейчас можно заняться задачами из беклога и тратим на них n человеко-недель.


      1. gtbear
        13.12.2016 15:02
        +2

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


        1. demi_urg
          13.12.2016 15:27
          +1

          Да, у каждого разработчика есть своя «песочница» на специальным devel кластере.
          Мы стараемся поддеживать на нем такую же инфраструктуру как и на продакшене. Там так же есть эмуляция нескольких ДЦ и все сервисы которые есть в боевом окружении. Мы внимательно следим за devel площадкой и даже мониторинг работает примерно так же.
          Все тесты запусаются так же в этом окружении и для ускорения времени их выполнения (прогон всех 75тысяч юнит тестов занимает около минуты) мы запускаем тесты паралельно на специальном кластере машин.


          1. gtbear
            13.12.2016 15:38

            ну а прогон тестов локально на машине разработчика возможен? как он например может отладить тест?


            1. demi_urg
              13.12.2016 15:52
              +1

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

              Под локальным я имею ввиду зайти по SSH на devel машину и запустить там тест.

              demiurg@www1.d3:~/badoo $ phpunit UTests/_packages/Platform/PlatformEnvironmentTest.php
              PHPUnit 5.3.2-a by Sebastian Bergmann and contributors.

              ............ 12 / 12 (100%)

              Time: 667 ms, Memory: 32.00MB

              OK (12 tests, 147 assertions)



              Настроить окружение на своем ноутбуке и писать код без доступа к devel площадке — задача нетривиальная.


          1. Bienne
            13.12.2016 23:07

            Как организована «песочница»? Это docker контейнеры, и у каждого разработчика свой собственный неперсекающийся набор контейнеров?


            1. demi_urg
              14.12.2016 12:25
              +1

              Песочница это просто папка с репозиторием в хоуме у разработчика на devel сервере.
              Нас это пока вполне устраивает, до докера в данном месте мы пока не дошли, возможно в будущем докер окажется удобнее.


    1. einstein_man
      13.12.2016 14:59
      +4

      В дополнение к demi_urg

      Есть такая штука как cppteam/ateam ideas.
      Это просто документ, куда скидываются достаточно слабо структурированные идеи — что можно улучшить и где надо бы допилить.
      Крупными мазками там также лежит техдолг, вида «нужно вот эту подсистему в будущем переделать, т.к. нам это понадобится для внедрения фичи X» или «я чувствую, что это заболит через какое-то время».

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

      Процедур особых нет, просто стараемся, чтобы работа по техдолгу / текущим «допилам» была где-то в пределах 20-40% времени на разработчика, не больше.


  1. rudenkovk
    13.12.2016 16:14
    +2

    Добрй день!
    У меня вопрос по мониторингу. Что вы используете как агенты? Что для навигации и отображения TS данных? Развивали на базе цианита (http://cyanite.io/) над кассандрой или что?


    1. che
      13.12.2016 16:54

      На Cyanite наше решение похоже мало. Только, пожалуй, тем что это тоже time series на Cassandra. Кроме этого мы смотрели и http://blueflood.io/ и http://opennms.github.io/newts/
      Но вдохновлялись мы больше, как это ни странно, rrdtool который, кстати, мы пока тоже продолжаем использовать.


  1. che
    13.12.2016 16:45

    Как у нас устроен сбор данных тема довольно объемная. Если отвечать кратко, то по разному :)

    Например, у нас есть целый отдел мониторинга и один из инструментов которым они пользуются является zabbix. К сожалению, я не могу рассказать более подробно, потому как не знаю всех нюансов.

    Множество технических и бизнес метрик собирают для себя сами разработчики. Что бы следить за состоянием своей части приложения и понимать что происходит.
    Каким образом:
    — Очень много метрик мы получаем из Pinba.
    — Большую часть данных отправляем прям из приложения и собираем при помощи LSD (см. раздел статьи LSD: Live Streaming Daemon).
    — Если говорить про c/go сервисы, каждый сервис написанный у нас предоставляет довольно подробную информацию о своем состоянии.

    А уже непосредственно за перекладывание данных в time series хранилище, а так же за навигацию и отображение отвечает наш собственный фреймворк (конечно же на php)


    1. rudenkovk
      13.12.2016 16:47

      Спасибо, в целом я понял. Как минимум не посмотрев поближе вопросов не имею :)


      1. che
        13.12.2016 16:55

        Мы уже анонсировали чуть выше, что планируем описать наше решение подробнее в полноценной статье.


      1. che
        13.12.2016 17:17
        +3

        Хочу сказать еще немного про сбор данных. Поскольку в нашей компании паттерн использования LSD + time series фреймворк практически один, ребята из нашего отдела написали решение, которое не только автоматизирует этот процесс, но и добавили туда несколько просто офигенных фич.

        Так что разработчику достаточно расставить в коде в нужных местах отправку события с вложенной в него структурой данных, и, например, сразу же иметь возможность видеть на дашборде графики, скажем, с количеством уникальных за сутки/час пользователей мужского пола из Парижа, к которым относится отправляемое событие. Внутри мы называет этот продукт Product Metrics, а его авторы выделились в отдельную команду Data-team. Они обещают подготовить для хабра отдельную статью про свое детище.


        1. rudenkovk
          13.12.2016 17:25

          ага, я понял. Будем ждать вашу статью.


  1. nizsheanez
    13.12.2016 20:04

    Как принимается решение о API демонов?(контракты)
    Просто разработчик садится и делает как нравится или есть этап где показывается/аппрувится написанный на бумажке контракт(какие поля и в какой форме входят/выходят).
    Есть ли какой-то SyleGuide как новые API должны выглядеть?

    Вопрос мой пожалуй полуночно-сумбурен — понятно что есть стандартные хедеры, и с ними приходит некий protobuf, мне интересно то что внутри протобуфа.


    1. mkevac
      13.12.2016 20:16
      +2

      Если говорить о демонах, то в тот момент когда от Feature команды приходит запрос о каком-то функционале, то мы договариваемся о том какие изменения в API понадобятся и делаем их. Тут все просто, т.к. стороны всего две.

      Если говорить о взаимодейтсвии между четырмя мобильными командами (iOS, Android, Windows Mobile, Mobile Web), платформой, веб командой, то у нас есть отдельная небольшая выделенная команда, которая занимается только API. По одному участнику из вот этих вот команд. Их задача договориться со всеми, понять и предугадать все возможные проблемы, записать результат в документ. По этому документу будут дальше работать люди, реализующие задачи.

      Но я сам далек от всего этого и от команды, рабтающей с API. Думаю что коллеги вам еще ответят более конкретно :-)


      1. Konojoto
        14.12.2016 14:45

        Думаю, что вопрос был всё-таки не про внешнее API, да и не наша сейчас вечеринка :–) Но если есть какие-то вопросы об этих вещах, то мы тоже всегда готовы рассказать.

        Я рассказывал недавно об особенностях нашего внешнего API на девконфе, и у нас какое-то время назад была статья о том, что у нас внутри протобуфа и как мы это развиваем.


    1. demi_urg
      14.12.2016 12:39

      API демонов обычно довольно простые, и каких либо проблем с тем что где то сделали так, что пользоваться невозможно у нас не возникало. Единственное что у нас более менее унифицированно — это отдача статистики самом сервисом. И сделано это для того что бы не писать каждый раз сбор метрик.


  1. Bienne
    13.12.2016 23:27

    Что у вас используется в качестве баз данных?
    Используете ли хранимые процедуры или обходитесь без них?
    Если есть хранимки то как происходит (и сколько длится по времени) накат обновлений?
    Очень интересна тема шардирования. Можно ли кратко, по каким параметрам шардируетесь, какие алгоритмы используете, возможно какие-то opensource golang проекты применяете.
    И еще, где всем любопытным можно еще вопросы позадавать помимо как здесь?


    1. Fally
      14.12.2016 00:54
      +3

      Старый добрый mysql, точнее percona server.
      Хранимки не используем, ибо сложно (можно ли?) атомарно выкладывать как пхп-код, так и код хранимок.
      В качестве шардированияя старый добрый virtual buckets, подробности можете найти в докладе нашего DBA.
      В golang-разработке используется как минимум gogoprotobuf (быстрее чем стандартный гугловый, тут подробнее)


    1. einstein_man
      14.12.2016 14:09

      > И еще, где всем любопытным можно еще вопросы позадавать помимо как здесь?
      задавайте здесь, не стесняйтесь.


  1. alexbyk
    20.12.2016 10:00
    +1

    Не могли бы вы рассказать подробнее про обработку фото (ресайз, наложение лого и тд). Какие библиотеки, фильтры используются?


    1. bo0rsh201
      20.12.2016 15:26
      +2

      Здравствуйте, если кратко, то сейчас схема такая:

      При заливке фото нарезается несколько базовых типовых размеров (а-ля большой, средний, маленький)
      в URL клиент явно указывает viewport, в который надо заресайзить картинку.

      Дальше на nginx мы с помощью lua динамически выбираем для заданного viewport максимально близкий физический размер и делаем downscale из него на лету.
      Помимо этого можно динамически накладывать фильтры — у нас это blur, pixelize и делать crop по координатам, которые переданы с клиента.

      Также на все фотки на лету накладывается watermark, которым можно управлять через параметры URL.

      Технически, мы и со стороны PHP и со стороны NGINX используем библиотеку http://www.leptonica.org
      В обоих местах к ней написаны наши собственные биндинги (модуль к nginx и расширение к php)

      Но сейчас есть множество готовых решений, которые дают похожий функционал из коробки.
      Как в виде нативных модулей nginx, так и в связке с https://openresty.org/


      1. alexbyk
        20.12.2016 17:07
        +1

        Спасибо за развернутый ответ. А скажите, leptonica — почему выбрали ее?

        Мне просто сейчас тоже надо выбрать инструмент как лучше даунскейлить фотки. Я провел множество разных тестов и у меня они показали, что downscale + Lanczos3 (который почти все предлагают по-умолчанию) работают одинаково медленно у всех кандидатов, libvips работает быстрее, так как видимо разбивает каждую фото на несколько частей и нагружает весь процессор, но в случае ресайза на сервере сразу нескольких фото это роли не играет. А если использовать более быстрый фильтр, где одна библиотека показывала преимущества перед другой, то фотографы сразу говорят «фу, мои фотки испорчены».

        Но про leptonica слышу впревые. Вот мне и интересно, почему крупная компания выбрала leptonica? У нее есть какие-то преимущества перед более популярными библиотеками, к которым биндинги уже есть?


        1. tony2001
          20.12.2016 17:38
          +2

          Артём немного перепутал, у нас в модуле для NGINX для операций с изображениями используется Intel Performance Primitives, а не Leptonica. У IPP сравнительно более сложный API, но она объективно работает быстрее той же лептоники, которую мы используем для аналогичных операций с изображениями в PHP.
          Насколько быстрее — точно не помню, но процентов 25 было, если я не ошибаюсь.

          Ранее у нас для всех операций с изображениями в PHP использовался ImageMagick. У него есть несколько безусловных плюсов: он тотально всеяден, там хорошая реализация bicubic interpolation, которая в итоге даёт очень приятный результат при ресайзе фотографий. Кроме того, ImageMagick — это такой Фотошоп под Линукс, там есть всё, что можно. Но у него есть один серьёзный минус — он ну очень медленный.

          Изначально нам нужно было решить проблему — ресайз фото медленный. На тот момент (примерно 7 лет назад), Лептоника точно так же не очень была известна =), но с задачей ресайза справлялась примерно в два раза быстрее.
          В процессе, как всегда, задача немного разрослась и теперь там не только ресайз, но и разнообразные операции над изображениями, но в Лептоника написана на понятном plain C и её патчить гораздо проще и приятнее, чем ImageMagick. Сейчас, возможно, есть какие-то другие библиотеки с аналогичным функционалом, но переходить на них будет уже сложнее из-за всяких кастомных вещей, которые мы добавили в Лептонику. В основном это функционал для генерации капчи, которая у нас выглядит примерно так:
          image


          1. alexbyk
            20.12.2016 19:36

            Спасибо за дополнение. У меня в принципе та же проблема: ресайз фоток, который устраивает фотографов(bi-cubic подобным они сказали сразу нет, да я и сам вижу разницу), жутко медленный, причем одинаково медленный и в браузерах, и в остальных библиотеках, до которых у меня дотянулись руки и я сомневаюсь, что это вообще как-то возможно ускорить. Так что, наверное, выберу IM из-за популярности


  1. lexand
    20.12.2016 17:14

    У меня вопрос по счетчикам и другой связанной с ними информацией.

    На сколько актуальными являются значения вроде «14541 человек в таком то городе», «451 человек сказали 'Да'» и т.п.?

    Поддерживаете ли вы точное значение в данных счетчиках, или вам достаточно знать приблизительное число?

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

    спасибо


    1. demi_urg
      20.12.2016 18:38
      +1

      Привет!

      Если я правильно понял вопрос, то вопрос о том, как считаются агригации по данным, которые расшардены по большому количеству сереров.
      В целом схема такая: у нас есть специализированые сишные сервисы, которые хранят все нужные данные в памяти и умеют быстро считать что-то по нужным срезам. Для синхранизации этих данных с данными в шардах мы используем очереди. Когда интересующие нас данные меняются в шардах мы кидаем событие, все эти события приходят в общую очередь и апдейтят данные в сервисе. Сервис раз в какое то время перестраивает индексы. Таким образом задержка между реальными данными и «счетчиками» составляет несколько минут