Конкурс Авито-2017 - Решение 2ое место - Василий Рубцов
"Бэк-офис в Avito: миллиард объявлений на 10 серверах" Вячеслав Крюков (Avito)
1. Бэк-офис в Avito:Бэк-офис в Avito:Бэк-офис в Avito:Бэк-офис в Avito:Бэк-офис в Avito:
миллиард объявлениймиллиард объявлениймиллиард объявлениймиллиард объявлениймиллиард объявлений
на 10 серверахна 10 серверахна 10 серверахна 10 серверахна 10 серверах
Вячеслав КрюковВячеслав КрюковВячеслав КрюковВячеслав КрюковВячеслав Крюков
SphinxSearch Meetup #2 @ AvitoSphinxSearch Meetup #2 @ AvitoSphinxSearch Meetup #2 @ AvitoSphinxSearch Meetup #2 @ AvitoSphinxSearch Meetup #2 @ Avito
2. Зачем нужен Backoffice?
• Модерация объявлений
• Управление
• пользователями
• магазинами
• сообщениями
• контекстными объявлениями
• И много еще зачем
• И для всего нужен поиск
SphinxSearch Meetup #2 @ Avito
4. Что мы хотим от поиска в Backoffice?
• Обрабатывать много объявленй
• Высокую актуальность
• Приемлемую скорость выполнения запросов
• Унификацию
SphinxSearch Meetup #2 @ Avito
5. Sql источник и дельта индексация - классика
жанра
• Делим индекс на две части Small и Main
• Запоминаем метку времени последней индексации Main
• Периодически переиндексируем Small от этой метки
• Пока его размер приемлем
SphinxSearch Meetup #2 @ Avito
13. Дельта индексация - известные проблемы
• Small быстро пухнет
• И переиндексируется с каждым разом медленнее
• Мы вытаскиваем повторно из базы все больше и больше данных
• Падает актуальность
• И надо переиндексировать Main
• Возможно, слишком часто, чем хотелось бы
SphinxSearch Meetup #2 @ Avito
14. Дельта индексация: почему часто
переиндексировать Main плохо?
• Мы вытаскиваем все данные
• Мы не запрещаем JOIN в запросах
• А даже любим их
• Переиндексировать Main это долго
• Либо очень сложно
SphinxSearch Meetup #2 @ Avito
15. Дельта индексация - пытаемся
оптимизировать
• Делим индекс на три части Small, Medium, Main
• Храним две метки времени индексации для Medium, Main
• И периодически переиндексируем Small от первой метки
• А Medium от второй
• Пока их размер приемлем
SphinxSearch Meetup #2 @ Avito
25. Дельта индексация: после оптимизации
• Переиндексация Main происходит реже
• Но она все равно нужна
• Если не раз в сутки
• Так раз в неделю
• И даже если раз в месяц - это плохо
• Хотим это делать в крайнем случае
SphinxSearch Meetup #2 @ Avito
26. Всякая экзотика
• Апдейтим атрибуты, а в дельте только изменения текста
• RT
• может упасть
• Мерж индексов
• быстро работает
• но фейлится в самый неподходящий момент
• Предложите свой вариант
SphinxSearch Meetup #2 @ Avito
27. Pipe источник индексации
• Необходима собственная реализация извлечения данных
• Широкие возможности: можно объеденять данные с различных серверов
БД, источников с разными форматами
SphinxSearch Meetup #2 @ Avito
29. TSV pipe + дельта индексация
Как это устроено
• Выделяем несколько частей-чанков
• Small, Medium, Main и т.п.
• Как для обычной дельта схемы
• Отдельный TSV файл
• соответствующий какому-либо чанку
• отсортирован по убыванию id объявления
SphinxSearch Meetup #2 @ Avito
30. TSV pipe + дельта индексация
Как это устроено
• Выделяем самый маленький TSV чанк - Pre
• Ставим его перед остальными TSV чанками
• В него генерируем данные
• по времени от сохраненной метки
• маленькими порциями
• Сортируем по убыванию id объявления
• После генерации сохраняем новую метку
SphinxSearch Meetup #2 @ Avito
31. TSV pipe + дельта индексация
Как это устроено
• Осуществляем последовательный мерж TSV чанков
• Мерж TSV чанков по лэтенси
• indexer забирает заданные TSV файлы и строит индексы
• Применяем TSV KL для удаленных объявлений
• Применяем Sphinx KL для приоритета актуальности младших чанков над
старшими
• Большие TSV файлы жмем
• Гибкие и простые блокировки
SphinxSearch Meetup #2 @ Avito
32. TSV pipe + дельта индексация
Профит
• Вычитываем данные из БД только один раз
• Одна метка
• Манипулировать отсортированными TSV файлами просто и быстро
• Можем вытаскивать данные не только из БД
• А из любого др. хранилища и любом др. формате
• indexer быстро обрабатывает TSV файлы
• Очень полезно при смене версии Sphinx
• И отсутствии обратной совместимости формата индексов
SphinxSearch Meetup #2 @ Avito
33. Мерж TSV чанков по лэтенси
Генерим данные в Pre
SphinxSearch Meetup #2 @ Avito
Pre
Small
Main
34. Мерж TSV чанков по лэтенси
Сгенерили
После генерации Pre сохранили новую мектку
SphinxSearch Meetup #2 @ Avito
Pre
Small
Main
35. Мерж TSV чанков по лэтенси
Смержили Pre в Small
SphinxSearch Meetup #2 @ Avito
Pre
Small
Main
36. Мерж TSV чанков по лэтенси
Генерим данные в Pre
SphinxSearch Meetup #2 @ Avito
Pre
Small
Main
37. Мерж TSV чанков по лэтенси
Сгенерили
SphinxSearch Meetup #2 @ Avito
Pre
Small
Main
38. Мерж TSV чанков по лэтенси
Смержили Pre в Small
SphinxSearch Meetup #2 @ Avito
Pre
Small
Main
39. Мерж TSV чанков по лэтенси
Генерим данные в Pre
SphinxSearch Meetup #2 @ Avito
Pre
Small
Main
40. Мерж TSV чанков по лэтенси
Сгенерили
SphinxSearch Meetup #2 @ Avito
Pre
Small
Main
41. Мерж TSV чанков по лэтенси
Смержили Pre в Small
SphinxSearch Meetup #2 @ Avito
Pre
Small
Main
42. Мерж TSV чанков по лэтенси
Генерим данные в Pre
SphinxSearch Meetup #2 @ Avito
Pre
Small
Main
43. Мерж TSV чанков по лэтенси
Сгенерили
SphinxSearch Meetup #2 @ Avito
Pre
Small
Main
44. Мерж TSV чанков по лэтенси
Смержили Pre в Small, мерж занял слишком много времени
SphinxSearch Meetup #2 @ Avito
Pre
Small
Main
45. Мерж TSV чанков по лэтенси
Смержили Small в Main
SphinxSearch Meetup #2 @ Avito
Pre
Small
Main
46. Мерж TSV чанков по лэтенси
Генерим данные в Pre
SphinxSearch Meetup #2 @ Avito
Pre
Small
Main
47. Мерж TSV чанков по лэтенси
Сгенерили
SphinxSearch Meetup #2 @ Avito
Pre
Small
Main
48. Мерж TSV чанков по лэтенси
Смержили Pre в Small
SphinxSearch Meetup #2 @ Avito
Pre
Small
Main
49. Мерж TSV чанков по лэтенси
Генерим данные в Pre
SphinxSearch Meetup #2 @ Avito
Pre
Small
Main
50. Мерж TSV чанков по лэтенси
Сгенерили
SphinxSearch Meetup #2 @ Avito
Pre
Small
Main
51. Мерж TSV чанков по лэтенси
Смержили Pre в Small
SphinxSearch Meetup #2 @ Avito
Pre
Small
Main
52. Мерж TSV чанков по лэтенси
Генерим данные в Pre
SphinxSearch Meetup #2 @ Avito
Pre
Small
Main
53. Мерж TSV чанков по лэтенси
Сгенерили
SphinxSearch Meetup #2 @ Avito
Pre
Small
Main
54. Мерж TSV чанков по лэтенси
Смержили Pre в Small
SphinxSearch Meetup #2 @ Avito
Pre
Small
Main
55. Мерж TSV чанков по лэтенси
Генерим данные в Pre
SphinxSearch Meetup #2 @ Avito
Pre
Small
Main
56. Мерж TSV чанков по лэтенси
Сгенерили
SphinxSearch Meetup #2 @ Avito
Pre
Small
Main
57. Мерж TSV чанков по лэтенси
Смержили Pre в Small
SphinxSearch Meetup #2 @ Avito
Pre
Small
Main
58. Мерж TSV чанков по лэтенси
Генерим данные в Pre
SphinxSearch Meetup #2 @ Avito
Pre
Small
Main
59. Мерж TSV чанков по лэтенси
Сгенерили
SphinxSearch Meetup #2 @ Avito
Pre
Small
Main
60. Мерж TSV чанков по лэтенси
Смержили Pre в Small, мерж занял слишком много времени
SphinxSearch Meetup #2 @ Avito
Pre
Small
Main
61. Мерж TSV чанков по лэтенси
Смержили Small в Main
SphinxSearch Meetup #2 @ Avito
Pre
Small
Main
62. Блокировки при мерже Pre-Small
Генерим Pre и лочим Small, что бы потом с ним смержиться
SphinxSearch Meetup #2 @ Avito
Pre
Small
Main
63. Блокировки при мерже Pre-Small
Сгенерли Pre, другая генерация Pre пока невозможна
SphinxSearch Meetup #2 @ Avito
Pre
Small
Main
64. Блокировки при мерже Pre-Small
Смержили Pre в Small
SphinxSearch Meetup #2 @ Avito
Pre
Small
Main
65. Блокировки при мерже Pre-Small
Разлочили Pre и Small, возможна следующая генерация Pre
SphinxSearch Meetup #2 @ Avito
Pre
Small
Main
66. Блокировки при мерже промежуточных TSV
чанков
Перед мержем Small в Main
SphinxSearch Meetup #2 @ Avito
Pre
Small
Main
67. Блокировки при мерже промежуточных TSV
чанков
Лочим Main, перемещаем Small в Small.tmp
Залочить Main можно, если в этот момент не был залочен Small
SphinxSearch Meetup #2 @ Avito
Pre
Small.tmp
Main
68. Блокировки при мерже промежуточных TSV
чанков
Мержим Small.tmp в Main, можем мержить Pre в Small
SphinxSearch Meetup #2 @ Avito
Pre
Small
Small.tmp
Main
69. Блокировки при мерже промежуточных TSV
чанков
Все еще мержим Small.tmp в Main, Small растет
SphinxSearch Meetup #2 @ Avito
Pre
Small
Small.tmp
Main
70. Блокировки при мерже промежуточных TSV
чанков
Получили новый Main, Small растет
SphinxSearch Meetup #2 @ Avito
Pre
Small
Main
71. Перегенерация Main
Надо согнать все данные по цепочке TSV чанков в конец перед Main
SphinxSearch Meetup #2 @ Avito
Pre
Small
Medium
Main
81. Перегенерация Main
Main.new переместили в Main, Medium.tmp удалили
После перегенерации Main сохранили новую мектку
SphinxSearch Meetup #2 @ Avito
Pre
Small
Medium
Main
82. Перегенерация Main
Особый, тяжелый случай
• Останавливаем реплику
• Вычитываем через Seq Scan все данные для Main
• Нарезаем TSV файлы по нодам
• Сохраняем новую метку
SphinxSearch Meetup #2 @ Avito
83. Реализация схемы TSV pipe + дельта
индексация
• Около 3000 строк PHP
• Генератор данных - TSVGeneratorBase
• AdmItems
• ProItems
• AdmAds
• ...
• Всего 9 генераторов и 70% кода
SphinxSearch Meetup #2 @ Avito
84. Реализация схемы TSV pipe + дельта
индексация
• Управление вводом/выводом - TSVResource
• Обычные TSV файлы
• .gz
• создание TSV файла c одной строкой
SphinxSearch Meetup #2 @ Avito
91. Архитектура поискового кластера
Распределение данных
• Нужно больше для обеспечения скорости выполнения запроса
• Чем для обработки большого числа запросов
• Утилизирует многоядреность
SphinxSearch Meetup #2 @ Avito
92. Архитектура поискового кластера
Распределение данных
• Равномерно распределяем наш миллиард объявлений по 100 нодам
• 10 нод на каждом из 10 контейнерах
• Можем переиграть число нод, обработав TSV файлы
• Намного быстрее, чем вычитать всю базу
SphinxSearch Meetup #2 @ Avito
93. Архитектура поискового кластера
Управление конфигурацией
• Контейнерная архитектура, LXC
• Динамическая конфигурация для indexer и searchd
• Конфигурация контейнеров в манфетах puppet
SphinxSearch Meetup #2 @ Avito
95. Архитектура поискового кластера
Запуск indexer на контейнерах Search-container01-10
• Каждую минуту по крону
• Только для тех индексов, для которых обновились TSV файлы
• touch <TSV файл> - индекс будет перестроен заново
• indexer срабатывает
• Small - мили сек
• Medium - сек
• Main - десятки сек
• Archive - сотни сек
SphinxSearch Meetup #2 @ Avito
96. Примерные объемы данных
• Индексы - десятки гб на ноду
• TSV файлы - десятки гб на ноду
SphinxSearch Meetup #2 @ Avito
97. Архитектура поискового кластера
Объединение контейнеров в кластере
SphinxSearch Meetup #2 @ Avito
HAproxy on app's
Search-pool01...10
Search-container01 ... Search-container10
Node1 ... Node10 Node91 ... Node100
98. Архитектура поискового кластера
Конфигурация индексов, поля и атрибуты, порядок соотв. колонкам в TSV
файле
#!/usr/bin/env bash
INDEX='items'
INDEX_CHUNKS="archive.gz main.gz medium.tsv small.tsv"
MAX_NODE_ID=100
HAS_KL=1
SOURCE_CONF="
field = title
field = description
attr_bigint = price
attr_uint = user_id
attr_uint = category_id
attr_uint = location_id
...
SphinxSearch Meetup #2 @ Avito