Highload Ozon
7. Алгоритмы
8. Технологии
11. Список серверов
Ozon — выход крупнейшего E-commerce России на рынок КНР (IPO).
Соотношение числа активных продавцов, работающих в рамках направления «Ozon Глобал», к общему числу равняется
Целевая аудитория [1]
- Рынок КНР.
- Возрастная категория: 18-45 лет; 40% женщин, 60% мужчин.
- Уникальных пользователей:
- в месяц 70 млн. (MAU)
- в день 15 млн. (DAU)
- Каталог;
- Поиск товаров в желаемой категории.
- Корзина (просмотр, изменение);
- Оформления заказа.
- Cтраница товара;
- Отзывы и рейтинг.
- Список заказов;
- Обновление статуса заказа в личном кабинете, трекинг заказа от службы доставки (получение новых данных о статусе);
- Рассылка Push-уведомлений об изменении статуса заказа.
В рамках MVP ограничимся двумя видами фулфилмента FBS и rFBS, откажемся от FBO, т.е. от хранения товара на собственных складах.
FBS (Fulfillment by Seller) — cеллер хранит товар на собственном складе, самомостоятельно собирает заказ и передаёте заказ в службу доставки.
rFBS (real FBS) — схема работы, при которой продавец сам отвечает за хранение и доставку товара.
Схема FBS от Ozon [11]
За ориентир взят Ozon в 2021г.
-
70 млн.
— MAU (см. операционные показатели) (80% от [1]) -
15 млн.
— DAU (20% от MAU) -
90 тыс.
— активных продавцов [19] -
108%
— YoY — годовые изменения количества заказов223.3 млн. - 2021г
;465.4 млн. - 2022г
[17] -
38%
— YoY — годовые изменения количества покупателей, которые разместили хотя бы один заказ в течение года25.6 млн. - 2021г
;35.2 млн. - 2022г
[17] -
36
карточек товара помещается на одной странице выдачи Озон
-
3%
— CR (конверсия в покупку)$CR = \frac{25.6}{12\cdot MAU} \cdot 100\% =3\%$ — что соответсвует средней конверсии по миру среди маркетплейсов [18] Откуда MAU равняется 70 млн. -
70%
— CAR (уровень брошенных корзин), 30% процентов посетителей интернет магазинов, положивших товар в корзину, рано или поздно завершают процесс покупки, остальные 70% - брошенные корзины. [15] -
2%
— конверсия в корзину из карточки товара — отношение количества добавлений товара в корзину к количеству уникальных посетителей, которые просмотрели карточку товара. Эта величина колеблится в диапазоне от 1% до 15%, используем нижнюю границу — 2%. -
51%
— конверсии от покупки к оставленному отзыву.15%
пользователей не пишут развернутые комментарии, но ставят оценку товару.6%
от тех кто оставил отзыв прикрепят фотографию [29] -
7%
— показатель отказа (Bounce Rate), следовательно конверсия из авторизации в наиболее вероятные действия, просмотр каталога и поиск, 93%, т.е 7% от DAU при заходе на главную страницу покидают сайт, ничего не сделав, а 93% хотя бы пользуются поиском или каталогом.[16]
Операционные показатели по годам [21]
Формула для расчёта месячной аудитории:
Год | П/г | П/г-YoY | MAU | З/г | З/г-YoY | Чз/г | Чз/г-YoY | SKU | SKU-YoY |
---|---|---|---|---|---|---|---|---|---|
2023 | 46.1 | +31% | 128 | 966 | +107% | 21 | +59% | 250 | +47% |
2022 | 35,2 | +37% | 98 | 465.4 | +108% | 13.2 | +52% | 170 | +107% |
TOTAL | — | — | — | 356.8 | — | — | — | — | — |
2021 |
25,6 | +86% | 70 | 223.3 | +202% | 8.7 | +61% | 82 | +645% |
2020 | 13,8 | +75% | 38 | 73.9 | +132% | 5,4 | +33% | 11 | — |
2019 | 7,9 | — | 22 | 31.8 | +105% | 4,0 | — | — | — |
2018 | — | — | — | 15.5 | +80% | — | — | — | — |
2017 | — | — | — | 8.6 | +50% | — | — | — | — |
2016 | — | — | — | 5.7 | — | — | — | — | — |
Расшифровка столбцов:
- П/г [млн.] — количество активных (уникальных) покупателей, разместивших заказ хотя бы раз в течение года.
- З/г [млн.] — количество заказов от всех покупателей за год. [25]
- Чз/г — среднее количество заказов, сделанных покупателем в течение года.
- SKU [млн.] — ассортимент единиц товара на площадке.
Cтатусы заказа [23]
Создан | Ожидает оплаты | В сборке |
---|
Передаётся в доставку | В пути | У курьера | Ожидает | Доставлено | Получен | Отменено |
---|
Наиболее вероятная цепочка статусов: 'В сборке' — 'Передаётся в доставку' — 'В пути' — 'У курьера' — 'Получен'. Итого в среднем заказ проходит через 5 статусов. Рассылка Push-уведомлений по двум статусам: 'В пути' и 'У курьера'/'Ожидает'.
Нагрузка на поиск и каталог в 2023г 11k RPS, пиковая 50k RPS [13].
Пропорционально росту MAU посчитаем RPS в 2021г, взяв некий процент от RPS в 2023г. Т.е. MAU за 2023 = 128 млн. 1.83
.
В период распродажи пиковый RPS на сервис поиска и каталога 27.5k, в то время как средний RPS 6k. В момент распродажи нагрузка возрастает в 4.5, возьмём пиковый множитель 5
.
x9,15
— множитель от средней нагрузки в 2021г к пиковой в 2023г:
-
612k
— заказов в сутки$\frac{З/г \cdot 10^6}{365} = 611780$ [1] -
60k
— заказов в минуту в дни распродаж [1] -
6kRPS
— нагрузка на поиск и каталог -
27.5kRPS
— в пике нагрузка на поиск и каталог (55% от [13])
Открытых источников информации нет. Данные о среднем количестве действий пользователя по типам в день получены из средних показателей конверсий по eCommerce [14] [15] [16], отталкиваясь от технических метрик Ozon [1] [13].
Действие | Расчёт | В среднем за день |
---|---|---|
Просмотр каталога и поиск | 37 | |
Заказ товара | 0.04 | |
Добавление в корзину | 0.13 | |
Просмотр отдельного товара | 6,5 | |
Отзывы и рейтинг | 0.02 | |
Обновление статуса заказа | 0.2 | |
Просмотр списка заказов | 0.14 | |
Рассылка Push-уведомлений | 0.08 |
Действие | Расчёт | Средняя нагрузка, 2021г | Пиковая нагрузка, 2023г x9,15
|
---|---|---|---|
Просмотр каталога и поиск | [13] | 6k RPS | 54.9k RPS |
Заказ товара | 7 RPS | 64 RPS | |
Добавление в корзину | 21 RPS | 192 RPS | |
Просмотр отдельного товара | 1050 RPS | 9 607 RPS | |
Отзывы и рейтинг | 4 RPS | 37 RPS | |
Обновление статуса заказа | 32 RPS | 293 RPS | |
Просмотр списка заказов | 23 RPS | 210 RPS | |
Рассылка Push-уведомлений | 12 RPS | 110 RPS | |
TOTAL | — | 7 150 RPS | 65 500 RPS |
Ozon позволяет добавлять до 15 фотографий к карточке товара, размером не более 10 Мб.[24] Возьмём среднюю оценку 7 фотографий на товар и средний размер фотографии 200 КБ, тогда общий объем фотографий 1,37 Мб
.
Описание товара может содержать текст и изображения. Среднее описание товара составляет 500 слов, что составляет около 1 Кб, с учётом дополнительных технических сведений 2 Кб. В среднем содержит 2 изображения ~ 400 Кб. В сумме ~0.4 Мб
.
Итого 1.77 Мб
на краточку. 138,42 Тб
Конверсия от покупки к оставленному отзыву 51%. Из таблицы операционных показателей видно, что за 2016г-2021г было сделано 356.8 млн. заказов 53.5 млн
, а остальные 128.5 млн
- полноценный отзыв. 6% имеют фотографии 21.4 млн.
Выделим на текст для отзыва в среднем 256 байт 0.25 Кб.
Заложим на медиаконтент в отзыве 0.5 Мб 10,2 Тб
Итого в сумме 150 Тб
хранилища требуется на момент конца 2021г.
YoY в 2022г для ассортимента SKU равняется +107% 422 Тб
.
YoY в 2022г количество заказов от всех покупателей за год равняется +108% 45 Тб
.
Итого суммарный рост за 2022г равен 160 Тб
. За 2023г равен 157,5 Тб
.
100Гбит/c
— трафик в пике на поиск и каталог на момент 2022г.(пропорционально росту MAU возьмём 70% от трафика в 2022г [30]) Т.е. отношение MAU
По итогу анализа трафика в панели инструментов браузера:
- Запрос на добавление в корзину в среднем имеет размер 70Кб.
- Размер перенесённого трафика при просмотре страницы товара в два раза больше размера трафика при просмотре каталога и поиске, что соответствует полученным данным 0.6Мб и 0.3Мб.
Тип запроса | Размер 1 запроса | Тбит/сутки, 2021г. | Гбит/с, 2021г | Пиковый Гбит/c, 2021г | Пиковый Гбит/c, 2023г |
---|---|---|---|---|---|
Страница товара | 0.6 Мб | 4.9 | 24.5 | 44.8 | |
Просмотр каталога и поиск |
|
14 | 70 | 128.1 | |
Добавление в корзину | 70Кб | 0.011 | 0.055 | 0.1 | |
TOTAL | 1 597 | 19 | 94.5 | 173 |
Особенности CDN в КНР [33]
-
Интернет в Китае полностью отличается от глобального интернета, похож на остров с ограниченными точками входа и выхода. Действует «Великий Китайский файрвол», который обладает способностью отслеживать, подвергать цензуре и блокировать ПО или информацию, которые, по его мнению, противоречат его национальным интересам.
-
Нельзя запустить сайт электронной коммерции без лицензии интернет-контент-провайдера (ICP). Лицензия ICP - это юридическое разрешение, которое позволяет любой компании, местной или международной, размещать веб-сайт на сервере в материковом Китае.
-
На территории КНР действует три Tier-1 оператора: China Telecom, China Mobile, China Unicom. Эти провайдеры не общаются друг с другом напрямую из-за отсутствия одноранговых соединений, они намеренно ограничивают пропускную способность своих соединений из-за конкуренции.
-
В Китае есть три точки входа и выхода подводного оптического волокна, которые влияют на общий интернет-трафик. Эти пункты расположены в Шаньтоу, Шанхае и Циндао.
-
Основная единица административно-территориального деления Китая называется провинцией.
Для глобальной балансировки BGP Anycast необходимо зарегистрировать новую автономную систему (AS) и получить коммерческую лицензию ICP.
Собственные DNS-серверы Anycast должны вещать индивидуально внутри каждого оператора, а не от одного оператора к другому. Необходимо избежать взаимного магистрального соединения между различными интернет-провайдерами. Возмем за основную AS - China Telecom Backbone, т.к. этот оператор наиболее распространён в южном Китае, где находится бОльшая часть населения. От остальных двух Tier-1 операторов нужно настроить BGP маршруты как можно приоритетней в нашу AS. Тем самым решится проблема с низкой пропускной способностью, вызванной конкуренцией между операторами.
Самый большой теоретический RTT находится между Урумчи и Гаунчжоу. Значение не привышает 100 ms, было измеренно с помощью иструмента самого Tier-1 оператора: China Telecom - LOOKING GLASS [35]
round-trip min/avg/max = 84.607/84.651/84.759 ms
Исходя из карты внутренних магистральных сетей Китая и плотности населения расположим 4 ЦОД в слеюдующих городах, см. в таблицу ниже. Утвердим за каждым ЦОД субъект страны так, чтобы на каждый приходилась, примерно, одинакая доля нагрузки. [35] В случае потери одного ЦОД нагрузка на соседние ЦОД не превысит 10k RPS. Т.е. нагрузка в непредвиденной ситуации на любой ЦОД не привешает ~30k RPS
.
В итоге, клиентский трафик заводится в 4 ЦОД через BGP Anycast. Далее посредством Equal-cost multi-path routing (ECMP) попадает на несколько LoadBalancer c защитой от DNS- и DoS-атак. ECMP роутинг может использоваться в сочетании с BGP, использования этой стратегии маршрутизации, при которой пакеты пересылаются по нескольким «лучшим путям», увеличивает пропускную способность сети.
Провинция | Всего, человек | в 2020, % | ЦОД |
---|---|---|---|
Пекин | 21893095 | 1,46 | CD-1 |
Тяньцзинь | 13866009 | 0,97 | CD-1 |
Хэбэй | 74610235 | 5,36 | CD-1 |
Шаньси | 34915616 | 2,67 | CD-1 |
Внутр. Монголия | 24049155 | 1,84 | CD-1 |
Ляонин | 42591407 | 3,27 | CD-1 |
Гирин | 24073453 | 2,05 | CD-1 |
Хэйлунцзян | 31850088 | 2,86 | CD-1 |
Шанхай | 24870895 | 1,72 | CD-2 |
Цзянсу | 84748016 | 5,87 | CD-2 |
Чжэцзян | 64567588 | 4,06 | CD-2 |
Аньхой | 61027171 | 4,44 | CD-2 |
Фуцзянь | 41540086 | 2,75 | CD-2 |
Цзянси | 45188635 | 3,33 | CD-2 |
Шаньдун | 101527453 | 7,15 | CD-1 |
Хэнань | 99365519 | 7,02 | CD-3 |
Хубэй | 57752557 | 4,27 | CD-4 |
Хунань | 66444864 | 4,9 | CD-2 |
Гуандун | 126012510 | 7,79 | CD-3 |
Гуаньси | 50126804 | 3,44 | CD-3 |
Хайнань | 10081232 | 0,65 | CD-3 |
Чунцин | 32054159 | 2,15 | CD-4 |
Сычуань | 83674866 | 6 | CD-4 |
Гуйчжоу | 38562148 | 2,59 | CD-3 |
Юньнань | 47209277 | 3,43 | CD-4 |
Тибет | 3648100 | 0,22 | CD-4 |
Шэньси | 39528999 | 2,79 | CD-4 |
Ганьсу | 25019831 | 1,91 | CD-4 |
Цинхай | 5923957 | 0,42 | CD-4 |
Нинся | 7202654 | 0,47 | CD-4 |
Синьцзян | 25852345 | 1,63 | CD-4 |
Гонконг | 7474200 | — | CD-3 |
Макао | 683218 | — | CD-3 |
Тайвань | 23561236 | — | CD-3 |
Город, провинция | № ЦОД | Доля населения | Пиковая нагрузка, 2023г | Охват населения |
---|---|---|---|---|
Пекин (Beiging) | DC-1 | 25.6% | 16 768 RPS | 369'376'511 |
Шанхай (Shanghai) | DC-2 | 26.9% | 17 619 RPS | 388'387'255 |
Гуанчжоу, Гуандун (Guangzhou, Guangdong) | DC-3 | 24.7% | 16 178R PS | 355'866'867 |
Сиань, Шэньси (Xi'an, Shaanxi) | DC-4 | 22.8% | 14 934 RPS | 327'866'745 |
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {},
"geometry": {
"coordinates": [
121.46751904896115,
31.230752631345794
],
"type": "Point"
}
},
{
"type": "Feature",
"properties": {},
"geometry": {
"coordinates": [
113.25935182000518,
23.130321873002856
],
"type": "Point"
}
},
{
"type": "Feature",
"properties": {},
"geometry": {
"coordinates": [
116.42355449358502,
39.901959762589314
],
"type": "Point"
}
},
{
"type": "Feature",
"properties": {},
"geometry": {
"coordinates": [
[
87.61421681343529,
43.83304144627465
],
[
103.83810774044815,
36.066566282805766
],
[
108.90219628792397,
34.27217060238723
],
[
114.29675517828841,
30.584575881594322
],
[
115.02860547935467,
30.19151287863273
],
[
115.9488438732886,
29.65583466262948
],
[
115.86222814415865,
28.700099346439163
],
[
113.26880729482582,
23.116239773516625
]
],
"type": "LineString"
}
},
{
"type": "Feature",
"properties": {},
"geometry": {
"coordinates": [
108.93482428457304,
34.308277327107945
],
"type": "Point"
}
}
]
}
Пройдя глобальную балансировку, трафик посредством стратегии ECMP [35] [37] — многопутевой маршрутизации с равной стоимостью — попадает на несколько LoadBalancer. ECMP потенциально предлагает существенное увеличение пропускной способности за счет балансировки нагрузки по нескольким каналам. А BGP, в свою очередь, поддерживает ECMP роутинг. Таким образом точками входа клиентского трафика являеются машины с LoadBalancer, которые имеют единый Virtual IP. После них DNS-запрос от LoadBalancer направляется на пул локальных real-серверов, заранее прописанный в конфиге Caching DNS сервер (Resolver, рекурсивный преобразователь). Resolver сервер получает информацию от авторитетного (Authoritative) сервера и кеширут её локально с заданным TTL. Политика выбора real-сервера для поступившего запроса — Round-Robin DNS.
В случае проблем на одной из LoadBalancer BGP-анонс его Virtual IP прекращается, таблицы маршрутизации перестраиваются, клиенты идут на оставшиеся балансировщики. В случае недоступности Resolver и Authoritative DNS сервера, запросы идут Resolver и Authoritative DNS сервера находящийся в одном из соседних ЦОД.
Технологии [37]
В качестве LoadBalancer выберем L7 Dnsdist по следующим причинам: есть поддержка Resolver и Authoritative, L7 позволяет интегрировать дополнительную логику, защита от DNS- и DoS-атак, умеет лимитировать клиентов по DNS запросу и по IP.
У L4 балансеров по типу Haproxy есть недостатки, которые заключаются в том, что теряется source IP клиента. А работающие на уровне ядра (Kernelspace) L4 балансеры сложны в конфигурации.
Т.к. Dnsdist является продуктом PowerDNS, выберем решения от той же компании. Resolver сервер — PowerDNS Recursor, Authoritative — PowerDNS Auth. DNS записи ресурсов будем хранить в Generic Postgresql Backend, эта DB позволяет кешировать и обновалять зоны. Редактировать DNS записи будем через PowerDNS-Admin.
Далее после real-DNS-серверов трафки направляется в API-шлюз. API-шлюз выступает как единая точка входа в ЦОД, отвечает за вертикальный(north-south) трафик. Выполняет следующие задачи:
- Абстрагирует сложности микросервисов и предлагает клиентам единообразный интерфейс для взаимодействия, GRPC Routing.
- Терминирует клиенский TLS, с внутренними сервисами общаться через mutual TLS.
- Обрабатывает аутентификацию и передаёт сервисам информацию о токенах, например, проверяет действительный ли JWT, прежде чем направить запрос во внутреннюю службу, распределяет нагрузку на конечную внутреннюю службу.
- Регулирует входящий и исходящий трафик, ставит глобальный и локальные Rate Limit, устанавливает политику ретраев, осуществляет трассировка запросов, отдаёт Gateway API Metrics в Prometheus, observability в ControlPlane.
Возможные варианты реализации:[42]
- Emissary-ingress – это API-шлюз с открытым исходным кодом, разработанный для Kubernetes. Этот проект CNCF появился в 2017 году.
- NGINX — это API-шлюз, который фактически предшествует Kubernetes и послужил основой для одного из первых контроллеров входящего трафика Kubernetes, называемого ingress-nginx. NGINX старее следующего конкурента — Envoy Gateway
- Envoy Gateway — это совершенно новый ingress controller. Это часть проекта CNCF Envoy-proxy, который является ядром двух отдельных CNCF API gateways (Emissary и Contour). В 2021 году разработчики из Emissary, Contour и Envoy собрались вместе и решили, что всем заинтересованным сторонам было бы лучше объединить свои усилия в единой расширяемой системе Envoy Gateway, которая будет выпущена в конце 2022 года.
Многие варианты API-шлюзов подходят под нашу архитектуру, выберем Envoy Gateway как самый передовой из них.
Исходишь трафик от API Gateway попадает в сервисную сеть, где принимается прокси-сайдкаром в целевом поде.
Service Mesh обеспечиваeт ряд преимуществ:
- Security: Поддержка автоматического шифрования — mutual TLS.
- Continuous Delivery: Доступность сложных шаблонов трафика, например, канареечный деплой, A / B-тестирования.
- Observability: tracing трафика.
Есть два наиболее популярных подхода реализации инфраструктурного слоя сервисной сетки:
- Сайдкар контейнером у Istio служит Envoy, которые не поддерживает PeakEWMA.
- Istio имеет обширным набором функций, что делает его более гибким, но и более сложным в настройке и управлении. Linkerd ориентирован на простоту и удобство использования.
- Linkerd имеет легкие и быстрые прокси-сервера, что обеспечивает меньшее использование ресурсов и более высокую производительность по сравнению с Istio.
Расположить везде сайдкарт контейнеры в большой системе довольно дорого, поэтому производительность прокси-сервера имеет не малую роль. Для балансируют нагрузку на соединения более высокого уровня, такие как вызовы RPC или HTTP существуют возможные алгоритмы балансировки: Weight round robin, Consistent Hash, Least Connected и PeakEWMA. Алгоритм PeakEWMA довольно эффективен, он поддерживается только в Finagle и Linkerd. По итогу выбираем Linkerd.
Эффективный PeakEWMA [5]
Принцип действия: рассчитываем скользящее среднее времени длительности запросов и, исходя из этого, выбираем бэкенд, на который вышлем нагрузку. Данный алгоритм использует концепцию экспоненциально взвешенных скользящих средних для определения «пиковой» нагрузки серверов. Присваивая веса недавним измерениям трафика, он точно фиксирует текущую нагрузку сервера и динамически корректирует свой выбор для входящих запросов.
На графике предствален эксперимент с тремя алгоритмами: round robin, least loaded, and peak exponentially-weighted moving average (“peakEWMA”) [5]
В Ozon пошли дальше и вместо сайдкар контейнеров написали свою кастомную реализацию data panel поверх "гошного" gRPS, сохранив для разработчиков семантику библиотечных вызовов. Назвали свой Service Mesh — Warder. Этим они избавились от затраты ресурсов на сайдкар контейнеры. Протестировав все алгоритмы балансировки в своей инфраструктуре, PeakEWMA показал наилучшии метрики при тестах, он обеспечивает лучшую связь между RPS и RT (Response Time).
erDiagram
PROFILE ||--o{ ORDER_INFO : includes
PROFILE ||--o{ ADDRESS : includes
PROFILE ||--o{ CART : includes
ORDER_INFO ||--o{ ORDER_ITEM : includes
PRODUCT ||--o{ ORDER_ITEM: includes
PRODUCT ||--o{ SHOPPING_CART_ITEM : includes
CATEGORY ||--|{ PRODUCT : includes
STATUS ||--|{ ORDER_INFO : includes
CART ||--o{ SHOPPING_CART_ITEM : includes
COMMENT ||--o{ PROFILE : includes
COMMENT ||--o{ PRODUCT : includes
PROFILE {
uuid id PK
text login UK
text description
text imgsrc
text phone
text passwordhash
}
PRODUCT {
uuid id PK
text name UK
text description
int price
text imgsrc
numeric rating
uuid category FK
int count_comments
}
COMMENT {
uuid id PK
uuid product_id FK
uuid profile_id FK
text comment
int rating
}
ORDER_INFO {
uuid id PK
uuid profile_id FK
uuid promocode_id FK
int status_id FK
uuid address_id FK
timestampz creation_at
timestampz delivery_at
}
STATUS {
serial id PK
text name UK
}
ORDER_ITEM {
uuid id PK
uuid order_info_id FK
uuid product_id FK
int quantity
int price
}
ADDRESS {
uuid id PK
uuid profile_id FK
text city
text street
text house
text flat
bool is_current
}
CATEGORY {
serial id PK
text name UK
int parent FK
}
CART {
uuid id PK
uuid profile_id FK
bool is_current
}
SHOPPING_CART_ITEM {
uuid id PK
uuid cart_id FK
uuid product_id FK
int quantity
}
Type | Byte size |
---|---|
SERIAL | 4 |
UUID | 16 |
INT | 4 |
NUMERIC(3, 2) | 8 |
timestampz | 8 |
boolean | 1 |
PROFILE
id(16) + login(32) + description(128) + imgsrc(64) + phone(19) + passwordHash(64) = 323
PRODUCT
id(16) + name(128) + description(1024) + price(4) + imgsrc(64) + rating(8) + category(16) + count_comments(4) = 1264
COMMENT
id(16) + product_id(16) + profile_id(16) + comment(256) + rating(4) = 308
id(16) + product_id(16) + profile_id(16) + comment(0) + rating(4) = 52
ORDER_INFO
id(16) + profile_id(16) + promocode_id(16) + status_id(4) + address_id(16) + creation_at(8) + delivery_at(8) = 84
STATUS
id(4) + name(8) = 12
ORDER_ITEM
id(16) + order_info_id(16) + product_id(16) + quantity(4) + price(4) = 56
ADDRESS
id(16) + profile_id(16) + city(16) + street(16) + house(8) + flat(8) + is_current(1) = 81
CATEGORY
id(4) + name(16) + parent(4) = 24
CART
id(16) + profile_id(16) + is_current(1) = 33
SHOPPING_CART_ITEM
id(16) + cart_id(16) + product_id(16) + quantity(4) = 52
Table | Row size [byte] | Number of row | Total |
---|---|---|---|
PROFILE | 323 |
|
9 Гб |
PRODUCT | 1264 | 300 Гб | |
COMMENT | 308; 52 | 40 Гб | |
ORDER_INFO | 84 | 28 Гб | |
STATUS | 12 | - | |
ORDER_ITEM | 56 | 32 Гб | |
ADDRESS | 81 |
|
4 Гб |
CATEGORY | 24 | - | |
CART | 33 | 1 Гб | |
SHOPPING_CART_ITEM | 52 | 8 Гб |
Table | Описание | Чтение | Запись |
---|---|---|---|
PROFILE | Хранение данных о пользователе | 210 QPS | 20 QPS |
PRODUCT | Информация о товаре | 65k QPS | 1k QPS |
COMMENT | Отзывы о товарах | 10k QPS | 37 QPS |
ORDER_INFO | Общая информация о заказе | 230 QPS | 64 QPS |
STATUS | Список статусов заказа | 500 QPS | 0.1 QPS |
ORDER_ITEM | Информация о товарах входящих в заказ | 230 QPS | 64 QPS |
ADDRESS | Данные сохранённых адресов пользователями | 210 QPS | 10 QPS |
CATEGORY | Дерево категорий | 30k QPS | 0.1 QPS |
CART | Информация о корзинах пользователей | 230 QPS | 192 QPS |
SHOPPING_CART_ITEM | Информация о товарах входящих в корзину | 500 QPS | 192 QPS |
Table | Database |
---|---|
PROFILE | PostgreSQL |
PRODUCT | PostgreSQL |
COMMENT | PostgreSQL |
ORDER_INFO | PostgreSQL |
STATUS | PostgreSQL |
ORDER_ITEM | PostgreSQL |
ADDRESS | PostgreSQL |
CATEGORY | PostgreSQL |
CART | PostgreSQL |
SHOPPING_CART_ITEM | PostgreSQL |
External Result Cache | Redis |
User Session | Redis |
ML-Ranking FeatureStore | Redis |
- neo4j-go-driver — драйвер для графовой БД Neo4j.
- go-ceph — драйвер для сетевого файлового хранилища CEPH.
- pgx — драйвер для основной БД PostgreSQL.
- go-elasticsearch — драйвер для БД поиска Elasticsearch.
Table | Поле | Структура данных |
---|---|---|
COMMENT | product_id | B-дерево |
ORDER_ITEM | order_info_id | B-дерево |
ADDRESS | profile_id | B-дерево |
SHOPPING_CART_ITEM | card_id | B-дерево |
Используем PostgreSQL для всех стандартных БД совместно с паттерном Database Per Service.
Преимущества PostgreSQL:
- Поддержка БД неограниченного размера
- Мощные и надёжные механизмы транзакций и репликации
- Легко масштабировать
- Балансировщик PgBouncer
User Session DB, ML-Ranking FeatureStore DB, External Result Cache — Redis
Redis легко масштабируется горизонтально. Кластеры Redis поддерживают master-slave репликацию и могут быть отказоустойчивыми. Redis обеспечивает моментальный доступ к данным.
В проекте используем JWT. В случае инцедентов, итечки секретного JWT ключа, нужно сделать невалидными пострадавшие токены и обновить пользователям затроннутые атакой сессии. Для необходимо хранить кому какой токен был выдан, для этого подойдёт in-memory key-value хранилище Redis.
В ML-Ranking FeatureStore DB храняться посчитаные векторные представления товаров — Prod2Vec.
CEPH — программно определяемая система хранения данных, объединяет несколько дисков обычной сетью. Для хранения фотографий будем использовать CEPH, суммарный объём 150 ТБ
, с возможностью масштабироваться до 300 ТБ
.
Шардинг и решардинг сложная процедура, и использование готовых инструментов для шардинга в случае непредвиденных ситуаций приводит к разбирательству с чёрным ящиком. Сделаем свой инструмент.
Shard Key — product_id
. Берём остаток от деления по модулю на 1024 от md5(product_id
) и в зависимости от интервала куда попадает резуьтат 0..127, 128..255, 256..383 и т.д. выбираем физисеский адрес шарда. Следовательно решардинг делаем в рамках одного кластера и для этого делим предыдущие интервалы попалам, получаем: 0..63, 64..127, 128..191 и т.д.
- Работает из коробки.
- Годами обкатанная технология.
- Низкое потребление ресурсов, так как никакой логики при репликации нет, изменения выполняются в том же порядке, что и на мастере.
- Простота конфигурации, настроил и забыл, простое побайтовое копирование через WAL.
- Реплицируется весь кластер целиком.
- Реплицируются все операции, включая ошибки.
- Изменения применяются в один поток.
- Работа только в рамках одной мажорной версии.
- Слейвы только read only.
Один мастер, одна синхронная реплика и несколько асинхронных. Паттерн работы с данными. Пишем в мастер. Если супер актуальные данные и нужно минимизировать отставания, то читаем с синхронной реплики. В ином случае с асинхронных. Избегаем обильного чтения с мастера и по возможности с синхронной реплики. Базовое правило — в мастер пишем, читаем только из слейвов. Сихроная реплика выполняет функцию фейловера, она всегда находиться в другом ДЦ.
Решаемые проблемы: если много удаляем/апдейтим записи в базе, то vacuum может работать довольно долго. Операции insert/update перестраивают индексы, идет перебалансировка деревьев.
Засчёт партиционирования кол-во индексов будет намного меньше, vacuum работает быстро на маленьких таблицах, следовательно все проблемы больших таблиц будут в N раз меньше. Кол-во партиций делаем не более 100-200.
В итоге, для таблицы PRODUCT
чтобы держать 65K RPS можно сделать 64 действующих шарда и 16 шардов в запас для решардинга. Один шард будет иметь: 1 синхронную реплику и 2 асинхронных реплики, 100 партиций: product_0, product_1, product_2...
Асинхронное межсервисное взаимодействие. Сбор измененных данных с паттерном Outbox на Apache Kafka. Внутреннее устройство: Используем Батчинг + сжатие. Этот паттерн решает проблему потери событий.
Иллюстрация продюсера в случае Delivery Service
OLAP — В Clickhouse пишутся асинхронно данные для аналитики и обучения ML. ML вектора для рекомендаций будут храниться в LanceDB.
Neo4j для логистики доставки, Delivery Service.
Поиск — один из основных источников дохода маркетплейсов. Сценарий, где пользователь приходит на платформу с конкретной целью приобрести товар гораздо более вероятен, чем тот, где он зашел полистать ленту.
Основаня задача поиска строиться следующим образом. По некому запросу нужно выбрать множество товаров и упорядочить его таким образом, чтобы результирующий отранжированный список максимизировал показатель удовлетворенности пользователей.
Релевантность — это смысловая близость документа к запросу. На языке математики это близость векторов.
Задача поиска товара по запросу решается в следющих этапах:
- Retrieval — этап получения всех релевантных товаров по запросу
- Ranking - этап ранжирования релевантных товаров из первого этапа.
- Re-ranking - этап реранжирования топ N товаров из прошлого этапа.
- Business Re-ranking - этап реранжирование товаров на основе бизнес-факторов.
На первой фазе осуществляется Retrieval и Ranking. Всё это происходит в распределенной документно-ориентированной БД с мощными возможностями поиска, которая многое умеет из коробки — ElasticSearch, далее ES. Json объект, который содержит в себе параметры выбора товаров, отправляется на сторону ES. Затем ES обрабатывает запрос, находит необходимые товары и возвращает ответ. В ходе Retrieval осуществляется векторный поиск ANN (приближенный поиск ближайших соседей). Даннынй вид поиска лучше тривиального метода, при котором выбор осуществляется по одному параметру, который указывает минимальное количество условий в запросе, которое должно выполняться, чтобы товар считался релевантным. Этот единственный параметр ставит условия на то, что 100% слов в запросе должны быть в названии товара. В случае, если возратилось пустое множество понижаем процент совпавших слов до 75%. Векторный поиск позволяет находить товары, которые близки к запросу, но не имеют точных совпадений в названии.
Для ранжирования ES из коробки использует алгоритм Okapi BM25. Он учитывает, сколько слов в запросе соответствует текстовым полям, по которым выполняется поиск в индексе. Для эффективности данного алгоритма используем фичи текстовой близости. Определим весами, которые будут прибовляться в общий score товара, следующие характеристики товара: полный путь категорий, фильтры, синонимы запроса, название категории.
На первой фазе поиска определось несколько тысяч наиболее релевантных товаров. Они попадут на следующий этап и будут реранжироваться ML-моделью. Алгоритм ML модели выберем наиболее простой — логистическая регрессия. Добавляем в формулу логистической регрессии параметры товара, а затем каждый параметр домножаем на соответствующий буст, чем регулируем влияние на общий score товара в выдаче. В качестве параметров используем только текстовую близость. Далее происходит реранжирование товаров на основе бизнес-факторов. Этот этап включает предпочтения, которые модель учесть не может, а бизнес требует. Применим, если требуется, буст товаров, которые учавствуют в маркетинговой промо акции.
В ES нет встроенного индексатора. Одна из основных проблем — доставка обновлений до поискового индекса в реальном времени. Цены, скидки, наличие товаров на складах и отзывы часто обновляются, отчего генерируется большой поток изменённых записей. Обновления индекса в ES делает Worker. Когда индекс набирает определённый большой объём, Worker запускает процедуру его распространения в кластер ES по Peer2Peer протоколу. P2P нужен чтобы не забить сетевой канал и тем самым не помешать соседним важным бизнес сервисам.
Технология | Область применения | Обоснование |
---|---|---|
Typescript | Frontend | Статическая типизация в сравнении с JS, быстрое выявление ошибок, удобная отладка, модульность |
React | Frontend | Гибкий и популярный фреймворк, в основе которого компонентный подход, одно из наиболее распространенных решений |
Golang | Backend | Минимализм, высокая производительность, относительно простая и эффективная конкурентная модель, богатая стандартная библиотека, активное сообщество |
Prometheus | Collection of metrics | Масштабируемость, высокая доступность, гибкий язык запросов, активное сообщество |
Grafana | Visualization of metrics, monitoring | Обширный функционал, интеграция со множеством источников метрик, алерты |
Docker | Container runtime | Стандартное решение, среда выполнения контейнеров по умолчанию в k8s |
Kubernetes | Container Deployment and Orchestration | Распределение экземпляров по узлам и Availability Zones; Перезапуск/перераспределение экземпляров по узлам при падении экземпляров, узлов, датацентров; Масштабирование через auto-scaling; Service discovery, Балансировка внешнего и внутреннего трафика; Сетевая связность |
PowerDNS | L7 Loadbalancer | Ориентирован под микросервисную архитектуру, быстро развивается, молодой и уже не уступает в функционале самому простому - traefik. |
Redis | Session Storage, Caching | Легко масштабируется, большое комьюнити, очень быстрый, проще в обслуживании, чем аналоги. |
PostgreSQL | Main Database | Надежность, большой функционал, большая экспертиза. |
ElasticSearch | Search Engine | Масштабируемая, одна из самых высоких по производительностей БД как для индексирования, так и для всех типов запросов. |
Apache Kafka | Message Broker for Even-Driven asynch arch | Наиболее подходящее решение для указанных задач, держит более высокие нагрузки в сравнении с RabbitMQ, IMB MQ и другими схожими технологиями, при этом преимущества аналогов в виде более гибкой настройки маршрутизации и т.п. не столь существенны для данного проекта |
Linkerd | Service mesh | Популярная сервисная сеть, предлагающая легкие сайдкар-прокси для управления межсервисным взаимодействием в облачных приложениях, поддержка PeakEWMA. |
Vault | Хранилище секретов | Хранилище поддерживает различные механизмы авторизации и политики доступа. Доступ к секретам осуществляется через веб-интерфейс, что повышает observability. |
InfluxDB | Logs aggregator | Time Series DB, обеспечивает высокую быстродействие при выполнении запросов и агрегаций логов. |
Clickhouse | OLAP | Cтолбцовая система управления базами данных (СУБД) для онлайн-обработки аналитических запросов. Распределенная обработка на нескольких серверах. Легко настраивается, имеет хорошую документацию и сообщество. |
Neo4j | Graph Database | Высокопроизводительная, масштабируемая графовая база данных. |
Service mesh — предоставляет проверки работоспособности, повторные запросы (retries), rate-limiting, таймауты(timeouts), функции восстановления после сбоев и размыкание цепи (curcuit breaking), поддерживает mTLS между сервисами, чтобы повысить безопасность взаимодействия на этом уровне, реализует списки контроля доступа (ACL) в качестве политик безопасности, поддерживает распределённую трассировку для отладки и расширенного мониторинга, позволяет узучать взаимодействие между сервисами.
API Gateway — регулирует входящий и исходящий трафик, ставит глобальный и локальные Rate Limit, устанавливает политику ретраев, осуществляет трассировка запросов. Однако является потециальной единой точкой отказа всех клиентских запросов, в связи с чем нужно применить качественное резервирование для данного компонента, например, в случае отказа перенаправлять пользователей в соседний ЦОД или иметь локальный резерв.
В проекте применяется комплексный подход, API Gateway и Service Mesh с единой Control Panel, что обеспечит всестороннюю видимость.
Отказоустойчивость на уровне DNS — в случае проблем на одной из DNS LoadBalancer BGP-анонс его Virtual IP прекращается, таблицы маршрутизации перестраиваются, клиенты идут на оставшиеся балансировщики. В случае недоступности real-DNS сервера, запросы идут в соседний ЦОД. Поддержка eBPF на DNS серверах.
Отказоустойчивое взаимодействие с внешними сервисами — сохранять последние полученные данные от внешних сервисов и использовать их в случает отказа. Изучить документацию внешних сервисов и выставить для них соответсвующий Rate Limit.
- Применение Gracefull shutdown на всех микросервисах.
- В случает повышения RT ограничение скорости запросов от клиентов по IP адресам для предотвращения перегрузок. (Failover policy)
- Повторная попытка выполнения запросов (Retry) только на уровне API Gateway в целях избежания ловинообразного эффекта.
- Проектирование с учётом сохранения работоспособности системы в user-friendly режиме при негативных сценариях (Graceful degradation).
- Резервирование ресурсов CPU и RAM, физических компонентов. Репликация баз данных.
- Плановые тренировки - отключение одного ЦОДа. В этом слачае нагрузка на соседних увеличиться не более чем по 10k RPS в пике. Расположение ЦОДов независимо, что соответсвует действительности, см. главу 3.
- Использование Event-driven архитектуры. Поддержка консистентности данных в различных БД без использования распределенных транзакций.
- Kafka реализует шаблон Saga (оркестрационный стиль) - помогает обеспечить согласованность в распределенных приложениях и координирует транзакции между несколькими микросервисами.
- Сбор измененных данных с паттерном Outbox, данный паттерн решает проблему потери событий.
- Агрегация логов с трассировкой. Применение паттерна request id.
- Профилирование. Регулярный запуск профилировщика для выявления узких мест производительности.
- Общирный мониторинг: Real user monitoring, Synthetic monitoring, External monitoring, Сбор метрик, хорошо настроенные алерты.
Service | RPS | CPU | RAM | Net |
---|---|---|---|---|
Catalog, Search | 30k RPS | 3000 | 30 Gb | 70 Gbit/s |
Product | 5250 RPS | 525 | 5.2 GB | 24.6 Gbits/s |
Card | 105 RPS | 10 | 105 Kb | 0.017 Gbit/s |
Review | 20 RPS | 2 | 2 Kb | |
Notification | 60 RPS | 6 | 6 Kb | |
Order | 35 RPS | 4 | 4 Kb | |
Delivery | 160 RPS | 16 | 16 Kb | |
User | 115 RPS | 12 | 12 Kb |
Запуск приложений в Kubernetes
Запуска проекта начнём с аренды виртуальных машин у Alibaba Cloud. Далнейшее развитие будем вести в гибридной облачной среде, сочетая преимущества локальной инфраструктуры с масштабируемостью и гибкостью облака.
Alibaba Cloud имеет известное и признанное имя лидера отрасли в области облачных вычислений. Особенно продвинут на рынке КНР, половина ЦОД на ходиться на территории материкового Китая.
- https://ozon.tech/
- https://habr.com/ru/companies/ozontech/articles/667600/
- https://www.youtube.com/watch?v=kIZ_4PNvkro
- https://habr.com/ru/companies/ozontech/articles/749328/
- https://linkerd.io/2016/03/16/beyond-round-robin-load-balancing-for-latency/
- https://tenchat.ru/media/1400080-privet-bezuprechniy-balans-ili-kombinatsiya-peakewma-i-p2c-ot-twitter
- https://super-video-tube.ru/video/7A7Cq9w0G9Y/ozon-tech-community-go-meetup/
- https://speakerdeck.com/ozontech/dmitrii-loghovskii-kak-zastavit-vashu-bazu-dannykh-dierzhat-20k-rps-varianty-masshtabirovaniia-i-ikh-minusy
- https://bigdataschool.ru/blog/transactional-outbox-pattern-on-neo4j-and-kafka.html
- https://speakerdeck.com/ozontech/viktor-korieisha-camyie-rasprostraniennyie-oshibki-pri-rabotie-s-apache-kafka
- https://seller-edu.ozon.ru/how-to-start/onboarding/step-4-choose-work-mode
- https://speakerdeck.com/ozontech/boris-kuzovatkin-put-posylki-kliuchievyie-tiekhnologhii-i-proiekty-v-loghistikie
- https://speakerdeck.com/ozontech/van-khachatrian-osobiennosti-stiek-i-protsiessy-komandy-poisk-riekomiendatsii-rieklama
- https://baymard.com/blog/ecommerce-checkout-usability-report-and-benchmark
- https://baymard.com/lists/cart-abandonment-rate
- https://vc.ru/marketing/684029-ecommerce-metriki-dlya-novichkov-chto-zameryat-v-internet-magazine
- https://corp.ozon.ru/tpost/ykmxt937i1-ozon-obyavlyaet-rezultati-za-chetvertii
- https://www.yaguara.co/average-e-commerce-conversion-rate/
- https://corp.ozon.ru/tpost/nlexf0jrb1-ozon-predostavlyaet-obnovlennuyu-informa
- https://russianblogs.com/article/24031270152/
- https://ir.ozon.com/ru/
- https://e-pepper.ru/news/kak-riteylery-motiviruyut-klientov-ostavlyat-otzyvy.html
- https://docs.ozon.ru/common-mobile/order/status/?country=RU
- https://seller-edu.ozon.ru/work-with-goods/trebovaniya-k-kartochkam-tovarov/media/foto-i-video-tovara
- https://top100.datainsight.ru/
- https://sia.ru/?section=484&action=show_news&id=458179
- https://journal.tinkoff.ru/news/review-ozon-3q2023/
- https://vc.ru/marketing/603057-tendencii-v-otzyvah-klientov-2023
- Опрос Market Papa
- https://speakerdeck.com/ozontech/dienis-dubovitskii-kak-razdavat-bolshiie-faily-biez-butylochnykh-ghorlyshiek?slide=5
- https://luminocity3d.org/WorldCity/
- https://media.chinatelecomeurope.com/view/1056582712/
- https://www.goclickchina.com/blog/
- https://www.goclickchina.com/blog/how-dns-anycast-works-behind-the-great-firewall-of-china/
- https://ipms.chinatelecomglobal.com/public/lookglass/lookglassDisclaimer.html
- https://ruchina.org/economy/census2020.html
- https://www.cisco.com/c/en/us/td/docs/ios-xml/ios/mp_l3_vpns/configuration/xe-3s/asr903/16-12-1/b-mpls-l3-vpns-xe-16-12-asr900/b-mpls-l3-vpns-xe-16-11-asr900_chapter_0101.pdf
- https://nag.ru/material/36217
- https://dnsdist.org/index.html
- https://istio.io/latest/docs/ops/deployment/architecture/
- https://linkerd.io/2.15/reference/architecture/
- https://www.cncf.io/blog/2023/03/15/linkerd-and-ingress-controllers-bringing-the-outside-world-in/
- https://habr.com/ru/companies/ozontech/articles/667600/
- https://habr.com/ru/companies/uzum/articles/753094/
- https://habr.com/ru/articles/545634/
- https://habr.com/ru/companies/sportmaster_lab/articles/756004/