速来报名!AICon北京站鸿蒙专场~ 了解详情
写点什么

银行业中的弹性系统

  • 2018-10-19
  • 本文字数:4355 字

    阅读完需:约 14 分钟

本文要点

  • 冗余和隔离是同一枚硬币的两面。
  • 防范自己的 Bug,而不仅仅是环境因素。
  • 减速比崩溃更容易跨越服务边界。
  • 同步 API 为故障传播提供了充足的机会——务必避免!
  • 已建立的云模式是有效的,即使没有调度程序和网格——第一天的架构应该简单到极点。

弹性是容忍失败,而不是消除它。

你不能把所有的时间都花在避免失败上。如果你这样做了,你将构建出一个脆弱到无可救药的系统。如果你真希望建立一个弹性系统,就必须构建一个能够吸收冲击并继续或恢复的系统。

在“斯塔林银行(Starling Bank)”,在现有银行公共服务大量中断的背景下,我们在一年的时间里从零开始创建了一家银行;我们知道,我们需要可靠的弹性方法。我们需要来自混沌工程的保障,以及使最好的创业公司得以茁壮成长的对简单性和严格优先级的执着追求。

以下是我们的弹性方法背后的原则和信念。

顺便说一下,我们的方法有一些特性,我在这里不做介绍,但它们仍然是必不可少的:

  • 混沌工程——因为弹性必须测试;
  • 监控——因为弹性需要可支持性;
  • 事件响应——因为弹性适用于系统和运行它的组织。

相反,我们关注的是从基础设施往上的弹性架构。

弹性架构

为客户提供弹性服务意味着,要确保在故障发生时,受错误影响的系统部分与系统整体相比很小。

有两种方法可以确保这一点。冗余是指确保系统作为一个整体扩展到故障范围之外。不管有多少受损,我们都有其他备用的。隔离是指确保故障局限在一个很小的范围内,而不能扩展到我们系统的边界。

无论你如何设计系统,都必须对这两个问题有很好的答案。有鉴于此,你必须针对你能想象到的每一个错误在脑海中测试你的设计。

请考虑以下方面的失败,希望对你有所帮助:

  • 基础设施层故障(如网络故障)以及应用程序层的故障(如未捕获的异常或终止);
  • 我们构建的软件的内部故障(由我们即 Bug 导致)以及外部故障(由其他人如非法消息导致)

仅仅假定通过测试可以消除内部故障是不够的。保护自己不受外界干扰和保护自己不受自己干扰一样重要。

设计的简单性是影响失败归因难易程度的最重要因素,所以总是选择满足你需求的最简单设计。

冗余

基础设施冗余在云中很容易实现。基础架构即代码使我们在创建多个时可以和创建一个一样容易。

云提供商,如 AWS 和 GCP,提供了 IaaS 原语,如负载均衡器缩放组,并在文档中清楚记录了它们的使用模式。像 Kubernetes 这样的执行环境提供了部署复制控制器等资源,其中,复制控制器持续保证服务的多个副本正在运行并可用。无服务器技术将在不进行任何配置的情况下为你扩展服务。

但也有一些限制。

状态是老敌人了。当实例假设本地状态准确时,扩展服务的难度就大许多。要么通过一个高可用的数据存储和外部共享状态,要么引入集群协调机制来保证每个实例的本地状况与对等实例的一致,总之,将服务器转化为分布式缓存。

我的建议是,至少对于创业公司来说,在第一天要保持非常简单。数据库用于共享状态。用它共享所有状态,直到达到其极限。本地内存仅用于瞬态状态。这为你提供了一个简洁的“不可变的”计算层和一个具有明确操作需求的数据库。你知道,你需要在某个时候改进这个基础设施,同步修改架构并监控指标。到那一天,你就从简单的扩展和冗余受益了。

无服务器环境通常提供一个无状态函数服务,并针对状态提供单独的数据库服务,这实际上是默认提供了简单巧妙的分离。

共享资源限制可能是另外一个问题。当后端数据存储仅支持接受 3 个连接时,将服务扩展到 10 个实例是没有意义的。事实上,当服务公开其他组件以加载它们无法支持的组件时,扩展服务可能是危险的。增加系统某一部分的性能会降低系统的整体性能。实际上,如果没有高强度的测试,你就无法了解所有这些限制。

隔离

在云基础设施层,AWS 在每个区域内提供单独的可用区,在基础设施组件之间提供强隔离。负载均衡器和伸缩组可以跨越多个可用区。

在 AWS 中已建立的构建模式可以确保你做好基础工作。其他云也有类似的功能。

在应用程序层,微服务自包含系统、甚至传统的 SOA 都是可以在服务之间引入强隔离带的设计方法,允许这些组件独立失败,而不影响整体的服务能力。

如果服务的单个实例崩溃,则服务不会中断。如果服务的每个实例都崩溃,客户体验可能会在某种程度上受到影响,但其他服务必须继续运行。

使用这种模式,系统分割得越细,单个服务故障影响的半径就越小。但还是那句话,魔鬼是在细节当中。服务之间可以通过许多微妙的方式相互依赖,这些方式跨越服务边界,使得错误会在系统中扩散。当服务密切相关时,通常可以简单地将它们视为单个服务,并将它们构建为单个服务。

有些方式可能不太明显,比如隐藏协议;服务实例可能通过负责 Master 选举的集群协议进行连接,或者通过针对每个事务(如果你参与了这类事务)进行网络投票的两阶段提交协议。工程师们常常会完全脱离这些网络交互,但它们用错误可以传播的方式将服务连接在一起。

就像在生活中一样,同居是一个不可掉以轻心的决定。如果你在同一个实例上运行多个服务,无论是经过深思熟虑的静态分组,还是使用像 Kubernetes 这样的调度器,这些服务的隔离程度都要比在单独的机器上低。它们都受许多相同故障条件的影响——尤其是硬件故障。

如果服务 X、Y 和 Z 的实例总是在同一台主机上一起运行,那么如果 X 可以任意运行并“毒害”主机,那么不管有多少个实例,X 的邻居都是 Y 和 Z。把它们分到一组,就侵蚀了服务 X、Y、Z 之间的隔离——即使你的技术应该保证这种“中毒”情况不会发生。

调度程序可以通过避免在任何地方部署相同的服务集来缓解这一问题。因此,如果一个有 Bug 的服务毒害了它的主机,你不会看到任何其他服务的完全失败,而是在更广泛的服务范围内产生较为分散的局部影响,而这可能根本不会影响客户体验。

在我们推出的架构中,斯塔林银行选择了一个简单的单服务 EC2 实例模型。这是一种权衡,特别注重简单性而不是经济性,但也提供了非常强的隔离。失去一个实例是很难察觉的。即使我们部署了一个流氓服务,对它的主机做了一些有害的事情,它也不容易影响到其他服务。

在应用层代码中传播错误的方法也很多。

也许最有害的因素是时间本身

在任何事务型系统中,时间都是最有价值的资源。即使你没有在处理器上进行主动调度,你也可能在完成工作的时间内持有重要的资源:连接、锁、文件、套接字。如果你磨磨蹭蹭,就会让别人挨饿。如果另一个线程无法继续,它可能不会释放它所持有的资源。它可能迫使其他服务进入等待状态,在整个系统中传播不良影响。

虽然死锁经常被描述为并发编程中的邪恶反派,但在现实中,由于事务运行缓慢而导致的资源匮乏可能是一个更常见而又同样严重的问题。

这一点太容易忽视了。工程师的第一直觉是安全而正确的:获取锁,进入一个事务,也许简单考虑了下超时设置然后就跳过了它——(工程师讨厌任何看起来随意的东西,对于如何处理超时,会有尴尬的选择)……日常开发中的这些简单诱惑能给生产环境造成严重伤害。

不能允许等待和延迟在服务之间传播。但是,除非你对这种不当行为有一些全局的预防措施,否则不难想象,你的系统容易受到攻击。你有固定大小的数据库连接池吗?或者线程池?你确定在进行 REST 调用时从不持有数据库连接吗?如果这样做了,当网络通信降级时,是否会耗尽连接池?其他还有什么会耗费时间?那些你几乎看不到的东西呢,比如日志调用?或者,你可能有一些需要反复收集的指标需要数据库访问,但由于池中的连接被用光了,所以数据库访问开始失败,导致大量的垃圾被写到日志中?然后,你也许会突破日志架构的限制,从而失去对正在发生的一切的可见性。构建一个噩梦般的场景是一件很有趣的事情,而这个场景是以一点点的拖延开始的。

预防措施有很多:断路器、“隔板(bulkheads)”、重试设置、最后传播期限……还有一些库可以帮助你在软件( hystrix resilience4j )中实现这些模式,也有一些服务网格或中间件( istio conduit linkerd )在底层提供了其中部分模式。但如果不投入时间和精力,它们都不会做正确的事情。和往常一样,任何代码的性能和故障模式都将反馈给工程师。

同步调用借用了别人的时间。而且,作为一个同步 API,按照合理的设计原则,你通常不知道这段时间对调用者有多么宝贵,也不知道它们多么容易受你的拖延或失败影响。你把他们扣为了人质。因此,我们更喜欢在服务之间使用异步 API,并且只在绝对必要或者是非常简单的只读调用中使用同步 API。

前端可以进行“乐观”的 UI 更新,而不是等待确认,并在离线时显示过时的信息。在大多数情况下,根据过时的信息进行决策需要付出一定的代价,但这种代价不一定很高。Pat Helland 曾经写道:计算由记忆、猜测和道歉组成。当系统表示偏离现实时总是有代价的,当现实在你背后发生变化时,它总会在某个时候偏离现实。在分布式系统中没有真正的“现在”。在决定需要完美的事务语义或同步响应之前,评估下“错误”的代价。

对于银行系统来说,容忍失败意味着容忍失败而不丢失信息。因此,虽然实现异步系统不一定需要队列,但你可能希望系统作为一个整体表现出一些类似队列的属性——至少一次最多一次交付,即使存在错误。通过这种方式,你可以确保某些服务始终拥有数据或命令的所有权。

你可以通过在服务中同时使用幂等性和追踪处理来达到这两个目的(如斯塔林的“DITTO”架构——有很多自治服务不断尝试做互相幂等的事情),或使用队列保证至少一次,使用幂等载荷保证至多一次(如 Nubank 的 Kafka 基础设施)、或设法把它们都委托给“企业服务总线”(如许多传统银行的架构)。

使用这些技术,完全有可能在异步交互服务的基础上创建响应性应用程序。

总结

编写弹性系统比以往任何时候都容易。在前 12 个月的运营中,斯塔林银行经历了许多局部故障和系统部分退化——从来没有出现过整个系统不可用。这主要是因为我们在每个层面上都强调冗余和隔离。

我们设计了一个能够容忍服务中断的架构,并特别重视这样一种观点,即慢服务对最终用户的威胁可能比死服务更大。

如果一开始我们对于上面列出的各项——混沌工程、监控和事件响应——没有可靠的方法,那也没有关系。但这得再一天介绍了。

关于作者

Greg Hawkins 是技术、金融科技、云计算和 DevOps 等领域的一名独立顾问。他在 2016 年至 2018 年期间担任斯塔林银行的首席技术官,这是英国一家仅限移动端的挑战者银行。在此期间,这家金融科技初创企业获得了银行牌照,两大移动平台上的下载量都突破 10 万次。现在,他仍然是斯塔林银行的高级顾问。斯塔林从零开始构建了全栈银行系统,成为英国第一个完全部署在云上、普通公众可以使用的经常账户,并满足了适用于零售银行的所有监管、安全和可用性预期。

查看英文原文: Resilient Systems in Banking

2018-10-19 16:102201
用户头像

发布了 1008 篇内容, 共 392.7 次阅读, 收获喜欢 344 次。

关注

评论 1 条评论

发布
暂无评论
发现更多内容

企业架构框架之DoDAF

冯文辉

企业架构

Flink 最佳搭档:开发部署平台 Zeppelin 的自白

Apache Flink

一口气说出 4 种分布式一致性 Session 实现方式,面试杠杠的~

楼下小黑哥

nginx redis 分布式 session

k8s极简史:K8s多集群技术发展的历史、现状与未来

华为云开发者联盟

Kubernetes 容器 云原生 华为云

tomcat 使用apr

zack

tomcat

计算机网络基础(七)---网络层-ICMP协议

书旅

计算机网络 网络协议 网络层

最新:英特尔断供浪潮系内部供应链调整,现已恢复供货

Geek_116789

波士顿动力狗 SPOT 权威购买指北

早睡蟒

Python 人工智能 学习 波士顿动力 机械狗

Oracle JDK7 bug 发现、分析与解决实战

vivo互联网技术

实操案例:字符串哈希表操作

华为云开发者联盟

程序员 编程语言 C语言 哈希表 字符串

itchat替代品,追妹子神器,个人微信给多个好友(群)发消息,定时提醒妹子喝水

Java_若依框架教程

技术 后端 itchat 微信消息 定时提醒

网传Intel断供浪潮,英特尔:供应链调整

Geek_116789

来自前端童鞋对后端的吐槽@#$%^

Java小咖秀

程序员 程序人生 大前端

凡架构必拆分,分则有度

菜根老谭

微服务 康威定律 架构思维 分治思维

Newbe.Claptrap 框架入门,第二步 —— 简单业务,清空购物车

newbe36524

容器 微服务 Reactive .net core ASP.NET Core

「架构师训练营」第 7周作业 - 性能测试

森林

「架构师训练营」第 7 周作业 - 总结

森林

金融科技的碎片化思考(上)

曲水流觞TechRill

金融科技 FinTech

什么?不写代码也能做功能开发!- RUOYI教程

Java_若依框架教程

Java 技术 后端 开发 框架

压测脚本

LEAF

Java 面向对象知识整理

多选参数

Java 编程

JVM系列之:详解java object对象在heap中的结构

程序那些事

Java JVM GC JOL

Flask 的 url 处理器

Leetao

Python flask Web框架

MySQL库表设计小技巧

Simon

MySQL 数据库设计

数据库周刊33丨5大国产数据库中标中国移动;Oracle7月CPU安全预警;腾讯Tbase新版本发布;“2020数据技术嘉年华”有奖话题遴选;阿里云技术面试题;APEX 实现数据库自动巡检;MYSQL OCP题库……

墨天轮

MySQL 数据库 oracle 阿里云 面试

报告|50%CRM品牌陷入竞争旋涡,破圈迫在眉睫

人称T客

架构师都该懂的 CAP 定理

闻人

架构 分布式 架构师

有趣的“第二个系统”

架构精进之路

提升认知 研发体系

Flink 1.11 Unaligned Checkpoint 解析

Apache Flink

flink

架构师第七周总结

傻傻的帅

架构师

智能标注原理揭秘,一文读懂人工智能如何解决标注难题

百度大脑

人工智能 百度 学习 AI 百度大脑

银行业中的弹性系统_服务革新_Greg Hawkins_InfoQ精选文章