Comments 9
100гб на 100 ярдов, это 1 кб на запись в среднем верно?? собственно откуда теоретически выйгрыш если в любой обычной субд, аля постгрес, обновить одну строку в 1кб размером занимает ровно столько же времени сколько и 1 колонку в этой в этой строке.
Не все строки обновляются одинаково часто, если взвесить по частоте обновления то с наивным алгоритмом одна запись была бы 10кб в среднем. Ну и экономим мы не астрономическое время (операции делаем батчевые, пытаться уменьшать летенси одной операции у нас не возникало необходимости), а cpu time, запись на диски, чтения с дисков, место на дисках, сеть. А эти штуки заметно уменьшаются.
Почему по старинке не делаете - набором таблиц, а документом сохраняете информацию? Таблица banners отдельно, отдельно embeddings, counters и так далее? И апдейтите свои счетчики - поля int в строках.
А то выглядит так - перешли на волне моды на NoSQL, а теперь героически боретесь с основополагающими недостатками документ-ориентированной технологии.
Даже сейчас считаю возможным выделить часто изменяющиеся данные типа счетчиков в отдельные таблицы, да и вообще говоря, применить не sql-сервера, а например, хранилища ключ-значение.
У нас довольно много сервисов потоковой обработки, и у них разные профили взаимодействия со стейтом. Ну и еще NDA есть, и конкретики не расскажешь. Поэтому далее несколько разрозненные аргументы, почему у нас так как есть.
Почему одна таблица?
* Среди всех стейтов может быть длинный хвост стейтов маленького размера и из-за этого суммарный размер ключей начинает нас волновать. Если делать несколько таблиц, то придется многократно хранить ключи и платить за это. (Это я не высасываю из пальца, несколько лет назад реально размышляли на такую тему)
* В одном сервисе нам критически важны быстрые лукапы по ключам, одна таблица тут помогает.
* В плоскую структуру наши стейты не разложить - получится неадекватное число колонок, а при разделении на небольшое число таблиц / колонок от работы с документами уйти не получится.
При этом у нас не везде одна таблица. У нас есть раздельные таблицы с одним множеством ключей там, где это необходимо/выгодно.
Про выбор БД, тут есть особенности разработки больших сервисов внутри больших IT компаний, брали YTsaurus, так как в нем был нужный функционал для обеспечения exactly once, его использовали ранее в отделе, и с командой YTsaurus можно взаимодействовать и заказывать фичи и улучшения :)
Обработчики обновляли один и тот же баннер, но у этого баннера один и тот же номер шарда, а значит, оба обработчика не могли пройти мимо обновления одного и того же значения оффсета в таблице. Но оффсеты мы обновляем исключительно транзакционно, при этом коммитим только после проверки открывшейся транзакции на ожидаемое значение. Этот механизм гарантирует, что хотя бы у одного обработчика либо упадёт проверка того, что оффсет ожидаемый, либо упадёт коммит транзакции с ошибкой конфликта записи. А когда у обработчика происходит ошибка, он полностью перезапускается, при этом сбрасывает весь свой кэш стейтов.
Кто нибудь понял о чем это, или все по диагонали читали?
На сколько я понял, номер шарда у них, это аналог версии баннера, а дальше делается просто CAS или Test And Set, как у многих атомарных операций - параллельно два обработчика меняют данные одно и того же баннера, но закоммитить изменения сможет только один из них, т.к. коммит выполнится только при условии, что версия баннера в базе совпадает с ожидаемой. Второй же обработчик увидит новый номер версии, проставленный первым, транзакция не пройдет и ему придется заново читать изменения из базы и снова пытаться повторить свои изменения.
„На данный момент на маленькое событие обновления одного счётчика мы перезаписали всю колонку счётчиков, которая может иметь размер порядка десяти килобайт. Хотелось бы отправлять в БД только само произведённое изменение.
На помощь приходят бинарные дельта-кодеки, в частности, xdelta. Он позволяет вычислить diff между любой парой бинарных строк, а затем наложить его на оригинальную строку и получить новое значение. Это как git diff и git apply, только не с текстовыми файлами в репозитории, а с любыми бинарными строками.“
Если я правильно понял то логика следующая:
RDBMS это не модно и не молодёжно, поэтому все сделаем на key/value storage.
нам надо сэкономить данные на чтение/запись - давайте часть записи хранить в отдельном поле
А как будем обновлять? Посчитаем xdelta…
было: пишем объект по ключу
Стало: читаем по ключу/ вычисляем дельту, пишем дельту.
Вместо одной операции на запись как писали выше в нормальную колонку БД где одно целое число надо заменить на другое и не надо ничего считать- нагородили огород с чтением/записью расчетом дельты.
При этом предполагаем что пока мы читаем/считаем дельту никто это поле не обновит. И если надо поменять счётчик a и счётчик b одновременно, то просто создаём себе проблему на ровном месте, которую успешно преодолеваем…
Эффективное обновление состояний в БД из сервисов потоковой обработки событий