Вводные
В ходе предварительного нагрузочноготестирования было выявлено, что обработка событий жизненного цикла часто упиралась в блокировки, что приводило к переотправке событий очередью. Несмотря на то, что это является вполне нормальной практикой — отправлять сообщения заново, если сейчас их обработать нельзя — с точки зрения производительности это приводит к нестабильности, и что хуже — чтению ненужных сообщений. Так как любая очередь сообщений работает с окном, а не отдельными записями — то уже обработанные сообщения вновь попадали в пайплайн событий, пусть и, благодаря кешу идентификаторов сообщений, не обрабатывались.
Очевидным решением было бы создать отдельный топик для переотправки, но тут так же возникают проблемы с производительностью, потому что возрастает ненужная нагрузка на очередь сообщений, и проблема блокировок никуда не уходит.
Единственным решением для оптимизации процесса является полный и безоговорочный отказ от блокировок и транзакций для работы с данными. Они только замедляют работу системы и не дают никаких преимуществ. К тому же, зачем платёжной системе вообще нужны транзакции и синхронизация доступа? Мы же работаем со слишком важными данными! Пусть все пишут одновременно! Параллелизм может быть только 1!
Решение
Все изменения в сервис можно увидеть в коммите.
Первым делом, нужно убрать все упоминания о нашем транзакционном прошлом. Поэтому ищем все упоминания @Transactional и удаляем их. Следующим шагом является удаление блокировок записей. Источник этого зла лежал в интерфейсе.
Теперь, все что осталось — это проверить, что наш процессор контрактов продолжает работать корректно. Для этого были специально написаны тесты для симуляции эффектов гонки (пример).
Следует разобрать один из тестов на состояние гонки, с целью понимания остальных, т.к. они по сути своей одинаковы.
Основная конструкция для тестирования обработки сообщений приведена ниже:
assertAckAll(
defaultContractLifecycleEventMessageQueue,
times(
CONCURRENCY,
() -> expectAutoApproved(
contract,
localWalletId,
ApprovalType.WITHDRAW)
)
);
Её особенностью является тот факт, что в начале мы ожидаем все необходимые сообщения с помощью функции times, и только когда все сообщения получены - передаём их функции, которая удостоверится, что результат обработки — ACK. Обработка сообщений будет запущена полностью параллельно без ограничений на количество потоков. Таким образом можно достичь эффектов гонки, и если такие проблемы в обработке сообщений есть, то они обязательно проявятся. Задавая значение констант TestCaseUtil.REPETITIONS и TestCaseUtil.CONCURRENCY можно запускать процесс обработки одного и того же события хоть тысячу раз в полностью параллельном режиме, ожидая, что обработка корректно завершится. Такой тест хорош тем, что его можно запускать в пайплайне сборки проекта и при этом не тратить слишком много ресурсов. На сборке проекта данный тест не сильно сказывается.
Нагрузочное тестирование
В прошлый раз, во время предварительного тестирования, у каждого сервиса было только 3 подключения к БД, в целом, с блокировками это хорошо работало, но после оптимизации, оказалось, что нагрузка на каждое подключение значительно превышает возможности обработки, и было принято решение увеличить количество подключений к БД до 8, события жизненного цикла контракта обрабатываются в 8 потоках максимум, так же есть другие события, у которых ограничение в 4 потока (у каждого события свои лимиты и они никак не влияют друг на друга). При такой конфигурации всем обработчикам должно хватать времени работы с подключением на выполнение своих запросов. Так как транзакции не используются и все запросы выполняются в режиме авто-коммита, то это вполне приемлемое решение.
Сам процесс нагрузочного тестирования разделен на 3 этапа:
Малая нагрузка;
Почти предельная нагрузка;
Аварийная работа в условиях превышения возможностей системы по своевременной обработки контрактов.
Малая нагрузка
На рисунках в спойлере отображены метрики работы системы в штатном режиме с небольшой нагрузкой. Следует уточнить, что метрика ack включает в себя processing, эта метрика нужна для того, что бы понимать сколько времени теряется на этапе работы пайплайна. Контракты создавались 50/50 на каждый узел, при этом половина контрактов была локальными (внутри узла), и другая половина — на сторонний узел. т. е. половина всех контрактов — локальные, половина — нелокальные. Отличным показателем является отсутствие NACK при обработке событий. Так же сам процесс обработки контрактов стал стабильнее и не вызывает никаких нареканий. Можно приступать к более тяжёлым нагрузкам.
Телеметрия для малой нагрузки
Почти предельная нагрузка
На рисунках в спойлере приведена телеметрия для более серьезной нагрузки на систему. Как видно, теперь одновременно в очереди обработки находятся уже десятки контрактов и поэтому время обработки каждого из них выросло до 8–15 секунд, вместо 3–6 ранее. Обработка самих событий при этом явно никак не изменилась, задержки обработки сообщений пульсара держатся на том же самом уровне и не превышают 1 секунды.
Телеметрия для предельной нагрузки
Аварийная нагрузка
На рисунках в спойлере телеметрия работы сервиса в аварийном режиме, когда система уже не справляется с нагрузкой. При создании 32 контрактов в секунду активно копится беклог и очередь необработанных контрактов. Система должна все равно справляться с такой проблемой, даже если не увеличивать ресурсы системы. В ходе этого теста хорошо заметно, что даже если продолжать создавать контракты, пусть и с низкой интенсивностью - сервис успешно разбирает накопившуюся очередь.
Телеметрия для аварийной нагрузки
Следует обратить внимание, что узел 0001 не смог сразу обработать свою очередь, узел 0000 его обогнал — это проблема с подключениями БД, они иногда падали. Возможно, что из‑за нехватки на самом сервере БД, автор не изучал эту проблему.
Отдельно по всем тестам следует обратить внимание на утилизацию ЦПУ, между тестами она не сильно отличается, что говорит о том, что потоки были полностью насыщены и дальнейшее увеличение производительности возможно только за счёт увеличения ресурсов. Но целью этой работы является не сжечь как можно больше электроэнергии, тем более что с алгоритмами, обладающими параллелизмом равным единице (на самом деле, если брать во внимание БД, то 1 за вычетом бесконечно малой величины, т.к. параллелизм равный 1 в реальных приложениях — это как скорость света) — следующий ограничивающий порог будет уже в железе — возможности обрабатывать пакеты и передавать их по сети, объем ОЗУ и дисковое пространство.
В ходе всех тестов на всех трёх физических машинах кластера гипервизор отчитывался о 16–18% утилизации ЦПУ, при этом в простое этот показатель составляет 6–7%. Все машины 32 ядерные с 64 потоками. Данная метрика важна, что бы учитывать полный эффект от нагрузки на систему. Даже если вместо виртуальных машин использовать реальные, то для маршрутизации все равно придётся использовать вычислительную мощь, пусть и маршрутизаторов.
К несчастью, ошибки все равно произошли, и 18 контрактов зависли в состоянии завершения. Скорее всего отсутствует какой‑то кейс при обработке событий пополнения/получения статуса завершения от другого узла. Удивительно, что все 18 ошибок произошли на втором тесте. В первом и третьем — они отсутствуют. Баг воспроизводится только на продовой конфигурации под высокой нагрузкой, без логов (а их будет слишком много) проанализировать дефект невозможно, а тратить 30–50 минут на отработку всех сценариев ради минорного бага — автор не может позволить, баг не будет исправлен. Наличие логов позволило бы осуществить эту операцию за 2–10 минут, но для этого требуются серверные nvme (читатель может поинтересоваться стоимостью Kioxia CD8 на 8 ТБ, а таких необходимо минимум три штуки).
Домашнее задание
Несмотря на то, что автор использовал определённую теорию, которую можно было бы назвать «теория проектирования автоматических систем произвольной сложности с заданными характеристиками, ограниченными законами физики», которая сильно помогает в упрощении процесса создания подобных систем. В проекте mireapay оказалось достаточно всего лишь одного метода, по этой статье данный метод можно дедуктивно воспроизвести. Хотя сервис контрактов — это нулевой уровень, пожалуй, нужно перейти на следующий и дать более сложный пример, как в данном домашнем задании. Автор не даст вам описание этого метода — используйте подсказки.
Для проверки ваших навыков, дорогой читатель, вам нужно перепроектировать сервис Баланс, что бы он больше не использовал транзакции или блокировки. Списывать средства со счета (или резервировать товар ;) ) можно без использования транзакций, блокировок данных. Достаточно только гарантии целостности от БД и поддержки уникальных ключей. Автор дал достаточно подсказок читателю, что бы решить эту задачу самостоятельно.
Поэтому переходим к постановке задачи:
Перепроектировать и переписать сервис Баланс для работы без транзакций и блокировок записей. Процесс обработки платежей при этом все равно должен подразумевать двух‑этапность, а именно: создание платежа и получение команды от клиента на подтверждение, либо отмену. Важно заметить, что отмена платежа может прийти даже до начала обработки создания. Поэтому важно предусмотреть этот вариант и не позволять создавать то, что уже отменено. Так же следует учитывать, что в процессе работы в произвольный момент может произойти отказ оборудования, падение приложения или другие варианты прекращения выполнения работы. Все сохранённые промежуточные данные не должны приводить к невозможности дальнейшей работы как текущего платежа, так и других. Более того, отмена может произойти в процессе создания в произвольный момент времени, в том числе параллельно. Возможна ситуация, когда создание не завершилось, операция прервалась на середине процесса, часть данных создана уже. Отмена должна происходить без ожидания завершения создания платежа.
При любой ситуации, неполные (некорректные с точки зрения конкретной операции) данные должны быть всегда корректными для всех остальных операций и не блокировать их работу.
Так как решений - несколько, то автором были выбраны пункты, которые позволят разграничить решения по их "качеству", а именно:
Получение текущего баланса производится за О(1);
-
Создание, подтверждение и отмена так же производится за О(1);
Дополнительный бонус, если отмена платежа не требует переотправки сообщений очередью и не используется кеширование.
Работа с базой данных ограничена командами INSERT, UPDATE, SELECT, у таблиц могут быть только индексы и ключи, например триггеры использовать нельзя;
Экспертный уровень: команда UPDATE не используется;
Мастерский уровень: Удельная производительность на ядро-секунду (количество подтверждённых(99%) или отменённых(1%) платежей на количество затраченных ядро-секунд за период времени системой целиком, включая БД и маршрутизацию трафика).
Примечания:
В расчёт сложности алгоритма не берётся сложность выборки данных конкретного пользователя, в силу бинарных деревьев оно всегда будет равно O(log(n)), постарайтесь абстрагироваться от того факта, что система многопользовательская, для первоначального решения достаточно одного пользователя;
Если берётся первый или последний элемент в индексе, то это считается за О(1), т.к. большинство современных БД хранят указатели на эти элементы;
Учитывать сложность алгоритмов самой БД для получения или сохранения записей не нужно, БД разные и работают по разному;
Пункты экспертного уровня и выше не обязательны к исполнению, так большинству архитекторов и разработчиков будет невозможно их достичь, но если вы себя считаете хотя бы середнячком, то стоит учитывать пункт экспертного уровня.
И автор напоминает ещё раз, что использовать блокировки записей или транзакции - нельзя!
Несмотря на то, что даже с этими пунктами все равно будет несколько вариантов уникальных решений (согласно его теории), автор не видит причин добавлять другие фильтры решений для их ранжирования, т.к. уже перечисленные выше удовлетворяют тем требованиям, что стоят перед информационными системами сейчас. Поэтому все решения удовлетворяющие первым трём пунктам будут считаться равнозначными.
Домашняя работа состоит из двух частей — проектирование и реализация. Дабы не отсекать тех, кто не умеет проектировать, но хотел бы научиться, автор предоставляет последнюю подсказку по домашней работе. Дальше все зависит только от тебя, читатель.
Подсказка для слабых духом
Заключение
Таквышло, что эта статья ещё и совмещает в себе результаты работы автора за год. Поставленной цели в 100 млн контрактов в день при ограниченных вычислительных ресурсах — автору удалось достичь. Цифра в 8 потоков была выбрана не случайно. В будущем, когда автор перепишет код на ЯП без рантайма, это позволит работать системе на ЦПУ отечественного производства — Эльбрусах и Байкалах. Возможно, что производительность будет ниже, но не в разы.
Использовать для платёжных систем JVM для обработки столь важных данных для государства — не самая лучшая затея, разве что в рамках пилота или натурных испытаний, а так же отсутствия адекватной альтернативы. Java — великолепный инструмент для прототипирования и отладки алгоритмов, решений, но итоговый продукт все равно должен быть воплощён в железе и максимально эффективно его утилизировать. Не нужно считать эти слова пустыми, автор вкладывает в них смысл — не надо транжирить ресурсы впустую. Работу JVM никак нельзя назвать эффективной, тем более что о скорости работы на Эльбрусах не пинал JVM только ленивый.
Автором были предложены механизмы реализации платёжной системы без необходимости использовать блокировки или транзакции, что снижает требования к оборудованию. Позволяет обрабатывать сообщения параллельно на нескольких машинах без потери производительности. Такой подход позволяет, даже в случае серьёзной аварии части системы, продолжить обрабатывать платежи без потери во времени обслуживания — платёж одновременно может обрабатываться на нескольких машинах. Разумеется, текущие показатели в ~20 секунд для обработки платежа при 100% нагрузке нельзя назвать хорошим, но его можно оптимизировать в 2–4 раза, если бы у автора были необходимые 2 недели — несколько месяцев, требуемые на конфигурирование системы и детальную настройку отправки сообщений, самих очередей сообщений. В условиях нехватки ресурсов — тратиться на оптимизацию в 2–4 раза — не имеет смысла, слишком малый выигрыш, который не стоит свеч. В данный момент прототип выполняет поставленную перед ним базовую функцию, а именно перевод средств со счета на счёт, при этом гарантируя отказоустойчивость, гораздо большую, чем описал автор. Статья уже превысила лимит по тексту.
Разумеется множество функций пока не реализовано, только в планах. Поэтому читайте статьи автора и в новом 2025 году. Автор желает всем успехов!
Для работодателей
Работодатель, поспеши завести себе Java-кота в команду! Мышей не ловит, но зато пишет Java-код, а еще проектирует немножко.
https://hh.ru/resume/b33504daff020c31070039ed1f77794a774336
И не забываем, дорогие мои HRы:
С 1 января при подписании трудового договора работодатель обязуется выплатить соискателю одну зарплату (+НДФЛ) за каждый месяц начиная с 1 января в качестве невозвращаемого приветственного бонуса.Так с 1 января — 1 зарплата, с 1 февраля 2 зарплаты и т.д. Сумма определяется в момент получения соискателем оффера и в силе в течении 10 рабочих дней, иначе рассчитывается исходя из даты подписания трудового договора за исключением случаев, когда перенос за границы 10 рабочих дней произошел по инициативе соискателя.
Комментарии (24)
VVitaly
26.12.2024 06:08:-) А как быть с блокировками и параллельностью при такой бизнес логике работы?
Есть один "Общий баланс" с минимально допустимым значением на который влияют операции по всем "Частным балансам".
Операция проверяет "Общий баланс" и если он "допустим", проверяет "Частный баланс", и если он больше суммы операции его уменьшает, после уменьшения "Частного баланса" необходимо уменьшить (на сумму операции) "Общий баланс". На все это у вас есть пара секунд до "ответа" - успешно операция выполнилась или нет.
И как предлагаете обойтись без транзакций и блокировок если у вас миллионы "Частных счетов" и тысяча операций в секунду? :-)lastrix Автор
26.12.2024 06:08Сущность баланс всегда принадлежит конкретному пользователю, на нее не может быть 1000рпс, да и количество обращений значения не имеет на самом деле. Больше сказать не могу, т.к. хочу, что бы вы сделали самостоятельно домашнее задание.
Если что, мне ваш код не нужен - и сам напишу =)VVitaly
26.12.2024 06:08Видимо понятия "Консолидированный баланс" для вас не существует? :-)
Тогда "для простоты", пусть "баланс всегда принадлежит конкретному пользователю" но есть условие проверки, что общая сумма "по 1000рпс" (десятка миллионов пользователей) за сутки (ну или за час) не должна превысить определенной конкретной величины.... :-)lastrix Автор
26.12.2024 06:08Когда происходит создание платежа - средства резервируются. Они находятся на балансе, но другие процессы их получить не могут. Это то, как работает сервис Баланс сейчас и то, как он должен работать после выполнения домашнего задания.
Про бухгалтерскую терминологию ничего не знаю.
Если на пальцах:
У вас есть 1000 рублей. Если одновременно будет 11 списаний по 100 рублей, то 10 из них сообщат, что списать могут и ждут команду на подтверждение или отмену, и 11 скажет, что денег нет, но вы держитесь. Какой конкретно платеж будет одинадцатым - определить нельзя, любой из 11, при условии, что создавались одновременно.
Блокировки записей тут не происходит, блокируются значения, сами средства, поэтому и есть возможность не использовать транзакции БД или блокировку записей.
VVitaly
26.12.2024 06:08Еще раз... Для непонятливых.... Внешняя от вашей логики система не ждет от вас ответа - "что списать могут и ждут команду на подтверждение или отмену"...
А ждет от вас однозначный ответ "да" или "нет" за ограниченное количество времени (банкомат ждет выдать вам денег или нет...).lastrix Автор
26.12.2024 06:08Банкомат работает с сервисом контрактов, а не с отдельными компонентами платежной системы.
Вы же, что бы получить деньги в банке (представляете, так можно, прийти в кассу и снять деньги) - не идете к инкасатору с документами вместо кассира, что бы он вам отсыпал денег?VVitaly
26.12.2024 06:08Банкомат тупо от управляющей системы (на свой запрос) ждет ответа - выдавать ему деньги или нет. А вот логика управляющей системы свой ответ предоставляет в зависимости от бизнес логики, которая (в свою очередь) проверяет кучу условий по тому запросу который пришел от банкомата. Одно из бизнес условий я вам озвучил - до проверки клиентского контракта необходимо проверить другой контракт (в условия/баланс которого входят миллионы клиентских). Так как решать то такую проблему?
30 лет назад когда большинство контрактов (и клиентские и консолидированные) были кредитные (не контролирующие в момент исполнения Online операции балансы), проблема не возникала, но... Времена и бизнес условия с тех пор изменились значительно...lastrix Автор
26.12.2024 06:08Банкомат - это просто "еще один кошелек", что бы выдать деньги мы можем передавать деньги на кошелек банкомата. Если успешно проходит - выдаем деньги. Тот кто стоит перед банкоматом деньги не получит, если у него на балансе нет нужной суммы и/или у банкомата нет нужных средств для выдачи - например не хватает банкнот или еще какой-либо мелочи. Причем при формировании таких запросов можно контроллировать такую штуку как "банкнотный ресурс" - потому что банкноты не являются "деньгами", это штуки, у которых есть серийник и от продажи чайников они никак не отличаются. Человек, который в банкомате снимает деньги для системы mireapay будет выглядеть как покупать банкнот с номерами 1,2,3,4. И это будет отражаться в контракте. Правда скорее всего для этого уже нужно будет банкоматы переделывать. Вряд ли серийники где-то хранятся в банкоматах сейчас и/или есть возможность у инкасаторов вводить такую информацию.
И это лишь один из вариантов решения. Если вас для принципиально, что банкомат - это тупая кнопка, то можно списывать деньги со счета клиента на какой-нибудь специальный счет. И потом система уже выдаст разрешение, что выдать деньги можно.
Но первый вариант мне кажется намного лучше, потому что у каждого банкомата будет свой цикл обработки и все что ему нужно будет - это дождаться завершения обработки контракта - считай разрешения, что можно выдать деньги или нет. Я уже не говорю про безопасность и аудит. На счете банкомата должен отражатся объем выданных средств. При начислении денег (клиент вносит сумму в банкомат) - банкомат переводит со своего счета на счет клиента - т.е. в явной форме еще и фиксируется откуда пришли деньги, потому что у каждого банкомата свой счет. Можно проводить аудит конкретного банкомата. Если удается - он завершает операцию, если нет - возвращает деньги. Если деньги вносит инкасатор - то деньги списываются в специальный счет - печатную машинку откуда деньги могут генерироваться в систему и который их и поглощает, цифры на этом счете можно рисовать любые, потому что это делает государство и ему без разницы какая сумма там будет, потому что эти деньги не существуют для экономики. Так как вся система контроллируется гос органами и только государство владеет узлами обработки, либо напрямую контроллируется специально обученным полковником - то это вполне нормально работает.
Вообще не очень понятно почему тема ушла в банкоматы, если это утилитарная вещь и ее реализовать можно многочисленными способами.
Причем эти два - это то что пришло в голову сразу. Существующие банкоматы, если я правильно понял ваши слова - вообще менять не надо, что бы они работали с mireapay. Сделать для них адаптер, который будет выполнять нужные команды - это вопрос 4-12 человеко-часов. Во всяком случае, если как вы говорите, ему надо сказать "да" или "нет".
VVitaly
26.12.2024 06:08Вы реально не понимаете? :-)
Есть "бизнес правило" - "со всех банкоматов для всех клиентов не выдавать налички на сумму более X миллиардов рублей за сутки" - даже если у клиентов (у каждого в отдельности) средства на контрактах/счетах есть... Именно это правило должно проверять до того как проверять есть у клиента средства или нет...
Все просто... :-)
Но без блокировок и транзакций (в которых проверяется данное условие при 1000 рпс по проверке одной суммы) есть идеи как это реализовать?lastrix Автор
26.12.2024 06:08Делаете всем банкоматам, у которых есть лимит один кошелек. Делаете правило, что на баланс в этот кошелек нельзя переводить больше, чем Х рублей за период.
Количество рпс значения не имеет. Все операции можно проводить параллельно.Вариант 2, делаете специальный ресурс "лимит", который банкоматы "покупают". В этом случае у всех банкоматов может быть свой кошелек.
Т.е. у вас будет контракт, состоящий из:
1. Перевод Х от клиента банкомату;
2. Банкомат покупает на Х лимитов с спец. кошелька;
3. Покупка у банкомата клиентом банкнот с серийниками, ну или если их нет - просто пишем, что "выдача наличных средств из банкомата YYY".
Т.к. каждый ресурс (а деньги на балансе - это ресурс) нужно в начале подготовить к списанию, то ваш лимит выглядит вообще просто - обычный ресурс, каждый день ставите лимит в Х миллиардов рублей по cron-правилу и все. Наступило 00:00 и не важно, сколько сейчас лимит - делаете его Х млрд рублей. И подключаете ваши банкоматы, хоть все сразу на покупку лимитов у кошелька. Количество рпс значения не имеет от слова полностью. Если решите домашнее задание, то поймете, что упретесь в сетевые адаптеры и IOPS. В этой статье не просто так в домашнем задании сказано про резервирование товаров. Это универсальный алгоритм. Так же как и протокол общения с ресурсными подсистемами, такими как баланс - он универсальный.
И если в первом случае сделать лимит очень сложно (на самом деле сложно, лично я браться не буду за такое), то в случае с покупкой банкоматом лимита с какого-то спец. кошелька - это вообще легко и просто. И даже если по каким-то причинам банкомат деньги не выдаст, то просто отменим контракт, потому что банкомат не подтвердил выдачу (у контракта есть возможность сделать так, что бы стороны подтвердили, что можно завершать, когда все готово к процессу завершения). Но у вас вроде как есть "установка" на да или нет, так что вам явно не подходит более безопасный вариант.И еще, про этот лимит вы мне сейчас говорите.
UPD: на самом деле можно даже ресурс "лимит" не создавать. Просто на кошельке держать деньги, которые могут быть переданы только банкоматам и больше никому. Система это прямо сейчас умеет. В этом случае даже усложнять ничего не придется. Оно просто будет работать.
UPD2: Для сервиса Баланс будет лучше, если лимит будет не устанавливаться в Х каждый день, а будут создаваться балансы заранее, в которых будет прописано, что АктивноС и АктивноДо - это с начала дня и до начала следующего дня. С точки зрения архитектуры сервиса Баланс, в т.ч. на данный момент это будет более правильным решением. Огромный +, что записи можно создавать заранее и не беспокоится, что что-то пройдет не так, а если и пойдет - сразу звать тех поддержку.
OpenA
26.12.2024 06:08Java — великолепный инструмент для прототипирования и отладки алгоритмов, решений, но итоговый продукт все равно должен быть воплощён в железе и максимально эффективно его утилизировать. Не нужно считать эти слова пустыми, автор вкладывает в них смысл — не надо транжирить ресурсы впустую.
Не я один значит думал о таком, что вместо докупки железа можно просто ресурсоемкие и нагруженые задачи выкинуть в нативные подпрограммы. Однако насчет хорошего инструмента для отладки я бы поспорил, переписывание с джавы потребует серьезной переделки и отладки заного. Джава это не питон, в котором модули типа thread asyncio, практически соответствуют реализациям тредов и корутин в С и С++ и довольно легко на них перекладываются. Так что как раз питон отлично подходит для отладки и прототипирования если цель в дальнейшем перенос на нативный код, а джава нет.
lastrix Автор
26.12.2024 06:08Бизнес логика не зависит от языка реализации. Вы не можете сделать сложение двух чисел разными способами, отличающимися от языка к языку.
Вот если мы будем говорить про криптографию, векторные операции - тогда да. Джава не подходит, потому что не умеет, но обычные if-else программы работают одинаково везде. Ветвление не удастся сделать как-то иначе, чем это позволяет оборудование.
Но, если мы говорим про общий случай, когда речь идет о произвольной программе из всего множества возможных, тогда да, я с вами согласен, но речь шла не про общий случай в статье =)
nin-jin
А в чем, собственно, заключается "обработка платежа"? Проверка баланса и сохранение транзакции?
lastrix Автор
Обработка платежа - это создать все необходимые записи, если их можно создать, ведь средств может не хватать, а затем завершить или отменить.
Смысл в том, что бы списать или начислить нужное количество средств и сохранить информацию о том, почему это было произведено. Транзакция описывает причину списания или зачисления. Это как пункт в чеке.
В рамках сервиса Баланс возможно агрегирование нескольких списаний с одной сущности баланс, а так же наоборот разделение списания между разными сущностями баланс, когда не хватает средств.
Приведу пример:
Вам нужно оплатить покупку билета в метро, скажем 50 рублей. Но у вас есть 20 рублей обычных и 30 рублей только для оплаты метро. В итоге ваше списание 50 рублей создаст 2 транзакции, хотя для вас это платеж один, продавец при этом получит ваши 20 обычных рублей и 30 специальных рублей, что он с ними будет делать - это отдельный разговор.
Пример 2:
Вы заказали пиццу (900р) и желаете сразу оплатить чаевые курьеру (100р), хотя система отправит 900р и 100р тем, кто их должен получить, с вашего баланса, на котором есть 1000 рублей, будет списано 1000 рублей и создано 2 транзакции, описывающие причину списания (одна на оплату пиццы, вторая на перевод чаевых).
(Это то, как сейчас работает сервис Баланс)
nin-jin
А можно сделать так: в обоих случаях вместо кучи 1-1 транзакций создаётся одна м-м, в которой записано сколько с каких счетов идёт списание и сколько куда начисление. А баланс счёта определяется разницей между всеми начислениями и всеми списаниям.
lastrix Автор
Это работает только при условиях:
1. Система не распределенная;
2. Все балансы одинаковые.
В сервисе Баланс все сущности типа баланс на данный момент величины векторные, приведу пример, есть рублевый баланс, но на них есть метка "Не для перевода заграницу", так же у вас есть рублевый баланс без ограничений, запишем их как (рубль,["Не для перевода заграницу"]) и (рубль,[]) соответственно. Эти балансы разные и их нельзя смешивать, это как разные типы. При попытке снять средства для оплаты зарубежной покупки - рубли с первого баланса недоступны.
Так же нужно учитывать, что сервис Баланс списывает деньги вникуда и зачисляет деньги изниоткуда. Куда уйдут деньги - решает сервис контрактов. Поэтому так важно, что бы сервис Баланс сообщил точно, какой тип средств он списал. Потому что разница между (рубль,["Не для перевода заграницу"]) и (рубль,[]) существенна.
В будущем, эта фича может быть использована для локализации денег в определенном контуре экономики государства. Например выдается кредит, льготный, фермеру на покупку оборудования, гсм и семян и только у отечесвенного производителя. На эти деньги он ничего кроме этих категорий купить не может. Он даже положить их на депозит не сможет, потому что это тоже "покупка", просто покупаешь в этом случае долг с типом "депозит".
Когда эти деньги получит отечественный производитель, то он с ними идет "куда-то", где ему эти деньги меняют на что-то, что было обговорено заранее в рамках программы, все же такие вещи не делаются персонально под одного фермера.
В приведенном вами примере идет настолько существенное упрощение, что работать это будет только если есть некая центральная СУБД, куда все стекается, у каждого в ней есть счет и в итоге получаем ЦБ дубль 2. Не надо так.
nin-jin
А зачем вы счета балансами называете? Я бы не стал пользоваться сервисом, который списывает деньги "вникуда" и эмитит их "изниоткуда". Каким образом вы собираетесь проверять положительность баланса без "центральной субд, куда всё стекается", я бы послушал.
lastrix Автор
Счет - это совокупность балансов. У вас на счету может быть множество валют одновременно и при этом эти валюты сами могут быть типизированными, как ранее описывал.
Сервис контрактов следит за тем, что бы, если 100 рублей списали у Васи, то эти 100 рублей обязательно у кого-то оказались.
Контракт не завершится, если сальдо с бульбой не сойдется. У кого-то -100, у кого-то +100. Иначе никак. Причем с соблюдением типа.
Сервис Баланс сделан целенаправленно именно таким, что работает с конкретным счетом и говорит о том, что он конкретно может по запросу сделать.
Приведу пример развернуто из того, что было выше:
Что бы перевести 100 рублей от Васи к Пете - сервис контрактов в начале попытается создать платеж у Васи, когда сервис Баланс скажет, что создал списание на 100 обычных рублей под идентификатором запроса Списание1, то сервис контрактов отправит запрос за зачисление 100 рублей Пете (мы не можем сразу же формировать зачисление, потому что не знаем вектор типа перечисляемых Пете рублей, у Васи могут быть маркированные рубли же, причем сам Вася о том, что его рубли меченные никогда не узнает, в будущем будет статья про СОРМ). Если сервис Баланс опять сообщит, что зачислить могу и жду подтверждения по идентификатору Зачисление1, тогда контракт переходит в стадию "Завершение". В этой стадии он уже не может быть отменен никем, даже системой, и отправляются подтверждения созданных ранее Списание1 и Зачисление1. В этот момент Петя получает свои деньги, а Вася получить обратно свои деньги уже не сможет, потому что контракты не отменяются и удалить их нельзя.
Если он отправил деньги Пете по ошибке, то нужно создавать контракт на обратный перевод.
А теперь представь себе, что Вася живет в Москве, а Петя в Рио - о какой централизованной БД может идти речь?
Деньги в системе никуда не пропадают.
Сервис Баланс - это подсистема большой системы и сами валюты - это один из ресурсов, которыми оперирует подсистема контрактов.
Вся платежная система строилась исходя из того, что будут центры в каждой области, плотность расположения узлов - в соответствии с нуждами экономики. Нет никакой централизации в проведении платежей у системы и она не нужна.
nin-jin
Вы не в курсе, что в номере счета зашит код валюты?
lastrix Автор
Еще раз повторяю. ЦБ и банки - это анахронизм и его давно пора убирать. Те государства, которые это своевременно не поймут - уйдут в историю.
В mireapay ничего в номер счета не зашито и нет смысла этого делать.
Вы пытаетесь разговаривать со мной с точки зрения текущей инфраструктуры, которую автор и ставит своей целью упразднить и убрать.
И да, у меня есть способ, как мигрировать на новую инфраструктуру. Это не быстрый процесс, но реальный.
lastrix Автор
Так же вы видимо забываете, что у меня нет заказчика и нет требований от него, что я обязан следовать требованиям "какого-то там регулятора с горы".
Что бы что-то требовать от меня, нужно для начала иметь влияние. А писать про "у нас оно работать так должно" - идите к тем, кто сидит на зарплате.
Если вы не способны мыслить за рамками вашего "загона", то пожалуйста, не тратьте хотя бы собственное время. Я уверен, что вы очень занятой человек, занимающий важную должность "где-то".
Этот разговор не стоит затрачиваемого вами времени.
nin-jin
Ох уж эти оторванные от жизни мечтатели. Как текущая система работает и почему именно так разбираться не стали. Даже в терминах поленились разобраться. Зато фантазируют о прекрасном будущем, где национальная валюта не будет контролироваться государством, налоговой плевать на отчётность, а мошенников не то что ловить не будут, а даже наоборот будут помогать, создавая децентрализованные миксеры.
lastrix Автор
У налоговой в системе mireapay контроль еще выше, чем в текущей системе. Налоговая буквально является частью платежной системы и все проводимые платежи по идее должны проводиться с уплатой налогов сразу в налоговую, минуя всякие юрлица, т.е. покупая что-то - НДС сразу улетает в налоговую, переводя зп сотруднику - НДФЛ сразу вычисляется системой;
Контроль у государства в mireapay еще выше, чем есть сейчас, потому что можно не только контроллировать куда уходят деньги, но и кому и почему. Этому будет посвящена отдельная статья про СОРМ и в целом гос безопасность с секретностью;
Мошенникам будет еще сложнее, потому что если физ лицо получает деньги от множества других лиц (или сумма слишком большая, скажем больше 100 тыс), то полученные деньги могут быть "временно" заморожены и доложено куда надо, что бы разобрались. Деньги будут на счету у "мошенника", но забрать их можно будет в любой момент и вернуть потерпевшему, пока заморозка конкретных средств не пройдет. Причем работает это таким образом, что замораживается конкретная сумма, а не вообще весь счет. Даже если будет ложное срабатывание - людям жизнь это не испортит, свои деньги, которые у него до этого были - он сможет тратить как и раньше.
Уважаемый, правда, я вижу что вам в боль со мной общаться и вам сложно понять мои слова. Вы не читали мои статьи, особенно от 1 сентября, где все описано.
Перечитайте, пожалуйста, мои статьи по mireapay. Вам яснее станет, что никаких мечтательством у меня и не пахнет в работе.
nin-jin
А давайте вы сперва научитесь пользоваться гиперссылками. Вашей статье определённо не хватает какого-то контекста, который есть исключительно в вашей голове. Снимите корону с головы и примите тот факт, что никто тут не следит за вашим творчеством.