Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to integrate Link tracking with go micro

2025-03-28 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)05/31 Report--

This article Xiaobian for you to introduce in detail "go micro how to integrate link tracking", the content is detailed, the steps are clear, the details are handled properly, I hope this "go micro how to integrate link tracking" article can help you solve your doubts, following the editor's ideas slowly in depth, let's learn new knowledge.

Opentracing is a specification and needs to be accompanied by a specific implementation, such as zipkin, jeager, and so on. Choose zipkin here.

Link tracking operational installation zipkin

Quickly start a zipkin server through docker:

Docker run-d-p 9411 9411 openzipkin/zipkin program structure

To facilitate the demonstration, the client and server are put into a project, and the directory structure of the program is as follows:

Main.go server program. Client/main.go client program.

Some configurations used by the config/config.go program, such as the name and listening port of the service, the access address of the zipkin, and so on.

Functions related to zipkin/ot-zipkin.go opentracing and zipkin.

Install dependency packages

Packages related to go-micro, opentracing and zipkin need to be installed:

Go get go-micro.dev/v4@latestgo get github.com/go-micro/plugins/v4/wrapper/trace/opentracinggo get-u github.com/openzipkin-contrib/zipkin-go-opentracing authoring server

First define a server-side business handler:

Type Hello struct {} func (h * Hello) Say (ctx context.Context, name * string, resp * string) error {* resp = "Hello" + * name return nil}

This program has only one method Say, enter name, and return "Hello" + name.

Then write a server-side framework program using go-micro:

Func main () {tracer: = zipkin.GetTracer (config.SERVICE_NAME, config.SERVICE_HOST) defer zipkin.Close () tracerHandler: = opentracing.NewHandlerWrapper (tracer) service: = micro.NewService (micro.Name (config.SERVICE_NAME), micro.Address (config.SERVICE_HOST), micro.WrapHandler (tracerHandler) ) service.Init () micro.RegisterHandler (service.Server (), & Hello {}) if err: = service.Run () Err! = nil {log.Println (err)}}

Here, NewService not only specifies the name and access address of the service, but also sets a HandlerWrapper for link tracking through micro.WrapHandler.

This HandlerWrapper is provided through go-micro 's opentracing plug-in, which needs to pass in a tracer. This tracer can be created from the zipkin-go-opentracing package installed earlier, and we encapsulated the creation logic in config.go:

Func GetTracer (serviceName string, host string) opentracing.Tracer {/ / set up a span reporter zipkinReporter = zipkinhttp.NewReporter (config.ZIPKIN_SERVER_URL) / / create our local service endpoint endpoint, err: = zipkin.NewEndpoint (serviceName, host) if err! = nil {log.Fatalf ("unable to create local endpoint:% + v\ n", err)} / / initialize our tracer nativeTracer Err: = zipkin.NewTracer (zipkinReporter, zipkin.WithLocalEndpoint (endpoint)) if err! = nil {log.Fatalf ("unable to create tracer:% + v\ n", err)} / / use zipkin-go-opentracing to wrap our tracer tracer: = zipkinot.Wrap (nativeTracer) opentracing.InitGlobalTracer (tracer) return tracer}

After the service is created, you also need to register the previously written business handler through micro.RegisterHandler.

Finally, get the service up and running through service.Run.

Write a client

Let's take a look at the processing logic on the client side:

Func main () {tracer: = zipkin.GetTracer (config.CLIENT_NAME, config.CLIENT_HOST) defer zipkin.Close () tracerClient: = opentracing.NewClientWrapper (tracer) service: = micro.NewService (micro.Name (config.CLIENT_NAME), micro.Address (config.CLIENT_HOST), micro.WrapClient (tracerClient) ) client: = service.Client () go func () {for {newService-> newOptions:

Func newOptions (opts... Option) Options {opt: = Options {... Server: server.DefaultServer,...} for _, o: = range opts {o (& opt)}...}

Traversing the opts is to execute each setting func, and finally to rpcServer.Init.

By the time the NewService is finished, all the WrapHandler we set has been added to a slice called HdlrWrappers.

Let's take a look at the execution process of the server-side Wrapper.

The code that executes Handler is in rpc_router.go:

Func (s * service) call (ctx context.Context, router * router, sending * sync.Mutex, mtype * methodType, req * request, argv, replyv reflect.Value, cc codec.Writer) error {defer router.freeRequest (req). For I: = len (router.hdlrWrappers); I > 0; iMurt-{fn = router.hdlrWrappers[ I-1] (fn)}. / / execute handler return fn (ctx, r, rawStream)}

According to the previous analysis, we can know that all the HandlerWrapper are recorded in router.hdlrWrappers. Here, the nesting of HandlerWrapper is realized by traversing router.hdlrWrappers. Note that the ergodic index is in the order from big to small, and then added by Wrap, first added to the outer layer.

In actual execution, the HandlerWrapper is first called to the first added Handler, then inward layer by layer, and finally to the business Handler we registered, and then returned layer by layer. Each HandlerWrapper can do its own work before and after calling the next layer, such as link tracking the detection execution time here.

Client Wrap

Remote invocation in the client is defined in Client, which is an interface that defines several methods:

Type Client interface {... Call (ctx context.Context, req Request, rsp interface {}, opts... CallOption) error...}

For the convenience of explanation, we only focus on the Call method, and omit the rest first.

Let's take a look at how Client is Wrap.

XXXWrapper

To Wrap a Client, you need to nest the Client through struct and implement the methods of the Client interface. As for the name of this struct, it is not mandatory and is usually named after XXXWrapper.

Take the otWrapper used in link tracking as an example, which is defined as follows:

Type otWrapper struct {ot opentracing.Tracer client.Client} func (o * otWrapper) Call (ctx context.Context, req client.Request, rsp interface {}, opts... client.CallOption) error {... If err = o.Client.Call (ctx, req, rsp, opts...); err! = nil {...}.

Note that the corresponding interface methods of the nested Client are all called in the interface methods implemented by XXXWrapper, which is the key to nested execution.

Wrap Client

With the XXXWrapper above, you also need to inject it into the execution process of the program.

Go-micro sets these XXXWrapper by calling micro.WrapClient when NewService:

Service: = micro.NewService (... Micro.WrapClient (tracerClient),)

Similar to WrapHandler, the parameter of WrapClient is not passed directly to the instance of XXXWrapper, but a func, defined as follows:

Type Wrapper func (Client) Client

This func needs to wrap the incoming Client into XXXWrapper and return an instance of XXXWrapper. The tracerClient passed here is such a func:

Return func (c client.Client) client.Client {if ot = = nil {ot = opentracing.GlobalTracer ()} return & otWrapper {ot, c}}

To achieve the nesting of Client, you can give an initial Client instance as the input of the first such func, then the output of the previous func as the input of the latter func, and then execute in turn, resulting in a Client instance to be used in the business code, which is similar to the Russian nesting doll, which has many layers of Client.

So when was this Russian nesting doll created?

In micro.NewService-> newService-> newOptions:

Func newOptions (opts... Option) Options {opt: = Options {... Client: client.DefaultClient,...} for _, o: = range opts {o (& opt)} return opt}

You can see that an initial value is set for Client, and then the Option passed in when traversing these NewService (WrapClient also returns Option). These Option are actually func, so traversing and executing these func will pass in some initial default values, including the initial value of Client.

So how does the output of the previous func serve as the input to the latter func? Let's take a look at the source code of WrapClient:

Func WrapClient (w... client.Wrapper) Option {return func (o * Options) {for I: = len (w); I > 0; I muri-{o.Client = w [I-1] (o.Client)}

You can see that the Wrap method gets the current Client instance from Options, passes it to Wrap func, and then the newly generated instance is set to the Client field of Options.

It is in this way that the above-mentioned Russian nesting doll is formed.

Let's take a look at the execution process of the client call.

Get the Client instance through the Client () method of service, and then execute the RPC call through the Call () method of the instance.

Client:=service.Client () client.Call ()

This Client instance is the nesting doll example described earlier:

Func (s * service) Client () client.Client {return s.opts.Client}

As mentioned earlier, the corresponding interface method of the nested Client is called in the interface method of the XXXWrapper implementation. This is the key to being able to nest execution.

Here is a diagram to make it easy for you to understand the execution process of Wrap Client's RPC call:

Differences between client-side Wrap and server-side Wrap

An important difference is that for multiple WrapClient, the later added is called first; for multiple WrapHandler, the first added is called first.

A strange thing is that if multiple Wrapper instances are passed in WrapClient, WrapClient will adjust the order, and the first of these instances will be called first, which is contrary to the order of multiple WrapClient processing, which is not well understood.

Func WrapClient (w... client.Wrapper) Option {return func (o * Options) {/ / apply in reverse for i: = len (w); I > 0; imuri-{o.Client = w [I-1] (o.Client)}

The client-side Wrap also provides a lower-level CallWrapper, which is executed in the same order as the server-side HandlerWrapper, which is added first and called first.

/ / wrap the call in reverse for i: = len (callOpts.CallWrappers); I > 0; iMurt-{rcall = callOpts.CallWrappersi [I-1] (rcall)}

Another big difference is that the Wrap on the server is temporarily added before calling a business Handler, while the Wrap on the client has been created when the Client.Call is called. What is the reason for doing so? This may be because on the server side, the business Handler and HandlerWrapper are registered separately, and the HandlerWrapper may not exist when registering the business Handler, so we have to adopt the dynamic Wrap method. On the client side, when initiating a call through Client.Call, Client is the main body of the call, and users have many ways to obtain Client, so they cannot require users to temporarily Wrap before each call.

Link tracking of Http service

With regard to the link tracking of Http or Restful services, httpClient of go-micro supports CallWrapper, and you can use WrapCall to add CallWrapper; for link tracking, but its httpServer implementation is relatively simple. The Handler processing within http is completely handed over, so you can only do this in the framework of http. For example, Restful services developed by go-micro+gin can use gin's middleware mechanism to do link tracking.

After reading this, the article "how to integrate link tracking with go micro" has been introduced. If you want to master the knowledge points of this article, you still need to practice and use it yourself. If you want to know more about related articles, welcome to follow the industry information channel.

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report