Pull to refresh

Comments 34

Спасибо за статью. Отличный результат!

Правильно ли я понял, что watch срабатывает, когда нужно внести изменения именно в реплику? Собственно лаг как раз в этом месте? Насколько большим может быть этот лаг?

И на сколько сократили количество ядер, в итоге?

ps. Спасибо за статью

Watch срабатывает, когда данные из oplog доезжают по сети от primary ноды до приложения. В обычном режиме, если у вас нет инфраструктурных проблем, лаг ± соответствует задержке вашей сети. Но он может увеличиваться по ряду причин.

Без watch нам не хватало ресурсов трёх нод по 8cpu на каждой, чтобы выдержать обычную нагрузку, т.е. 24cpu. С watch 15 подов в среднем потребляют по 20% cpu, т.е. 3cpu. Получается, что сократили как минимум в 8 раз.

Спасибо за статью, интересный кейс, приятный текст!
Но да, сколько ядер в итоге то нужно для 30k+ rps? И было бы интересно еще узнать, на сколько сервисов в конечном счете этот прием лег: только на ценообразование и оптовых клиентов, или коллеги из других команд переняли опыт и смогли его масштабировать по всей компании, улучшив профит? Или mongo - не всегда целевое решение в компании, а довольно редкое? Вот как будто недосказанность есть легкая по этому кейсу) был бы рад еще рассказам о нечто подобном в вашей практике

сколько ядер в итоге то нужно для 30k+ rps

Я писал, что с помощью cpulimit выставил для приложения лимит в 100%. Другими словами, ресурсов одного ядра достаточно.

на сколько сервисов в конечном счете этот прием лег

Завезли его ещё в один сервис, который сейчас на финишном этапе разработки.

Или mongo - не всегда целевое решение в компании, а довольно редкое?

Пожалуй, да. Хотя за последний год многие команды выбрали монгу в качестве основной СУБД для своих новых проектов.

был бы рад еще рассказам о нечто подобном в вашей практике

Постараюсь в обозримом будущем поделиться ещё чем-нибудь интересным.

а если сущность в монге сильно другая чем в горячем хранилище? как тут быть?

В сообщении watch приходит модель БД. Никто не запрещает обработать(конвертнуть/обогатить/…) её так, как заблагорассудится, перед тем, как разместить в горячем хранилище.

Минус в том что Watch это курсор с пуллингом, когда такох курсоров много сам пуллинг будет сжирать CPU базы.
Второй минус - в Atlas в некоторых сценариях масштабирования базы Cahngestream Cursor просто перестают получать апдейты, каеф.
А так в целом штука полезная, но не понятно причем тут 30k RPS - сократить количество запросов за счет InMem кэша да, но RPS просто не докатываются до MongoDB.

Минус в том что Watch это курсор с пуллингом, когда такох курсоров много сам пуллинг будет сжирать CPU базы.

А много - это сколько?

в Atlas в некоторых сценариях масштабирования базы Cahngestream Cursor просто перестают получать апдейты, каеф.

Не работал с atlas, но было бы интересно узнать, о каких сценариях масштабирования идёт речь, и о причинах, по которым change stream cursor перестаёт получать апдейты и при этом не возвращает ошибку.

не понятно причем тут 30k RPS - сократить количество запросов за счет InMem кэша да, но RPS просто не докатываются до MongoDB.

Я могу ошибаться, но этому кейсу вроде бы вся статья посвящена: как с помощью watch запилить in-memory хранилище, избавиться от запросов в бд, и какой профит можно от этого получить. 30k rps на ресурсах одного ядра, имхо, убедительный профит.

Вы ещё не столкнулись с эффектами горизонтального масштабирования и активного использования ChangeStream, а именно - большой трафик, высокое пoтребление CPU на спининг курсоров.Если ты, читающий данное сообщение думаешь о применении этого механизма в сервисной архитектуре - не наступай на мои грабли, выгружай ChangeStream в Kafka например

Как с Марусей поговорил)

Не знаю к чему вы Марусю преплетаете, но вся ваша статья сводится к абстрактным тестам сервисов которые не читают данные из базы. Как вам уже указывали, вы использовали частный случай event sourcing, причём в худшей реализации - курсоры. А внедрев этот подход в целых двух сервисах представляете его как серебренную пулю.

Научили ли вы архитектуре - я считаю что нет. Дали плохой совет - скорее да и тому несколько причин:

  • С Atlas вы не работали, о цене трафика и того как на это влияет использования watch вы тоже не в курсе;

  • Исходники MongoDB Connector не изучали - а даже там есть механизм с watchdog для отлова умерших курсоров;

Не вижу смысла вести дальнейшую дискуссию

Не знаю к чему вы Марусю преплетаете

потому что, как с ботом поговорил

причём в худшей реализации - курсоры

А что вы знаете о курсорах mongodb? Известно ли вам, что даже базовый find реализован с помощью курсора?

Исходники MongoDB Connector не изучали 

Который из коннекторов и какое это имеет отношение к статье?

Не вижу смысла вести дальнейшую дискуссию

А вот это прекрасно!

Не слишком ли рисковано строить архитектуру приложения на основе внутренних механизмов репликации БД? Не говоря уже о том, что данный подход выглядит несколько странно/непривычно с архитектурной точки зрения.

На самом деле подход довольно привычный. Это частный случай event driven архитектуры. Из непривычного здесь только то, что в роли агента (источника события) выступает не приложение, а СУБД, оно же служит и транспортом. То что Watch основан на внутреннем механизме репликации БД вообще восхитительно. Вы гарантировано получаете правильную последовательность событий.

>То что Watch основан на внутреннем механизме репликации БД вообще восхитительно

А на сколько внутренний механизм гарантирует обратную совместимость? Не будет ли проблем при обновлении версий монги?

Watch в mongodb существует с версии 4.4. Во всех последующих релизах вплоть до текущего стабильного 7.0 обратная совместимость не ломалась.

Спасибо за статью! Было бы интересно взглянуть на упрощённый пример реализации.

Ха! А я наоборот реализацию усложнил, чтобы обработать различные отказы.

В ближайшее время постараюсь написать вариант реализации попроще.

Вы построили event sourcing? Ясно, он будет отдавать состояние со скоростью памяти. А оплоги репликации бд как источник вместо вездесущей Кафки это интересно, спасибо.

Спасибо за статью. Интересное решение, может пригодится.

Обычное решение проблемы производительности чтения — это горизонтальное масштабирование

А вы не думали просто добавить кеш?

Ценообразование явно выдерживает делей в часы-минуты поэтому скорее всего эффективно кешируется. Перед тем как скейлить дБ и тратить цпу на ненужные вычисления...

Прочитал дальше - ровно то что сделали. Вотч как способ кеш обновлять. Окей.

«Ненужные вычисления» - это доли процента по сравнению с сетевыми i/o.

Доброго дня. Спасибо за статью. Суть ясна - копируем всё что есть из СУБД к себе в RAM, вместо Redis-а, а с помощью watch - у нас происходит обновление/инвалидация нашего внутреннего кэша.

Но обмануть закон сохранения энергии ещё никому не удавалось. Когда данных много, ну например 100 Гб. Они явно уже в сервис не влезут. Появляется необходимость шардинга, но уже Ваших сервисов, например - по месяцам. Но один в поле не воин, одна шарда - это не отказоустойчиво. Надо 3 хотябы. Ну и вот Вы создали кластер редиса. Который работает быстрее редиса, потому что у редиса видимо нет API - чтобы данные напрямую из него тащить и watch интегрировать в него. Появился чудо-сложный балансировщик трафика, которому надо ещё правильно клиентские запросы балансировать по Вашим шардам-репликам. А ещё Вы сталкиваетесь с людскими хотелками - хотим отчёт за год, а у Вас данные по разным шардам...

То есть, возникнет тот момент, когда Вы ощутите, что закон сохранения энергии начинает Вас догонять. Что все те проблемы, от которых Вы попытались убежать - настигли Вас, но в других местах. Отсюда возникает потребность сформировать общие положения и рекомендации на каких объёмах данных Вас ещё не догнало то, от чего Вы убежали. А когда начнёт догонять - Вы получите ценобразовательный Redis, подключенный через Watch к MongoDB. Со всеми проблемами редиса, будьте готовы к такому.

А ещё было бы не плохо понять сложность самих запросов на чтение. Ну это простые выборки какие-то, или множественные соединения с кучей агрегаций и вычислительных слоёв. Есть ли там Иерархические группировки данных, например. То есть что Вы имели ввиду под чтением, какова его сложность.

Итого, в рекомендации к применению может войти: объём данных, сложность исполняемых запросов на чтение (сортировки, иерархия, агрегация, много-джоинов), сложность структуры хранимых данных в самом кэше, сложность пост-обработки данных перед помещением в свой кэш, что-то ещё.



Отсюда возникает потребность сформировать общие положения и рекомендации на каких объёмах данных Вас ещё не догнало то, от чего Вы убежали.

В целом мы и не пытались разместить большие объёмы данных в RAM, я писал об этом:
"семь из восьми сущностей — это справочные данные, а полный размер их коллекций не превышает нескольких мегабайт".

Когда данных много, ну например 100 Гб. Они явно уже в сервис не влезут. Появляется необходимость шардинга, но уже Ваших сервисов, например - по месяцам. Но один в поле не воин, одна шарда - это не отказоустойчиво. Надо 3 хотябы. Ну и вот Вы создали кластер редиса. Который работает быстрее редиса, потому что у редиса видимо нет API - чтобы данные напрямую из него тащить и watch интегрировать в него. Появился чудо-сложный балансировщик трафика, которому надо ещё правильно клиентские запросы балансировать по Вашим шардам-репликам. А ещё Вы сталкиваетесь с людскими хотелками - хотим отчёт за год, а у Вас данные по разным шардам...

Если есть потребность заиметь горячую сотню другую гигабайт данных, то нужно быть готовым решать не тривиальные технические задачи, взвешивать решения и, возможно, идти на компромиссы, потому что серебряной пули не существует. Я думаю, кейс с большим объёмом данных в RAM - хорошая тема для другой статьи.

А ещё было бы не плохо понять сложность самих запросов на чтение.

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

Есть и сложные запросы с различными вариантами сортировок, которые генерируют менеджеры и внутренние системы-потребители. Это капля в море с точки зрения нагрузки. Но их мы уже, как правило, выполняем средствами mongodb. А сложной иерархии, агрегаций или джойнов средствами БД мы избегаем.

Вопрос следующий… а как узнать самый ранний токен с sharded , мы же стрим читаем с монгоса ( монго роутера ), откуда эту инфу взять на уровне кластера. В каждом репликасете шарде свой оплог

Очень интересный вопрос. Постарался найти ответ на него в документации, но пока не получилось.

:) Вот я тоже как только не искал не могу найти, а в watch не видел чтобы можно было указать просто earliest, чтобы change stream читало с условного начала (хвоста) oplog но именно на монгороутере

Пройдемся по тексту:

выбрав map, built-in хэш-таблицу в Go, вы лишитесь всех сортировок.

Спорное заявление. Много пакетов существует готовых и хорошо оптимизированных если не хотите делать сами. В общем и целом весь раздел особенности и недостатки – сплошные недостатки.

Далее..
Как статья которая рассказывает о Watch кейсе – ок

Взять Mongo которая судя по описанию является узким местом во всей структуре, превратить её в какой-то фреймворк чтоб меньше делать и этим создать неуправляемое поведение ради кэша в RAM – интересный кейс.

Ускорение удалось? Да! Успех ли это? Ну, если считать ускорение через попу носорога успехом – безусловно.

Резюме такое: Буду максимальным душнилой, но не считаю что вы что-то ускорили и это некий "тру" путь к высоконагруженным приложениям. На вид очередная борьба с ведьмами из-за неправильного инжиниринга. Конечно, под капот я не заглядывал, но по описанию очень похоже. Более того сам горизантальный шаринг будет как снежный ком накручивать в дальнейшем усложнения в взаимодействии.
Вот выше комментарий был что когда данных много, например 100гб. При текущей стоимости RAM – 100гб это ничто. Говорю как человек у которого есть сервис с кэшем внутри себя на 450гб. И если нужно больше, просто докупается либо RAM (если позволяет сервер), либо новый сервер. И как бЭ кому не хотелось рассказать о том что 450гб ого-го, это много...а если откажет...все придет к тому что одно приложение(монолит) которое внутри себя молотит и считает кэш на условном сервере будет быстрее во много-много раз чем любая связка Redis/Watch, и точек отказа меньше...и само поведение более предсказуемо.

Много пакетов существует готовых и хорошо оптимизированных если не хотите делать сами.

Не понял, причём тут built-in map. Я map привёл в качестве примера к двум предыдущим предложениям: "С Watch вы не получаете полноценную реплику данных. Её функциональность будет ограничена той структурой, которую вы выберете для хранения данных."

Резюме такое: Буду максимальным душнилой, но не считаю что вы что-то ускорили и это некий "тру" путь к высоконагруженным приложениям. На вид очередная борьба с ведьмами из-за неправильного инжиниринга. Конечно, под капот я не заглядывал, но по описанию очень похоже. Более того сам горизантальный шаринг будет как снежный ком накручивать в дальнейшем усложнения в взаимодействии.Вот выше комментарий был что когда данных много, например 100гб. При текущей стоимости RAM – 100гб это ничто. Говорю как человек у которого есть сервис с кэшем внутри себя на 450гб. И если нужно больше, просто докупается либо RAM (если позволяет сервер), либо новый сервер. И как бЭ кому не хотелось рассказать о том что 450гб ого-го, это много...а если откажет...все придет к тому что одно приложение(монолит) которое внутри себя молотит и считает кэш на условном сервере будет быстрее во много-много раз чем любая связка Redis/Watch, и точек отказа меньше...и само поведение более предсказуемо.

Если честно, ничего не понял) Какие ведьмы? Что шардинг накручивать будет? Что там ваш монолит молотит на условном сервере? При чём тут связка redis/watch. Но за интерес к статье спасибо!

Да, я неправильно прочитал. Тогда по поводу built-in map вопрос снят.

Про ведьм это общее выражение. Я вкладываю в него то что вы решаете проблему, которую сами же и создали.

Sign up to leave a comment.

Articles