Objective
Because of the prevalence of micro-services, many companies will be the original fine granularity than the larger service split into a number of small services, so that each small service to do their own thing.
After splitting, you will not be able to avoid the mutual call between the service problem! If the call is not handled well, it is possible to cause the entire system paralysis, such as some of the basic services have failed, then the use of these basic services are to do a certain amount of processing, can not let them appear large area of paralysis!!!
Under normal circumstances the solution is to fuse the service, not because the provider has problems and let the caller also obsolete.
Fuse generally refers to the software system, due to some reasons to make the service overload phenomenon, in order to prevent the entire system failure, thereby adopting a protective measure.
For this problem, Steeltoe's circuit breaker is a good choice. The sample code for this article is also based on it.
Steeltoe's Circuit breaker
What is Steeltoe? Steeltoe can be said to be a solution for building microservices. Specific access to it's official website:
http://steeltoe.io/
Return to the point, first look at the official description of circuit breaker:
What does when is a service depend on stops responding? Circuit breakers enable bypass a failing service, allowing it time to recover, and preventing your the users from Seein G Nasty error messages. Steeltoe includes a. NET implementation of Netflix Hystrix, a proven circuit breaker implementation with rich metrics and Monitoring features.
It is not hard to find out that circuit breaker can help us deal with the failure of the service very well. It also contains the. NET (Core) Implementation of the Netflix Hystrix.
With regard to the fusing mechanism, there is a very classic diagram (which takes the official documents directly), and the core depicts the relationship between the three states.
Having said that, let's look at a simple example to get a little deeper understanding.
Note: Service discovery and Service registration are not the focus of this article, so the Steeltoe features are not used here.
Simple example
Define a simple order service, the service is simple, a return directly to the corresponding order number interface, here with the default ASP. NET Core Web API project to make adjustments.
[Route("api/[controller]")]publicclass ValuesController : Controller{ // GET api/values/123 [HttpGet("{id}")] publicstringGet(string id) { return $"order-{id}"; } }
Another new service to call the above order service.
Let go of the fuse-related, define a service interface and implementation for accessing order services.
publicinterface IOrderService{ Task<stringGetOrderDetailsAsync(string orderId);}publicclass OrderService : IOrderService{ public async Task<stringGetOrderDetailsAsync(string orderId) { usingnewHttpClient()) { return await client.GetStringAsync($"http://localhost:9999/api/values/{orderId}"); } }}
The simple thing is to initiate an HTTP request to the order service and take a look at the returned results.
Ignoring the fuse, it is now possible to get the results through this orderservice.
[HttpGet]public async Task<stringGet([FromServices] Services.IOrderServicestring"0"){ return await service.GetOrderDetailsAsync(id);}
The results are as follows:
This is the most ideal situation! What happens if we stop the order service?
Very embarrassing, the caller of this order service is also obsolete.
Of course, Try-catch can also help us deal with this embarrassing problem, but this is not the result we want!
Let's take a look at how to deal with this problem slightly gracefully after introducing circuit breaker.
Define a Getorderdetailshystrixcommand and let it inherit Hystrixcommand .
Public classgetorderdetailshystrixcommand:hystrixcommand<string>{Private ReadOnlyIOrderService _service;Private ReadOnlyIlogger<getorderdetailshystrixcommand> _logger;Private string_orderid; Public Getorderdetailshystrixcommand(Ihystrixcommandoptions options, IOrderService service, ilogger<getorderdetailshystrixcommand> Logger):Base(options) { This._service= Service; This._logger= Logger; This.isfallbackuserdefined=true; } PublicAsync task<string>Getorderdetailsasync(stringORDERID) {_orderid = OrderId;returnAwaitExecuteasync(); }protected OverrideAsync task<string>RunAsync() {varresult = await _service.Getorderdetailsasync(_orderid); _logger.loginformation("Get The result: {0}", result);returnResult }protected OverrideAsync task<string>Runfallbackasync() {//Breaker already open if(! This._circuitbreaker.allowrequest) {returnAwait Task.Fromresult("Please wait for sometimes"); } _logger.loginformation($"Runfallback");returnAwait Task.Fromresult<string> ($"Runfallbackasync---orderid={_orderid}"); }}
Here are a few places to note:
- Constructors must have ihystrixcommandoptions this parameter
- Runasync is where the call is actually executed
- Runfallbackasync is for some reason unable to get the return result when it will be executed where the so-called graceful downgrade.
The next thing to do is to register in startup.
publicvoidConfigureServices(IServiceCollection services){ services.AddSingleton<IOrderService, OrderService>(); services.AddHystrixCommand<GetOrderDetailsHystrixCommand>("Order", Configuration); services.AddMvc();}
Can see, in the addition of the fuse command, also used the configuration of this parameter, which means that we have less configuration!!
Configuration is put into the appsettings.json inside, see below How to configure:
{ "Hystrix": { "command": { "Default": { "Circuitbreaker": { //Whether enabled, default is True "Enabled": true, //The minimum number of fuse triggers within the specified time window "Requestvolumethreshold": 5, //fuse How long after the time to try to request "Sleepwindowinmilliseconds": the, ///failure rate to reach the percentage after the fuse "Errorthresholdpercentage": -, //Whether forced to turn on the fuse "ForceOpen": false, //Whether to force off the fuse "forceclosed": false }, //Whether to enable fallback "Fallback": { "Enabled": true } } } }}
Need to add a node named Hystrix , inside the command node is the place we want to pay attention to!
Default, which is configured for all command! If you have a particular command to configure separately, you can add the appropriate command node under commands.
Other configuration items have been interpreted in a commented manner.
The following diagram simulates the availability of order services from available ---unavailable.
In addition to the service is not available, there may be a situation where the probability will be relatively large, time-out !
For example, there is a service that is usually responsive, suddenly for some time without knowing what the reason, processing the request is a lot slower, this period of time the client has been waiting for a long time, even timed out.
When this happens, a time-out is usually set, as long as there is no response in this time is considered to be a timeout!
You can complete the timeout configuration by using the following configuration:
{ "Hystrix": { "command": { "Default": { "Execution": { "Timeout": { "Enabled": true }, "Isolation": { "strategy": "THREAD", "Thread": { //Timeout period "Timeoutinmilliseconds": + } } }, } } }}
Summarize
Here are just a few of the more common and simple features, it can also combine multiple requests, caching requests and many other useful functions. Overall, the steeltoe of the fuse function, used up is relatively simple, but also more flexible.
Additional configuration and instructions can be found in the official documentation.
Sample code for this article:
Circuitbreakerdemo
Talk about the simple application of circuit breaker in. NET Core