小程序 坚屏_如何构建坚如磐石的应用程序
小程序 堅屏
不同的應用程序設計選項概述 (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/
小程序 堅屏
總結
以上是生活随笔為你收集整理的小程序 坚屏_如何构建坚如磐石的应用程序的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 突然梦到一个人是什么意思
- 下一篇: web开发环境_Web开发人员的开发环境