A thorough understanding of the hystrix go source code

Time:2021-10-25

Opening

The last article mainly introducedhystrix-goIn this article, let’s comprehensively analyze the source code. This article is very long. Please read it patiently. In addition, because the direct release of the source code affects the mobile phone reading experience, I cut the source code into pictures.

Or the example of the previous article

A thorough understanding of the hystrix go source code
Most of the articles only explain the responsibilities and functions of each module. Considering that if it is only explained, it is still difficult for readers to connect the overall process. So I intend to analyze it step by step from this example.
Just start right from the beginninghystrix.ConfigureCommandLet’s go.
A thorough understanding of the hystrix go source code

As mentioned in the previous article, this operation is mainly for each usercommandNameCustomize your own rule configuration. If not customized, the default value is used. The configuration values will eventually be stored incircuitSettingsthismapType, its initialization operation isinit()Executed.
A thorough understanding of the hystrix go source code
Next executionhystrix.DoDoIt is a synchronous operation. It will block and wait until the end of the execution function or the fuse returns an error, such as circuit breaker opening and exceeding the maximum concurrency.
A thorough understanding of the hystrix go source code
This function requires three parameters, and the first parameter representscommandNameThe second parameter is the anonymous function of normal business, such as external service calls in the function. If the call fails, the operation of the third parameter will be executed, which can be called minimum operation. When the fuse is turned on, the system will also call this function directly. The types of these two parameters are anonymous function and closure function.
A thorough understanding of the hystrix go source code
As can be seen from the figure,DoThe function just further encapsulates the last two parameters into a function. Then callDoC

A thorough understanding of the hystrix go source code

DocThe first argument to the function is the contextcontext.Contextcontext.ContextIt usually appears in different placesGoroutineSynchronize the specified data between. If you have usedginFramework, often deal with it.

The third and fourth parameters areDoTwo closure functions further wrapped in. The so-called closure, my understanding is: there are free variables. This free variable depends on the environment in which the closure function is runDoCIn,runFuncandfallbackFuncCtype
A thorough understanding of the hystrix go source code
That is, the free variables of these two closures arecontext.Context

DocVariable in functionrandfNo more explanation. Because we’re callingDoFunction passed the third parameter, so theerrChan = GoC(ctx, name, r, f)。 Bottom useselectCan monitor multiplechannel。 When someonechannelWhen there is data, read from it. Let’s look downGoC

GocIs the core code block. It is where your core business functions are really executed. I’ll start with a general introduction to the core functions of this function.
It will first verify some rules, such as judging whether the fuse is on and deciding whether your business can be executed at present. Determine whether the access token can be obtained. If you can, execute your business logic. If you succeed, report the successful status and fail. In addition to reporting the status, if an exception handling function is passed in, execute the exception handling function. In addition, there are some operations such as returning tokens. Let’s look at the code.
A thorough understanding of the hystrix go source code
This code will not be explained. But we can take a lookcommandWhat other parameters are there in the structure.
A thorough understanding of the hystrix go source code
commandInside, the two key fields areeventsandcircuit。 actuallyeventsIt mainly stores event type information, such as successful executionsuccess, or failedtimeoutcontext_canceledWait. Circuit is a pointer typeCircuitBreaker, CircuitBreakerIt’s a real fuse.commandIt mainly records the status of a single execution and some operation interaction with the fuse. Interactive what? Main directionCircuitBreakerReport execution status events.

Next, let’s look at the following code
A thorough understanding of the hystrix go source code
GetCircuit(name), you can know from the function name that a fuse is obtained by name.
A thorough understanding of the hystrix go source code
This function code is very clear, if not fromcircuitBreakersThe corresponding is found in the queryCircuitBreaker, then create one.

The code here has a little detail. firstcircuitBreakersyesmapType, we all knowmapIs not concurrency safe. Therefore, a read lock is added when searching. If no value is found, the read lock is released. Try to obtain the write lock. We are in the write lock and further confirm whether it existscircuitBreakers, why? This is because there may be other problems in the process from releasing the read lock to obtaining the write lockGoroutineCreate one step ahead. Therefore, it needs to be further confirmed that if it does not exist at this time, it really does not exist. PassnameGenerate acircuitBreakers。 Let’s seenewCircuitBreaker(name)Function.
A thorough understanding of the hystrix go source code
The main thing is to initialize and create a fuseCircuitBreakerOperation, we can seeCircuitBreakerWhat fields are there.

A thorough understanding of the hystrix go source code
It mainly describes several fields,openIndicates whether the current fuse is on,executorPoolIt is the flow control center. All requests need to obtain the token first.metricsThe type of is*metricExchange, it can be regarded as a carrier for reporting execution status events. Through it, the execution status information is stored in the data set of each dimension status (success times, failure times, timeout…) of the actual fuse execution.

newCircuitBreaker(name)Initialization is also initializedexecutorPoolandmetrics

Look firstnewMetricExchange(name)。 Look at itmetricExchangestructure
A thorough understanding of the hystrix go source code
UpdatesIt’s achannelType, byUpdatesCollection of reported execution events.metricCollectorsStored ismetricCollector.MetricCollectorSlice, andmetricCollector.MetricCollectorIs an interface type.

A thorough understanding of the hystrix go source code

newMetricExchange(name)In,
A thorough understanding of the hystrix go source code
As you can see, initializationUpdatesThe capacity of the channel is2000。 initializationmetricCollectorsThe main logic isInitializeMetricCollectors
A thorough understanding of the hystrix go source code
I marked the key points. I want to see othersnewDefaultMetricCollector
A thorough understanding of the hystrix go source code
This function returns aMetricCollectorType, structureDefaultMetricCollectorRealizedMetricCollectorAll methods. I want to see othersDefaultMetricCollector, it stores all the information about the execution status of the fuse. Look at the pointer typerolling.Number
A thorough understanding of the hystrix go source code
rolling.NumberIt is the underlying storage structure that really stores the status information of each execution event. How is it saved only10Information within seconds.
A thorough understanding of the hystrix go source code
Are you surprised?
newMetricExchange(name)There is another detail, which will be opened separatelygfunctiongo m.Monitor()To receivechannelTypeUpdatesInformation, i.e. execution event status information.
A thorough understanding of the hystrix go source code
After receiving the event information, callIncrementMetricsFirst integrate the status information, and finally report the integrated execution status event informationcollector.Update(r)
A thorough understanding of the hystrix go source code

A thorough understanding of the hystrix go source code

Then look back at initializing the flow control centernewExecutorPool(name)。 Have a look firstexecutorPoolStructure.
A thorough understanding of the hystrix go source code
It mainly focuses on two fields,TicketsRepresents the access token with buffered channelchannel, initializationchannelThe capacity depends on what you set at the beginningMaxConcurrentRequests。 When a request comes, fromchannelTake out a token and return it after calling.poolMetricsIt is the specific index of flow control.
A thorough understanding of the hystrix go source code

ExecutedIndicates the number of requests that have been processed by the current bucket. In addition, innewExecutorPool(name)Function, like the routine just now, starts ago m.Monitor()Specifically update the maximum value of the current bucket.
A thorough understanding of the hystrix go source code
A thorough understanding of the hystrix go source code

Come here,GetCircuit(name)The code to get a fuse is over.
go back toGoC, we got onecircuitBreakersPointer to.
A thorough understanding of the hystrix go source code
Next, we create a condition variablesync.NewCond。 The scenario of condition variable is to notify those threads locked by mutex when shared resources change.
Here it is used to coordinate notification that you can return the access token.

Then there is a sentencereturnOnce := &sync.Once{}, aboutsync.Once, I analyzed an article beforeDo you really know sync. Once。 What is the meaning of its existence here? When we look down, we will find that two are actually opened in the backGoroutine
A thorough understanding of the hystrix go source code
Its function is to ensure that the fastest oneGoroutinefunctionerrWithFallback()andreportAllEvent(), and it is guaranteed that it will be executed only once.

Then look down,
A thorough understanding of the hystrix go source code
This function is used to report execution events.
A thorough understanding of the hystrix go source code

It’s easy to understand the front. Let’s start with this paragraph:
A thorough understanding of the hystrix go source code
What does this sentence mean? Because there is a situation: the current fuse is on and has passedSleepWindowTime. At this time, the request is in the half open state, and it is allowed to try to execute. If the execution is successful, it indicates that the service is restored and the fuse can be closed. next,
A thorough understanding of the hystrix go source code
The assembly execution status event is then insertedUpdatesIn the channel. Just initializedmetricExchangeSeparateGoroutineReceive. In this way, the reporting process corresponds to.

The next two are the screenshots just nowGoroutine, let’s look at the first one first.
A thorough understanding of the hystrix go source code

The screenshot shows the top half. One updefer func() { cmd.finished <- true }()As a notification of the end of normal operation. And thencmd.circuit.AllowRequest()Judge whether it can be requested.
A thorough understanding of the hystrix go source code
There are two situations that can go down. The first one is that the fuse is closed. correspondingcircuit.IsOpen()
A thorough understanding of the hystrix go source code
First, judge whether the fuse is forced to open or has been opened. If so, return directlytrue。 Otherwise, it means that the current fuse is closed. Then judge whether the sum of each bucket value in the past ten seconds is less than the set valueRequestVolumeThresholdValue. If it is less than, it indicates that the fuse should also be closed and returnsfalse。 If it is greater than or equal to, you should further judge whether the error percentage exceeds your own settingErrorPercentThreshold。 If it exceeds, the error rate is too high, and the fuse needs to be opened at this time.
A thorough understanding of the hystrix go source code
This code is easy to understand. What’s interesting isint(errPct + 0.5)+0.5For rounding, if you directly convert a floating-point number to an integer, you must remove the decimal point. Yes0.5, then supposeErrorPercentThresholdset up50, if yes<45.5, the fuse will continue to close, otherwise open the fuse.

Ifcircuit.IsOpen()No, then look againcircuit.allowSingleTest()。 Although the fuse is on, if the current time is greater than (the time when the fuse was last opened)+SleepWindowAt this time, the fuse is in the half open state, and the next step can be carried out. Then it will returntrue

Ifcmd.circuit.AllowRequestreturnfalse, then it’s executionreturnTicketReturn the token (although there is no token at this time). This code is very interesting, through variablesticketCheckedplussync.NewCondImplementation logic.cmd.errorWithFallback(), report the fuse on event(circuit open)And operationfallBakckThe minimum guarantee function (if any), the execution ends, and the response.

A thorough understanding of the hystrix go source code

If returntrue, then play and go,

A thorough understanding of the hystrix go source code
If you can’t get the access token, as just now, report the event that the current request has exceeded the concurrent number(max concurrency), run the minimum guarantee operation and respond.

If you get the access token, you can really execute your own business coderun(ctx)。 The routine is similar to the above.
Look at the second oneGoroutine
A thorough understanding of the hystrix go source code
ThreecaseIt indicates the end of normal execution, the cancellation of business execution and timeout respectively. As for whyDoIs a synchronous operation becauseDoclast,
A thorough understanding of the hystrix go source code, andGoIs an asynchronous process.
Here, fromDoThe general process of execution is over.
Finally, we can directly give its general flow chart.
A thorough understanding of the hystrix go source code
Some relationships between their structures.
A thorough understanding of the hystrix go source code
Share some strange things

Long press to pay attention to the late night canteen in the library

This work adoptsCC agreement, reprint must indicate the author and the link to this article

Wu qinkuri