大规模系统设计模式和原则
小军的求知笔记
小军的求知笔记
微信号
Golang_Porter
功能介绍
分享个人成长笔记,勇敢做自己。
如今即使是小公司也可能面临处理TB级的数据或构建每分钟要处理成千上万个事件的系统。谈到“大规模”,通常我们指的是系统需要在短时间内处理大量的请求、数据或事件。
如果没有经过合理设计试图实现大规模系统注定是失败的或者代价会很高。本文介绍一些常用的设计原则和模式来实现大规模系统。当我们提到大规模一般都是分布式系统,我们会从三个方面来说明系统有多好或者多稳定:
可用性:系统必须高可用。系统正常运行时间比例是用户体验的关键,那种没人能使用的系统就更不用说了。可用性一般使用“多少个9”来衡量。
性能:一个系统即使在高负载下也应该能工作和执行任务。而且,处理速度对用户体验非常重要;事实表明,这是防止用户流失的最重要因素之一!
可靠性:系统应该准确地处理数据并返回正确的结果。可靠的系统不会无故地失败、返回不正确的结果或创建损坏的数据。可靠的系统架构是尽力避免故障,当出现故障时,它将检测、报告,甚至尝试自动修复故障。
我们可以通过两种方式扩展系统:
垂直扩展(scale-up):将系统部署到性能更高的服务器,CPU、内存配置都更高。
水平扩展(scale-out):将系统部署到更多的服务器上,即创建更多的虚拟机或容器来处理大规模请求、数据或事件。
垂直扩展一般不太接受,有两个原因:
系统需要停机部署
单个服务器性能存在极限。
另一方面,为了能够水平扩展,必须满足一定条件。例如,系统必须无状态。(大多数的数据库不支持直接水平扩展)。
本文的目的是让您了解一些不同的设计模式和原则,使系统能够向外扩展,同时保持可靠性和弹性。限于篇幅不深入探讨每一个主题,只提供一个概述。在每个主题中,会添加有用的链接,可以获得有关该主题的更全面的内容。
下面开始吧!
幂等性
幂等这个术语来自数学,定义如下:
f(f(x)) = f(x)
乍一看可能有点吓人,但它背后的逻辑很简单:不管我们对参数x调用函数f多少次,都会得到相同的结果。这个属性为系统提供了极大的稳定性,因为它允许我们简化代码,也使我们的操作更容易:失败的HTTP请求可以重试,崩溃的进程可以重新启动,而不用担心副作用。
此外,一个长时间运行的任务可以被分解成多个部分,每个部分本身可以是幂等的,这意味着,当任务崩溃并重新启动时,所有已经执行的部分将被跳过(可恢复性)。
异步
当我们进行同步调用时,执行路径将被阻塞,直到返回响应。这种阻塞有资源开销,主要是内存和上下文切换的开销。当可以使系统更高效时,我们就使用异步调用来设计系统。
健康检查
这种模式是特定于微服务的:每个服务都应该实现一个/health接口,在系统正常运行后快速返回。假设一切正常,请求应该返回HTTP 200,如果服务出现故障,应该返回500内部错误。当前,我们知道一些错误不会被健康检查发现,但是假设一个系统在高负载情况下响应很慢,也会被健康检查反映出来,请求会变得迟钝,这也可以帮助我们识别出问题,并自动生成一个警报,等待运维人员处理。我们也可以选择暂时将节点从队列中移除(请参阅下面的服务发现),直到它再次稳定下来。
断路器
断路器是一个从电力领域借用的术语:当电路闭合时,电流流动,当电路打开时,电流停止。
当一个依赖服务不可用时,所有的请求都将失败。根据快速失败原则,我们希望请求快速失败而不是等待直到超时。这也就是断路器的使用场景:通过封装一个带有断路器的函数调用,断路器将识别调用一个特定的服务(例如一个特定的IP)是否会失败,如果会失败的话,就直接返回调用失败,而不会真正地执行依赖调用。
断路器会维持一个状态(open/close),并通过定期调用依赖服务来刷新状态。Netflix的Hystrix库是一个被广泛使用的断路器实现,如今在其他库中也很常见。
服务发现
在微服务的动态世界中,虚拟机/容器经常删除重建,我们需要一种方法来知道新节点何时加入或删除。服务发现(也称为服务注册)能解决这个问题,让每个节点都向一个中心服务注册,类似黄页。这样,当服务B想要调用服务A时,它将首先调用服务发现来请求可用节点(ip)列表,它将缓存这些节点并使用一段时间。
超时、睡眠和重试
任何网络都可能出现短暂的错误、延迟和拥塞问题。当服务A调用服务B时,请求可能会失败,如果发起重试,第二次请求可能会成功。也就是说,重要的是不要以一种傻瓜式(循环)实现重试,而要在reties之间“设置”延迟机制(也称为“睡眠”)。原因是我们应该注意被调用的服务,可能有多个其他服务同时调用服务B,如果所有这些服务都继续重试,结果将是“重试风暴”,服务B将被请求轰炸,这些请求可能会压垮它,使服务B崩溃。为了避免“重试风暴”,通常的做法是使用指数后退重试机制,这将在重试之间引入指数增长的延迟,并最终导致“超时”,从而阻止任何过多的重试。
降级
有时我们只是需要一个“B计划”。假设我们正在使用推荐服务,以便为客户提供最好、最准确的推荐。但是,当服务宕机或短时间内无法访问时,我们能做什么呢?
我们可以有另一个服务作为后备:该服务可以保存我们所有客户的推荐快照,每周刷新,当它被调用时,它所需要做的就是返回特定客户的相关快照数据。这种快照是静态的很容易保存。这些快照可能有点过时,尽管不是最新的建议总比什么都没有要好得多。
优秀的工程师在构建系统的时候会考虑这些选项!请注意,断路器实现可能包括一个服务降级功能!
指标、监控和告警
限流
限流是另一个有用的模式,有助于减少来自系统的压力。有3种限流方式:
客户端限流: https://cloud.google.com/architecture/rate-limiting-strategies-techniques#client-side_strategies
服务端限流: https://cloud.google.com/architecture/rate-limiting-strategies-techniques#techniques-enforcing-rate-limits
地理位置限流: https://docs.aws.amazon.com/waf/latest/developerguide/waf-rule-statement-type-geo-match.html
预览时标签不可点
微信扫一扫
关注该公众号
继续滑动看下一个
轻触阅读原文
小军的求知笔记
向上滑动看下一个
知道了
微信扫一扫
使用小程序
取消
允许
取消
允许
:
,
。
视频
小程序
赞
,轻点两下取消赞
在看
,轻点两下取消在看
分享
留言