Comments 122
Второй вопрос: используете ли вы у себя service discovery (везде или точечно) и есть ли история успеха по этому поводу?
Спасибо!
Отвечаю на первый вопрос:
От PHP отказываться пока не хотим, он успешно решает поставленные задачи. Помимо самого Avito мы используем его и в других проектах: Автотека, Актидилер и Актиагент.
Маленькие микросервисы, которые не требуют много бизнес логики и должны работать быстро — пишем на Go.
Какие данные анализируете?
На каких данных обучали первоначально?
Увы, полностью рассказывать все механизмы борьбы с кликфродом и на каких именно данных это обучается мы не можем, т.к. это является коммерческой тайной.
Мы стараемся собирать всю возможную информацию которая нам доступна и передаем нашим специалистам, которые оптимизируют и настраивают различные веса для них. Но если поверхностно, то статистика кликов, история пользователя, параметры объявления.
В первую очередь смотрите на клики которые происходят и собирайте по ним информацию. Кто кликал, когда, куда кликал еще. Нормальный пользователь оставляет за собой след в интернете, а у роботов следов нету.
Почитайте про fingerprint https://habrahabr.ru/company/oleg-bunin/blog/321294/
Как бороться с кликфродом на начальном этапе, пока нет собственных данных о кликфроде?
Например:
Есть сайт-маркетплейс с каталогом товаров от разных поставщиков + исторические данные о переходах/конверсиях (без разметки о кликфроде). Решили продавать рекламу с оплатой за клики (переходы на карточки товаров).
Варианты решения на старте:
- Только вручную
- Обучить модель на собственных исторических данных о переходах и выявлять аномалии?
- Платные сторонние решения? Какие?
Все интересное что можно было рассказать, есть в докладе: youtu.be/OGf6mawQwaw
Если появятся более детальные вопросы — готов на них ответить.
Доклад посмотрел, весьма интересно, но по схеме больше похоже просто на сервисную архитектуру. Расскажите пожалуйста про service discovery и масштабирование всего этого дела.
Service discovery и инфраструктура у нас общая с Авито, отличие — больше гибкости в выборе стека технологий. Архитектура действительно сервисная, масштабируется и живет все в кубернетисе.
В плане взаимодействия с источниками все непросто, к поставщикам уникальных данных приходится подключаться на их условиях без альтернатив — шифрование проприетарным софтом на сертифицированном железе. Под такие источники заводим отдельные сервисы, которые работает только с ними, а внутри к ним уже ходим как к простым API.
Для поиска мы используем поисковый движок sphinxsearch. Данные храним в realtime индексах — это позволяет обновлять данные на выдаче очень быстро.
Чтобы быстро доставлять новые данные в индекс, мы написали GO демон который готовит и рассылает запросы с обновлениями на все поисковые сервера.
Сейчас у нас 38.5млн активных объявлений. В пик мы получаем около 16К запросов в секунду. 95 процентиль времени ответа поиска примерно 12мс.
Realtime индексы со временем деградируют в производительности, поэтому ежедневно делаем полную реиндексацию и еще один раз в день производим оптимизацию индексов.
Если не секрет, сколько времени занимает реиндексация одного сервера в вашей ситуации?
Монолит развертывается набором python-скриптов на основе библиотеки fabric.
Сервисы развертываются через CI/CD сервер в Kubernetes кластер при помощи специального пакетного менеджера helm.
В первую очередь стоит изучить документацию https://www.postgresql.org/docs/, она написана очень хорошо и подробно. Много полезной информации обсуждается в рассылках: https://www.postgresql.org/list/. Также советуем посмотреть обучающие видео или пройти курсы от Postgres Pro: https://postgrespro.ru/education/courses
Конечно, если вам требуется понимание
в точности как работает каждая строчка библиотеки, весь стек вызовов конкретной, нужной тебе функции, все детали алгоритмов, используемых в этой функции
То можете посмотреть исходники на C — https://github.com/postgres/postgres
Если вы используете не PostgreSQL, то просто поищите Ваше название github :)
Очень интересно. На kubernetes? Для каких нужд (devel/prod)? Кто клиенты и как они заказывают себе ресурсы? Есть ли какие-то ограничения по ресурсам, автоматически ли апрувите или нет?
Как для dev, так и для prod.
В случае dev это автотесты, dev-окружения для разработки, staging, внутренние ресурсы.
В случае prod — сервисы, обрабатывающие запросы пользователей и различные демоны для обработки данных.
Клиенты — другие юниты компании. Каждый юнит отвечает за заказ hardware для своих задач, естественно, мы имеем некоторый запас на всякий случай.
Используем «ванильный» PostgresSQL версий 9.2, 9.4, и 9.5. Из необычного можно отметить прокидывание данных через сессионные переменные внутрь deferred триггеров, отправку метрик через механизм LISTEN/NOTIFY в графит (aka pg_metricus, подробнее https://habrahabr.ru/company/avito/blog/323900/). Активно используем pgq и londiste. Сделали свой деплоер хранимых процедур через переопределение search_path, может быть когда-нибудь расскажем подробнее.
Из contrib используем pg_stat_statements, int_array, dblink и pageinspect.
JSON в базах храним как text, как json, и как jsonb, но индексы не используем и поиск/фильтрацию по jsonb не делаем.
Логика бэкенда пока лежит на базе сильно, но мы работаем над этим.
Баз меньше 100, таблиц от 10 до 1000 на базу. Хранимых процедур тоже где-то от 10 до 1000 на базу, а где-то их и нет совсем.
Не совсем про backend вопрос, но коллега просил передать:
По нашим наблюдениям, до сих пор, к сожалению, самым эффективным способом "медиации" рекламных систем остаётся построение водопадов - по очереди опрашиваем рекламные системы с разными порогами цен.
Это достаточно стандартный подход. Сложность заключается в определении порядка вызова систем и параметров, с которыми мы их вызываем. На порядок может влиять общее соотношение параметров: СРМ, fill rate, latency. Косвенно может определяться через потери трафика.
Ещё следует обратить внимание на техническое решение, которое управляет показами рекламы:
мы пробовали вызывать всё либо из Google DFP, либо из AdFox и получали очень значимые потери при обращении из Google в Яндекс и наоборот. Поэтому поверх Adfox, DFP есть ещё своя оболочка, которая определяет кого, где и с каким приоритетом вызывать.
Для компенсации провалов, любые изменения мы выкатываем через A/B тесты, сначала на малой части трафика, а потом в экспериментах 50/50 трафика. Это позволяет избегать потерь от неудачных решений.
Про API думаем и даже делаем. Пока обкатываем на внутренних проектах. А расскажите, какие у вас потребности в открытом API Авито?
Может, на него есть какие-то особенные надежды в рамках проекта или песочниц для новых юнитов?
Питон у нас живет в Data Science, почти все аналитики его использут. Так же он есть в антиспаме, рекомендациях и модерации. Все инструменты Computer Vision или Machine Learning конечно же написаны на Python.
Python такой же инструмент как PHP, или Go, который успешно решает определенный круг задач. Те же DBA используют его вместо bash скриптов.
Почему его нет? Это какое-то техническое ограничение (данные так побиты что их тяжело объединить), либо считается что и так нормально?
Возможно же вообще сделать поиск товаров в радиусе N километров. Есть такое в планах?
К сожалению, есть такие проблемы.
Работа по их решению уже ведется, и решить их не так просто как кажется изначально.
Пока этого функционала нет, вы можете пользоваться сортировкой по удалённости в приложении.
Вы увидите те объявления, для которых мы знаем (или думаем что знаем) расположение продавца.
Я всегда был уверен что причина есть! Подозреваю что это из-за того что объявления побиты по городам и могут храниться в разных базах. Так? Было бы интереснее подробнее узнать про то как организовано хранилище объявлений.
Все, что связано с машинным обучением в Avito – это все сплошная история успеха Python: антифрод, распознавание изображений, сервисы рекомендаций.
Рекомендации полностью автоматизированны? Каким образом проходит ручной тест их эффективности?
Или эффективность меряется тоже полностью в автоматическом режиме по пользовательскому поведению?
По Вашему мнению когда оправдано использование NoSql, если его использование вообще может быть оправдано.
NoSql оправданно использовать тогда, когда это решение является лучшим для своих задач.
Факторы по которым оно выбирается “лучшим” могут различаться в каждом конкретном примере. Возможно вам нужна mongodb, чтобы быстро проверить прототип фичи, понять что гипотеза работает и приступать к построению космолета, а может вам нужен быстрый и масштабируемый кэш, а надежность данных является вторичным фактором.
Сегментация у нас, например, на Tarantool построена https://youtu.be/1RS6GvK-JfU?t=50m40s
Различная статистика по просмотрам лежит в шардированном редисе на 512Гб.
- Сколько всего разных БД используете в Авито? Перечислите.
- Максимальное кол-во разных БД в одном проекте?
- Любимая БД у Go разработчиков? Почему?
- Какой стек разработки используете для проектов на Go? Для сборки, тестирования, деплоя?
- Используете per-project dependencies или всё в $GOPATH?
- Какой системой управления зависимостями в Go пользуетесь?
- Какой IDE пользуется большинство, какими плагинами?
- PostgreSQL, Memcached, Redis, Tarantool, MongoDB, SphinxSearch, Vertica.
- Все они используются в основном проекте Avito.
- Тут вопрос не про то, что любят разработчики, а про то, что нужно в конкретной задаче.
- Выше в треде про GO.
- Выше.
- Выше.
- Большинство разработчиков используют продукты Jetbrains.
Конечно, иногда бывают провалы. Но сильный не тот, кто не упал, а кто после падения сумел подняться.
Поэтому если что-то идет не так, то мы быстро (около 10 секунд) откатываем все сервера на предыдущую “стабильную” версию или готовим хотфиксы, которые оперативно загружаем.
Потом проводим работу над ошибками, чтобы не допускать их в будущем.
- Что и как используете для инфраструктурного мониторинга?
- Есть APM (Application Performance Monitoring)? Если да, то что и как используете?
Про нашу систему мониторинга есть подробная статья: https://habrahabr.ru/company/avito/blog/335410/
Если кратко, то collectd+heapster+brubeck+graphite+grafana+moira
2. Как заворачиваете PHPшные микросервисы в контейнеры (имею в виду — где размещаются процессы nginx, FPM)?
3. Используете ли API Gateways? Если да — то какие задачи они у вас решают и какая технология используется?
- Обычный JSON поверх HTTP. Что-то типа JSONRpc
- Один контейнер с nginx, второй контейнер с php-fpm, где располагается и код.
- В качестве API Gateway в данный момент используется сам монолит Avito :) Но есть отдельные кейсы, когда перед пачкой однотипных микросервисов стоит прослойка-gateway. Например у нас есть несколько разных рекомендательных сервисов, ответы которых собираются такой вот прослойкой и отдаются в Avito.
2 если правильно понял вопрос — в одном поде два контейнера — один с nginx и один с php-fpm.
3 да, чаще всего для параллельного сбора данных с разных сервисов, иногда с кешированием, а также для проверки авторизации.
Используете нейросети, предсказываете что-нибудь?
Работаем, у нас более 70Тб в Вертике. Храним и анализируем все, что можем. Тут про это писали: https://habrahabr.ru/company/avito/blog/322510/
Нейросети используются для распознавания изображений. Предсказываем всякое, например вероятность клика пользователем по рекламному объявлению в Авито.Контекст.
Идеальный кандидат хорошо знает Computer Science, знает алгоритмы и структуры данных, и конечно знает тот инструмент, которым он пользуется. Не важно это Python, PostgreSQL, PHP, GO или что-то ещё.
Высшее образование не объязательно, возраст тоже не имеет значение.
В первую очередь мы смотрим не столько знания языка, сколько умение решать прикладные задачи.
Junior мы отличаем от Middle разработчика лишь тем, что Junior всё знает, но реального опыта у него нет.
Список вакансий вы можете посмотреть тут, у нас всегда описаны требования под каждую. Но в данный момент мы не ищем Junior разработчиков.
Так же вы можете напрямую пообщаться с рекрутерами, которые сидят в канале телеграмм — https://t.me/AvitoJob
Про резервное копирование БД подробно рассказывали на HighLoad++ https://habrahabr.ru/company/oleg-bunin/blog/311472/. Для управления бекапами используем Bacula.
1. Что используете для балансировки нагрузки? nginx?
2. Какой rps примерно держит один сервер с php?
3. Сохранение в базу, кеши где происходит? Сразу при получении запроса? Rabbit?
4. Нет ли проблем с too many connections в mysql?
Деплой кода хранимых процедур и выкатка миграций – тема для отдельной статьи, когда-нибудь мы её напишем и опубликуем :)
В двух словах, хранимые процедуры выкатываются в новую схему, создаётся пользователь БД у которого в search_path указана эта новая схема. Новый PHP код соединяется с базой под этим новым пользователем и использует код новых хранимых процедур. Это позволяет в любой момент безболезненно откатиться.
Для наката миграций на схемы данных используются небольшие самописные библиотеки. Но автоматически они накатываются только в микросервисах, в большом Avito – только в test и dev средах. Сначала схемы, потом код, чтобы была возможность откатиться.
- Да, nginx.
- У нас 20000rps к бекенду, 65 железных серверов с php-монолитом, 300rps на каждый. С переходом на PHP7 каждый сервер смог держать в три раза больше, т.е. до 1000rps держать можем. Подробнее про переход на 7.0 писали тут: https://habrahabr.ru/company/avito/blog/338140/.
- В зависимости от задачи. В большинстве случаев сразу, в особо тяжелых – через RabbitMQ, либо через pgq. В кэши пишем сразу, в кэши пишем много.
- У нас нет MySQL. Мы используем PostgreSQL с PgBouncer'ами, которые эту проблему решают.
Как выкладка происходит в плане взаимодействия разработки и тестирования?
Разработчики разработали новую фичу, она прошла некоторый QA, а как дальше это попадает на прод? Есть промежуточная площадка (препрод), где фичу гоняют на живых данных, или она сразу уезжает в прод?
Разработчик разрабатывает новую фичу, затем передает её в review, где другие разработчики смотрят на написаный код и дают различные советы.
После этого, задача передается в тестирование, где собираются тестовые стенды и проходят ручные и авто тесты.
Если фича касается только внутренних отделов, например, она для поддержки или модерации, то стенд с ней передают нескольким командам, которые дают обратную связь.
Часть фич после тестов добавляется в билд через A/B тест, где её будут видеть лишь определенный процент людей.
Если положительное влияние фичи очевидно, то она просто попадает в билд и выкатывается на прод.
Спасибо!
Поднимаем docker-образы в minikube-окружении на ноутбуках разработчиков. Чтобы упростить и облегчить окружение многие вещи поднимаются в kubernetes-кластере в датацентре, например снепшоты баз данных, индексы sphinx, staging-версии микросервисов.
Ну и конечно набор самописных скриптов, которые помогают все это развернуть и актуализировать.
* Как вводите в боевую эсплуатацию нововведения? Пускаете 10% траффика на измененную часть либо 10% контейнеров обновляете и следите за метриками?
* Чем собираете метрики? Все средствами k8n или есть свои решения, допилки. (ПС прошел по ссылке, там написано, вопрос снят).
* Сколько виртуальных машин занимает дев версия для разработки или быстрого теста?
про деплой/откат: https://habrahabr.ru/company/avito/blog/339996/#comment_10471460
про схему тестирования фич: https://habrahabr.ru/company/avito/blog/339996/#comment_10471484
Про метрики у нас была отличная статья и скоро будет еще одна.
https://habrahabr.ru/company/avito/blog/335410/
Про кол-во виртуальных машин ответить не получится, т.к. сильно зависит от сервиса и фич которые нужно разрабатывать или тестировать.
Как организуете хранение больших объемом данных в Postgres? Используете шардирование? Какие инструменты для автоматизации обслуживания Postgres применяете?
Рассматривали стек Hadoop? Если рассматривали, то чем не устроил?
Какое оборудование и сколько рассказать не можем.
Postgres, Redis, Tarantool, Memcache, Sphinx шардируется во многих случаях. Про обслуживание Postgres рассказывали на разных конференциях, например https://habrahabr.ru/company/oleg-bunin/blog/311472/
Hadoop рассматривали. Не подошел, аргументов много, в частности нам нужен был инструмент анализа, позволяющий объединять большие разнородные данные (JOIN друг с другом дюжины многомиллиардных таблиц).
Почему я не могу добавить в видео в категории «Музыкальные инструменты»? Для многих это актуально.
Избыточность или дублирование в угоду скорости работы бд, такое бывало?
Очень часто.
Например чтобы показать preview объявления на странице поиска нам не надо знать об объявлении всё, достаточно картинки, цены, названия, ещё нам надо немного информации о пользователе.
Чтобы каждый раз не вынимать эту информацию из большой таблицы соединённой с другой большой таблицей у нас есть материализованное представление содержащее только необходимую нам информацию. Обращение к такой таблице занимает минимум времени и ресурсов.
Более того, такая таблица легко реплицируется на другой сервер и нагрузка на основную базу ещё более снижается.
2. Как доставляются данные до демонов (message broker)?
3. При шардировании сколько объявлений умещается на одну тачку?
4. Как происходит деплой, чем выкатываете в прод?
- В качестве рекомендательного демона используется микросервис, написанный на питоне.
- Уточните пожалуйста, что вы имеете в виду? Какого типа данные?
- Про шардирование — всё зависит от решаемых с его помощью задач.
- Если цель — просто хранить на диске, то от размеров диска.
- Если распределение большой читающей нагрузки — то от размера оперативной памяти.
- Существуют и другие ограничения, например пропускная способность сети или CPU.
- Про деплой писали комментарии выше, посмотрите.
Нельзя было хотя-бы капчу сделать, ну или подтверждение по телефону в самом крайнем случае. Я не знаю, какой процент посетителей вы на этом теряйте, но я принципиально не пользуюсь сервисом с таким наплевательским отношением к потенциальному клиенту, так как даже объявления нельзя прочитать, а публиковать мне по-сути и и никогда не было нужно.
Сколько их примерно сейчас?
Несколько десятков
Каким образом продумываете и согласовываете API?
Есть требования и разработчики ориентируются на них, стараясь заранее закладывать тот функционал, который может потребоваться в дальнейшем.
Какой характер связности между ними? Все со всеми или каждый с монолитом?
Сильно зависит от ситуации, но четкого деления нет. Сервис предоставляет api, любой другой сервис может взаимодействовать с ним.
Как вносите изменения в API?
Либо расширение существующих методов, либо создание новых, либо версионирование. В любом случае, всегда поддерживаем обратную совместимость.
Какой порядок миграции на новую версию API в куче мест где уже используется старая версия? Насколько я понял, сервисы разнесены по разным репозиториям, поэтому вариант «разработчик API заодно сам меняет все usages» невозможен.
Разработчики сервиса обычно делают библиотеки-“клиенты” для него. Версии библиотек фиксируются. Таким образом внедрение новых фич не задевает остальных. Сейчас работаем над автогенерацией кода клиентов для сокращения времени на поддержку клиентов на разных языках.
Какой по вашим ощущениям оверхед по сравнению с монолитом это даёт?
В первое время с этим трудно жить, сложнее всего когда нужно найти баг, который появляется неизвестно где. В остальном такая компоновка позволяет сократить общие затраты на разработку и поддержку сервиса, даёт гибкость, которая необходима проектах такого масштаба.
А как вы храните секреты (разного рода credentials для сервисов)? Как это интегрируете с CI/CD?
Вы используете интроспекцию-рефлексию при разработке кода?
AMA. Avito. Backend