Интервью по системному дизайну - Проектирование платежных систем; Дополнительные вопросы и возможные проблемы
10 ноября 2022 г.Исходный
У нас будет благотворительная акция, которая продлится 3 дня (скажем, с пятницы по воскресенье). Мы хотим собрать 100 миллионов долларов, и будет 10 благотворительных организаций, поэтому каждый пользователь нашей системы может решить, куда он / она хочет пожертвовать деньги. Можно предположить, что клиентская часть готова, а также у нас есть соглашение с какой-то сторонней платежной системой, поэтому нет необходимости обрабатывать денежные переводы с одного счета на другой. Также нам нужно собрать все деньги на один банковский счет и после завершения мероприятия нам нужно как-то распределить собранные деньги между всеми 10 благотворительными фондами. И последнее, о чем следует упомянуть, это то, что нам нужно обработать любую ошибку, с которой мы можем столкнуться при обработке платежа.
Функциональные требования
- Обработка транзакций с использованием сторонних сервисов (поставщиков платежных услуг, таких как Stripe, Braintree и т. д.)
- Отслеживайте, какие пожертвования относятся к определенной благотворительной организации (чтобы иметь возможность распределить все пожертвованные деньги между благотворительными организациями).
Нефункциональные требования
Поскольку мы собираемся работать с платежами, наша система должна быть высокосогласованной, нам необходимо обрабатывать устаревшие данные.
Кроме того, поскольку для обработки наших транзакций будет использоваться какой-либо сторонний сервис, нам необходимо обеспечить некоторый процесс согласования (процесс, который обеспечит согласованность наших сохраненных данных). Наша система должна быть надежной и отказоустойчивой.
:::подсказка Обычно план собеседования по проектированию системы выглядит так:
- Функциональные требования
- Нефункциональные требования
- API
- Структуры данных
- Дизайн высокого уровня
- Подробнее о дизайне
- Подведение итогов
Но в этой статье мы сосредоточимся на дизайне высокого уровня, чтобы обсудить возможные проблемы с ним и дополнительные вопросы, которые могут возникнуть во время интервью.
:::
Дизайн высокого уровня
- Пользователь отправляет форму в пользовательском интерфейсе (форма содержит информацию о кредитной карте, идентификатор благотворительной организации и сумму денег, которую пользователь хочет пожертвовать этой благотворительной организации.
- Веб-сервер вызывает PSP для проведения платежа.
- PSP ответила подтверждением того, что платеж прошел успешно
- Веб-сервер сохраняет данные в БД
Проблемы с этим дизайном:
- пользователь дважды нажал кнопку отправки, что произойдет в этом случае? Система выполняет 2 разных платежа?
- при работе с конфиденциальными данными, как обращаться с информацией о кредитной карте?
- как сделать систему надежной и отказоустойчивой?
Нажмите кнопку «Отправить» несколько раз
Мы можем решить эту проблему несколькими способами:
- у нас могут быть некоторые ограничения JavaScript, но это не поможет, если пользователь отключит JavaScript в браузере. Это также не так надежно, поскольку пользователи могут попытаться изменить ваш код javascript (вместо того, чтобы вы запутали свой код, чтобы сделать это действие практически невозможным)
- обеспечить идемпотентный API с двухэтапной обработкой.
Давайте рассмотрим второй подход. Во-первых, мы предоставляем страницу с раскрывающимся списком 10 благотворительных организаций, суммой, которую пользователь хочет пожертвовать, и кнопкой «Далее»:
После этого мы сгенерируем UUID из PSP и сохраним его в своей БД, после сохранения данных перенаправляем пользователя на страницу оплаты:
Весь процесс будет выглядеть следующим образом:
UUID использовался для того, чтобы сделать наш запрос идемпотентным. Другими словами, если мы будем вызывать нашу PSP с методом, который выполняет транзакции несколько раз для одного UUID, результат останется прежним.
Размещение страниц кредитных карт, предоставляемых PSP
Хранение информации о кредитных картах — непростая задача, поскольку нам необходимо соблюдать сложные правила, такие как Стандарт безопасности данных индустрии платежных карт (PCI DSS) в США. Большинство компаний избегают хранения информации о кредитных картах и вместо этого размещают платежные страницы, предоставляемые PSP. Вот пример оплаты Stripe:
https://stripe.com/payments/checkout?embedable=true
Системы PSP, такие как Stripe, получили внутренние механизмы повторной попытки на случай, если первая попытка перевести деньги по какой-либо причине не удалась. Имея это в виду и тот факт, что мы не будем хранить конфиденциальные данные в нашем хранилище, мы можем сказать, что если по какой-то причине платеж не будет выполнен, мы не сможем автоматически повторить попытку сделать это еще раз, что мы можем сделать, это проверить результат платежа и в зависимости от результата сделать запись об этой операции последовательно. Для этого нам нужен механизм согласования.
Сверка
Вот весь процесс:
На шаге 4 наша запись в таблице транзакций будет выглядеть так:
| идентификатор (пк) | благотворительный идентификатор (fk) | сумма | статус | обновлен | |----|----|----|----|----| | UUID123 | 1 | 500 (строка) | в процессе | отметка времени |
У нас будет поле статуса, которое указывает текущий статус транзакции.
:::информация Обратите внимание, что поле суммы имеет тип String, а не double. Причина этого в том, что double обычно не является хорошим выбором, поскольку программное обеспечение, протоколы и т. д. могут поддерживать различную числовую точность при сериализации, или число может быть очень большим или очень маленьким.
:::
На шаге 8 PSP вызывает наш веб-перехватчик и подтверждает, что транзакция успешно завершена. После этого мы можем изменить статус на Завершено.
| идентификатор (пк) | благотворительный идентификатор (fk) | сумма | статус | обновлен | |----|----|----|----|----| | UUID123 | 1 | 500 (строка) | завершено | отметка времени |
Если между шагами 1–4 что-то пошло не так, мы просто не сохраняем данные в БД, и наша БД остается согласованной.
Если между шагами 4–8 что-то пошло не так, мы можем предоставить процесс согласования, который будет периодически считывать таблицу транзакций и проверять все транзакции со статусом в процессе и отметкой времени старше, чем X, и отправлять такие записи в выделенную очередь, чтобы финансовый отдел мог обрабатывать ее вручную. Или, если PSP предоставляет API для проверки транзакций по идентификатору, мы можем автоматизировать его.
Последнее, о чем здесь стоит упомянуть, это система двойной записи. Отличный подход к бухгалтерскому учету, идея, лежащая в основе этого заключается в том, что вы получили 2 записи для каждой транзакции с дебетом и кредитом соответственно. Но в нашем дизайне это может быть излишним.
Оригинал