Нагруженный поиск на Sphinx




 Стачка! 2012, Ульяновск
о проекте




   Стачка! 2012, Ульяновск
о проекте


•     В top10 сайтов Рунета
•     90М+ запросов в сутки (AVITO, TORG, API)
•     130К+ запросов в минуту
•     120К+ пользователей online (LiveInternet)
•     230К+ новых объявлений в сутки
•     400K+ картинок в день
•     8М+ пользователей размещали объявления



       Стачка! 2012, Ульяновск
проблемы



1) Постоянный рост
    2010 год 7М просмотров
    2011 год 25М просмотров
    2012 год 80М просмотров
    2013 год ?




* среднесуточное кол-во просмотров за март по данным LiveInternet



      Стачка! 2012, Ульяновск
проблемы



2) Архитектура в наследство (все делает БД)
•    Полнотекстовый поиск (tsearch)
•    Аналитика (triggers, тяжелые запросы)
•    Излишняя денормализация
•    Логи операций
•    Синхронность




       Стачка! 2012, Ульяновск
решение

Используйте наиболее
подходящие инструменты


1.   Аналитика: IMDB + PHP
2.   Поиск: Sphinx
3.   Мелкие оптимизации
4.   Конфигурация
5.   Фоновые процессы



      Стачка! 2012, Ульяновск
архитектура




                             + system




   Стачка! 2012, Ульяновск
поиск по объявлениям




   Стачка! 2012, Ульяновск
поиск похожих объявлений




   Стачка! 2012, Ульяновск
поиск / цифры



•    140М запросов в сутки
•    3К запросов в секунду в пики
•    7М документов в индексе
•    Размер индекса 3GB+
•    Каждые 20 минут полная переиндексация
•    16 серверов (x16 core)




       Стачка! 2012, Ульяновск
поиск / требования


•    tmax < 30 минут

     •   время на применение услуг к объявлению
     •   время на премодерацию
     •   время на переиндексацию
•    сохранить быстрые настройки поиска
•    поддержать целостность данных
•    решить проблему селективности выборки из БД



         Стачка! 2012, Ульяновск
поиск / архитектура


                                   clients



                                    sphinxql

    M                        S1      ...       S15


                             uftp + rsync




     indexer            repca           londiste     DB



   Стачка! 2012, Ульяновск
поиск / индексация


      время переиндексации 20 мин

1.    Построение снапшота активных объявлений
2.    Многопоточная индексация из БД
3.    Предварительный деплой на слейвы
      сразу после построения индекса [uftp]
4.    Проверка индексов [rsync, indextool]
5.    Ротация [kill -HUP $pid]


        Стачка! 2012, Ульяновск
поиск / построение снапшота

                                                        Pg Master

   items tables               triggers
  items tables                               items MV

                                           londiste
                                         replication
                                                       Pg Memory
                              storage
                             procedure
    shapshot                                 items MV


        sphinx



   Стачка! 2012, Ульяновск
поиск / построение снапшота


Для чего нужен снапшот + слейв:
•    Целостность поискового индекса
•    Снятие IO с мастера
•    Денормализация атрибутов
•    Отдельный пул для долгих коннектов
•    Паралельное вычитывание базы
•    seq scan из shared buffers



       Стачка! 2012, Ульяновск
поиск / многопоточная индексация



#!/bin/bash
CONF='indexer.sphinx.conf'
INDEXES = [...]
for IDX in ${INDEXES}; do
  (indexer -c ${CONF} ${IDX} && deploy ${IDX}) &
done




   Стачка! 2012, Ульяновск
поиск / многопоточная индексация


#indexer.sphinx.conf
source index_src { ... }
index index_name {
   source = index_src
   path   = /sources_new/index_name
}
indexer { mem_limit = 1536M }

#sphinx.conf
index index_name {
   path   = /sources/index_name
}



   Стачка! 2012, Ульяновск
поиск / ротация


#!/bin/bash
NEWNAME_RE='s/(.*).([a-z]*)$/1.new.2/g'
SOURCES=/sources/
SOURCES_NEW=/sources_new/
for f in `ls -1 $SOURCES_NEW`; do
    NEWNAME=`basename $f|sed -e ${NEWNAME_RE}`
    cp "${SOURCES_NEW}${f}" "${SOURCES}${NEWNAME}"
done
kill -HUP `cat sphinx.pid`




   Стачка! 2012, Ульяновск
поиск / настройки


•    отдельные конфиги для индексатора и поиска
•    на каждый фильтр свой атрибут (MVA медленно)
•    дисковые индексы хранятся в RAM (tmpfs)
•    query_log только при необходимости
•    dict = keywords - быстрее поиск, нет коллизий
•    настройки под характеристики железа (через
тесты)



       Стачка! 2012, Ульяновск
поиск / настройки searchd

searchd
{
    workers             = prefork
    prefork             = 32 # CPU cores * 2
    prefork_rotation_throttle = 50
    seamless_rotate     = 1
    preopen_indexes     = 1
    read_buffer         = 64K
    read_unhinted       = 64K
    compat_sphinxql_magics = 0
    binlog_path         = # не используем RT
    ...
}


     Стачка! 2012, Ульяновск
поиск / клиенты

•    lazy initialization
•    используем кеш
•    по возможности используем multi-query
•    вычисляем оптимальный max_matches
     = offset + limit
•    сортируем результаты в обратном порядке,
     если offset > total_matches / 2
•    фильтрация по селективным атрибутам


        Стачка! 2012, Ульяновск
поиск / поиск похожих




   Стачка! 2012, Ульяновск
поиск / поиск похожих

SELECT
  id, price,
  sint(if(loc_id=637640,12,0)) +
    sint(if(loc_id>=637690 AND loc_id<=639990,9,0)) AS rnk_location ,
  15-interval(abs(price-830000),0,83000,124500,166000)*3 AS rnk_price ,
  sint(if(price=0,-2,0)) AS rnk_empty_price ,
  in(val210,1202,1177,3476,1211,1187,3477,1207)*7 AS
rnk_similar_brand ,
  ...
  sint(if(val185=860,3,0)) AS rnk_transmission ,
  ( rnk_location + rnk_price + rnk_empty_price + rnk_images +
    rnk_brand + rnk_model + rnk_year + rnk_body + rnk_engine +
    rnk_similar_brand + rnk_mileage + rnk_shop + rnk_transmission
  ) AS rnk
FROM items_category_9
WHERE loc_id BETWEEN 621550 AND 662819
ORDER BY rnk DESC, sort_time DESC
LIMIT 6 OPTION max_matches =6, ranker=wordcount




       Стачка! 2012, Ульяновск
backoffice




                              E D
                       O R
                    N S
      C E
    Стачка! 2012, Ульяновск
backoffice / цифры



•    70M документов в индексе
•    25GB размер индексов
•    70GB данных для индексации
•    16 серверов (1 сервер = 1 нода + pool)
•    Ежеминутная индексация
•    Раз в час мерж дельты




       Стачка! 2012, Ульяновск
backoffice / архитектура



                       1
                             1                                          8/8/16
                   1
            Pool



                                                                    3
                                                            3
                                                    3
                                          Group 1




                                                        3
                                           3                    4
   Node 1          Node 2        Node 3             Node 4




   Стачка! 2012, Ульяновск
backoffice / реализация




+ основной индекс + дельта
+ MVA для поиска по параметрам (здесь можно)
+ 3 уровня - ноды/группа/pool
-    дельта по last_update_txtime с нахлестом
-    медленная полная переиндексация :(




       Стачка! 2012, Ульяновск
Стачка! 2012, Ульяновск
cпасибо!
                     вопросы?

Роман Павлушко
rpavlushko@avito.ru
twitter.com/pavlushko
slideshare.net/pavlushko/




   Стачка! 2012, Ульяновск

Avito Stachka 2012

  • 1.
    Нагруженный поиск наSphinx Стачка! 2012, Ульяновск
  • 2.
    о проекте Стачка! 2012, Ульяновск
  • 3.
    о проекте • В top10 сайтов Рунета • 90М+ запросов в сутки (AVITO, TORG, API) • 130К+ запросов в минуту • 120К+ пользователей online (LiveInternet) • 230К+ новых объявлений в сутки • 400K+ картинок в день • 8М+ пользователей размещали объявления Стачка! 2012, Ульяновск
  • 4.
    проблемы 1) Постоянный рост 2010 год 7М просмотров 2011 год 25М просмотров 2012 год 80М просмотров 2013 год ? * среднесуточное кол-во просмотров за март по данным LiveInternet Стачка! 2012, Ульяновск
  • 5.
    проблемы 2) Архитектура внаследство (все делает БД) • Полнотекстовый поиск (tsearch) • Аналитика (triggers, тяжелые запросы) • Излишняя денормализация • Логи операций • Синхронность Стачка! 2012, Ульяновск
  • 6.
    решение Используйте наиболее подходящие инструменты 1. Аналитика: IMDB + PHP 2. Поиск: Sphinx 3. Мелкие оптимизации 4. Конфигурация 5. Фоновые процессы Стачка! 2012, Ульяновск
  • 7.
    архитектура + system Стачка! 2012, Ульяновск
  • 8.
    поиск по объявлениям Стачка! 2012, Ульяновск
  • 9.
    поиск похожих объявлений Стачка! 2012, Ульяновск
  • 10.
    поиск / цифры • 140М запросов в сутки • 3К запросов в секунду в пики • 7М документов в индексе • Размер индекса 3GB+ • Каждые 20 минут полная переиндексация • 16 серверов (x16 core) Стачка! 2012, Ульяновск
  • 11.
    поиск / требования • tmax < 30 минут • время на применение услуг к объявлению • время на премодерацию • время на переиндексацию • сохранить быстрые настройки поиска • поддержать целостность данных • решить проблему селективности выборки из БД Стачка! 2012, Ульяновск
  • 12.
    поиск / архитектура clients sphinxql M S1 ... S15 uftp + rsync indexer repca londiste DB Стачка! 2012, Ульяновск
  • 13.
    поиск / индексация время переиндексации 20 мин 1. Построение снапшота активных объявлений 2. Многопоточная индексация из БД 3. Предварительный деплой на слейвы сразу после построения индекса [uftp] 4. Проверка индексов [rsync, indextool] 5. Ротация [kill -HUP $pid] Стачка! 2012, Ульяновск
  • 14.
    поиск / построениеснапшота Pg Master items tables triggers items tables items MV londiste replication Pg Memory storage procedure shapshot items MV sphinx Стачка! 2012, Ульяновск
  • 15.
    поиск / построениеснапшота Для чего нужен снапшот + слейв: • Целостность поискового индекса • Снятие IO с мастера • Денормализация атрибутов • Отдельный пул для долгих коннектов • Паралельное вычитывание базы • seq scan из shared buffers Стачка! 2012, Ульяновск
  • 16.
    поиск / многопоточнаяиндексация #!/bin/bash CONF='indexer.sphinx.conf' INDEXES = [...] for IDX in ${INDEXES}; do (indexer -c ${CONF} ${IDX} && deploy ${IDX}) & done Стачка! 2012, Ульяновск
  • 17.
    поиск / многопоточнаяиндексация #indexer.sphinx.conf source index_src { ... } index index_name { source = index_src path = /sources_new/index_name } indexer { mem_limit = 1536M } #sphinx.conf index index_name { path = /sources/index_name } Стачка! 2012, Ульяновск
  • 18.
    поиск / ротация #!/bin/bash NEWNAME_RE='s/(.*).([a-z]*)$/1.new.2/g' SOURCES=/sources/ SOURCES_NEW=/sources_new/ forf in `ls -1 $SOURCES_NEW`; do NEWNAME=`basename $f|sed -e ${NEWNAME_RE}` cp "${SOURCES_NEW}${f}" "${SOURCES}${NEWNAME}" done kill -HUP `cat sphinx.pid` Стачка! 2012, Ульяновск
  • 19.
    поиск / настройки • отдельные конфиги для индексатора и поиска • на каждый фильтр свой атрибут (MVA медленно) • дисковые индексы хранятся в RAM (tmpfs) • query_log только при необходимости • dict = keywords - быстрее поиск, нет коллизий • настройки под характеристики железа (через тесты) Стачка! 2012, Ульяновск
  • 20.
    поиск / настройкиsearchd searchd { workers = prefork prefork = 32 # CPU cores * 2 prefork_rotation_throttle = 50 seamless_rotate = 1 preopen_indexes = 1 read_buffer = 64K read_unhinted = 64K compat_sphinxql_magics = 0 binlog_path = # не используем RT ... } Стачка! 2012, Ульяновск
  • 21.
    поиск / клиенты • lazy initialization • используем кеш • по возможности используем multi-query • вычисляем оптимальный max_matches = offset + limit • сортируем результаты в обратном порядке, если offset > total_matches / 2 • фильтрация по селективным атрибутам Стачка! 2012, Ульяновск
  • 22.
    поиск / поискпохожих Стачка! 2012, Ульяновск
  • 23.
    поиск / поискпохожих SELECT id, price, sint(if(loc_id=637640,12,0)) + sint(if(loc_id>=637690 AND loc_id<=639990,9,0)) AS rnk_location , 15-interval(abs(price-830000),0,83000,124500,166000)*3 AS rnk_price , sint(if(price=0,-2,0)) AS rnk_empty_price , in(val210,1202,1177,3476,1211,1187,3477,1207)*7 AS rnk_similar_brand , ... sint(if(val185=860,3,0)) AS rnk_transmission , ( rnk_location + rnk_price + rnk_empty_price + rnk_images + rnk_brand + rnk_model + rnk_year + rnk_body + rnk_engine + rnk_similar_brand + rnk_mileage + rnk_shop + rnk_transmission ) AS rnk FROM items_category_9 WHERE loc_id BETWEEN 621550 AND 662819 ORDER BY rnk DESC, sort_time DESC LIMIT 6 OPTION max_matches =6, ranker=wordcount Стачка! 2012, Ульяновск
  • 24.
    backoffice E D O R N S C E Стачка! 2012, Ульяновск
  • 25.
    backoffice / цифры • 70M документов в индексе • 25GB размер индексов • 70GB данных для индексации • 16 серверов (1 сервер = 1 нода + pool) • Ежеминутная индексация • Раз в час мерж дельты Стачка! 2012, Ульяновск
  • 26.
    backoffice / архитектура 1 1 8/8/16 1 Pool 3 3 3 Group 1 3 3 4 Node 1 Node 2 Node 3 Node 4 Стачка! 2012, Ульяновск
  • 27.
    backoffice / реализация +основной индекс + дельта + MVA для поиска по параметрам (здесь можно) + 3 уровня - ноды/группа/pool - дельта по last_update_txtime с нахлестом - медленная полная переиндексация :( Стачка! 2012, Ульяновск
  • 28.
  • 29.
    cпасибо! вопросы? Роман Павлушко rpavlushko@avito.ru twitter.com/pavlushko slideshare.net/pavlushko/ Стачка! 2012, Ульяновск