The previous post briefly introduced Go-micro's overall frame structure, this one mainly writes Go-micro uses the way the example, the middle will be interspersed some go-micro the source code, and calls the flowchart, helps everybody better understanding Go-micro's bottom. More detailed and more specific call process and details will be explained in detail in a future post.
Example of GitHub address: GOMICRORPC run through the example, you will understand a probable.
Environment required for installation
Go-micro Service discovery is using Consul by default,
-dev
Or use Docker to run directly
8300:83008301:83018301:83018302:8302 8302:83028400:84008500:850053 /UDP Consul
I personally prefer etcdv3 reasons I have also mentioned in the last article, Gomicro Service found not support consul cluster, I have also written etcdv3 cluster building and use of posts, there is time for everyone to look at
Installing the GO-MICRO Framework
Get Github.com/micro/go-micro
Basic knowledge of installing protobuf and relying on prtobuf I'm not going to talk about it here, if you don't know, you can look at the official document, a cross-platform, cross-language data serialization library, easy to learn.
is Go-micro used to help us build the service interface and a series of calling code
get -u-v github.com/golang/protobuf/{proto,protoc-gen-get -u-v github.com/micro/ Protoc-gen-micro
Protobuf can also be installed directly from the source code
wget https://GITHUB.COM/PROTOCOLBUFFERS/PROTOBUF/RELEASES/DOWNLOAD/V3.6.1/ protobuf-all-3.6.1.tar.gztar zxvf protobuf-all-3.6. 1 . TAR.GZCD protobuf-3.6. 1/. /autogen.sh. /H
Install the micro kit, this installation is optional, Micro provides a series of tools to help us better use Go-micro.
Get Github.com/micro/micro
Example 1
Create the proto file Common.proto, which contains the parameters that are passed in and returned, with parameters that contain commonly used base types, arrays, maps, and so on. There is also a say service that has an RPC method in it.
Syntax ="Proto3";p ackage model;message sayparam {stringmsg =1;} Message Pair {Int32 key=1; stringValues =2;} Message Sayresponse {stringmsg =1; //ArrayRepeatedstringValues =2; //Mapmap<string, pair> Header =3; Resptype type=4;}enumResptype {NONE=0; ASCEND=1; Descend=2;}//Service Interfaceservice Say {RPC Hello (sayparam) returns (Sayresponse) {}}
Run in the root directory, generate two template files
Protoc--proto_path= $GOPATH/src:. --micro_out=. --go_out=. Example1/proto/*
A file is a go structure file for Proto, and an interface file for Go-micro RPC.
Server side:
Type Saystruct{}func (s*say) Hello (CTX context. Context, req *model. Sayparam, RSP *model. Sayresponse) Error {FMT. Println ("received", req. MSG) RSP. Header= Make (map[string]*model. Pair) RSP. header["name"] = &model. Pair{key:1, Values:"ABC"} RSP. MSG="Hello World"RSP. Values= Append (RSP). Values,"a","b") RSP. Type=model. Resptype_descendreturnNil}func Main () {//I use the ETCD as a service found, if the use of consul can be removedReg: = Etcdv3. Newregistry (Func (OP *Registry. Options) {op. Addrs= []string{ "http://192.168.3.34:2379","http://192.168.3.18:2379","http://192.168.3.110:2379", } }) //Initializing the serviceService: =Micro. NewService (micro. Name ("LP.SRV.EG1"), Micro. Registry (REG),)//Register HandlerModel. Registersayhandler (service. Server (),New(Say))//Run Server ifERR: = Service. Run (); Err! =Nil {panic (err)}}
Service discovery I was using ETCDV3 to replace the default consul
Micro. NewService initializes the service and then returns an instance of a service interface, the approximate flow of the NewService () method is as follows,
The default value is initialized for each interface, and the default value is replaced with the value passed in, which is where the go-micro replaceable plug-in.
The service has an init () optional method, which is a single-instance method,
Func (S *service) Init (opts ... Option) { // process options for _, O: = range opts { O (& s.opts) } s.once.do (func () { // Save user Action action: = S.opts.cmd.app (). Action // set service action S.opts.cmd.app (). Action = Func (c *CLI. Context) { ... .. // This is not going to show the code. ......... }}
In the official case, it is not necessary to show the call, because the Init method is called when the default value is replaced
such as micro. Name () method, the Init () method has been called
// Name of the service string Option { return func (o *Options) { o.server.init (Server). Name (n)) }}
Service. Run () method invocation Process
Because the port is not specified at initialization time, the system automatically assigns a port number to the server and registers the server information with the register.
Beferstart and Afterstart can also be customized.
Client side:
Func Main () {//I use the ETCD as a service found, if the use of consul can be removedReg: = Etcdv3. Newregistry (Func (OP *Registry. Options) {op. Addrs= []string{ "http://192.168.3.34:2379","http://192.168.3.18:2379","http://192.168.3.110:2379", } }) //Initializing the serviceService: =Micro. NewService (micro. Registry (REG),) Sayclent:= Model. Newsayservice ("LP.SRV.EG1", service. Client ()) RSP, err:= Sayclent.hello (context. Background (), &model. Sayparam{msg:"Hello server"}) ifErr! =Nil {panic (err)} FMT. PRINTLN (RSP)}
Above the two files generated according to the proto file is an RPC interface file, the interface file has helped us to call the method of the entire process encapsulated.
You just need to give the service name and Licent. Then call the Hello method
Source:
Func (c *sayservice) Hello (CTX context. Context,inch*sayparam, opts ... client. Calloption) (*Sayresponse, error) {req:= C.c.newrequest (C.name,"Say.hello",inch) out:=New(sayresponse) Err:= C.c.call (CTX, req, out, opts ...) ifErr! =Nil {returnnil, err}return out, nil}
The main process is in the C.c.call method. Simply put, the process is as follows
is to get the node information address, according to the address to inquire whether there is a connection in the pool, if there is to take out, if not then create, and then transfer the data, transfer the client back to the pool. The size of the pool is also controllable, this part of the code is particularly cool to read, specific details and processing process will be detailed in a future post to explain
Example 2
Example 1, do a simple service, can no longer be simple, just to let everyone familiar with the Go-micro. After reading the example 1 should have more ideas, want to use more Go-micro features, such as PROTOBUF generated classes are together, if you want the model and API separate how to deal with, how to use the Go-micro bidirectional flow, how to use the message push, and so on. So I made a small example of this, and this example contains something.
In this example, I'll just say the organizational structure, and there is not much code, we have time to look at the OK.
Proto two folders, a model A rpcapi, is to separate the data and APIs, the API refers to the model
Look at Rpcapi.
" Proto3 " "github.com/lpxxn/gomicrorpc/example2/proto/model/common.proto"; // Service Interface service Say { RPC Hello (model. Sayparam) returns (model. Sayresponse) {} RPC Stream (model. srequest) returns (stream model). sresponse) {}}
Import the Common.proto in the model
At the time of Generation one just go_out another as long as the micro_out is good.
Protoc--proto_path= $GOPATH/src:. --go_out=. Example2/proto/model/*. Proto
Subscribe to a message
// Register subscribers if err: = Server. Subscribe (server. Newsubscriber (Common. Topic1, subscriber. Handler)); Err! = Nil { panic (err) }
When a message is sent, all services that subscribe to the LP.SRV.EG2.TOPIC1 message receive a message
Client sends information
P: = micro. Newpublisher (Common. Topic1, service. Client ()) &model. Sayparam{msg:lib. Randomstr (lib. Random (3))})
If the production environment must not use Go-micro default information publishing and subscription processing, micro plug-in plugin is a lot of mature plug-ins.
Small function with bidirectional flow
This method only sends some data to the client at a time, sending only a portion at a time. For example, we give the client push the data is very large, one-time all pushed past, is not very correct practice, partial push back is better.
Func (S *say) Stream (CTX context. Context, req *model. Srequest, Stream Rpcapi. Say_streamstream) Error { forI: =0; I <int(req. Count); i++{rsp:= &model. sresponse{} forJ: = Lib. Random (3,5); J <Ten; J + +{rsp. Value= Append (RSP). Value, Lib. Randomstr (lib. Random (3,Ten))) } ifERR: = stream. Send (RSP); Err! =Nil {returnErr}//Simulation ProcessTime. Sleep (time. Microsecond * -) } returnNilreturnNil}
Hopefully this small example will get you started Go-micro.