小程序 坚屏_如何构建坚如磐石的应用程序

小程序 坚屏

不同的应用程序设计选项概述 (An overview of different app design options)

When we design software, we constantly think about error cases. Errors have a huge impact on the way we design and architecture a solution. So much so, in fact, that there is a philosophy known as Let It Crash.

在设计软件时,我们会不断考虑错误情况。 错误对我们设计和构建解决方案的方式产生巨大影响。 实际上,如此之多,有一种被称为“ 让它崩溃”的哲学。

Let it crash is the Erlang way to treat failures by just letting the application crash and allowing a supervisor to restart the crashed process from a clean state.

让它崩溃是通过使应用程序崩溃并允许管理员从干净状态重新启动崩溃的进程来处理故障的Erlang方法。

Errors could be everywhere, and the more your application grows, the more there will be points of failure that you need to keep under control. External service calls, sending email, database queries are all operations that could fail.

错误可能无处不在,并且您的应用程序增长的越多,需要控制的故障点就越多。 外部服务呼叫,发送电子邮件,数据库查询都是可能失败的操作。

失败种类 (Kinds of Failures)

A failure can have different origins which lead to different impacts on your service availability. Think of a scenario where we’re running too many SQL queries and the database server is going to throttle the application. In that case, we could retry the query or add a catch in the code to identify the failing queries and provide a sensible response to the user.

故障的来源可能不同,从而对您的服务可用性产生不同的影响。 考虑一下我们正在运行太多SQL查询并且数据库服务器将限制应用程序的情况。 在这种情况下,我们可以重试查询或在代码中添加捕获以识别失败的查询并向用户提供明智的响应。

These kinds of errors are called Transient Errors, which means that the database server is temporary overloaded but it’s going to come back soon.

这些类型的错误称为“ 瞬时错误”,这意味着数据库服务器是暂时过载的,但很快就会回来。

Transient errors are not related to any problem in the application. They are usually caused by external conditions such as network failures, overloaded servers, or service rate limits. For that reason, it’s safe for a client to ignore it and retry the failed operation after a while.

暂时性错误与应用程序中的任何问题无关。 它们通常是由外部条件引起的,例如网络故障,服务器超载或服务速率限制。 因此,对于客户端来说,忽略它并在一段时间后重试失败的操作是安全的。

These errors are much more frequent within cloud native applications, because the apps are split into different services and deployed on different servers that communicate over the network.

这些错误在云本机应用程序中更为常见,因为这些应用程序分为不同的服务,并部署在通过网络进行通信的不同服务器上。

识别瞬态错误 (Identifying Transient Errors)

Transient errors can usually be detected in an automatic manner. We can recognise the errors by inspecting the transport layer metadata (for example HTTP errors, network errors, timeouts) or when they are explicitly marked as transient (such as rate limits).

通常可以自动检测瞬态错误。 我们可以通过检查传输层元数据(例如HTTP错误,网络错误,超时)或将其明确标记为瞬态(例如速率限制)来识别错误。

处理错误 (Treating the Errors)

There are different actions we can do in case of an error. One trivial approach could be to just retry the request, API call, or query.

如果发生错误,我们可以采取不同的措施。 一种简单的方法是仅重试请求,API调用或查询。

Even though this solution might be fine in many cases, there are lot of cases when it can lead to a performance decrease for the app.

即使此解决方案在许多情况下可能都很好,但在很多情况下,它可能导致应用程序性能下降。

Let’s take the case of a network failure. Indefinitely retrying some API calls to a disconnected service would result in continuous network timeouts, and the application will be stuck waiting for a response for a very long time.

让我们以网络故障为例。 无限期地重试对断开连接的服务的某些API调用将导致连续的网络超时,并且应用程序将被阻塞,等待很长时间。

Before going ahead with complex implementations, let’s evaluate the pros and cons of the “just-retry” option.

在进行复杂的实现之前,让我们评估一下“ just-retry”选项的优缺点。

PROS

优点

  • Trivial implementation.

    琐碎的实现。
  • Stateless (every retry request is isolated and you don’t need any extra information).

    无状态的(每个重试请求都是隔离的,您不需要任何其他信息)。

CONS

缺点

  • For heavily loaded applications, the caller will continuously send requests to the degraded server resulting in a denial of service.

    对于负载较重的应用程序,调用者将不断向降级的服务器发送请求,从而导致服务被拒绝。
  • Cannot provide a response until the server comes back.

    在服务器恢复之前无法提供响应。

This simple retry strategy can be considered as a very first approach to solving the issue. For low traffic apps it would work, but if you have a more complex architecture, it’s definitely not enough.

可以将这种简单的重试策略视为解决问题的第一种方法。 对于低流量的应用程序,它可以工作,但是如果您拥有更复杂的架构,那绝对不够。

So let’s discuss a more resilient approach.

因此,让我们讨论一种更具弹性的方法。

窃取IEEE的想法 (Stealing an Idea from the IEEE)

The next stop of your journey for a reliable application is to avoid the wasted time and to make the application more responsive. The exponential backoff algorithm could be the right tool for the job.

使用可靠的应用程序的下一个步骤是避免浪费时间,并使应用程序响应更快。 指数补偿算法可能是这项工作的正确工具。

The concept of the exponential backoff directly comes from the Ethernet network protocol (IEEE 802.3) where it’s used for packet collision resolution.

指数补偿的概念直接来自以太网网络协议(IEEE 802.3),用于分组冲突解决。

For our purposes, the exponential backoff can be used to avoid wasting time between timed out calls or to avoid hammering an overloaded server with an continual flow of requests that cannot be resolved.

对于我们的目的,可以使用指数退避来避免在两次超时调用之间浪费时间,或者避免用无法解决的连续请求流对过载的服务器造成冲击。

Binary exponential backoff for packet collisions can be resumed with help from the follow definition:

数据包冲突的二进制指数补偿可以在以下定义的帮助下恢复:

After *c* collisions, a random number of slot times between 0 and 2*c* - 1 is chosen. For the first collision, each sender will wait 0 or 1 slot times. After the second collision, the senders will wait anywhere from 0 to 3 slot times. After the third collision, the senders will wait anywhere from 0 to 7 slot times (inclusive), and so forth. As the number of retransmission attempts increases, the number of possibilities for delay increases exponentially - Exponential backoff - Wikipedia

在* c *冲突之后,选择0到2 * c *-1之间的随机时隙时间。 对于第一次冲突,每个发送方将等待0或1个时隙。 第二次冲突后,发送方将等待0到3个时隙。 第三次冲突后,发件人将在0到7个时隙(含)之间的任何时间等待,依此类推。 随着重传尝试次数的增加,延迟的可能性呈指数增长- 指数退避-维基百科

This algorithm can be quickly adapted to many use cases. The following example is a PHP message handler class that exponentially waits for a response from an API endpoint.

该算法可以快速适应许多用例。 以下示例是一个PHP消息处理程序类,该类以指数形式等待来自API端点的响应。

<?php
/*** Assume that we're using a message bus which is able to* retry failed messages with a custom retry delay.*/
class FetchCarMessageHandler
{public function handle(Message $msg){try {$id = (int)$msg->getContent();$cars = $client->get('/car/'.$id);return Result::success($cars);} catch (TimeoutException $e) {$lastBackoff = $msg->getLastBackoff();// The infrastructure layer will automagically retry the message after XYZ secondsreturn Result::retryAfter($lastBackoff * 2, $msg);}}
}

重试与指数退避 (Retry vs Exponential Backoff)

The previous two strategies are both sub-optimal. They guarantee that you’ll eventually be able to generate a response to give back to the client, but they rely on continuously calling the external service until a successful response is received.

前两个策略都不是最优的。 他们保证您最终将能够生成响应并回馈给客户端,但是它们依赖于不断调用外部服务,直到收到成功的响应为止。

We may be lucky and receive a response after a couple of retries, or we could fall in the retry-wait-retry-wait… infinite loop and never receive the response.You know, Murphy’s law is always here: “Anything that can go wrong will go wrong.”

我们可能是幸运和几个重试后得到答复,或者我们可以落在重试等待重试等待...无限循环,从来没有收到response.You知道,墨菲定律总是在这里:“ 凡是可以去错误会出错 。”

As you might imagine, scaling a service oriented infrastructure that in case of failure continuously retries the request to the dependant services is the perfect recipe for application collapse.

就像您想象的那样,扩展面向服务的基础结构,以在发生故障的情况下连续重试对相关服务的请求,这是解决应用程序崩溃的完美方法。

We need a stronger strategy to maintain infrastructure resilience.

我们需要一个更强大的战略来维持基础架构的弹性。

电子产品可以帮助我们 (Electronics may Help Us)

In case of continuous errors, the easy thing to do is clear. We do not want to loop and retry calling an external service. The point is we’ll just stop doing it, by taking the concept of Circuit Breakers from electronics.

如果连续出现错误,那么很容易做到。 我们不想循环并重试调用外部服务。 关键是,我们将从电子产品中采用断路器的概念来停止这样做。

从电子学到计算机科学 (From Electronics to Computer Science)

A circuit breaker is a component that wraps a protected call to an external service and can monitor the responses by checking the service health. Exactly like an electronic component, a software circuit breaker could be open or closed. An open status would mean that the service behind the circuit is down, and a closed status would mean that the service is up.

断路器是将受保护的呼叫包装到外部服务并可以通过检查服务运行状况来监视响应的组件。 就像电子组件一样,软件断路器可以打开关闭打开状态将意味着电路后面的服务已关闭,而闭合状态将意味着服务已启动。

So the circuit breaker can autonomously control the service status and decide to open or close the circuit, so that in case of disconnection or server overload, the client stops sending new connections and the degraded service can use more resources to come back to a healthy state.

因此,断路器可以自主控制服务状态并决定打开关闭电路,以便在断开连接或服务器过载的情况下,客户端停止发送新的连接,并且降级的服务可以使用更多的资源来恢复正常状态。

In case of an open circuit, we could decide to quickly answer to the client with a fallback response. For example, cached data, default data, or whatever make sense for the particular application.

开路的情况下,我们可以决定Swift返回给客户端与后备响应。 例如,缓存数据,默认数据或对特定应用程序有意义的任何数据。

Let’s see a real example from the e-commerce world. We’re going to use the circuit breaker method to protect the product listing API call.

让我们从电子商务世界中看到一个真实的例子。 我们将使用断路器方法来保护产品列表API调用。

<?php
class CircuitBreaker
{private $maxFailures;private $service;private $redisClient;public function __construct(int $maxFailures, callable $service){$this->maxFailures = $maxFailures;$this->service = $service;$this->redisClient = new RedisClient();}private function isUp(string $key){return (int)$this->redisClient->get($key) < $this->maxFailures;}private function fail(string $key, int $ttl){$this->redisClient->incr($key, 1);$this->redisClient->expire($key, $ttl);}public function __invoke(){[$arguments, $defaultResponse] = func_get_args();$key = md5($arguments);if (!$this->isUp($key)) {return $defaultResponse;}try {$result = call_user_func_array($this->service, $arguments);return $result;} catch (\Throwable $e) {$this->fail($key, 10);return $defaultResponse;}}
}

The circuit breaker will transparently handle all errors and show the default response in case of an API call failure. It also allows defining a max number of retries to avoid too many failed calls.

断路器将透明地处理所有错误,并在API调用失败的情况下显示默认响应。 它还允许定义最大重试次数,以避免太多的失败呼叫。

In this case, protecting a third party service API call is a very simple task: we just need to provide the callback and number of max failures allowed, after which the circuit breaker will be opened for 10 seconds and the default response is given back to the client, as in the example below.

在这种情况下,保护第三方服务API调用是一个非常简单的任务:我们只需要提供允许的回调和最大失败次数,然后将断路器打开10秒钟,并将默认响应返回给客户端,如下例所示。

<?php
$productListing = new CircuitBreaker(10, function($searchKey) {// $result is given from the api callreturn $result;}
);
$productsToShow = $productListing(['t-shirt'], []);

结论 (Conclusion)

Whether you’re designing a SOA, micro services or a cloud native application, you should be ready to tackle the failure case in the right way. Errors and failures are in the same room from the day you launch your app.

无论您是设计SOA,微服务还是云本机应用程序,都应该准备好以正确的方式解决故障案例。 从启动应用程序之日起,错误和失败就在同一房间内。

Here some of the well known tactics to build a real rock solid app:

这里有一些众所周知的策略来构建一个真正的坚如磐石的应用程序:

  • https://docs.microsoft.com/en-us/azure/architecture/patterns/retry

    https://docs.microsoft.com/zh-CN/azure/architecture/patterns/retry

  • https://en.m.wikipedia.org/wiki/Exponential_backoff

    https://zh.m.wikipedia.org/wiki/Exponential_backoff

  • https://martinfowler.com/bliki/CircuitBreaker.html

    https://martinfowler.com/bliki/CircuitBreaker.html

翻译自: https://www.freecodecamp.org/news/how-to-build-a-rock-solid-app-29dffe7875d2/

小程序 坚屏

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

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

相关文章

C# 分层

三层架构分为&#xff1a;表现层&#xff08;UI&#xff09;、业务逻辑层&#xff08;BLL&#xff09;、数据访问层&#xff08;DAL&#xff09;再加上实体类库&#xff08;Model&#xff09; 转载请注明出自朱朱家园http://blog.csdn.net/zhgl7688 1、实体类库&#xff08;Mod…

leetcode1177. 构建回文串检测(前缀和)

给你一个字符串 s&#xff0c;请你对 s 的子串进行检测。 每次检测&#xff0c;待检子串都可以表示为 queries[i] [left, right, k]。我们可以 重新排列 子串 s[left], …, s[right]&#xff0c;并从中选择 最多 k 项替换成任何小写英文字母。 如果在上述检测过程中&#xf…

java界面化二叉排序树_层次序创建二叉树(图形界面和控制台输入实现)

1 2018.11.72 XT34 /**5 * 功能&#xff1a;构造二叉树6 * 说明&#xff1a;7 * 1.主函数输入模式有两种&#xff0c;BT参数 true 图形界面&#xff0c;false 控制台输入8 * 2.构造树是按层次遍历结果输入的 如&#xff1a;ABCDE*F**GH9 */1011 import javax.swing.*;12 import…

web开发环境_Web开发人员的开发环境

web开发环境With all the tools and programs available, it can be challenging to figure out the best way to set up your development environment on your computer.使用所有可用的工具和程序&#xff0c;寻找在计算机上设置开发环境的最佳方法可能是一项挑战。 In this…

使用.net Stopwatch class 来分析你的代码

当我们在调试&#xff0c;优化我们的代码的时候&#xff0c;想知道某段代码的真正的执行时间&#xff0c;或者我们怀疑某段代码&#xff0c;或是某几段代码执行比较慢&#xff0c; 需要得到具体的某段代码的具体执行时间的时候。有一个很好用的类Stopwatch。 Stopwatch 类在 Sy…

Docker 部署 postgresql 与 pgadmin4

Docker快速部署PostgreSQL服务 快速开始 请新建一个目录postgresql&#xff0c;进入目录postgresql&#xff0c;将以下文件保存为docker-compose.yml&#xff0c;然后执行docker-compose up version: 3 services:mydb:image: postgres:11volumes:- db-data:/var/lib/postgresql…

leetcode151. 翻转字符串里的单词

给定一个字符串&#xff0c;逐个翻转字符串中的每个单词。 示例 1&#xff1a; 输入: “the sky is blue” 输出: “blue is sky the” 代码 class Solution {public String reverseWords(String s) {int ns.length(),i0;ArrayList<String> arrayListnew ArrayList<…

java衍生作用_java-如何从AffineTransform衍生的形状对象中“...

您可以使用AffineTransform.transform(Point2D, Point2D)变换多边形上的单个点.如果您不使用旋转变换来移动船,而是将船的位置保持在一个(x,y)位置,那么事情就简单得多.您可以在move()中移动飞船的位置,而不是尝试平移多边形.然后,当您想给船上油漆时,例如做&#xff1a;// Opt…

初学者设计数据库_面向初学者的完整数据库设计课程

初学者设计数据库This database design course will give you a deeper grasp of database design. Caleb Curry teaches the equivalent of an entire college course during this eight hour video.本数据库设计课程将使您更深入地了解数据库设计。 在这8个小时的视频中&…

Qt QTcpSocket使用总结

socket的连接是异步的&#xff0c;所以必须等连接建立完成才能使用&#xff0c;所以分别加入waitForConnected()和waitForBytesWritten()后调试通过1&#xff09;只有使用waitForConnected()后,QTcpSocket才真正尝试连接服务器&#xff0c;并返回是否连接的结果2&#xff09;避…

[bzoj1303][CQOI2009]中位数图

来自FallDream的博客&#xff0c;未经允许&#xff0c;请勿转载&#xff0c;谢谢。 给定一个n个数排列&#xff0c;求有多少段长度为奇数的区间&#xff0c;中位数是b. n<100000 时间限制0.1s 我一开始没看到排列&#xff0c;想着怎么还能O(n)做的啊&#xff1f;&#xff1f…

falsk 请求没有返回值报错

线上报警 5xx 错误&#xff0c;查看日志发现报这个错&#xff0c; TypeError: The view function did not return a valid response. The function either returned None or ended without a return statement. 这个方法没有有效的返回结果 页面报这个错误 Internal Server Err…

java的iterator接口_java Iterator接口和LIstIterator接口分析_java_脚本之家

java Iterator接口和LIstIterator接口分析目录1.Iterator接口2.ListIterator3.Iterator和ListIterator的区别正文在继续看ArrayList源码之前&#xff0c;先了解Iterator接口和ListIterator接口&#xff0c;下篇文章详细讲解ArrayList是如何实现它们的。我们知道&#xff0c;接…

leetcode468. 验证IP地址

编写一个函数来验证输入的字符串是否是有效的 IPv4 或 IPv6 地址。 IPv4 地址由十进制数和点来表示&#xff0c;每个地址包含4个十进制数&#xff0c;其范围为 0 - 255&#xff0c; 用(".")分割。比如&#xff0c;172.16.254.1&#xff1b; 同时&#xff0c;IPv4 地…

播客#45:迪伦·以色列

On todays episode, I interview Dylan Israel. Dylan is a software engineer, a YouTuber, and the creator of several programming courses.在今天的一集中&#xff0c;我采访了迪伦以色列。 迪伦(Dylan)是一位软件工程师&#xff0c;一名YouTuber&#xff0c;并且是几门编…

PHPstorm快捷键

当前文件搜索类&#xff1a;ctrln 全文检索文件&#xff1a;ctrlshiftn 收起侧边栏&#xff1a;alt1&#xff08;自定义&#xff09; 个人学习记录&#xff0c;持续更新中。。。 转载于:https://www.cnblogs.com/zaijiang/p/7806260.html

JS基础_强制类型转换-Number

https://www.cnblogs.com/ZHOUVIP/p/7225267.html转载于:https://www.cnblogs.com/robinunix/p/11011188.html

JavaScript变量和作用域

JavaScript有两种变量&#xff0c;全局变量和局部变量 如果在任何函数定义之外声明了一个变量&#xff0c;则该变量是全局变量&#xff0c;且该变量的值在整个持续范围内都可以访问和修改 如果在函数定义内声明来了一个变量&#xff0c;则该变量为局部变量。每次执行该函数时都…

python 微信bot_使用Python创建Twitter Bot

python 微信botHave you ever wantd to create a Twitter bot? In this tutorial John G. Fisher shows how to create a bot with Python that tweets images or status updates at a set interval.您是否曾经想创建一个Twitter机器人&#xff1f; 在本教程中&#xff0c;约翰…

leetcode1487. 保证文件名唯一

给你一个长度为 n 的字符串数组 names 。你将会在文件系统中创建 n 个文件夹&#xff1a;在第 i 分钟&#xff0c;新建名为 names[i] 的文件夹。 由于两个文件 不能 共享相同的文件名&#xff0c;因此如果新建文件夹使用的文件名已经被占用&#xff0c;系统会以 (k) 的形式为新…