108
Бэк-офис в Avito: Бэк-офис в Avito: Бэк-офис в Avito: Бэк-офис в Avito: Бэк-офис в Avito: миллиард объявлений миллиард объявлений миллиард объявлений миллиард объявлений миллиард объявлений на 10 серверах на 10 серверах на 10 серверах на 10 серверах на 10 серверах Вячеслав Крюков Вячеслав Крюков Вячеслав Крюков Вячеслав Крюков Вячеслав Крюков SphinxSearch Meetup #2 @ Avito SphinxSearch Meetup #2 @ Avito SphinxSearch Meetup #2 @ Avito SphinxSearch Meetup #2 @ Avito SphinxSearch Meetup #2 @ Avito

"Бэк-офис в Avito: миллиард объявлений на 10 серверах" Вячеслав Крюков (Avito)

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

Основное хранилище объявлений• PostgreSQL• Данные нормализованы

SphinxSearch Meetup #2 @ Avito

Что мы хотим от поиска в Backoffice?• Обрабатывать много объявленй• Высокую актуальность• Приемлемую скорость выполнения запросов• Унификацию

SphinxSearch Meetup #2 @ Avito

Sql источник и дельта индексация - классикажанра

• Делим индекс на две части Small и Main• Запоминаем метку времени последней индексации Main• Периодически переиндексируем Small от этой метки• Пока его размер приемлем

SphinxSearch Meetup #2 @ Avito

Дельта индексацияПереиндексируем Small

SphinxSearch Meetup #2 @ Avito

Small

Main

Дельта индексацияПереиндексируем Small

SphinxSearch Meetup #2 @ Avito

Small

Main

Дельта индексацияПереиндексируем Small, Small уже совсем и не Small

SphinxSearch Meetup #2 @ Avito

Small

Main

Дельта индексацияПереиндексировали Main, Small стал маленьким

SphinxSearch Meetup #2 @ Avito

Small

Main

Дельта индексацияПереиндексируем Small

SphinxSearch Meetup #2 @ Avito

Small

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

Дельта индексацияПереиндексируем

SphinxSearch Meetup #2 @ Avito

Small

Medium

Main

Дельта индексацияПереиндексируем Small

SphinxSearch Meetup #2 @ Avito

Small

Medium

Main

Дельта индексацияПереиндексируем Small...Small...

SphinxSearch Meetup #2 @ Avito

Small

Medium

Main

Дельта индексацияПереиндексируем 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 сохранили новую мектку

SphinxSearch Meetup #2 @ Avito

Pre

Small

Main

Мерж TSV чанков по лэтенсиСмержили Pre в Small

SphinxSearch Meetup #2 @ Avito

Pre

Small

Main

Мерж TSV чанков по лэтенсиГенерим данные в Pre

SphinxSearch Meetup #2 @ Avito

Pre

Small

Main

Мерж TSV чанков по лэтенсиСгенерили

SphinxSearch Meetup #2 @ Avito

Pre

Small

Main

Мерж TSV чанков по лэтенсиСмержили Pre в Small

SphinxSearch Meetup #2 @ Avito

Pre

Small

Main

Мерж TSV чанков по лэтенсиГенерим данные в Pre

SphinxSearch Meetup #2 @ Avito

Pre

Small

Main

Мерж TSV чанков по лэтенсиСгенерили

SphinxSearch Meetup #2 @ Avito

Pre

Small

Main

Мерж TSV чанков по лэтенсиСмержили Pre в Small

SphinxSearch Meetup #2 @ Avito

Pre

Small

Main

Мерж TSV чанков по лэтенсиГенерим данные в Pre

SphinxSearch Meetup #2 @ Avito

Pre

Small

Main

Мерж TSV чанков по лэтенсиСгенерили

SphinxSearch Meetup #2 @ Avito

Pre

Small

Main

Мерж TSV чанков по лэтенсиСмержили Pre в Small, мерж занял слишком много времени

SphinxSearch Meetup #2 @ Avito

Pre

Small

Main

Мерж TSV чанков по лэтенсиСмержили Small в Main

SphinxSearch Meetup #2 @ Avito

Pre

Small

Main

Мерж TSV чанков по лэтенсиГенерим данные в Pre

SphinxSearch Meetup #2 @ Avito

Pre

Small

Main

Мерж TSV чанков по лэтенсиСгенерили

SphinxSearch Meetup #2 @ Avito

Pre

Small

Main

Мерж TSV чанков по лэтенсиСмержили Pre в Small

SphinxSearch Meetup #2 @ Avito

Pre

Small

Main

Мерж TSV чанков по лэтенсиГенерим данные в Pre

SphinxSearch Meetup #2 @ Avito

Pre

Small

Main

Мерж TSV чанков по лэтенсиСгенерили

SphinxSearch Meetup #2 @ Avito

Pre

Small

Main

Мерж TSV чанков по лэтенсиСмержили Pre в Small

SphinxSearch Meetup #2 @ Avito

Pre

Small

Main

Мерж TSV чанков по лэтенсиГенерим данные в Pre

SphinxSearch Meetup #2 @ Avito

Pre

Small

Main

Мерж TSV чанков по лэтенсиСгенерили

SphinxSearch Meetup #2 @ Avito

Pre

Small

Main

Мерж TSV чанков по лэтенсиСмержили Pre в Small

SphinxSearch Meetup #2 @ Avito

Pre

Small

Main

Мерж TSV чанков по лэтенсиГенерим данные в Pre

SphinxSearch Meetup #2 @ Avito

Pre

Small

Main

Мерж TSV чанков по лэтенсиСгенерили

SphinxSearch Meetup #2 @ Avito

Pre

Small

Main

Мерж TSV чанков по лэтенсиСмержили Pre в Small

SphinxSearch Meetup #2 @ Avito

Pre

Small

Main

Мерж TSV чанков по лэтенсиГенерим данные в Pre

SphinxSearch Meetup #2 @ Avito

Pre

Small

Main

Мерж TSV чанков по лэтенсиСгенерили

SphinxSearch Meetup #2 @ Avito

Pre

Small

Main

Мерж TSV чанков по лэтенсиСмержили Pre в Small, мерж занял слишком много времени

SphinxSearch Meetup #2 @ Avito

Pre

Small

Main

Мерж TSV чанков по лэтенсиСмержили Small в Main

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

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Согнали

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

Время генерации/мержа, кол-во items

Отставание Small

Отставание medium

Спасибо, вопросы ?Спасибо, вопросы ?Спасибо, вопросы ?Спасибо, вопросы ?Спасибо, вопросы ?