Pull to refresh
20
0.5
Виктор Поморцев @SpiderEkb

Консультант направления по разработке

Send message

В случае со счетами там проблем вообще нет.

Запись лочится на время уменьшения одного поля на сумму платежного документа для переноса этой суммы на холд. Все. Проверки платежа (а это долго) уже идут потом, вне лока.
Это именно архитектурное решение вместо залочить запись, провести весь комплекс проверок, если проверки прошли, внести изменения, разлочить запись.

Если проверки не прошли, то ничего страшного - еще раз короткий лок и возврат суммы на счет с холда. Тут логических противоречий не будет.

Это архитектурное решение для ситуации с большой плотностью обращений к записи.

Где плотность ниже - там возможно повторное чтение. И там бывают ситуации (скажем, обновление какого-то дневного агрегата), когда "ну вклинился кто-то, да и бог с ним - он его обновил (или создал), мы тогда не будем обновлять (создавать) - ничего страшного не случится".

Т.е. тут опять надо не тупо технически решать, а понимать логику бизнес-процесса.

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

Все это не просто так придумывалось, а на основе множества граблей и набитых шишек.

Как раз проще и дешевле решать конфликты если кто-то вклинился. Тут как в гите - что-то решается автоматом (ну просто смотрим - мы поменяли поле А, но кто-то вклинился и поменял поле Б - новое значение поля Б не противоречит нашему значению поля А - можно просто взять новое значение Б, новое значение А и сохранить запись). А что-то требует ручного вмешательства или более серьезной обработки.

К сожалению, уровень моего понимания тут очень поверхностный. Я по комплаенсу и клиентским данным :-)

Но если говорить о картах, то я понимаю сие так (не гарантирую что это 100% правильно): баланс по карте и баланс по счету к которому она привязана не есть одной и то же. Это разные сущности. Баланс по карте - в платежной системе (ПС). Баланс по счету - в банке. Т.е. оплачивая что-то картой, вы используете "деньги ПС". А банк имеет обязательство перед ПС погасить эту сумму. Со счета, который к этой карте привязан. Но если там не хватит денег, то из денег банка (а дальше уже будет с вами разбираться). Тот самый пример с двумя картами и одним счетом - это пример медленного взаимодействия банка с платежной системой.

На деле там, конечно, сложнее. Вы платите картой. ПС посылает в банк запрос "гарантируете оплату?" Если банк отвечает положительно, то ПС ее проводит и отсылает банку уведомление о списанной сумме (при этом уменьшая у себя баланс по карте). Банк должен его принять, и перевести с вашего счета деньги на холд. И ждать когда от получателя (не знаю, через ПС или напрямую) придет подтверждение что деньги зачислены на счет продавца (или была отмена покупки).

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

Короче, там все сильно заморочено...

Тоже вариант, да... Но там вообще все сложно. Мультивалютные проводки - слышал про такое, но как оно организовано вообще не в курсе...

Покажите мне где я говорил что локи не нужны...

Вы отстаиваете тезис, с которым никто не спорит.

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

Вот вы гите работаете? Когда работает в репозитории - лочите на время работы все объекты с которыми работаете? Или таки нет? или все-таки даете возможность кому-то еще с этими объектами работать, а потенциальные конфликты решаете потом при мерже?

Там уже нет т.к. второе чтение с проверкой блокирует запись от любых изменений.

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

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

Да, именно так. Холд - это блокировка суммы на счете с тем, чтобы не получалось технического овердрафта (я, кстати, сталкивался с ситуацией в одном мелком банке, когда имея на счете 1000р и две привязанных к нему карты, купить сначала на 1000р по одной карте, а потом сразу (и даже не сразу, а в течении чуть не дня, минимум нескольких часов) еще на 1000р по другой карте. А на следующий день получить "технический овердрафт" в 1000р (отрицательный баланс счета -1000р).

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

При этом вы можете через другого караванщика отправить еще кому-то денег, а не ждать окончательного результата (передал или вернул) от первого.

Это чисто архитектурное решение, давно уже являющееся стандартом в отрасли (по крайней мере в банках и платежных системах).

Вы поймите, те, кто работает в этой предметной области, мыслят категориями бизнес-логики, а не чисто техническими. Без понимания (хотя бы на базовом уровне) как все это работает, тут ничего хорошего не сделаешь. Мало быть хорошим технарем, надо еще понимать логику процессов.

А вы упираетесь в чисто технические аспекты, которые, в целом, и так очевидны.

Любые приложения, которые меняют что-то в базе, должны использовать локи, и если у них база общая, то одну и ту же систему локов.

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

То, что я описал, подходит к любой операции в этой цепочке. В общем случае, к любой последовательности "прочитали - проверили - рассчитали - сохранили в одной транзакции БД".

А вот это не совсем так. Потому что в реальной жизни цепочка "прочитали - проверили - рассчитали - сохранили" может по времени занимать несколько часов. Или дней. Поэтому и вводится система холдов. Где в одной короткой транзакции деньги со счета переводятся на холд (там единственная проверка - чтобы денег на счете хватило), а дальше уже идут все процессуальные проверки. Но счет (запись) при этом не заблокирована уже и доступна для любых других операций.

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

Делать все это в одной транзакции БД категорически неверно. Это не просто переложить деньги из кармана в карман. Это как отправить посылку - отнести ее на почту (где ее проверят на предмет отсутствия запрещенных к пересылке предметов - ее могут еще и тут завернуть), потом дождаться или подтверждения получения или возврата с пометкой "адресат выбыл".

Вот насчет нескольких языков тоже удивило. Сам работаю с RPG (это язык такой, не игры), C/C++ ну и до кучи еще гредл, SQL и XML. Для каждого свой набор плагинов, VSCode сам определяет (по расширению) с чем работаем.

другие процессы будут ждать, остальные id останутся свободными

Вот это и есть проблема. Сколько ждать? Если ждать достаточно долго, то Второй процесс ждет первого, третий ждет второго и далее по цепочке. В итоге миллионы клиентов по всей стране не могут расплатиться картами банка в течении нескольких часов.

А там нет какого-то одного "приложения". Там целый комплекс модулей-акторов, которые занимаются обработкой платежных документов. И каждый из них выполняет свою логическую функцию.

Еще раз - банк (АБС) - это очень много (и данных и логики) и очень сложно. Порядка трех десятков тысяч модулей, полутора десятков тысяч таблиц.

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

Все описания в статье - это как пытаться концепцию ООП объяснять на примере котиков и собачек или геометрических фигур. Примитивизировано до полной потери смысла.

Ну там не совсем так.

Есть комплекс проверок в системе расчетов. Они над каждым платежом выполняются последовательно (и там набор проверок и их порядок еще зависит от того, кто является плательщиком, а кто получателем - ФЛ, ИП, ЮЛ... И что за платеж - исходящий (в другой банк), входящий (из другого банка), внутренний (внутри банка)...

Каждая проверка возвращает код - ок/не ок (если не ок, то там свой код у каждой проверки). Если очередная проверка вернула не ок, то платеж отправляется в комплаенс на ручной контроль с этим самым кодом (чтобы знали что не понравилось). Там уже руками ставят статус разрешить или запретит и возвращают обратно в расчетный конвейер.

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

Т.е. долгих локов не бывает никогда. А баланс всегда отражает тут сумму, которой владелец счета может распоряжаться.

Не надо делать все последовательно. В примере из статьи меняются 2 счета конкретных пользователей, это 2 отдельных ресурса. У других пользователей будут свои счета, это 2 других ресурса, операции с ними будут идти параллельно первым. Лок делается на связку "название сущности + id".

Компания в рамках зарплатного проекта распределяет з/п на счета 1000 своих сотрудников. И что, пока не распределит все, с ее счетом ничего нельзя сделать?

Тут рассматривается крайне примитивный пример, бесконечно далекий от реальности. В реальной жизни все может быть хуже. Если вы надолго залочили ресурс и при этом у вас высокая интенсивность работы с БД - рано или поздно вы столкнетесь с дедлоками (опыт-с...). А дедлок в высоконагруженной системе чреват появлением лавинных эффектов - одно ждет другого, то еще чего-то ждет ив результате достаточно быстро вся система встает колом.

Поэтому еще раз - блокировка нужна, но она должна быть очень кратковременной. Как этого добиться - это уже архитектура а не разработка.

Ну, так скажем, через банк за сутки проходит более 100 000 000 операций. И каждая требует обработки. Делать все последовательно - просто времени не хватит. Да и клиенты возмущаться начнут - "целых 10 секунд прошло, а деньги со счета на счет еще не перекинулись..." (забыли как лет 25 назад по межбанку платеж мог несколько дней идти)...

Поэтому да. Параллельно. Но, как уже неоднократно писал - блокировки короткие. Со счета на холд перекинули сумму и дальше уже не держим запись. Можем спокойно все проверки проводить. А с холда они спишутся реально уже когда из другого банка подтверждение придет что до них дошли деньги. Или обратно с холда на счет если была отмена операции или подтверждение не получено в установленный срок. Но это уже может завтра или послезавтра произойти (не будете же вы держать запись заблокированной - получится что клиент одну операцию в день может провести?)

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

Да, посмотрел по нашей документации. Есть отдельная таблица

Остатки в оборотно-сальдовой ведомости

В оборотно-сальдовой ведомости хранятся входящие/исходящие остатки за каждую дату по всем счетам, существующим в системе.

Данные по оборотам пишутся (линковщиком) в таблицу в режиме on-line - одновременно с записью в таблицу парных проводок (бухгалтерский журнал).

Следует учитывать, что в таблицу данные помещаются только при условии движения средств по счету (включая переоценку и дооценку).

Просто я никогда с этой таблицей не сталкивался... Иногда приходится работать с основной таблицей счетов, изредка - таблица проводок.

Не знаю где как, но у нас эти разработчики ничего ни про какие кеши не знают. Они знают только что есть REST API для получения списка счетов и остатков по ним. Или для получения истории операций (выписки) по счету.

Связкой между REST API и соответствующим веб-сервисом на умной шине занимаются другие люди. Третьи люди (это уже мы, кто на АБС работает) занимаются разработкой сервис-модулей для веб-сервисов. Т.е. собственно того, что отвечает за формирование выборки из БД по соответствующему запросу. На нашей стороне точно нет никаких кешей. Получили параметры запроса, сформировали resulset, отдали его вебсервису.

Кеширование, если оно и есть, возможно где-то на уровне умной шины.

Это да... В точку :-)

Команд много. Даже на уровне АБС. И каждая работает по своему направлению. Но при этом все интегрированы друг с другом.

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

Бухгалтерия (а она ив банке есть) - это одно. Собственно банк (АБС) - это другое. АБС живет своей жизнью. И да, она (АБС) подчиняется [достаточно жестким] регламентам ЦБ.

EOD начинается в полночь по МСК. Заканчивается... Ну точно не скажу, но часам к трем-четырем утра (опять по МСК же). Дальше там есть еще фаза USRAFT - ряд обязательных операций в начале нового дня (это где-то 5-6 часов утра - время, когда нагрузка на систему относительно невелика). Что там происходит в полном объеме не скажу - много чего. По нашей линии, к примеру, сверка клиентских данных со списками росфина (того, что обновилось за прошлый день - где-то клиентские данные поменялись, также может прийти и загрузиться новая версия списков) и обновления стоплистов и списков совпадений... Или рассылка разного рода уведомлений клиентам (на стороне АБС, конечно, не сама рассылка - этим одна из внешних систем занимается, но подготовкой кому что послать занимается АБС). Например, идет выборка клиентов у которых заканчивается срок действия ДУЛ - их надо предупредить что через ... дней, если они не предоставят обновленные данные, наступит блокировка.

Так или иначе, к началу рабочего дня (9 МСК) АБС уже гарантировано работает в новом дне и готова к работе с полной нагрузкой.

А бухгалтерия банка живет сама по себе и подчиняется другим законам. Думаю, что она является таким же клиентом для АБС, как и другие.

Information

Rating
2,169-th
Location
Екатеринбург, Свердловская обл., Россия
Works in
Date of birth
Registered
Activity