HighLoad в платформе для интернет-магазинов автозапчастей

    image

    В прошлом топике мы обещали рассказать о внутреннем устройстве нашей платформы www.abcp.ru (SaaS решение). Сегодня мы расскажем о самом интересном модуле платформы — складах для хранения прайс-листов.

    Как было в начале?


    Уже на второй год работы платформы мы столкнулись с растущими потребностями клиентов в объёмах строк прайс-листов, которые необходимо хранить в базе данных. На этот момент данные хранились просто в одной таблице обычного MySQL. Оказалось, что типичный магазин хочет подключить к своему магазину 7 миллионов позиций товаров, но не может платить больше 5000 рублей в месяц. Мы не были готовы к такому повороту ни технически ни экономически, поэтому сдерживали клиентов как могли, а в это время разрабатывали систему хранения, выдерживающую значительные объёмы данных (до 50 миллиардов записей).

    Для сдерживания производительности системы при росте данных мы провели много программных оптимизаций и даже купили серьёзную СХД Hewlett-Packard StorageWorks за 25 тысяч евро, куда поместили нашу базу MySQL (в расчёте на высокую скорость работы дисковой системы), но этих улучшений хватало ненадолго, а время шло.

    Как оказалось, этап стресса для нашей команды продлится более двух лет. Если бы мы знали реальные сроки разработки, это был бы сильный удар по нашей мотивации. Но мы не знали :) Поэтому у нас всё получилось.

    image

    Выбор варианта решения


    Входные данные были такие: система должна хранить очень много записей (определили, что 50 миллиардов будет более чем достаточно), ежедневно может обновляться примерно половина этих данных. Необходимо добиться децентрализации в хранении данных и допускать частичную деградацию при проблемах с оборудованием.

    В то время о HighLoad мы знали лишь то, что это очень круто, что есть какие-то конференции на эту тему и что в интернете полно интересных статей. Было модно использовать в проектах NoSQL решения, говорить слова типа “шардинг” и всё такое подобное. Также мы знали, что Oracle — это очень мощная база данных, которая к тому же умеет масштабироваться и поэтому рассматривали и такой вариант.

    После долгих мучений мы отбросили:

    1. Мощную субд Oracle. Т.к. это дорого и это сложно.
    2. Много разных настоящих NoSQL. Т.к. на тот момент они были недостаточно надёжными либо не выдерживали требований по смешанной нагрузке чтение/обновление.

    В итоге победил привычный MySQL (innoDB). Проверенное решение, бесплатно, много специалистов. На все грабли мы уже с ним наступили, поэтому для нашей команды эта СУБД была идеальным для создания новой версии хранения прайс-листов с заявленными характеристиками. Слово “шардинг” нам тоже помогло.

    И вот что у нас получилось


    Новая система хранения прайс-листов представляет собой распределённый вариант на основе простых, недорогих и понятных MySQL, которые мы используем в режиме NoSQL, т.е. просто INSERT, UPDATE, DELETE и SELECT. Без всяких JOIN и с минимальным количеством условий в WHERE.

    image

    На данный момент сервис хранит ~750 млн записей о продаваемых товарах. В течение суток продавцы полностью обновляют треть информации (~250 млн записей). Количество операций UPDATE примерно в 10 раз больше, чем количество операций SELECT. Скорость заливки/обновления прайсов в сервисе на данный момент составляет 30000 позиций в секунду, что позволяет обновить вышеупомянутые ~250 миллионов за 10% суточного времени.

    Схема выглядит как эталонный пример горизонтального масштабирования БД, но, конечно, внутри новой службы всё гораздо сложнее. Для более быстрого обновления были разработаны и отдельные модули (тоже в формате шардинга) для конвертации “зоопарка” прайс-листов в эталонный формат, и отдельные diff-службы, вычисляющие разницу между прайс-листами (это работает быстрее, чем полное обновление прайс-листа). Ещё одним полностью оправдавшим себя решением стало внедрение в качестве «сердца» системы — сервера RabbitMQ. Само использование асинхронных очередей натолкнуло нашу команду на ряд идей, позволяющих значительно ускорить работу системы.

    Разумеется, мы достигли отличных экономических показателей. К примеру, если значительно расширять подсистему хранения позиций на складах, то ежемесячная себестоимость хранения/использования одного миллиона позиций составит ~100 рублей. Даже при текущем курсе валюты.

    Также, подбирая наиболее оптимальное оборудование для созданных модулей, мы получили дополнительный экономический выигрыш примерно на 10-20%.

    Если вы разрабатываете проекты в области торговли автозапчастями, то можете использовать наше API для хранения прайс-листов и поиска по ним (доступ предоставляем по запросу).

    На сегодня всё, до встречи в следующем топике!
    NodaSoft
    Company
    Ads
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More

    Comments 31

      +5
      Количество полезной информации в топике впечатляет.
        –2
        Все наши сотрудники сказали то же самое.
          +4
          Пост «как нарисовать сову».
          0
          >>Количество операций UPDATE примерно в 10 раз больше, чем количество операций SELECT.
          Как-то совсем непонятно. У вас прайсы которые никому не интересно читать но зачем-то интересно писать?
          Или вы там на полном серьезе делаете на каждый чих update where id =.?

          На счет полезности информации — создать топик для откровений «мы смогли только innoDB как noSql заюзать» в 2015 году это сильно.
            +2
            > Как-то совсем непонятно. У вас прайсы которые никому не интересно читать но зачем-то интересно писать?

            Это не у нас прайсы ) это у автолюбителей прайсы. Представьте себе обычный прайс-лист компании Mercedes содержит более 600 тысяч позиций. А mitsubishi — более миллиона. Но в ближайшие сутки из этого объёма покупатели будут искать примерно 5000 позиций и нельзя угадать какие позиции будут затребованы. А цены и наличие меняются каждый день. Нужно всё обновлять и желательно каждый день.

            > Или вы там на полном серьезе делаете на каждый чих update where id =.?

            Допустим на складе поставщика за последние 5 минут изменилось наличие для 10 позиций. Мы считаем, что update where… это самый правильный способ обновить данные. У вас есть вариант более лучший?

            > На счет полезности информации — создать топик для откровений «мы смогли только innoDB как noSql заюзать» в 2015 году это сильно.

            А это топик о том, что даже в 2015 году можно не стесняться и использовать простые способы для достижения результатов в бизнесе. Возможно люди на хабре ждут каких-то новых технологий, я же писал о реальных результатах.
              0
              insert into prices(entry, price) values ('втулка', 100), ('гайка', 50), ('хреновина', 300),… on duplicate key update price=values(price)
              Если упираетесь в производительность диска, то не поможет, конечно. А если в обмен между приложением и базой, то поможет.
                0
                это будет 3500-4000 запросов в секунду на сервер (правда на один поток)
                  0
                  1. Да. Огромное количество инсертов может привести к проблемам с производительностью диска.
                  2. Фактически, заливаются операционные данные, к которым идут постоянные обращения. И тут надо, во-первых, обеспечить валидность данных в любой момент времени. Во-вторых, закладываться на пиковую нагрузку, чтобы в любой момент обеспечить допустимое время отклика.

                  Для обеспечения этих требований в наших условиях вариант с предварительным расчетом дифа между заливаемыми прайсами и апдейтом только изменившихся строк работает быстрее.

                  Ну, а там, где прайс изменяется кардинально или заливается в первый раз применяется как раз похожий insert.
                0
                >>А это топик о том, что даже в 2015 году можно не стесняться и использовать простые способы для достижения >>результатов в бизнесе.
                Я не имел ввиду, что mysql не очень. Если его использовать в таком плане, отличий от других noSQL критических не будет. Все все равно будет утыкаться в скорость накопителей. Вопрос то в горизонтальном масштабировании, шардинге, как организовали, какие конкретные проблемы возникали, как поиск организовали. вот это интересно.

                >>Допустим на складе поставщика за последние 5 минут изменилось наличие для 10 позиций. Мы считаем, что update >>where… это самый правильный способ обновить данные. У вас есть вариант более лучший?
                Ниже уже написали про infile, insert on dublicate. Вообще трудно предложить хороший вариант, не зная деталей.

                >>Возможно люди на хабре ждут каких-то новых технологий, я же писал о реальных результатах.
                Мне всегда казалось, что на хабре ждут рассказа не о том как что-то сделали, а о том как это сделали :)

                  0
                  >> Я не имел ввиду, что mysql не очень. Если его использовать в таком плане, отличий от других noSQL критических не будет.
                  >> Все все равно будет утыкаться в скорость накопителей. Вопрос то в горизонтальном масштабировании, шардинге,
                  >> как организовали, какие конкретные проблемы возникали, как поиск организовали. вот это интересно.

                  Это тема отдельной большой статьи, но если кратко, то:
                  1. В нашем случае мы определили оптимальный объём одной базы в 10 млн.записей
                  2. На одном средненьком сервере вполне умещается 4 таких базы параллельно.
                  3. Поисковой запрос выполняется параллельно в нескольких базах, не во всех, а только в тех, где есть прайс-листы по которым запущен поиск в данный момент. Несколько прайсов может быть в одной базе.
                  4. Обновление прайс-листов также происходит параллельно. Планируется к разработке алгоритм распределяющий прайсы одного заказчика по разным базам.
                  5. Однако есть случаи, когда под определённого заказчика создаются выделенные базы, чтобы исключить конкуренцию за ресурсы.
                  6. Разработан механизм автоматического распределения данных между базами. Логический балансер. Система определяет самые незагруженные склады и при каждом обновлении решает в какую базу залить этот прайс.
                  7. Можно в любой момент добавлять сервера и склады, включать их в глобальный список и прайсы при обновлении перераспределятся, что приведёт к оптимальному количеству записей на базу (см.пункт 1).
                  8. Можно для каждой базы включить режим освобождения и база постепенно очистится до нуля. Используем для обновления ПО, для переноса данных между серверами и для других целей.

                  >> Допустим на складе поставщика за последние 5 минут изменилось наличие для 10 позиций. Мы считаем, что update
                  >> where… это самый правильный способ обновить данные. У вас есть вариант более лучший?
                  >> Ниже уже написали про infile, insert on dublicate. Вообще трудно предложить хороший вариант, не зная деталей.

                  infile это хороший вариант, но не в нашем случае, я немного раскрыл смысл об этом камментом выше.
                +4
                Не совсем. У каждого магазина есть прайс скажем в 5млн записей. Здесь данные от разных поставщиков. Прайс от этих поставщиков они могут получать раз в день, в неделю или в месяц. В одном прайсе может быть от 10 000 позиций. Соответственно они то что получили, то и загружают.
                Получается update-ов грубо уже 10 000.

                На другой стороне у нас пользователи. Сайт автозапчастей это не соц.сеть, там посетителей не много. Заходят они в основном для поиска запчастей. И как правило пользователь ищет 1-3 позиции, большинство 1 позицию.

                Вот и получается, что обновили вы 10тыс записей, а 1000 пользователей делали по 1 запросу.

                Специфика здесь такова, что прайс надо обновлять как можно быстрее, т.к. цена может упасть и если ты медленно обновишь, то купят у твоего конкурента. Или если цена поднялась, то все купят у тебя. И у тебя есть 2 варианта:
                а) отказать им — тогда минус в карму
                б) продать и получить убытки
                  +1
                  Если вам не нужно искать скопом по всей совокупности строк прайсов — то вообще не понятно где тут HighLoad.

                  5 миллионов строк я загружал лет 8 назад на P3-500/512Mb, LOAD DATA INFILE уже тогда работал быстрее на порядок чем xls парисились.

                  И да, были прайсы Mercedes как сейчас помню, не миллион строк, но близко к тому, правда они сразу в csv шли.
                  Странно что вы упираетесь в INSERT, если уж взяли mysql то нужно было использовать myisam, load data infile и правильные индексы. В конце концов можно использовать как facebook — как чисто raw-хранилище, заводить базу на клиента и по таблице на прайс. Тогда обновление будет вообще молниеносное — TRUNCATE TABLE + LOAD DATA INFILE.

                    0
                    > Если вам не нужно искать скопом по всей совокупности строк прайсов

                    нужно искать скопом по всем залитым прайсам, нужно чтобы скорость ответа была менее 0.5 секунды с учётом всего-всего

                    > LOAD DATA INFILE

                    кто-то должен был это написать, спасибо. Но к сожалению это не подходит, искать надо скопом по всем прайс-листам.
                      0
                      А почему вам LOAD DATA INFILE то не подходит? Он сильно быстрее чем INSERT-ы пачками.
                        0
                        А одинаковый прайс от разных поставщиков 2 раза загружаете?
                          +1
                          Выглядит это так, как будто ученик пришел не подготовленным и чтоб ему хотя бы с натяжкой поставить 3, задаем уточняющие вопросы ))
                            +1
                            Ну так интересно же почему то или иное решение выбрано.

                            Извините, если вам кажется будто вопросы простые и очевидные.

                            Я вот навскидку могу предложить по десятку аргументов за и против загрузки одинаковых прайсов от разных поставщиков.

                              0
                              Конечно поставщиков слишком много и возможно встречаются одинаковые прайсы (ну или почти одинаковые). Но нам легче заливать всё подряд, чем сравнивать файлы друг с другом.
                              0
                              А я думал, что Вы задаёте уточняющие вопросы потому что вам интересно, а не потому что стараетесь поставить нам плюс куда-нибудь в карму.
                              0
                              Разумеется нет. Если поставщик даёт всем клиентам одинаковый прайс — мы таких поставщиков клиентам подключаем централизованно, ведь для всех одинаковые данные. И соответственно обновляем один раз сразу для всех клиентов.
                            0
                            Я там не работаю ))
                            Просто в свое время разрабатывал сайт автозапчастей и там со всем этим столкнулся. Отвечал на вопрос, почему update-ов больше чем select
                              0
                              Я тоже делал сайт автозапчастей, и не один. И прайсы — там не самая головная боль, с каталогами производителей на порядок большая.
                        +3
                        Полезной информации практически нет. Пост в духе «Ай какие мы молодцы!»
                          0
                          Приношу извинения за то, что пост воспринимается Вами в таком духе. Никого в том числе нас не интересует молодцы мы или нет. Поверьте, мы уже давно переболели этой болезнью. Всех, в т.ч. нас интересует только результаты, которые можно оценить реальным рублём. И мы такую оценку получаем, с этим всё впорядке. Насчёт полезности — я лишь хотел донести то, что упомянул камментом выше — для достижения целей иногда годятся и простые технологии, что мы и проверили на себе.
                          +1
                          Ну на хабре если пишут, то пишут как оно там внутри работает. Просто из 2 статей я вынес для себя только то, что в рунете есть такой сайт. И все. А то что там ЯП-PHP, БД-MYSQL, ну и что.
                          А вот если расскажете как устроена БД, почему именно так(все таки 2 года ведь мучились, значит дров то много наломали), вот тогда будет интересно.
                            +3
                            В защиту автора — полезная инфа все-таки есть :D
                            Oracle дорого и непонятно, noSQL непонятно и страшно, mySql рулит.
                            Что характерно про postgresql ни слова.
                              0
                              спасибо за хорошие слова )
                            0
                            Были произнесены интересные слова типа

                            • Формат шардинга
                            • diff-службы
                            • Внедрение сервера RabbitMQ


                            Учитывая немалую суточную производительность системы и, насколько я могу судить, крайне полезный продукт для вторичных приложений, хотелось бы услышать хотя бы примерно где что начинается и заканчивается.

                            А то слова знакомые, но представить всё достаточно сложно. Какая-то одна большая интрига — вроде бы декольте глубокое, но хочется больше.

                            P.S. На конференции по sphinx в 2011 году (в данном случае это неважно) создатели avito.ru рассказывали, что для обновления своей доски объявлений (я думаю, многие представляют впечатляющий объем данных под капотом) они использовали несколько фаз — денормализация > валидация -> нормализация. Заявленное максимальное время обновления любого объявления — 15 минут.

                            Где-то там на стыке денормализация > валидация, а может до денормализации, конечно же, есть и фильтрация… не всю же базу перелопачивать, но это уже детали.
                              0
                              … и тишина…
                                0
                                Здравствуйте!

                                Сообщество хабра считает данный пост крайне неудачным. Поэтому мотивация к сожалению задушена.
                                  0
                                  Это, конечно, жаль, но я бы вас попросил, если есть время, раскрыть эти вопросы. Хотя бы крупными мазками. Заранее спасибо.

                              Only users with full accounts can post comments. Log in, please.