管理分布式计算第一个谬误(网络可靠)的指南

分布式计算是一个复杂的领域,面临着众多挑战,了解与之相关的谬误对于构建健壮且可靠的分布式系统至关重要。以下是分布式计算的八个谬误及其意义:

1. 网络可靠:假设网络连接始终可用且可靠,当网络中断发生时,即使网络中断是暂时的,也可能会导致系统故障。设计能够通过冗余和容错机制妥善处理网络故障的系统至关重要。

2. 延迟为零:高估分布式组件之间的通信速度可能会导致系统缓慢且无响应。承认网络延迟并对其进行优化对于提供高效的用户体验至关重要。

3. 带宽是无限的:认为网络带宽是无限的可能会导致网络过载并导致拥塞。高效的数据传输和带宽管理对于避免性能瓶颈至关重要。

4. 网络是安全的:假设网络本质上是安全的,可能会导致漏洞和数据泄露。实施强大的安全措施(包括加密和身份验证)对于保护分布式系统中的敏感信息是必要的。

5. 拓扑不会改变:网络不断发展,假设静态拓扑可能会导致配置错误和系统不稳定。系统的设计应能够适应不断变化的网络条件和配置。

6. 只有一个管理员:相信单个管理员控制整个分布式系统可能会导致协调问题和冲突。现实中,分布式系统往往涉及多个管理员,需要明确的治理和协调机制。

7. 传输成本为零:忽视与数据传输相关的成本可能会导致资源利用效率低下并增加运营费用。优化数据传输并考虑相关成本对于经济高效的分布式计算至关重要。

8. 网络是同质的:假设所有网络组件和节点具有相同的特征可能会导致兼容性问题和性能差异。系统的设计应能够处理异构性并适应各种类型的设备和平台。

理解这些谬论至关重要,因为它们强调了分布式计算的挑战和复杂性。如果不考虑这些谬误,可能会导致系统故障、安全漏洞和运营成本增加。构建可靠、高效和安全的分布式系统需要深入了解这些谬论,并实施适当的软件设计和架构以及 IT 运营策略来解决这些问题。

不可靠的网络

在这篇博文中,我们将讨论第一个谬论、它对微服务架构的影响,以及如何规避这一限制。假设我们使用 spring-boot 来编写微服务,它使用 MongoDB 作为后端,在 Kubernetes 中部署为 StatefulSet。并在 EKS 上运行它。您可能还会质疑,为我们提供可靠的网络是您的云提供商的工作,而我们却为高可用性而向他们付费。虽然这种期望可能没有错,但不幸的是,当您通过云租用硬件时,它并不总是按预期工作。假设您的云提供商承诺 99.99% 的可用性,这令人印象深刻,对吗?不,不是这样!我会解释如何做。99.99% 的可用性可能会导致。

  • 10,000 个请求中的每个请求都失败。

  • 1,00,000 个请求中每 10 个请求都会失败。

您可能会说您的系统无法获得这种流量!很公平,但这是云提供商的可用性数据,而不是您的服务实例,这意味着如果该云在其网络内收到十亿个网络请求,则有 1,00,000 个将失败!让事情变得更复杂的是,您不能指望他们使用其硬件将这些故障分布到所有帐户;根据您的运气,您可能会遇到许多此类失败。这里的问题是,您是否只想在这些中断不会影响到您的情况下经营一家企业?我希望不是!这是对分布式计算的第一个(也是最关键的)谬误的基本描述。

网络故障的影响

我们以电子商务系统为例;我们通常会从产品微服务中看到产品目录;但是,在构建产品目录响应时,可能会从另一个微服务获取 SKU 可用性。不过,有人可能会说,我可以通过 Choreography 将 SKU 信息复制到产品目录中,但就本示例的范围而言,我们假设这还没有到位。因此,产品服务正在对 SKU 服务进行 REST API 调用。当此调用失败时会发生什么?您如何向最终用户传达他们正在查看的产品是否可用?

可怕的东西,是吗?嗯,没那么可怕;作为工程师,我们喜欢在更艰难的领域勇敢地面对,因此我们有一些技巧。

容错和弹性编码

这个话题本身就值得写一本书,而不是一篇博客文章。但我会尽力涵盖所有内容,同时保持简单。我在这里分享的大部分内容都是 NimbleWork 中 SaaS 业务从整体架构过渡到微服务时收集的经验。我希望其他人也觉得它有帮助。

短暂中断的模式

以下模式有助于避免我们通常所说的短暂中断或突发事件。基本假设是,此类中断的生命周期最多为一到两秒。

重试

最简单的事情之一是将网络调用包装在重试逻辑中,以便在调用服务最终放弃之前进行多次尝试。这里的想法是,来自云提供商的临时网络障碍不会持续比获取数据的重试时间更长的时间。几乎所有常见编程语言中的微服务库和框架都提供了此功能。退休人员本身必须细致入微或离散;例如,在收到 400 时重试不会更改输出,直到请求签名发生更改。以下是使用 Spring WebFlux WebClient 进行 REST API 调用时使用重试的示例。

webClient.get().uri(uri).headers(headers -> headers.addAll(httpHeaders)).retrieve().bodyToMono(new ParameterizedTypeReference<Map<String, Object>>() {}).log(this.getClass().getName(), Level.FINE).retryWhen(Retry.backoff(3, Duration.ofSeconds(2)).jitter(0.7).filter(throwable -> throwable instanceof RuntimeException ||(throwable instanceof WebClientResponseException &&(((WebClientResponseException) throwable).getStatusCode() == HttpStatus.GATEWAY_TIMEOUT || ((WebClientResponseException) throwable).getStatusCode() == HttpStatus.SERVICE_UNAVAILABLE || ((WebClientResponseException) throwable).getStatusCode() == HttpStatus.BAD_GATEWAY))).onRetryExhaustedThrow((retryBackoffSpec, retrySignal) -> {log.error("Service at {} failed to respond, after max attempts of: {}", uri, retrySignal.totalRetries());return retrySignal.failure();})).onErrorResume(WebClientResponseException.class, ex -> ex.getStatusCode().is4xxClientError() ? Mono.empty() : Mono.error(ex));

以下是我们试图通过这段代码实现的目标的摘要:

  • 两秒内最多重试 3 次。

  • 根据抖动随机间隔重试之间的时间。

  • 仅当上游服务提供 HTTP 504、503 或 502 状态时才重试。

  • 记录错误并在最大尝试次数耗尽时将其传递给下游。

  • 为客户端错误包装一个空响应,或者将上一步中的错误传递到下游。

这些重试可以帮助您从预计不会持续很长时间的突发事件或障碍中恢复过来。如果我们调用的上游服务由于某种原因重新启动,这也可能是一个很好的机制。

注意:使用滚动更新策略在 Kubernetes 中运行副本集有助于减少此类事件,从而减少重试。

虽然这是使用 Spring 中的 Reactor 项目实现的示例,但所有主要框架和语言都提供了替代方案。

  • 如果您使用 Spring 框架但不使用响应式编程,请使用Spring Retry 。

  • 当您使用 Akka 和 Scala 或 Java 时的主管策略。

  • `scala.util.{Failure, Try}` 如果您在没有任何框架的情况下使用 Scala。

  • 在 Python 中重试装饰器。

  • JavaScript 中的获取重试。

我确信这不是一份详尽的清单。这种模式可以解决短暂的网络故障。但如果持续停电怎么办?比本文后面的内容更多。

最后已知的好版本

如果被调用的服务持续崩溃并且各个客户端的所有重试都耗尽怎么办?我更喜欢回退到最后一个已知的好版本。有几种策略可以在基础设施和客户端上启用“最后已知的良好版本”策略。我们将简要介绍其中的每一个。

部署:从基础设施的角度来看,最简单的选择是重新部署到服务的最后一个已知的稳定版本。这是假设下游应用程序仍然兼容调用这个旧版本。在 Kubernetes 中更容易做到这一点,它保存了之前的部署修订。

在下游缓存:另一种方法是客户端保存最后一个成功的响应,以便在服务出现故障时可以依靠;在浏览器或移动用户界面上向最终用户显示与过时数据相关的提示是一个不错的选择。

下游缓存

浏览器或任何客户端都会不断地将数据写入内存存储,直到收到来自上游的心跳。该机制为通过 gRPC 或 REST 进行服务调用的 UI 和无头客户端提供了各种实现。无论客户类型如何,这里都总结了应该做什么。

  • 客户端在其第一个 API 调用上进行注册,以便服务进行跟踪。

  • 对客户端的后续更新作为从服务到客户端的推送进行管理。

  • 客户端在本地保留状态,浏览器上的 Redux,或无头客户端的 Redis、Memcached(如果您的灵魂允许的话,也可以使用 LinkedHashMap)。

  • 如果您的规模不足以承担推送的费用,您可以使用 ReactJS 的 RTK 和 Angular 的 NgRx 存储等工具,并不断拉取状态更新。当您收到任何 5XX 状态错误时,请务必告知最终用户他们可能会看到过时的数据。

持续中断的模式

如果任何分布式架构都是一个只有点的系统,那我们就很幸运了,但事实并非如此。因此,我们必须构建我们的系统来处理长期中断。以下是一些在这方面有帮助的模式。

隔离壁 

隔离壁是为了应对由上游服务的缓慢导致的故障。虽然理想的解决方案是解决上游问题,但这并不总是可行的。设想一个场景,你调用的服务(X)依赖于另一个表现出缓慢响应时间的服务(Y)。如果服务(X)遭受大量的流入流量,那么它的很大一部分线程可能会等待较慢的上游服务(Y)响应。这种等待不仅会减慢服务(X)的速度,而且还会增加请求丢失的速度,导致客户端更多的重试并加剧瓶颈现象。

为了减轻这个问题,一个有效的方法是局部化失败的影响。例如,您可以为调用较慢的服务创建一个有限线程数的专用线程池。这样做可以将缓慢和超时的影响局限于特定的API调用,从而提高整体服务的吞吐量。

断路器

可以轻松避免断路器;我们必须编写永远不会宕机的服务!然而,现实情况是我们的应用程序经常依赖于其他人开发的外部服务。在这些情况下,断路器作为一种模式就变得非常有价值。它通过代理在服务之间路由所有流量,一旦达到定义的故障阈值,代理就会立即开始拒绝请求。事实证明,这种模式在外部服务长时间网络中断期间特别有用,否则可能会导致呼叫服务中断。尽管如此,确保在此类场景中提供无缝的用户体验至关重要,我们发现两种有效的方法:

  • 通知用户受影响区域发生中断,同时使他们能够使用系统的其他部分。

  • 允许客户端缓存用户事务,提供“202 Accepted”响应,而不是像往常一样的“200”或“201”,并在上游服务再次可用时恢复这些事务。

结论

尽管云提供商致力于高可用性,但由于这些网络的规模庞大且不可预测,网络故障仍然不可避免,这凸显了对弹性系统的迫切需求。这段旅程让我们沉浸在分布式计算领域,挑战我们作为工程师,用容错和弹性策略武装自己。采用重试、最后已知的良好版本策略等技术,以及开发两端都有状态管理的独立客户端-服务器架构,使我们能够应对网络中断的不可预测性。

当我们探索错综复杂的分布式系统时,采用这些策略对于确保流畅的用户体验和系统稳定性至关重要。欢迎来到云中微服务的世界,这里的挑战激发创新,而弹性是我们应对不可靠网络的基石。


作者:Anadi Misra

更多技术干货请关注公号【云原生数据库

squids.cn,云数据库RDS,迁移工具DBMotion,云备份DBTwin等数据库生态工具。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/146397.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SpringMVC log4j1升级log4j2

整个升级过程耗时5个小时&#xff0c;中间耗时最长的是找合适的包和升级后日志无法打印以及无法控制日志输出位置&#xff0c;完成后感觉其实很简单&#xff0c;如果一开始就能看到我现在写的笔记&#xff0c;可能几分钟就搞定了。 第一步&#xff1a;首先上log4j2所需要的包 …

根据店铺ID/店铺链接/店铺昵称获取京东店铺所有商品数据接口|京东店铺所有商品数据接口|京东API接口

要获取京东店铺的所有商品数据&#xff0c;您需要使用京东开放平台提供的API接口。以下是一些可能有用的API接口&#xff1a; 商品SKU列表接口&#xff1a;该接口可以获取指定店铺下的所有商品SKU列表&#xff0c;包括商品ID、名称、价格等信息。您可以使用该接口来获取店铺中…

一文看分布式锁

为什么会存在分布式锁&#xff1f; 经典场景-扣库存&#xff0c;多人去同时购买一件商品&#xff0c;首先会查询判断是否有剩余&#xff0c;如果有进行购买并扣减库存&#xff0c;没有提示库存不足。假如现在仅存有一件商品&#xff0c;3人同时购买&#xff0c;三个线程同时执…

Go 语言数组基础教程 - 数组的声明、初始化和使用方法

数组用于在单个变量中存储相同类型的多个值&#xff0c;而不是为每个值声明单独的变量。 声明数组 在Go中&#xff0c;有两种声明数组的方式&#xff1a; 使用var关键字&#xff1a; 语法 var array_name [length]datatype{values} // 这里定义了长度 或者 var array_n…

vivado产生报告阅读分析6-时序报告2

1、复查时序路径详情 单击“ OK ”运行报告命令后 &#xff0c; 将打开一个新窗口。这样您即可复查其中内容。在其中可查看执行选定的每种类型 (min/max/min_max ) 的分析之后所报告的 N 条最差路径。 下图显示的“Report Timing ” &#xff08; 时序报告 &#xff09; 窗口…

竞赛选题 深度学习驾驶行为状态检测系统(疲劳 抽烟 喝水 玩手机) - opencv python

文章目录 1 前言1 课题背景2 相关技术2.1 Dlib人脸识别库2.2 疲劳检测算法2.3 YOLOV5算法 3 效果展示3.1 眨眼3.2 打哈欠3.3 使用手机检测3.4 抽烟检测3.5 喝水检测 4 最后 1 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 基于深度学习的驾…

初学编程学习,计算机编程怎么自学,中文编程工具下载

初学编程学习&#xff0c;计算机编程怎么自学&#xff0c;中文编程工具下载 给大家分享一款中文编程工具&#xff0c;零基础轻松学编程&#xff0c;不需英语基础&#xff0c;编程工具可下载。 这款工具不但可以连接部分硬件&#xff0c;而且可以开发大型的软件&#xff0c;象如…

RT-Thread STM32F407 PWM

为了展示PWM效果&#xff0c;这里用ADC来采集PWM输出通道的电平变化 第一步&#xff0c;进入RT-Thread Settings配置PWM驱动 第二步&#xff0c;进入board.h&#xff0c;打开PWM宏 第三步&#xff0c;进入STM32CubeMX&#xff0c;配置时钟及PWM 第四步&#xff0c;回到R…

[Vue 配置] Vite + Vue3 项目配置 Tailwind CSS

文章归档&#xff1a;https://www.yuque.com/u27599042/coding_star/yqzi9olphko9ity1 Tailwind CSS 官网&#xff1a;https://www.tailwindcss.cn/docs/installation/using-postcss 安装 pnpm i -D tailwindcss postcss autoprefixer生成配置文件 npx tailwindcss init -p配…

一起学docker系列之五docker的常用命令--操作容器的命令

目录 前言1 启动容器2 查看容器3 退出容器4 启动已经停止的容器5 重启容器6 停止容器7 删除已经停止的容器8 启动容器说明和举例9 查看容器日志10 查看容器内运行的进程11 查看容器内部细节12 进入正在运行的容器并进行交互13 导入和导出容器结语 前言 当涉及到容器化技术&…

Linux三剑客:awk的高级用法

目录 awk高级用法 awk控制语句—if-else判断 awk控制语句—while循环 awk控制语句—do-while循环 awk控制语句—for循环 shell脚本中较相似的控制语句 break和continue next awk数组 awk自定义函数 awk中调用shell 命令 这一篇主要介绍awk的高级用法&#xff0c;因为…

Qt遇到常见问题记录

1.Qt版本选择 Qt4.8.7是Qt4的终结版本&#xff0c;是Qt4系列版本中最稳定最经典的 &#xff08;很多嵌入式板子还是用Qt4.8&#xff09;&#xff0c;其实该版本是和Qt5.5差不多时间发布的。 参考链接 Qt 5.5 Released Qt5.6.3最最后支持xp系统的长期支持版本&#xff0c;Q…

Python | 机器学习之SVM支持向量机

​&#x1f308;个人主页&#xff1a;Sarapines Programmer&#x1f525; 系列专栏&#xff1a;《人工智能奇遇记》&#x1f516;少年有梦不应止于心动&#xff0c;更要付诸行动。 目录结构 1. 机器学习之SVM支持向量机概念 1.1 机器学习 1.2 SVM支持向量机 2. SVM支持向量机…

vscode代码上传到gitlab

打开终端 1.1输入一下内容提交到本地仓库 PS D:\VueProject2\mall-admin-web> git add . PS D:\VueProject2\mall-admin-web> git commit -m “商品优化&#xff0c;屏蔽不要内容” 1.2提交到远程仓库 master应该被替换为 Gitee 仓库中默认的分支名称 PS D:\VueProje…

jenkins 使用原生 git clone 命令,指定ssh密钥文件

使用环境变量 GIT_SSH_COMMAND 从Git版本2.3.0可以使用环境变量GIT_SSH_COMMAND&#xff0c;如下所示&#xff1a; GIT_SSH_COMMAND"ssh -i ~/.ssh/id_rsa_example" git clone example请注意&#xff0c;-i有时可以被您的配置文件覆盖&#xff0c;在这种情况下&…

快速弄懂C++中的智能指针

智能指针是C中的一个对象&#xff0c;它的行为类似于指针&#xff0c;但它提供了自动的内存管理功能。当智能指针超出作用域时&#xff08;比如说在函数中使用智能指针指向了一个对象&#xff0c;当该函数结束时会自动销毁该对象&#xff09;&#xff0c;它会自动删除其所指向的…

合并word中参考文献-(Endnote生成)

合并word中的 两部分的参考文献引用 Merge Citations in the Word document Original&#xff1a; A is a big character [78-80] and B is another one [81-85] Modified&#xff1a; A and B are big characters [78-85] Solutions&#xff1a; Remove the space betwee…

蓝桥杯 第 3 场算法双周赛4,7题

迷宫逃脱 一眼数字三角形模型&#xff0c;因为是要求最大值&#xff0c;而且对转移状态有限制&#xff0c;所以需要注意dp状态的初始化&#xff0c;可以将所有状态赋值为-0x7f&#xff0c;然后将dp[0][1]和dp[1][0]初始化为0&#xff0c;又因为考虑到起始点a[1][1]&#xff0c…

AWD比赛中的一些防护思路技巧

## 思路1&#xff1a; 1、改服务器密码 &#xff08;1&#xff09;linux&#xff1a;passwd &#xff08;2&#xff09;如果是root删除可登录用户&#xff1a;cat /etc/passwd | grep bash userdel -r 用户名 &#xff08;3&#xff09;mysql&#xff1a;update mysql.user set…