大道至简-Shopify 构建弹性支付系统的 10 条原则

发布时间 2023-11-29 13:13:56作者: 公众号-JavaEdge

0 大纲

  1. Lower the Timeouts, and Let the Service Fail Early
  2. Add Circuit Breakers
  3. Capacity Planning
  4. Add monitoring and alerting
  5. Implement Structured Logging
  6. Use Idempotency Keys
  7. Be Consistent with Reconciliation
  8. Incorporate Load Testing
  9. Get on top of incident management
  10. Organize Incident Retrospectives

1 降低超时时间,让服务尽早失败

默认超时时间为 60 秒。根据 Shopify 的经验,5 秒的读取超时时间和 1 秒的写入超时时间是不错的设置。

超时时间也可以在数据存储中设置。例如,MySQL 有 MAX_EXECUTION_TIME 优化提示,用于以毫秒为单位设置每个 SELECT 查询的超时时间。

Go 中的 http.Client 和 Node.JS 中的 http.request 等其他编程语言中的 HTTP 客户端根本没有默认超时时间!这意味着一个无响应的服务器可能会无限期地占用您的资源,并不必要地增加基础架构费用。

2 添加断路器

Shopify 开发了 Semian 来使用 Ruby 中的断路器来保护 Net::HTTP、MySQL、Redis 和 gRPC 服务。

通过在检测到服务已关闭时立即引发异常,他们通过不等待预期会发生的另一次超时来节省资源。

就像在家中或公寓中会发现的断路器一样,一旦断路器打开或触发,就没有什么可以通过。

3 容量规划

如果我们的队列中有 50 个请求到达,处理一个请求平均需要 100 ms,那吞吐量是每秒 500 个请求。

N+1 查询会增加请求的延迟并降低吞吐量。

capacity = throughput x latency

4 添加监控和告警

谷歌的站点可靠性工程(SRE)书中列出了一个面向用户的系统应该监控的四个黄金信号: 延迟、流量、错误和饱和度。

5 实现结构化日志记录

将日志存储在集中地方,并使它们易于搜索。

指标提供了系统行为的高级概述,而日志记录允许我们了解单个 Web 请求或后台作业内部发生的事情。

在分布式系统中,传递某种关联标识符很有用。一个假设的例子是当买家在结账时启动支付,关联_id 由我们的 Rails 控制器生成。

6 使用幂等键

确保支付或退款只发生一次,尽管偶尔会出现小故障。

请改用通用唯一词汇排序标识符 (ULID) 作为这些幂等键,而不是随机版本 4 UUID。

在 Shopify 的规模下,每一百万次不可靠的支付处理机会意味着它每天发生很多次。如果这是超时的支付 API 调用,他们希望重试请求,但要安全地进行重试。

7 与调节保持一致

在数据库中存储与 Shopify 的金融合作伙伴的调节中断。

通过调节,他们确保自己的记录与金融合作伙伴的记录一致。他们调节单个记录,如费用或退款,以及尚未支付给商户的当前余额等汇总记录。

8 结合负载测试

如果传入工作的数量足够大,他们的服务器甚至会耗尽内存来存储队列上的工作并崩溃。

Shopify 定期模拟大量抢购活动以获得基准测试结果。

9 掌握事件管理

事件通常从值班服务所有者收到页面开始,这可能是基于监视的自动警报,也可能是如果有人注意到问题,他们会手动发送。

每个事件通道都有 3 个角色:值班事件管理器(IMOC)、支持响应管理器(SRM)和服务所有者。

10 复盘

对于每个事件,Shopify 会提出 3 个问题:确切发生了什么?他们对系统有什么错误的假设?他们可以做些什么来防止这种情况发生?

一旦了解了这些,通常会分配几个行动项来实施保护措施,以防止同样的事情再次发生。

本文由博客一文多发平台 OpenWrite 发布!