"Бэк-офис в Avito: миллиард объявлений на 10 серверах"...

Preview:

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

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

Recommended