Upload
avitotech
View
167
Download
3
Embed Size (px)
Citation preview
Бэк-офис в 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
Зачем нужен Backoffice?• Модерация объявлений• Управление
• пользователями• магазинами• сообщениями• контекстными объявлениями
• И много еще зачем• И для всего нужен поиск
SphinxSearch Meetup #2 @ Avito
Что мы хотим от поиска в Backoffice?• Обрабатывать много объявленй• Высокую актуальность• Приемлемую скорость выполнения запросов• Унификацию
SphinxSearch Meetup #2 @ Avito
Sql источник и дельта индексация - классикажанра
• Делим индекс на две части Small и Main• Запоминаем метку времени последней индексации Main• Периодически переиндексируем Small от этой метки• Пока его размер приемлем
SphinxSearch Meetup #2 @ Avito
Дельта индексацияПереиндексируем Small, Small уже совсем и не Small
SphinxSearch Meetup #2 @ Avito
Small
Main
Дельта индексацияПереиндексировали Main, Small стал маленьким
SphinxSearch Meetup #2 @ Avito
Small
Main
Дельта индексацияПереиндексировали Main, Small стал маленьким
SphinxSearch Meetup #2 @ Avito
Small
Main
Дельта индексация - известные проблемы• Small быстро пухнет• И переиндексируется с каждым разом медленнее• Мы вытаскиваем повторно из базы все больше и больше данных• Падает актуальность• И надо переиндексировать Main• Возможно, слишком часто, чем хотелось бы
SphinxSearch Meetup #2 @ Avito
Дельта индексация: почему частопереиндексировать Main плохо?
• Мы вытаскиваем все данные• Мы не запрещаем JOIN в запросах• А даже любим их• Переиндексировать Main это долго• Либо очень сложно
SphinxSearch Meetup #2 @ Avito
Дельта индексация - пытаемсяоптимизировать
• Делим индекс на три части Small, Medium, Main• Храним две метки времени индексации для Medium, Main• И периодически переиндексируем Small от первой метки• А Medium от второй• Пока их размер приемлем
SphinxSearch Meetup #2 @ Avito
Дельта индексацияПереиндексируем Small...Small...Medium
SphinxSearch Meetup #2 @ Avito
Small
Medium
Main
Дельта индексацияПереиндексируем Small...Small...Medium...Small
SphinxSearch Meetup #2 @ Avito
Small
Medium
Main
Дельта индексацияПереиндексируем Medium...Small...Small
SphinxSearch Meetup #2 @ Avito
Small
Medium
Main
Дельта индексацияПереиндексируем Medium...Small...Small...Medium
SphinxSearch Meetup #2 @ Avito
Small
Medium
Main
Дельта индексацияПереиндексируем Medium...Small...Small
SphinxSearch Meetup #2 @ Avito
Small
Medium
Main
Дельта индексацияПереиндексируем Medium...Small...Small...Main...Medium...Small
SphinxSearch Meetup #2 @ Avito
Small
Medium
Main
Дельта индексация: после оптимизации• Переиндексация Main происходит реже• Но она все равно нужна• Если не раз в сутки• Так раз в неделю• И даже если раз в месяц - это плохо• Хотим это делать в крайнем случае
SphinxSearch Meetup #2 @ Avito
Всякая экзотика• Апдейтим атрибуты, а в дельте только изменения текста• RT
• может упасть• Мерж индексов
• быстро работает• но фейлится в самый неподходящий момент
• Предложите свой вариант
SphinxSearch Meetup #2 @ Avito
Pipe источник индексации• Необходима собственная реализация извлечения данных• Широкие возможности: можно объеденять данные с различных серверов
БД, источников с разными форматами
SphinxSearch Meetup #2 @ Avito
TSV pipe• TSV - Tab Separated Values• Работает быстрее XML Pipe• Проще обрабатывается
SphinxSearch Meetup #2 @ Avito
TSV pipe + дельта индексацияКак это устроено
• Выделяем несколько частей-чанков• Small, Medium, Main и т.п.• Как для обычной дельта схемы• Отдельный TSV файл
• соответствующий какому-либо чанку• отсортирован по убыванию id объявления
SphinxSearch Meetup #2 @ Avito
TSV pipe + дельта индексацияКак это устроено
• Выделяем самый маленький TSV чанк - Pre• Ставим его перед остальными TSV чанками• В него генерируем данные
• по времени от сохраненной метки• маленькими порциями
• Сортируем по убыванию id объявления• После генерации сохраняем новую метку
SphinxSearch Meetup #2 @ Avito
TSV pipe + дельта индексацияКак это устроено
• Осуществляем последовательный мерж TSV чанков• Мерж TSV чанков по лэтенси• indexer забирает заданные TSV файлы и строит индексы• Применяем TSV KL для удаленных объявлений• Применяем Sphinx KL для приоритета актуальности младших чанков над
старшими• Большие TSV файлы жмем• Гибкие и простые блокировки
SphinxSearch Meetup #2 @ Avito
TSV pipe + дельта индексацияПрофит
• Вычитываем данные из БД только один раз• Одна метка• Манипулировать отсортированными TSV файлами просто и быстро• Можем вытаскивать данные не только из БД• А из любого др. хранилища и любом др. формате• indexer быстро обрабатывает TSV файлы• Очень полезно при смене версии Sphinx• И отсутствии обратной совместимости формата индексов
SphinxSearch Meetup #2 @ Avito
Мерж TSV чанков по лэтенсиСгенерили
После генерации Pre сохранили новую мектку
SphinxSearch Meetup #2 @ Avito
Pre
Small
Main
Мерж TSV чанков по лэтенсиСмержили Pre в Small, мерж занял слишком много времени
SphinxSearch Meetup #2 @ Avito
Pre
Small
Main
Мерж TSV чанков по лэтенсиСмержили Pre в Small, мерж занял слишком много времени
SphinxSearch Meetup #2 @ Avito
Pre
Small
Main
Блокировки при мерже Pre-SmallГенерим Pre и лочим Small, что бы потом с ним смержиться
SphinxSearch Meetup #2 @ Avito
Pre
Small
Main
Блокировки при мерже Pre-SmallСгенерли Pre, другая генерация Pre пока невозможна
SphinxSearch Meetup #2 @ Avito
Pre
Small
Main
Блокировки при мерже Pre-SmallРазлочили Pre и Small, возможна следующая генерация Pre
SphinxSearch Meetup #2 @ Avito
Pre
Small
Main
Блокировки при мерже промежуточных TSVчанковПеред мержем Small в Main
SphinxSearch Meetup #2 @ Avito
Pre
Small
Main
Блокировки при мерже промежуточных TSVчанковЛочим Main, перемещаем Small в Small.tmp
Залочить Main можно, если в этот момент не был залочен Small
SphinxSearch Meetup #2 @ Avito
Pre
Small.tmp
Main
Блокировки при мерже промежуточных TSVчанковМержим Small.tmp в Main, можем мержить Pre в Small
SphinxSearch Meetup #2 @ Avito
Pre
Small
Small.tmp
Main
Блокировки при мерже промежуточных TSVчанковВсе еще мержим Small.tmp в Main, Small растет
SphinxSearch Meetup #2 @ Avito
Pre
Small
Small.tmp
Main
Блокировки при мерже промежуточных TSVчанковПолучили новый Main, Small растет
SphinxSearch Meetup #2 @ Avito
Pre
Small
Main
Перегенерация MainНадо согнать все данные по цепочке TSV чанков в конец перед Main
SphinxSearch Meetup #2 @ Avito
Pre
Small
Medium
Main
Перегенерация MainПереместили Medium в Medium.tmp, генерируем Main.new
SphinxSearch Meetup #2 @ Avito
Pre
Small
Main
Medium.tmp
Main.new
Перегенерация MainГенерируем Main.new, растет Small
SphinxSearch Meetup #2 @ Avito
Pre
Small
Main
Medium.tmp
Main.new
Перегенерация MainГенерируем Main.new, растет Small и готов к мержу в Medium
SphinxSearch Meetup #2 @ Avito
Pre
Small
Main
Medium.tmp
Main.new
Перегенерация MainГенерируем Main.new, смержили Small в Medium
SphinxSearch Meetup #2 @ Avito
Pre
Small
Medium
Main
Medium.tmp
Main.new
Перегенерация MainГенерируем Main.new, опять растет Small
SphinxSearch Meetup #2 @ Avito
Pre
Small
Medium
Main
Medium.tmp
Main.new
Перегенерация MainГенерируем Main.new, опять смержили Small в Medium
SphinxSearch Meetup #2 @ Avito
Pre
Small
Medium
Main
Medium.tmp
Main.new
Перегенерация MainГенерируем Main.new, растет Small
SphinxSearch Meetup #2 @ Avito
Pre
Small
Medium
Main
Medium.tmp
Main.new
Перегенерация MainMain.new сгенерился, опять смержили Small в Medium
SphinxSearch Meetup #2 @ Avito
Pre
Small
Medium
Main
Medium.tmp
Main.new
Перегенерация MainMain.new переместили в Main, Medium.tmp удалили
После перегенерации Main сохранили новую мектку
SphinxSearch Meetup #2 @ Avito
Pre
Small
Medium
Main
Перегенерация MainОсобый, тяжелый случай
• Останавливаем реплику• Вычитываем через Seq Scan все данные для Main• Нарезаем TSV файлы по нодам• Сохраняем новую метку
SphinxSearch Meetup #2 @ Avito
Реализация схемы TSV pipe + дельтаиндексация
• Около 3000 строк PHP• Генератор данных - TSVGeneratorBase
• AdmItems• ProItems• AdmAds• ...• Всего 9 генераторов и 70% кода
SphinxSearch Meetup #2 @ Avito
Реализация схемы TSV pipe + дельтаиндексация
• Управление вводом/выводом - TSVResource• Обычные TSV файлы• .gz• создание TSV файла c одной строкой
SphinxSearch Meetup #2 @ Avito
Реализация схемы TSV pipe + дельтаиндексация
• Мержер файлов - PHPMerger• Мерж предсортированных TSV файлов• Мерж с TSV KL
SphinxSearch Meetup #2 @ Avito
Реализация схемы TSV pipe + дельтаиндексацияВыделение TSV чанка в отдельную сущность
SphinxSearch Meetup #2 @ Avito
TSVChunkFirst
TSVChunkMedium
TSVChunkMedium
TSVChunkLast
Реализация схемы TSV pipe + дельтаиндексацияВыделение TSV чанка в отдельную сущность
• Первый чанк - TSVChunkFirst• process• processRange• processFull• generate• reset
SphinxSearch Meetup #2 @ Avito
Реализация схемы TSV pipe + дельтаиндексацияВыделение TSV чанка в отдельную сущность
• Промежуточный чанк - TSVChunkMedium, последний чанк - TSVChunkLast• process• processFull• merge• move• reset• archive
SphinxSearch Meetup #2 @ Avito
Реализация схемы TSV pipe + дельтаиндексацияВыделение TSV чанка в отдельную сущность
• TSVManager - cборщик цепочки чанков из экземпляров• TSVChunkFirst• TSVChunkMedium• TSVChunkLast
• Запускает обработку цепочки
SphinxSearch Meetup #2 @ Avito
Реализация схемы TSV pipe + дельтаиндексацияКонфигурация
'adm_items' => [
'nodes' => 100,
'path' => '/path/to/tsv',
'chunks' => [
'pre' => [],
'small' => [],
'medium' => ['latency' => 1000, 'throttle' => 15 * 60],
'main' => ['gzip' => 1, 'latency' => 40000, 'throttle' => 61 * 60],
'archive' => ['gzip' => 1, 'throttle' => 61 * 60, 'schedule' => ['wH' => '002']], // schedule - воскресенье 2 ночи
],
]
SphinxSearch Meetup #2 @ Avito
Архитектура поискового кластераРаспределение данных
• Нужно больше для обеспечения скорости выполнения запроса• Чем для обработки большого числа запросов• Утилизирует многоядреность
SphinxSearch Meetup #2 @ Avito
Архитектура поискового кластераРаспределение данных
• Равномерно распределяем наш миллиард объявлений по 100 нодам• 10 нод на каждом из 10 контейнерах• Можем переиграть число нод, обработав TSV файлы• Намного быстрее, чем вычитать всю базу
SphinxSearch Meetup #2 @ Avito
Архитектура поискового кластераУправление конфигурацией
• Контейнерная архитектура, LXC• Динамическая конфигурация для indexer и searchd• Конфигурация контейнеров в манфетах puppet
SphinxSearch Meetup #2 @ Avito
Архитектура поискового кластераРаздача TSV файлов по контейнерам при индексации
SphinxSearch Meetup #2 @ Avito
Cron-server, генерация TSV файлов
Search-container01 ... Search-container10
Node1
Small1 Medium1 Main1 Archive1
... Node10 Node91 ... Node100
Small100 Medium100 Main100 Archive100
Архитектура поискового кластераЗапуск indexer на контейнерах Search-container01-10
• Каждую минуту по крону• Только для тех индексов, для которых обновились TSV файлы• touch <TSV файл> - индекс будет перестроен заново• indexer срабатывает
• Small - мили сек• Medium - сек• Main - десятки сек• Archive - сотни сек
SphinxSearch Meetup #2 @ Avito
Примерные объемы данных• Индексы - десятки гб на ноду• TSV файлы - десятки гб на ноду
SphinxSearch Meetup #2 @ Avito
Архитектура поискового кластераОбъединение контейнеров в кластере
SphinxSearch Meetup #2 @ Avito
HAproxy on app's
Search-pool01...10
Search-container01 ... Search-container10
Node1 ... Node10 Node91 ... Node100
Архитектура поискового кластераКонфигурация индексов, поля и атрибуты, порядок соотв. колонкам в 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
Архитектура поискового кластераКонфигурация индексов, привязка tsv файлам ноды
source s_archive_1:s_template
{
tsvpipe_command = ssh ... -q cron-server cat /path/to/tsv/archive_1.*gz | zcat
}
index archive_1:template
{
type = plain
source = s_archive_1
path = /home/sphinx/src/archive_1
}
SphinxSearch Meetup #2 @ Avito
Архитектура поискового кластераКонфигурация индексов, Sphinx KL
source s_kl_main_1:s_kl_template
{
xmlpipe_command = ssh ... -q cron-server /path/to/kl.sh /path/to/tsv/main_1.*gz
}
source s_main_1:s_template
{
tsvpipe_command = ssh ... -q cron-server cat /path/to/tsv/main_1.*gz | zcat
}
index main_1:template
{
type = plain
source = s_main_1
source = s_kl_main_1
path = /path/to/indexes/main_1
}
SphinxSearch Meetup #2 @ Avito
Архитектура поискового кластераКонфигурация индексов, сборка индекса ноды
index items_1
{
type = distributed
local = archive_1
local = main_1
local = medium_1
local = small_1
}
SphinxSearch Meetup #2 @ Avito
Архитектура поискового кластераКонфигурация индексов, сборка индекса контейнера
index items
{
type = distributed
agent = localhost:9314:items_1
agent = localhost:9314:items_11
agent = localhost:9314:items_21
agent = localhost:9314:items_31
agent = localhost:9314:items_41
agent = localhost:9314:items_51
agent = localhost:9314:items_61
agent = localhost:9314:items_71
agent = localhost:9314:items_81
agent = localhost:9314:items_91
}
SphinxSearch Meetup #2 @ Avito
Архитектура поискового кластераКонфигурация индексов, сборка индекса кластера
index items
{
type = distributed
agent = search-container01:9314:items
agent = search-container02:9314:items
agent = search-container03:9314:items
agent = search-container04:9314:items
agent = search-container05:9314:items
agent = search-container06:9314:items
agent = search-container07:9314:items
agent = search-container08:9314:items
agent = search-container09:9314:items
agent = search-container10:9314:items
}
SphinxSearch Meetup #2 @ Avito
Оптимизации и лайфхаки• Обновите версию Sphinx• threads, thread_pool• local, dist_threads, agent, max_children• Ограничение выдачи• Обратный поиск• Универсальные поля• JSON атрибуты• Ranker может многое
SphinxSearch Meetup #2 @ Avito