# micro **Repository Path**: JMArch/micro ## Basic Information - **Project Name**: micro - **Description**: 支持jmtext和thrift的micro gorpc包 - **Primary Language**: Go - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 1 - **Created**: 2018-07-27 - **Last Updated**: 2020-12-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # rpc-go README 标签(空格分隔): jumei 文档 --- ## Getting started - [Install Protobuf](#install-protobuf) - [Install Thrift](#install-thrift) - [Writing a Service](#writing-a-service) - [Plugins](#plugins) ## Install Protobuf Protobuf is required for code generation You'll need to install: - [protoc-gen-micro](https://github.com/micro/protoc-gen-micro) ## Install Thrift 如果需要使用Thrift协议传输,您可能需要安装Thrift来生成对应的 Request&Response Struct - [thrift](https://thrift.apache.org/download) ## Writing a service This is a simple greeter RPC service example ### Create service proto One of the key requirements of microservices is strongly defined interfaces. Micro uses protobuf to achieve this. Here we define the Greeter handler with the method Hello. It takes a HelloRequest and HelloResponse both with one string arguments. ```proto syntax = "proto3"; option go_package = "greeter"; service Greeter { rpc Hello(HelloRequest) returns (HelloResponse) {} } message HelloRequest { string name = 1; } message HelloResponse { string greeting = 2; } ``` ### Generate the proto After writing the proto definition we must compile it using protoc with the micro plugin. ```shell protoc --proto_path=$GOPATH/src:. --micro_out=. --go_out=. path/to/greeter.proto ``` 完毕后,需要将 imports 中前缀为 `github.com/micro/go-micro/` 替换为 `gitee.com/JMArch/micro/` 也可以使用项目中的脚本`micro/example/proto/make.sh`来生成 ### Generate the thrift go 如果对于以上的Hello方法,对于HelloRequest和HelloResponse你需要使用Thrift协议,您只需要编写对应的Thrift文件(greeter.thrift),如 ```thrift struct HelloRequest { 1: required string name; } struct HelloResponse { 1: required string greeting; } ``` 然后使用命令生成对应的golang版本的Struct ```shell thrift --gen go greeter.thrift ``` 之后,使用生成的greeter-consts.go、greeter.go、GoUnusedProtection__.go替换由protoc生成的 \*.pb.go文件即可 ### Write the service Below is the code for the greeter service. It does the following: 1. Implements the interface defined for the Greeter handler 2. Initialises a micro.Service 3. Registers the Greeter handler 4. Runs the service ```go package main import ( "context" "fmt" "log" "net/http" "time" _ "net/http/pprof" "gitee.com/JMArch/go-plugins/registry/etcdv3" "gitee.com/JMArch/go-plugins/transport/tcp" micro "gitee.com/JMArch/micro" proto "gitee.com/JMArch/micro/example/proto" "gitee.com/JMArch/micro/example/thrift/gen-go/datafmt" jmconst "gitee.com/JMArch/micro/jm-const" "gitee.com/JMArch/micro/metadata" "gitee.com/JMArch/micro/monitor" "gitee.com/JMArch/micro/registry" "gitee.com/JMArch/micro/server" ) type Greeter struct{} func (g *Greeter) Hello(ctx context.Context, req *proto.HelloRequest, rsp *proto.HelloResponse) error { rsp.Greeting = "Hello " + req.Name if md, ok := metadata.FromContext(ctx); ok { rsp.Greeting += "@" + md[jmconst.JumeiServerPort] } return nil } type GreeterThrift struct{} func (g *GreeterThrift) Hello(ctx context.Context, req *datafmt.HelloRequest, rsp *datafmt.HelloResponse) error { rsp.Greeting = "Hello " + req.Name if md, ok := metadata.FromContext(ctx); ok { rsp.Greeting += "@" + md[jmconst.JumeiServerPort] } return nil } func main() { go func() { log.Println(http.ListenAndServe("localhost:6060", nil)) }() // Create a new service. Optionally include some options here. service := micro.NewService( micro.Server( server.NewServer( server.Metadata(metadata.Metadata{ jmconst.JumeiRPCSecretKey: "xxx", // rpc secret,jmtext协议必填,thrift选填 jmconst.JumeiServerRespTimeout: "5000", // 处理返回超时时间,单位ms,默认不超时 jmconst.JumeiServerDataFormat: "application/jmtext", // 接受的协议类型,还有application/jmtext可选。*此值必须存在。 }), // server.Address("0.0.0.0:34567"), // 指定绑定的端口号。如果不指定,则会自动挑选一个可用端口号(建议不指定) server.MaxProcess(1000), // 最多同时处理的request数,默认Int64.Max server.Monitor( monitor.NewMonitor( monitor.Path("./"), // 监控日志path;默认位置/home/logs/monitor/ monitor.File("monitor_tmp.log"), // 监控日志名;默认名monitor.log monitor.Level("info"), // 监控日志级别debug/info/error;默认级别info monitor.MaxSize(4096), // 监控日志分割大小,单位mb;默认大小2048 )), // 使用自建监控 ), ), micro.Name("jm_greeter"), // 服务名。最好不要使用带“.”的服务名 micro.Version("2.0.1"), // 服务版本 micro.Transport(tcp.NewTransport()), // 选用tcp方式传输数据 micro.Registry(etcdv3.NewRegistry( registry.Addrs("127.0.0.1:2379"), )), // 选用etcdv3服务注册注。如果服务名包含“.”,则会将“.”转换为“/” micro.RegisterInterval(time.Second*6), // 服务注册间隔。注:服务注册间隔需要小于服务失效时间的TTL micro.RegisterTTL(time.Second*10), // 服务注册失效时间TTL ) s := service.Server() // Register handler // proto.RegisterGreeterHandler(s, new(Greeter)) datafmt.RegisterGreeterHandler(s, new(GreeterThrift)) // Run the server if err := service.Run(); err != nil { fmt.Println(err) } } ``` ### Run service ``` go run examples/service/main.go ``` Output ``` 2016/03/14 10:59:14 Listening on [::]:50137 2016/03/14 10:59:14 Broker Listening on [::]:50138 2016/03/14 10:59:14 Registering node: greeter-ca62b017-e9d3-11e5-9bbb-68a86d0d36b6 ``` ### Define a client Below is the client code to query the greeter service. The generated proto includes a greeter client to reduce boilerplate code. ```go package main import ( "context" "fmt" "io/ioutil" "math/rand" "strings" "sync" "time" "gitee.com/JMArch/go-plugins/registry/etcdv3" "gitee.com/JMArch/go-plugins/selector/weights" "gitee.com/JMArch/go-plugins/transport/tcp" micro "gitee.com/JMArch/micro" "gitee.com/JMArch/micro/client" "gitee.com/JMArch/micro/example/proto" jmconst "gitee.com/JMArch/micro/jm-const" "gitee.com/JMArch/micro/metadata" "gitee.com/JMArch/micro/registry" ) func main() { // Create a new service. Optionally include some options here. service := micro.NewService( micro.Client(client.NewClient( client.ContentType("application/jmtext"), // 选择使用thrift协议,相应的还有 application/jmtext client.DialTimeout(time.Second*2), // 连接超时设置,默认5秒 client.RequestTimeout(time.Second*10), // 请求超时设置,默认5秒 client.Retries(1), // 请求失败、出错后重试次数,默认1次。重试次数最好大于0。 client.PoolTTL(time.Minute), // 连接闲置缓存时间,默认1分钟 client.PoolSize(100), // 默认缓存连接数,默认100个 )), micro.Name("greeter.client"), // 客户端名称 micro.Transport(tcp.NewTransport()), // 选用tcp连接,默认http micro.Selector(weights.NewSelector()), // 使用权重模式负载均衡,默认随机模式 micro.Registry( etcdv3.NewRegistry( // 设置服务注册地址,默认为:localhost:default_port // default_port视各服务注册方式而定 registry.Addrs("127.0.0.1:2379"), ), // etcdv3 ), // 选择服务注册方式,默认consul。 ) // Create new greeter client greeter := proto.NewGreeterService("jm_greeter", service.Client()) // greeter := datafmt.NewGreeterService("jm_greeter", service.Client()) data, _ := ioutil.ReadFile("list.log") rand.Seed(time.Now().UnixNano()) start := time.Now() data = []byte("abc") var wg sync.WaitGroup for i := 0; i < 100000; i++ { wg.Add(1) time.Sleep(time.Millisecond * 100) go func(index int) { // Call the greeter ctx := metadata.NewContext(context.TODO(), metadata.Metadata{ jmconst.JumeiDataCompress: jmconst.JumeiDataCompressYes, // 是否压缩数据,只有jmtext协议支持压缩 jmconst.JumeiRPCSecretKey: "xxx", // 请求使用的secret_key,只有jmtext协议必填 jmconst.JumeiRPCUser: "weit", // rpc_uer jmconst.JumeiRPCPassword: "pwd", // rpc_pwd }) var rsp *proto.HelloResponse var err error hello := rand.Intn(100) > 40 if hello { rsp, err = greeter.Hello(ctx, &proto.HelloRequest{ Name: fmt.Sprintf("%d.%s", index, string(data[:rand.Intn(len(data))])), }) } else { rsp, err = greeter.Hello1(ctx, &proto.HelloRequest{ Name: fmt.Sprintf("%d.%s", index, string(data[:rand.Intn(len(data))])), }) } if err != nil { fmt.Printf("error: %v, index:%d\n", err, index) } else { prefix := "" if hello { prefix = "Hello" } else { prefix = "Hello1" } if !strings.HasPrefix(rsp.GetGreeting(), fmt.Sprintf("%s %d.", prefix, index)) { fmt.Printf("%s %v\n", prefix, hello) panic("index error: " + rsp.GetGreeting()) } // Print response fmt.Println(rsp.GetGreeting(), "result") } wg.Done() }(i) } wg.Wait() fmt.Println(time.Now().Sub(start)) } ``` ### Run the client ```shell go run client.go ``` Output ``` Hello John ``` ## Plugins By default go-micro only provides a few implementation of each interface at the core but it's completely pluggable. There's already dozens of plugins which are available at [github.com/micro/go-plugins](https://gitee.com/JMArch/go-plugins). Contributions are welcome! ### Plugin as option Alternatively you can set the plugin as an option to a service ```go import ( "gitee.com/JMArch/micro" // etcd v3 registry "gitee.com/JMArch/go-plugins/registry/etcdv3" // tcp transport "gitee.com/JMArch/go-plugins/transport/tcp" ) func main() { registry := etcdv3.NewRegistry() transport := tcp.NewTransport() service := micro.NewService( micro.Name("greeter"), micro.Registry(registry), micro.Transport(transport), ) service.Init() service.Run() } ```