double.huang 4 yıl önce
işleme
69b6f5b3ae
100 değiştirilmiş dosya ile 5427 ekleme ve 0 silme
  1. 22 0
      .gitignore
  2. 214 0
      README.md
  3. 18 0
      bloom/bloom.go
  4. 29 0
      bookstore/api/bookstore.api
  5. 31 0
      bookstore/api/bookstore.go
  6. 13 0
      bookstore/api/etc/bookstore-api.yaml
  7. 12 0
      bookstore/api/internal/config/config.go
  8. 29 0
      bookstore/api/internal/handler/addhandler.go
  9. 29 0
      bookstore/api/internal/handler/checkhandler.go
  10. 27 0
      bookstore/api/internal/handler/routes.go
  11. 39 0
      bookstore/api/internal/logic/addlogic.go
  12. 40 0
      bookstore/api/internal/logic/checklogic.go
  13. 23 0
      bookstore/api/internal/svc/servicecontext.go
  14. 20 0
      bookstore/api/internal/types/types.go
  15. 21 0
      bookstore/go.mod
  16. 441 0
      bookstore/go.sum
  17. 38 0
      bookstore/rpc/add/add.go
  18. 16 0
      bookstore/rpc/add/add.proto
  19. 305 0
      bookstore/rpc/add/add/add.pb.go
  20. 38 0
      bookstore/rpc/add/adder/adder.go
  21. 10 0
      bookstore/rpc/add/etc/add.yaml
  22. 12 0
      bookstore/rpc/add/internal/config/config.go
  23. 39 0
      bookstore/rpc/add/internal/logic/addlogic.go
  24. 27 0
      bookstore/rpc/add/internal/server/adderserver.go
  25. 20 0
      bookstore/rpc/add/internal/svc/servicecontext.go
  26. 38 0
      bookstore/rpc/check/check.go
  27. 16 0
      bookstore/rpc/check/check.proto
  28. 306 0
      bookstore/rpc/check/check/check.pb.go
  29. 38 0
      bookstore/rpc/check/checker/checker.go
  30. 10 0
      bookstore/rpc/check/etc/check.yaml
  31. 12 0
      bookstore/rpc/check/internal/config/config.go
  32. 36 0
      bookstore/rpc/check/internal/logic/checklogic.go
  33. 27 0
      bookstore/rpc/check/internal/server/checkerserver.go
  34. 20 0
      bookstore/rpc/check/internal/svc/servicecontext.go
  35. 6 0
      bookstore/rpc/model/book.sql
  36. 100 0
      bookstore/rpc/model/bookmodel.go
  37. 5 0
      bookstore/rpc/model/vars.go
  38. 139 0
      breaker/main.go
  39. 15 0
      breaker/plot.py
  40. 98 0
      chat/home.html
  41. 142 0
      chat/internal/client.go
  42. 49 0
      chat/internal/hub.go
  43. 65 0
      chat/main.go
  44. 2 0
      config/loadfromyaml/date.yml
  45. 21 0
      config/loadfromyaml/main.go
  46. 22 0
      etcd/pub/Dockerfile
  47. 27 0
      etcd/pub/pub.go
  48. 22 0
      etcd/sub/Dockerfile
  49. 24 0
      etcd/sub/sub.go
  50. 139 0
      filex/pread.go
  51. 33 0
      fx/fx_test.go
  52. 35 0
      fx/square.go
  53. 18 0
      go.mod
  54. 407 0
      go.sum
  55. 26 0
      graceful/dns/api/Dockerfile
  56. 11 0
      graceful/dns/api/config/config.go
  57. 9 0
      graceful/dns/api/etc/graceful-api.json
  58. 11 0
      graceful/dns/api/graceful.api
  59. 32 0
      graceful/dns/api/graceful.go
  60. 43 0
      graceful/dns/api/handler/gracefulhandler.go
  61. 19 0
      graceful/dns/api/handler/routes.go
  62. 7 0
      graceful/dns/api/svc/servicecontext.go
  63. 7 0
      graceful/dns/api/types/types.go
  64. 22 0
      graceful/dns/rpc/Dockerfile
  65. 4 0
      graceful/dns/rpc/etc/config.json
  66. 15 0
      graceful/dns/rpc/graceful.proto
  67. 159 0
      graceful/dns/rpc/graceful/graceful.pb.go
  68. 50 0
      graceful/dns/rpc/gracefulrpc.go
  69. 28 0
      graceful/etcd/api/Dockerfile
  70. 11 0
      graceful/etcd/api/config/config.go
  71. 12 0
      graceful/etcd/api/etc/graceful-api.json
  72. 11 0
      graceful/etcd/api/graceful.api
  73. 32 0
      graceful/etcd/api/graceful.go
  74. 43 0
      graceful/etcd/api/handler/gracefulhandler.go
  75. 19 0
      graceful/etcd/api/handler/routes.go
  76. 7 0
      graceful/etcd/api/svc/servicecontext.go
  77. 7 0
      graceful/etcd/api/types/types.go
  78. 4 0
      graceful/etcd/discov/discov-namespace.yaml
  79. 319 0
      graceful/etcd/discov/etcd.yaml
  80. 24 0
      graceful/etcd/rpc/Dockerfile
  81. 8 0
      graceful/etcd/rpc/etc/graceful-rpc.json
  82. 15 0
      graceful/etcd/rpc/graceful.proto
  83. 159 0
      graceful/etcd/rpc/graceful/graceful.pb.go
  84. 50 0
      graceful/etcd/rpc/gracefulrpc.go
  85. 170 0
      http/breaker/client/client.go
  86. 3 0
      http/breaker/good.sh
  87. 3 0
      http/breaker/heavy.sh
  88. 59 0
      http/breaker/server.go
  89. 5 0
      http/breaker/start.sh
  90. 70 0
      http/demo/main.go
  91. 65 0
      http/post/main.go
  92. 11 0
      http/shedding/Dockerfile
  93. 63 0
      http/shedding/main.go
  94. 67 0
      limit/period/periodlimit.go
  95. 66 0
      limit/token/tokenlimit.go
  96. 148 0
      load/main.go
  97. 14 0
      load/plot.py
  98. 95 0
      load/simulate/client/main.go
  99. 13 0
      load/simulate/client/plot.py
  100. 26 0
      load/simulate/cpu/Dockerfile

+ 22 - 0
.gitignore

@@ -0,0 +1,22 @@
+# Ignore all
+*
+
+# Unignore all with extensions
+!*.*
+!**/Dockerfile
+!**/Makefile
+
+# Unignore all dirs
+!*/
+!api
+
+.idea
+**/.DS_Store
+**/logs
+
+# gitlab ci
+.cache
+
+# vim auto backup file
+*~
+!OWNERS

+ 214 - 0
README.md

@@ -0,0 +1,214 @@
+<img align="right" width="150px" src="https://raw.githubusercontent.com/tal-tech/zero-doc/main/doc/images/go-zero.png">
+
+# go-zero
+
+English | [简体中文](readme-cn.md)
+
+[![Go](https://github.com/tal-tech/go-zero/workflows/Go/badge.svg?branch=master)](https://github.com/tal-tech/go-zero/actions)
+[![codecov](https://codecov.io/gh/tal-tech/go-zero/branch/master/graph/badge.svg)](https://codecov.io/gh/tal-tech/go-zero)
+[![Go Report Card](https://goreportcard.com/badge/github.com/tal-tech/go-zero)](https://goreportcard.com/report/github.com/tal-tech/go-zero)
+[![Release](https://img.shields.io/github/v/release/tal-tech/go-zero.svg?style=flat-square)](https://github.com/tal-tech/go-zero)
+[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
+
+## 0. what is go-zero
+
+go-zero is a web and rpc framework that with lots of engineering practices builtin. It’s born to ensure the stability of the busy services with resilience design, and has been serving sites with tens of millions users for years.
+
+go-zero contains simple API description syntax and code generation tool called `goctl`. You can generate Go, iOS, Android, Kotlin, Dart, TypeScript, JavaScript from .api files with `goctl`.
+
+Advantages of go-zero:
+
+* improve the stability of the services with tens of millions of daily active users
+* builtin chained timeout control, concurrency control, rate limit, adaptive circuit breaker, adaptive load shedding, even no configuration needed
+* builtin middlewares also can be integrated into your frameworks
+* simple API syntax, one command to generate couple of different languages
+* auto validate the request parameters from clients
+* plenty of builtin microservice management and concurrent toolkits
+
+<img src="https://raw.githubusercontent.com/tal-tech/zero-doc/main/doc/images/architecture-en.png" alt="Architecture" width="1500" />
+
+## 1. Backgrounds of go-zero
+
+At the beginning of 2018, we decided to re-design our system, from monolithic architecture with Java+MongoDB to microservice architecture. After researches and comparison, we chose to:
+
+* Golang based
+  * great performance
+  * simple syntax
+  * proven engineering efficiency
+  * extreme deployment experience
+  * less server resource consumption
+* Self-designed microservice architecture
+  * I have rich experience on designing microservice architectures
+  * easy to location the problems
+  * easy to extend the features
+
+## 2. Design considerations on go-zero
+
+By designing the microservice architecture, we expected to ensure the stability, as well as the productivity. And from just the beginning, we have the following design principles:
+
+* keep it simple
+* high availability
+* stable on high concurrency
+* easy to extend
+* resilience design, failure-oriented programming
+* try best to be friendly to the business logic development, encapsulate the complexity
+* one thing, one way
+
+After almost half a year, we finished the transfer from monolithic system to microservice system, and deployed on August 2018. The new system guaranteed the business growth, and the system stability.
+
+## 3. The implementation and features of go-zero
+
+go-zero is a web and rpc framework that integrates lots of engineering practices. The features are mainly listed below:
+
+* powerful tool included, less code to write
+* simple interfaces
+* fully compatible with net/http
+* middlewares are supported, easy to extend
+* high performance
+* failure-oriented programming, resilience design
+* builtin service discovery, load balancing
+* builtin concurrency control, adaptive circuit breaker, adaptive load shedding, auto trigger, auto recover
+* auto validation of API request parameters
+* chained timeout control
+* auto management of data caching
+* call tracing, metrics and monitoring
+* high concurrency protected
+
+As below, go-zero protects the system with couple layers and mechanisms:
+
+![Resilience](https://raw.githubusercontent.com/tal-tech/zero-doc/main/doc/images/resilience-en.png)
+
+## 4. Future development plans of go-zero
+
+* auto generate API mock server, make the client debugging easier
+* auto generate the simple integration test for the server side just from the .api files
+
+## 5. Installation
+
+Run the following command under your project:
+
+```shell
+go get -u github.com/tal-tech/go-zero
+```
+
+## 6. Quick Start
+
+0. full examples can be checked out from below:
+
+     [Rapid development of microservice systems](https://github.com/tal-tech/zero-doc/blob/main/doc/shorturl-en.md)
+
+     [Rapid development of microservice systems - multiple RPCs](https://github.com/tal-tech/zero-doc/blob/main/doc/bookstore-en.md)
+
+1. install goctl
+
+   `goctl`can be read as `go control`. `goctl` means not to be controlled by code, instead, we control it. The inside `go` is not `golang`. At the very beginning, I was expecting it to help us improve the productivity, and make our lives easier.
+
+   ```shell
+   GO111MODULE=on go get -u github.com/tal-tech/go-zero/tools/goctl
+   ```
+
+   make sure goctl is executable.
+
+2. create the API file, like greet.api, you can install the plugin of goctl in vs code, api syntax is supported.
+
+   ```go
+   type Request struct {
+     Name string `path:"name,options=you|me"` // parameters are auto validated
+   }
+
+   type Response struct {
+     Message string `json:"message"`
+   }
+
+   service greet-api {
+     @handler GreetHandler
+     get /greet/from/:name(Request) returns (Response);
+   }
+   ```
+   
+   the .api files also can be generate by goctl, like below:
+
+   ```shell
+   goctl api -o greet.api
+   ```
+   
+3. generate the go server side code
+
+   ```shell
+   goctl api go -api greet.api -dir greet
+   ```
+
+   the generated files look like:
+
+   ```Plain Text
+   ├── greet
+   │   ├── etc
+   │   │   └── greet-api.yaml        // configuration file
+   │   ├── greet.go                  // main file
+   │   └── internal
+   │       ├── config
+   │       │   └── config.go         // configuration definition
+   │       ├── handler
+   │       │   ├── greethandler.go   // get/put/post/delete routes are defined here
+   │       │   └── routes.go         // routes list
+   │       ├── logic
+   │       │   └── greetlogic.go     // request logic can be written here
+   │       ├── svc
+   │       │   └── servicecontext.go // service context, mysql/redis can be passed in here
+   │       └── types
+   │           └── types.go          // request/response defined here
+   └── greet.api                     // api description file
+   ```
+
+   the generated code can be run directly:
+
+   ```shell
+   cd greet
+   go mod init
+   go mod tidy
+   go run greet.go -f etc/greet-api.yaml
+   ```
+
+   by default, it’s listening on port 8888, while it can be changed in configuration file.
+
+   you can check it by curl:
+
+   ```shell
+   curl -i http://localhost:8888/greet/from/you
+   ```
+
+   the response looks like:
+
+   ```http
+   HTTP/1.1 200 OK
+   Date: Sun, 30 Aug 2020 15:32:35 GMT
+   Content-Length: 0
+   ```
+
+4. Write the business logic code
+
+    * the dependencies can be passed into the logic within servicecontext.go, like mysql, reds etc.
+    * add the logic code in logic package according to .api file
+
+5. Generate code like Java, TypeScript, Dart, JavaScript etc. just from the api file
+
+   ```shell
+   goctl api java -api greet.api -dir greet
+   goctl api dart -api greet.api -dir greet
+   ...
+   ```
+
+## 7. Benchmark
+
+![benchmark](https://raw.githubusercontent.com/tal-tech/zero-doc/main/doc/images/benchmark.png)
+
+[Checkout the test code](https://github.com/smallnest/go-web-framework-benchmark)
+
+## 8. Documents (adding)
+
+* [Rapid development of microservice systems](https://github.com/tal-tech/zero-doc/blob/main/doc/shorturl-en.md)
+* [Rapid development of microservice systems - multiple RPCs](https://github.com/tal-tech/zero-doc/blob/main/doc/bookstore-en.md)
+
+## 9. Chat group
+
+Join the chat via https://join.slack.com/t/go-zeroworkspace/shared_invite/zt-m39xssxc-kgIqERa7aVsujKNj~XuPKg

+ 18 - 0
bloom/bloom.go

@@ -0,0 +1,18 @@
+package main
+
+import (
+	"fmt"
+
+	"github.com/tal-tech/go-zero/core/bloom"
+	"github.com/tal-tech/go-zero/core/stores/redis"
+)
+
+func main() {
+	store := redis.NewRedis("localhost:6379", "node")
+	filter := bloom.New(store, "testbloom", 64)
+	filter.Add([]byte("kevin"))
+	filter.Add([]byte("wan"))
+	fmt.Println(filter.Exists([]byte("kevin")))
+	fmt.Println(filter.Exists([]byte("wan")))
+	fmt.Println(filter.Exists([]byte("nothing")))
+}

+ 29 - 0
bookstore/api/bookstore.api

@@ -0,0 +1,29 @@
+type (
+	addReq {
+		book string `form:"book"`
+		price int64 `form:"price"`
+	}
+	
+	addResp {
+		ok bool `json:"ok"`
+	}
+)
+
+type (
+	checkReq {
+		book string `form:"book"`
+	}
+	
+	checkResp {
+		found bool `json:"found"`
+		price int64 `json:"price"`
+	}
+)
+
+service bookstore-api {
+	@handler AddHandler
+	get /add (addReq) returns (addResp)
+	
+	@handler CheckHandler
+	get /check (checkReq) returns (checkResp)
+}

+ 31 - 0
bookstore/api/bookstore.go

@@ -0,0 +1,31 @@
+package main
+
+import (
+	"flag"
+	"fmt"
+
+	"bookstore/api/internal/config"
+	"bookstore/api/internal/handler"
+	"bookstore/api/internal/svc"
+
+	"github.com/tal-tech/go-zero/core/conf"
+	"github.com/tal-tech/go-zero/rest"
+)
+
+var configFile = flag.String("f", "etc/bookstore-api.yaml", "the config file")
+
+func main() {
+	flag.Parse()
+
+	var c config.Config
+	conf.MustLoad(*configFile, &c)
+
+	ctx := svc.NewServiceContext(c)
+	server := rest.MustNewServer(c.RestConf)
+	defer server.Stop()
+
+	handler.RegisterHandlers(server, ctx)
+
+	fmt.Printf("Starting server at %s:%d...\n", c.Host, c.Port)
+	server.Start()
+}

+ 13 - 0
bookstore/api/etc/bookstore-api.yaml

@@ -0,0 +1,13 @@
+Name: bookstore-api
+Host: 0.0.0.0
+Port: 8888
+Add:
+  Etcd:
+    Hosts:
+      - localhost:2379
+    Key: add.rpc
+Check:
+  Etcd:
+    Hosts:
+      - localhost:2379
+    Key: check.rpc

+ 12 - 0
bookstore/api/internal/config/config.go

@@ -0,0 +1,12 @@
+package config
+
+import (
+	"github.com/tal-tech/go-zero/rest"
+	"github.com/tal-tech/go-zero/zrpc"
+)
+
+type Config struct {
+	rest.RestConf
+	Add   zrpc.RpcClientConf
+	Check zrpc.RpcClientConf
+}

+ 29 - 0
bookstore/api/internal/handler/addhandler.go

@@ -0,0 +1,29 @@
+package handler
+
+import (
+	"net/http"
+
+	"bookstore/api/internal/logic"
+	"bookstore/api/internal/svc"
+	"bookstore/api/internal/types"
+
+	"github.com/tal-tech/go-zero/rest/httpx"
+)
+
+func AddHandler(ctx *svc.ServiceContext) http.HandlerFunc {
+	return func(w http.ResponseWriter, r *http.Request) {
+		var req types.AddReq
+		if err := httpx.Parse(r, &req); err != nil {
+			httpx.Error(w, err)
+			return
+		}
+
+		l := logic.NewAddLogic(r.Context(), ctx)
+		resp, err := l.Add(req)
+		if err != nil {
+			httpx.Error(w, err)
+		} else {
+			httpx.WriteJson(w, http.StatusOK, resp)
+		}
+	}
+}

+ 29 - 0
bookstore/api/internal/handler/checkhandler.go

@@ -0,0 +1,29 @@
+package handler
+
+import (
+	"net/http"
+
+	"bookstore/api/internal/logic"
+	"bookstore/api/internal/svc"
+	"bookstore/api/internal/types"
+
+	"github.com/tal-tech/go-zero/rest/httpx"
+)
+
+func CheckHandler(ctx *svc.ServiceContext) http.HandlerFunc {
+	return func(w http.ResponseWriter, r *http.Request) {
+		var req types.CheckReq
+		if err := httpx.Parse(r, &req); err != nil {
+			httpx.Error(w, err)
+			return
+		}
+
+		l := logic.NewCheckLogic(r.Context(), ctx)
+		resp, err := l.Check(req)
+		if err != nil {
+			httpx.Error(w, err)
+		} else {
+			httpx.WriteJson(w, http.StatusOK, resp)
+		}
+	}
+}

+ 27 - 0
bookstore/api/internal/handler/routes.go

@@ -0,0 +1,27 @@
+// Code generated by goctl. DO NOT EDIT.
+package handler
+
+import (
+	"net/http"
+
+	"bookstore/api/internal/svc"
+
+	"github.com/tal-tech/go-zero/rest"
+)
+
+func RegisterHandlers(engine *rest.Server, serverCtx *svc.ServiceContext) {
+	engine.AddRoutes(
+		[]rest.Route{
+			{
+				Method:  http.MethodGet,
+				Path:    "/add",
+				Handler: AddHandler(serverCtx),
+			},
+			{
+				Method:  http.MethodGet,
+				Path:    "/check",
+				Handler: CheckHandler(serverCtx),
+			},
+		},
+	)
+}

+ 39 - 0
bookstore/api/internal/logic/addlogic.go

@@ -0,0 +1,39 @@
+package logic
+
+import (
+	"context"
+
+	"bookstore/api/internal/svc"
+	"bookstore/api/internal/types"
+	"bookstore/rpc/add/adder"
+
+	"github.com/tal-tech/go-zero/core/logx"
+)
+
+type AddLogic struct {
+	logx.Logger
+	ctx    context.Context
+	svcCtx *svc.ServiceContext
+}
+
+func NewAddLogic(ctx context.Context, svcCtx *svc.ServiceContext) AddLogic {
+	return AddLogic{
+		Logger: logx.WithContext(ctx),
+		ctx:    ctx,
+		svcCtx: svcCtx,
+	}
+}
+
+func (l *AddLogic) Add(req types.AddReq) (*types.AddResp, error) {
+	resp, err := l.svcCtx.Adder.Add(l.ctx, &adder.AddReq{
+		Book:  req.Book,
+		Price: req.Price,
+	})
+	if err != nil {
+		return nil, err
+	}
+
+	return &types.AddResp{
+		Ok: resp.Ok,
+	}, nil
+}

+ 40 - 0
bookstore/api/internal/logic/checklogic.go

@@ -0,0 +1,40 @@
+package logic
+
+import (
+	"context"
+
+	"bookstore/api/internal/svc"
+	"bookstore/api/internal/types"
+	"bookstore/rpc/check/checker"
+
+	"github.com/tal-tech/go-zero/core/logx"
+)
+
+type CheckLogic struct {
+	logx.Logger
+	ctx    context.Context
+	svcCtx *svc.ServiceContext
+}
+
+func NewCheckLogic(ctx context.Context, svcCtx *svc.ServiceContext) CheckLogic {
+	return CheckLogic{
+		Logger: logx.WithContext(ctx),
+		ctx:    ctx,
+		svcCtx: svcCtx,
+	}
+}
+
+func (l *CheckLogic) Check(req types.CheckReq) (*types.CheckResp, error) {
+	resp, err := l.svcCtx.Checker.Check(l.ctx, &checker.CheckReq{
+		Book: req.Book,
+	})
+	if err != nil {
+		logx.Error(err)
+		return &types.CheckResp{}, err
+	}
+
+	return &types.CheckResp{
+		Found: resp.Found,
+		Price: resp.Price,
+	}, nil
+}

+ 23 - 0
bookstore/api/internal/svc/servicecontext.go

@@ -0,0 +1,23 @@
+package svc
+
+import (
+	"bookstore/api/internal/config"
+	"bookstore/rpc/add/adder"
+	"bookstore/rpc/check/checker"
+
+	"github.com/tal-tech/go-zero/zrpc"
+)
+
+type ServiceContext struct {
+	Config  config.Config
+	Adder   adder.Adder
+	Checker checker.Checker
+}
+
+func NewServiceContext(c config.Config) *ServiceContext {
+	return &ServiceContext{
+		Config:  c,
+		Adder:   adder.NewAdder(zrpc.MustNewClient(c.Add)),
+		Checker: checker.NewChecker(zrpc.MustNewClient(c.Check)),
+	}
+}

+ 20 - 0
bookstore/api/internal/types/types.go

@@ -0,0 +1,20 @@
+// Code generated by goctl. DO NOT EDIT.
+package types
+
+type AddReq struct {
+	Book  string `form:"book"`
+	Price int64  `form:"price"`
+}
+
+type AddResp struct {
+	Ok bool `json:"ok"`
+}
+
+type CheckReq struct {
+	Book string `form:"book"`
+}
+
+type CheckResp struct {
+	Found bool  `json:"found"`
+	Price int64 `json:"price"`
+}

+ 21 - 0
bookstore/go.mod

@@ -0,0 +1,21 @@
+module bookstore
+
+go 1.15
+
+require (
+	github.com/alicebob/miniredis v2.5.0+incompatible // indirect
+	github.com/dchest/siphash v1.2.1 // indirect
+	github.com/go-sql-driver/mysql v1.6.0 // indirect
+	github.com/golang/mock v1.4.3
+	github.com/golang/protobuf v1.4.2
+	github.com/gomodule/redigo v2.0.0+incompatible // indirect
+	github.com/google/gops v0.3.7 // indirect
+	github.com/iancoleman/strcase v0.1.3 // indirect
+	github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 // indirect
+	github.com/tal-tech/go-zero v1.1.7
+	github.com/zeromicro/antlr v1.0.0 // indirect
+	go.uber.org/automaxprocs v1.4.0 // indirect
+	golang.org/x/net v0.0.0-20200707034311-ab3426394381
+	google.golang.org/grpc v1.29.1
+	google.golang.org/protobuf v1.25.0
+)

+ 441 - 0
bookstore/go.sum

@@ -0,0 +1,441 @@
+cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/ClickHouse/clickhouse-go v1.4.3/go.mod h1:EaI/sW7Azgz9UATzd5ZdZHRUhHgv5+JMS9NSr2smCJI=
+github.com/DATA-DOG/go-sqlmock v1.4.1 h1:ThlnYciV1iM/V0OSF/dtkqWb6xo5qITT1TJBG1MRDJM=
+github.com/DATA-DOG/go-sqlmock v1.4.1/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
+github.com/StackExchange/wmi v0.0.0-20170410192909-ea383cf3ba6e/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
+github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
+github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
+github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
+github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
+github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6 h1:45bxf7AZMwWcqkLzDAQugVEwedisr5nRJ1r+7LYnv0U=
+github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc=
+github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc=
+github.com/alicebob/miniredis v2.5.0+incompatible h1:yBHoLpsyjupjz3NL3MhKMVkR41j82Yjf3KFv7ApYzUI=
+github.com/alicebob/miniredis v2.5.0+incompatible/go.mod h1:8HZjEj4yU0dwhYHky+DxYx+6BMjkBbe5ONFIF1MXffk=
+github.com/alicebob/miniredis/v2 v2.14.1/go.mod h1:uS970Sw5Gs9/iK3yBg0l9Uj9s25wXxSpQUE9EaJ/Blg=
+github.com/antihax/optional v0.0.0-20180407024304-ca021399b1a6/go.mod h1:V8iCPQYkqmusNa815XgQio277wI47sdRh1dUOLdyC6Q=
+github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
+github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
+github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
+github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
+github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
+github.com/bkaradzic/go-lz4 v1.0.0/go.mod h1:0YdlkowM3VswSROI7qDxhRvJ3sLhlFrRRwjwegp5jy4=
+github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
+github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
+github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
+github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
+github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
+github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
+github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h4xcZ5GoxqC5SDxFQ8gwyZPKQoEzownBlhI80=
+github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
+github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa h1:OaNxuTZr7kxeODyLWsRMC+OD03aFUH+mW6r2d+MWa5Y=
+github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
+github.com/coreos/go-semver v0.2.0 h1:3Jm3tLmsgAYcjC+4Up7hJrFBPr+n7rAqYeSw/SZazuY=
+github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
+github.com/coreos/go-systemd/v22 v22.0.0 h1:XJIw/+VlJ+87J+doOxznsAWIdmWuViOVhkQamW5YV28=
+github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk=
+github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
+github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM=
+github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
+github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/dchest/siphash v1.2.1/go.mod h1:q+IRvb2gOSrUnYoPqHiyHXS0FOBBOdl6tONBlVnOnt4=
+github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
+github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
+github.com/dsymonds/gotoc v0.0.0-20160928043926-5aebcfc91819/go.mod h1:MvzMVHq8BH2Ji/o8TGDocVA70byvLrAgFTxkEnmjO4Y=
+github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4 h1:qk/FSDDxo05wdJH28W+p5yivv7LuLYLRXPPD8KQCtZs=
+github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
+github.com/emicklei/proto v1.9.0 h1:l0QiNT6Qs7Yj0Mb4X6dnWBQer4ebei2BFcgQLbGqUDc=
+github.com/emicklei/proto v1.9.0/go.mod h1:rn1FgRS/FANiZdD2djyH7TMA9jdRDcYQ9IEN9yvjX0A=
+github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
+github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
+github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
+github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
+github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4=
+github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94=
+github.com/frankban/quicktest v1.7.2/go.mod h1:jaStnuzAqU1AJdCO0l53JDCJrVDKcS03DbaAcR7Ks/o=
+github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
+github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
+github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
+github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
+github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
+github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
+github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8=
+github.com/go-redis/redis v6.15.7+incompatible h1:3skhDh95XQMpnqeqNftPkQD9jL9e5e36z/1SUm6dy1U=
+github.com/go-redis/redis v6.15.7+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
+github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
+github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
+github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
+github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
+github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
+github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
+github.com/go-xorm/builder v0.3.4 h1:FxkeGB4Cggdw3tPwutLCpfjng2jugfkg6LDMrd/KsoY=
+github.com/go-xorm/builder v0.3.4/go.mod h1:KxkQkNN1DpPKTedxXyTQcmH+rXfvk4LZ9SOOBoZBAxw=
+github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:9wScpmSP5A3Bk8V3XHWUcJmYTh+ZnlHVyc+A4oZYS3Y=
+github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:56xuuqnHyryaerycW3BfssRdxQstACi0Epw/yC5E2xM=
+github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
+github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
+github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
+github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=
+github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
+github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
+github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY=
+github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/mock v1.4.3 h1:GV+pQPG/EUUbkh47niozDcADz6go/dUwhVzdUQHIVRw=
+github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
+github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
+github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
+github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
+github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
+github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
+github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
+github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
+github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+github.com/gomodule/redigo v2.0.0+incompatible h1:K/R+8tc58AaqLkqG2Ol3Qk+DR/TlNuhuh457pBFPtt0=
+github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
+github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo=
+github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
+github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w=
+github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/gops v0.3.7/go.mod h1:bj0cwMmX1X4XIJFTjR99R5sCxNssNJ8HebFNvoQlmgY=
+github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
+github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
+github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
+github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
+github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
+github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4 h1:z53tR0945TRRQO/fLEVPI6SMv7ZflF0TEaTAoU7tOzg=
+github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
+github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho=
+github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
+github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
+github.com/grpc-ecosystem/grpc-gateway v1.14.3 h1:OCJlWkOUoTnl0neNGlf4fUm3TmbEtguw7vR+nGtnDjY=
+github.com/grpc-ecosystem/grpc-gateway v1.14.3/go.mod h1:6CwZWGDSPRJidgKAtJVvND6soZe6fT7iteq8wDPdhb0=
+github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI=
+github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
+github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
+github.com/iancoleman/strcase v0.0.0-20191112232945-16388991a334/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE=
+github.com/iancoleman/strcase v0.1.2/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE=
+github.com/iancoleman/strcase v0.1.3 h1:dJBk1m2/qjL1twPLf68JND55vvivMupZ4wIzE8CTdBw=
+github.com/iancoleman/strcase v0.1.3/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE=
+github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
+github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks=
+github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo=
+github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
+github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
+github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns=
+github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
+github.com/justinas/alice v1.2.0 h1:+MHSA/vccVCF4Uq37S42jwlkvI2Xzl7zTPCN5BnZNVo=
+github.com/justinas/alice v1.2.0/go.mod h1:fN5HRH/reO/zrUflLfTN43t3vXvKzvZIENsNEe7i7qA=
+github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
+github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
+github.com/keybase/go-ps v0.0.0-20161005175911-668c8856d999/go.mod h1:hY+WOq6m2FpbvyrI93sMaypsttvaIL5nhVR92dTMUcQ=
+github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
+github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
+github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
+github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=
+github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
+github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs=
+github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
+github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
+github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8=
+github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
+github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
+github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
+github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
+github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
+github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
+github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
+github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
+github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
+github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
+github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
+github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
+github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
+github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
+github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
+github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
+github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms=
+github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
+github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA=
+github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs=
+github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/gomega v1.5.0 h1:izbySO9zDPmjJ8rDjLvkA2zJHIo+HkYXHnf7eN7SSyo=
+github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
+github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
+github.com/pierrec/lz4 v2.5.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
+github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
+github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
+github.com/prometheus/client_golang v1.5.1 h1:bdHYieyGlH+6OLEk2YQha8THib30KP0/yD0YH9m6xcA=
+github.com/prometheus/client_golang v1.5.1/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=
+github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
+github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
+github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
+github.com/prometheus/common v0.9.1 h1:KOMtN28tlbam3/7ZKEYKHhKoJZYYj3gMH4uc62x7X7U=
+github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4=
+github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
+github.com/prometheus/procfs v0.0.8 h1:+fpWZdT24pJBiqJdAwYBjPSk+5YmQzYNPYzQsdzLkt8=
+github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
+github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
+github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
+github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
+github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
+github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
+github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
+github.com/shirou/gopsutil v0.0.0-20180427012116-c95755e4bcd7/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
+github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc=
+github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
+github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
+github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
+github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
+github.com/soheilhy/cmux v0.1.4 h1:0HKaf1o97UwFjHH9o5XsHUOF+tqmdA7KEzXLpiyaw0E=
+github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
+github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
+github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
+github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
+github.com/spf13/pflag v1.0.1 h1:aCvUg6QPl3ibpQUxyLkrEkCHtPqYJL4x9AuhqVqFis4=
+github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
+github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
+github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
+github.com/tal-tech/go-zero v1.0.16 h1:oT7sOFftEUdD/XcXF0xEugX9yhnw4DcQkeMNFLi5KO8=
+github.com/tal-tech/go-zero v1.0.16/go.mod h1:y2wBHTkxNJw79K9/wCSeDKzv2pCT6x45oOmXEsJdQK8=
+github.com/tal-tech/go-zero v1.0.27 h1:QMIbaTxibMc/OsO5RTAuKZ8ndbl2dGN6pITQEtp2x/A=
+github.com/tal-tech/go-zero v1.0.27/go.mod h1:JtNXlsh/CgeIHyQnt5C5M2IcSevW7V0NAnqO93TQgm8=
+github.com/tal-tech/go-zero v1.1.7 h1:rs78kI5ZiBx1RIl562qDzkBV8P7CdnbCiljknyC4mXg=
+github.com/tal-tech/go-zero v1.1.7/go.mod h1:BEylLQnv5moldpMT1lH3kUoMEcdaIp+r9Lgp+41dXxg=
+github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
+github.com/tmc/grpc-websocket-proxy v0.0.0-20171017195756-830351dc03c6 h1:lYIiVDtZnyTWlNwiAxLj0bbpTcx1BWCFhXjfsvmPdNc=
+github.com/tmc/grpc-websocket-proxy v0.0.0-20171017195756-830351dc03c6/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
+github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
+github.com/urfave/cli v1.22.4/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
+github.com/urfave/cli v1.22.5 h1:lNq9sAHXK2qfdI8W+GRItjCEkI+2oR4d+MEHy1CKXoU=
+github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
+github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8=
+github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
+github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg=
+github.com/xwb1989/sqlparser v0.0.0-20180606152119-120387863bf2 h1:zzrxE1FKn5ryBNl9eKOeqQ58Y/Qpo3Q9QNxKHX5uzzQ=
+github.com/xwb1989/sqlparser v0.0.0-20180606152119-120387863bf2/go.mod h1:hzfGeIUDq/j97IG+FhNqkowIyEcD88LrW6fyU3K3WqY=
+github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/gopher-lua v0.0.0-20191220021717-ab39c6098bdb h1:ZkM6LRnq40pR1Ox0hTHlnpkcOTuFIDQpZ1IN8rKKhX0=
+github.com/yuin/gopher-lua v0.0.0-20191220021717-ab39c6098bdb/go.mod h1:gqRgreBUhTSL0GeU64rtZ3Uq3wtjOa/TB2YfrtkCbVQ=
+github.com/zeromicro/antlr v0.0.1/go.mod h1:nfpjEwFR6Q4xGDJMcZnCL9tEfQRgszMwu3rDz2Z+p5M=
+github.com/zeromicro/antlr v1.0.0 h1:XqOf69i6619D3FveNpToDbqkLckw06o9M0+6E1R3jVE=
+github.com/zeromicro/antlr v1.0.0/go.mod h1:nfpjEwFR6Q4xGDJMcZnCL9tEfQRgszMwu3rDz2Z+p5M=
+go.etcd.io/bbolt v1.3.4 h1:hi1bXHMVrlQh6WwxAy+qZCV/SYIlqo+Ushwdpa4tAKg=
+go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
+go.etcd.io/etcd v0.0.0-20200402134248-51bdeb39e698 h1:jWtjCJX1qxhHISBMLRztWwR+EXkI7MJAF2HjHAE/x/I=
+go.etcd.io/etcd v0.0.0-20200402134248-51bdeb39e698/go.mod h1:YoUyTScD3Vcv2RBm3eGVOq7i1ULiz3OuXoQFWOirmAM=
+go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk=
+go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
+go.uber.org/automaxprocs v1.3.0 h1:II28aZoGdaglS5vVNnspf28lnZpXScxtIozx1lAjdb0=
+go.uber.org/automaxprocs v1.3.0/go.mod h1:9CWT6lKIep8U41DDaPiH6eFscnTyjfTANNQNx6LrIcA=
+go.uber.org/automaxprocs v1.4.0 h1:CpDZl6aOlLhReez+8S3eEotD7Jx0Os++lemPlMULQP0=
+go.uber.org/automaxprocs v1.4.0/go.mod h1:/mTEdr7LvHhs0v7mjdxDreTz1OG5zdZGqgOnhWiR/+Q=
+go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A=
+go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
+go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4=
+go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
+go.uber.org/zap v1.14.1 h1:nYDKopTbvAPq/NrUVZwT15y2lpROBiLLyoRTbXOYWOo=
+go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc=
+golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
+golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
+golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k=
+golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
+golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
+golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
+golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ=
+golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20191002035440-2ec189313ef0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU=
+golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20171017063910-8dbc5d05d6ed/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1 h1:sIky/MyNRSHTrdxfsiUSS4WIAMvInbeXljJz+jDjeYE=
+golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs=
+golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
+golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200410132612-ae9902aceb98 h1:ibc1eDGW5ajwA4qzFTj0WHlD9eofMe1gAre+A0a3Vhs=
+golang.org/x/tools v0.0.0-20200410132612-ae9902aceb98/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
+google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20190927181202-20e1ac93f88c/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
+google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
+google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f h1:ohwtWcCwB/fZUxh/vjazHorYmBnua3NmY3CAjwC7mEA=
+google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
+google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
+google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA=
+google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
+google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.29.1 h1:EC2SB8S04d2r73uptxphDSUG+kTKVgjRPF+N3xpxRB4=
+google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
+google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
+google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
+google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
+google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
+google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
+google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
+google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
+google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
+gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
+gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
+gopkg.in/cheggaaa/pb.v1 v1.0.28/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
+gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
+gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
+gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
+gopkg.in/h2non/gock.v1 v1.0.15/go.mod h1:sX4zAkdYX1TRGJ2JY156cFspQn4yRWn6p9EMdODlynE=
+gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
+gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
+gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
+gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
+gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
+gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
+honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
+honnef.co/go/tools v0.0.1-2020.1.4 h1:UoveltGrhghAA7ePc+e+QYDHXrBps2PqFZiHkGR/xK8=
+honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
+rsc.io/goversion v1.0.0/go.mod h1:Eih9y/uIBS3ulggl7KNJ09xGSLcuNaLgmvvqa07sgfo=
+rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
+rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
+sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
+sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=
+sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=

+ 38 - 0
bookstore/rpc/add/add.go

@@ -0,0 +1,38 @@
+// Code generated by goctl. DO NOT EDIT!
+// Source: add.proto
+
+package main
+
+import (
+	"flag"
+	"fmt"
+
+	"bookstore/rpc/add/add"
+	"bookstore/rpc/add/internal/config"
+	"bookstore/rpc/add/internal/server"
+	"bookstore/rpc/add/internal/svc"
+
+	"github.com/tal-tech/go-zero/core/conf"
+	"github.com/tal-tech/go-zero/core/logx"
+	"github.com/tal-tech/go-zero/zrpc"
+	"google.golang.org/grpc"
+)
+
+var configFile = flag.String("f", "etc/add.yaml", "the config file")
+
+func main() {
+	flag.Parse()
+
+	var c config.Config
+	conf.MustLoad(*configFile, &c)
+	ctx := svc.NewServiceContext(c)
+	adderSrv := server.NewAdderServer(ctx)
+
+	s, err := zrpc.NewServer(c.RpcServerConf, func(grpcServer *grpc.Server) {
+		add.RegisterAdderServer(grpcServer, adderSrv)
+	})
+	logx.Must(err)
+
+	fmt.Printf("Starting rpc server at %s...\n", c.ListenOn)
+	s.Start()
+}

+ 16 - 0
bookstore/rpc/add/add.proto

@@ -0,0 +1,16 @@
+syntax = "proto3";
+
+package add;
+
+message addReq {
+    string book = 1;
+    int64 price = 2;
+}
+
+message addResp {
+    bool ok = 1;
+}
+
+service adder {
+    rpc add(addReq) returns(addResp);
+}

+ 305 - 0
bookstore/rpc/add/add/add.pb.go

@@ -0,0 +1,305 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.25.0
+// 	protoc        v3.14.0
+// source: add.proto
+
+package add
+
+import (
+	context "context"
+	proto "github.com/golang/protobuf/proto"
+	grpc "google.golang.org/grpc"
+	codes "google.golang.org/grpc/codes"
+	status "google.golang.org/grpc/status"
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+	reflect "reflect"
+	sync "sync"
+)
+
+const (
+	// Verify that this generated code is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+	// Verify that runtime/protoimpl is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+// This is a compile-time assertion that a sufficiently up-to-date version
+// of the legacy proto package is being used.
+const _ = proto.ProtoPackageIsVersion4
+
+type AddReq struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Book  string `protobuf:"bytes,1,opt,name=book,proto3" json:"book,omitempty"`
+	Price int64  `protobuf:"varint,2,opt,name=price,proto3" json:"price,omitempty"`
+}
+
+func (x *AddReq) Reset() {
+	*x = AddReq{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_add_proto_msgTypes[0]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *AddReq) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*AddReq) ProtoMessage() {}
+
+func (x *AddReq) ProtoReflect() protoreflect.Message {
+	mi := &file_add_proto_msgTypes[0]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use AddReq.ProtoReflect.Descriptor instead.
+func (*AddReq) Descriptor() ([]byte, []int) {
+	return file_add_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *AddReq) GetBook() string {
+	if x != nil {
+		return x.Book
+	}
+	return ""
+}
+
+func (x *AddReq) GetPrice() int64 {
+	if x != nil {
+		return x.Price
+	}
+	return 0
+}
+
+type AddResp struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Ok bool `protobuf:"varint,1,opt,name=ok,proto3" json:"ok,omitempty"`
+}
+
+func (x *AddResp) Reset() {
+	*x = AddResp{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_add_proto_msgTypes[1]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *AddResp) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*AddResp) ProtoMessage() {}
+
+func (x *AddResp) ProtoReflect() protoreflect.Message {
+	mi := &file_add_proto_msgTypes[1]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use AddResp.ProtoReflect.Descriptor instead.
+func (*AddResp) Descriptor() ([]byte, []int) {
+	return file_add_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *AddResp) GetOk() bool {
+	if x != nil {
+		return x.Ok
+	}
+	return false
+}
+
+var File_add_proto protoreflect.FileDescriptor
+
+var file_add_proto_rawDesc = []byte{
+	0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x03, 0x61, 0x64, 0x64,
+	0x22, 0x32, 0x0a, 0x06, 0x61, 0x64, 0x64, 0x52, 0x65, 0x71, 0x12, 0x12, 0x0a, 0x04, 0x62, 0x6f,
+	0x6f, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x62, 0x6f, 0x6f, 0x6b, 0x12, 0x14,
+	0x0a, 0x05, 0x70, 0x72, 0x69, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x70,
+	0x72, 0x69, 0x63, 0x65, 0x22, 0x19, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x52, 0x65, 0x73, 0x70, 0x12,
+	0x0e, 0x0a, 0x02, 0x6f, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x02, 0x6f, 0x6b, 0x32,
+	0x29, 0x0a, 0x05, 0x61, 0x64, 0x64, 0x65, 0x72, 0x12, 0x20, 0x0a, 0x03, 0x61, 0x64, 0x64, 0x12,
+	0x0b, 0x2e, 0x61, 0x64, 0x64, 0x2e, 0x61, 0x64, 0x64, 0x52, 0x65, 0x71, 0x1a, 0x0c, 0x2e, 0x61,
+	0x64, 0x64, 0x2e, 0x61, 0x64, 0x64, 0x52, 0x65, 0x73, 0x70, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
+	0x6f, 0x33,
+}
+
+var (
+	file_add_proto_rawDescOnce sync.Once
+	file_add_proto_rawDescData = file_add_proto_rawDesc
+)
+
+func file_add_proto_rawDescGZIP() []byte {
+	file_add_proto_rawDescOnce.Do(func() {
+		file_add_proto_rawDescData = protoimpl.X.CompressGZIP(file_add_proto_rawDescData)
+	})
+	return file_add_proto_rawDescData
+}
+
+var file_add_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
+var file_add_proto_goTypes = []interface{}{
+	(*AddReq)(nil),  // 0: add.addReq
+	(*AddResp)(nil), // 1: add.addResp
+}
+var file_add_proto_depIdxs = []int32{
+	0, // 0: add.adder.add:input_type -> add.addReq
+	1, // 1: add.adder.add:output_type -> add.addResp
+	1, // [1:2] is the sub-list for method output_type
+	0, // [0:1] is the sub-list for method input_type
+	0, // [0:0] is the sub-list for extension type_name
+	0, // [0:0] is the sub-list for extension extendee
+	0, // [0:0] is the sub-list for field type_name
+}
+
+func init() { file_add_proto_init() }
+func file_add_proto_init() {
+	if File_add_proto != nil {
+		return
+	}
+	if !protoimpl.UnsafeEnabled {
+		file_add_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*AddReq); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_add_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*AddResp); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: file_add_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   2,
+			NumExtensions: 0,
+			NumServices:   1,
+		},
+		GoTypes:           file_add_proto_goTypes,
+		DependencyIndexes: file_add_proto_depIdxs,
+		MessageInfos:      file_add_proto_msgTypes,
+	}.Build()
+	File_add_proto = out.File
+	file_add_proto_rawDesc = nil
+	file_add_proto_goTypes = nil
+	file_add_proto_depIdxs = nil
+}
+
+// Reference imports to suppress errors if they are not otherwise used.
+var _ context.Context
+var _ grpc.ClientConnInterface
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the grpc package it is being compiled against.
+const _ = grpc.SupportPackageIsVersion6
+
+// AdderClient is the client API for Adder service.
+//
+// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
+type AdderClient interface {
+	Add(ctx context.Context, in *AddReq, opts ...grpc.CallOption) (*AddResp, error)
+}
+
+type adderClient struct {
+	cc grpc.ClientConnInterface
+}
+
+func NewAdderClient(cc grpc.ClientConnInterface) AdderClient {
+	return &adderClient{cc}
+}
+
+func (c *adderClient) Add(ctx context.Context, in *AddReq, opts ...grpc.CallOption) (*AddResp, error) {
+	out := new(AddResp)
+	err := c.cc.Invoke(ctx, "/add.adder/add", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+// AdderServer is the server API for Adder service.
+type AdderServer interface {
+	Add(context.Context, *AddReq) (*AddResp, error)
+}
+
+// UnimplementedAdderServer can be embedded to have forward compatible implementations.
+type UnimplementedAdderServer struct {
+}
+
+func (*UnimplementedAdderServer) Add(context.Context, *AddReq) (*AddResp, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method Add not implemented")
+}
+
+func RegisterAdderServer(s *grpc.Server, srv AdderServer) {
+	s.RegisterService(&_Adder_serviceDesc, srv)
+}
+
+func _Adder_Add_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(AddReq)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(AdderServer).Add(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/add.adder/Add",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(AdderServer).Add(ctx, req.(*AddReq))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+var _Adder_serviceDesc = grpc.ServiceDesc{
+	ServiceName: "add.adder",
+	HandlerType: (*AdderServer)(nil),
+	Methods: []grpc.MethodDesc{
+		{
+			MethodName: "add",
+			Handler:    _Adder_Add_Handler,
+		},
+	},
+	Streams:  []grpc.StreamDesc{},
+	Metadata: "add.proto",
+}

+ 38 - 0
bookstore/rpc/add/adder/adder.go

@@ -0,0 +1,38 @@
+// Code generated by goctl. DO NOT EDIT!
+// Source: add.proto
+
+//go:generate mockgen -destination ./adder_mock.go -package adder -source $GOFILE
+
+package adder
+
+import (
+	"context"
+
+	"bookstore/rpc/add/add"
+
+	"github.com/tal-tech/go-zero/zrpc"
+)
+
+type (
+	AddReq  = add.AddReq
+	AddResp = add.AddResp
+
+	Adder interface {
+		Add(ctx context.Context, in *AddReq) (*AddResp, error)
+	}
+
+	defaultAdder struct {
+		cli zrpc.Client
+	}
+)
+
+func NewAdder(cli zrpc.Client) Adder {
+	return &defaultAdder{
+		cli: cli,
+	}
+}
+
+func (m *defaultAdder) Add(ctx context.Context, in *AddReq) (*AddResp, error) {
+	client := add.NewAdderClient(m.cli.Conn())
+	return client.Add(ctx, in)
+}

+ 10 - 0
bookstore/rpc/add/etc/add.yaml

@@ -0,0 +1,10 @@
+Name: add.rpc
+ListenOn: 127.0.0.1:8080
+Etcd:
+  Hosts:
+  - 127.0.0.1:2379
+  Key: add.rpc
+DataSource: root:@tcp(localhost:3306)/gozero
+Table: book
+Cache:
+  - Host: localhost:6379

+ 12 - 0
bookstore/rpc/add/internal/config/config.go

@@ -0,0 +1,12 @@
+package config
+
+import (
+	"github.com/tal-tech/go-zero/core/stores/cache"
+	"github.com/tal-tech/go-zero/zrpc"
+)
+
+type Config struct {
+	zrpc.RpcServerConf
+	DataSource string
+	Cache      cache.CacheConf
+}

+ 39 - 0
bookstore/rpc/add/internal/logic/addlogic.go

@@ -0,0 +1,39 @@
+package logic
+
+import (
+	"context"
+
+	add "bookstore/rpc/add/adder"
+	"bookstore/rpc/add/internal/svc"
+	"bookstore/rpc/model"
+
+	"github.com/tal-tech/go-zero/core/logx"
+)
+
+type AddLogic struct {
+	ctx    context.Context
+	svcCtx *svc.ServiceContext
+	logx.Logger
+}
+
+func NewAddLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AddLogic {
+	return &AddLogic{
+		ctx:    ctx,
+		svcCtx: svcCtx,
+		Logger: logx.WithContext(ctx),
+	}
+}
+
+func (l *AddLogic) Add(in *add.AddReq) (*add.AddResp, error) {
+	_, err := l.svcCtx.Model.Insert(model.Book{
+		Book:  in.Book,
+		Price: in.Price,
+	})
+	if err != nil {
+		return nil, err
+	}
+
+	return &add.AddResp{
+		Ok: true,
+	}, nil
+}

+ 27 - 0
bookstore/rpc/add/internal/server/adderserver.go

@@ -0,0 +1,27 @@
+// Code generated by goctl. DO NOT EDIT!
+// Source: add.proto
+
+package server
+
+import (
+	"context"
+
+	"bookstore/rpc/add/add"
+	"bookstore/rpc/add/internal/logic"
+	"bookstore/rpc/add/internal/svc"
+)
+
+type AdderServer struct {
+	svcCtx *svc.ServiceContext
+}
+
+func NewAdderServer(svcCtx *svc.ServiceContext) *AdderServer {
+	return &AdderServer{
+		svcCtx: svcCtx,
+	}
+}
+
+func (s *AdderServer) Add(ctx context.Context, in *add.AddReq) (*add.AddResp, error) {
+	l := logic.NewAddLogic(ctx, s.svcCtx)
+	return l.Add(in)
+}

+ 20 - 0
bookstore/rpc/add/internal/svc/servicecontext.go

@@ -0,0 +1,20 @@
+package svc
+
+import (
+	"bookstore/rpc/add/internal/config"
+	"bookstore/rpc/model"
+
+	"github.com/tal-tech/go-zero/core/stores/sqlx"
+)
+
+type ServiceContext struct {
+	c     config.Config
+	Model model.BookModel
+}
+
+func NewServiceContext(c config.Config) *ServiceContext {
+	return &ServiceContext{
+		c:     c,
+		Model: model.NewBookModel(sqlx.NewMysql(c.DataSource), c.Cache),
+	}
+}

+ 38 - 0
bookstore/rpc/check/check.go

@@ -0,0 +1,38 @@
+// Code generated by goctl. DO NOT EDIT!
+// Source: check.proto
+
+package main
+
+import (
+	"flag"
+	"fmt"
+
+	"bookstore/rpc/check/check"
+	"bookstore/rpc/check/internal/config"
+	"bookstore/rpc/check/internal/server"
+	"bookstore/rpc/check/internal/svc"
+
+	"github.com/tal-tech/go-zero/core/conf"
+	"github.com/tal-tech/go-zero/core/logx"
+	"github.com/tal-tech/go-zero/zrpc"
+	"google.golang.org/grpc"
+)
+
+var configFile = flag.String("f", "etc/check.yaml", "the config file")
+
+func main() {
+	flag.Parse()
+
+	var c config.Config
+	conf.MustLoad(*configFile, &c)
+	ctx := svc.NewServiceContext(c)
+	checkerSrv := server.NewCheckerServer(ctx)
+
+	s, err := zrpc.NewServer(c.RpcServerConf, func(grpcServer *grpc.Server) {
+		check.RegisterCheckerServer(grpcServer, checkerSrv)
+	})
+	logx.Must(err)
+
+	fmt.Printf("Starting rpc server at %s...\n", c.ListenOn)
+	s.Start()
+}

+ 16 - 0
bookstore/rpc/check/check.proto

@@ -0,0 +1,16 @@
+syntax = "proto3";
+
+package check;
+
+message checkReq {
+    string book = 1;
+}
+
+message checkResp {
+    bool found = 1;
+    int64 price = 2;
+}
+
+service checker {
+    rpc check(checkReq) returns(checkResp);
+}

+ 306 - 0
bookstore/rpc/check/check/check.pb.go

@@ -0,0 +1,306 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.25.0
+// 	protoc        v3.14.0
+// source: check.proto
+
+package check
+
+import (
+	context "context"
+	proto "github.com/golang/protobuf/proto"
+	grpc "google.golang.org/grpc"
+	codes "google.golang.org/grpc/codes"
+	status "google.golang.org/grpc/status"
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+	reflect "reflect"
+	sync "sync"
+)
+
+const (
+	// Verify that this generated code is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+	// Verify that runtime/protoimpl is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+// This is a compile-time assertion that a sufficiently up-to-date version
+// of the legacy proto package is being used.
+const _ = proto.ProtoPackageIsVersion4
+
+type CheckReq struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Book string `protobuf:"bytes,1,opt,name=book,proto3" json:"book,omitempty"`
+}
+
+func (x *CheckReq) Reset() {
+	*x = CheckReq{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_check_proto_msgTypes[0]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *CheckReq) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*CheckReq) ProtoMessage() {}
+
+func (x *CheckReq) ProtoReflect() protoreflect.Message {
+	mi := &file_check_proto_msgTypes[0]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use CheckReq.ProtoReflect.Descriptor instead.
+func (*CheckReq) Descriptor() ([]byte, []int) {
+	return file_check_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *CheckReq) GetBook() string {
+	if x != nil {
+		return x.Book
+	}
+	return ""
+}
+
+type CheckResp struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Found bool  `protobuf:"varint,1,opt,name=found,proto3" json:"found,omitempty"`
+	Price int64 `protobuf:"varint,2,opt,name=price,proto3" json:"price,omitempty"`
+}
+
+func (x *CheckResp) Reset() {
+	*x = CheckResp{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_check_proto_msgTypes[1]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *CheckResp) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*CheckResp) ProtoMessage() {}
+
+func (x *CheckResp) ProtoReflect() protoreflect.Message {
+	mi := &file_check_proto_msgTypes[1]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use CheckResp.ProtoReflect.Descriptor instead.
+func (*CheckResp) Descriptor() ([]byte, []int) {
+	return file_check_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *CheckResp) GetFound() bool {
+	if x != nil {
+		return x.Found
+	}
+	return false
+}
+
+func (x *CheckResp) GetPrice() int64 {
+	if x != nil {
+		return x.Price
+	}
+	return 0
+}
+
+var File_check_proto protoreflect.FileDescriptor
+
+var file_check_proto_rawDesc = []byte{
+	0x0a, 0x0b, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x05, 0x63,
+	0x68, 0x65, 0x63, 0x6b, 0x22, 0x1e, 0x0a, 0x08, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x71,
+	0x12, 0x12, 0x0a, 0x04, 0x62, 0x6f, 0x6f, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04,
+	0x62, 0x6f, 0x6f, 0x6b, 0x22, 0x37, 0x0a, 0x09, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73,
+	0x70, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08,
+	0x52, 0x05, 0x66, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x70, 0x72, 0x69, 0x63, 0x65,
+	0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x70, 0x72, 0x69, 0x63, 0x65, 0x32, 0x35, 0x0a,
+	0x07, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x65, 0x72, 0x12, 0x2a, 0x0a, 0x05, 0x63, 0x68, 0x65, 0x63,
+	0x6b, 0x12, 0x0f, 0x2e, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x2e, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x52,
+	0x65, 0x71, 0x1a, 0x10, 0x2e, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x2e, 0x63, 0x68, 0x65, 0x63, 0x6b,
+	0x52, 0x65, 0x73, 0x70, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+}
+
+var (
+	file_check_proto_rawDescOnce sync.Once
+	file_check_proto_rawDescData = file_check_proto_rawDesc
+)
+
+func file_check_proto_rawDescGZIP() []byte {
+	file_check_proto_rawDescOnce.Do(func() {
+		file_check_proto_rawDescData = protoimpl.X.CompressGZIP(file_check_proto_rawDescData)
+	})
+	return file_check_proto_rawDescData
+}
+
+var file_check_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
+var file_check_proto_goTypes = []interface{}{
+	(*CheckReq)(nil),  // 0: check.checkReq
+	(*CheckResp)(nil), // 1: check.checkResp
+}
+var file_check_proto_depIdxs = []int32{
+	0, // 0: check.checker.check:input_type -> check.checkReq
+	1, // 1: check.checker.check:output_type -> check.checkResp
+	1, // [1:2] is the sub-list for method output_type
+	0, // [0:1] is the sub-list for method input_type
+	0, // [0:0] is the sub-list for extension type_name
+	0, // [0:0] is the sub-list for extension extendee
+	0, // [0:0] is the sub-list for field type_name
+}
+
+func init() { file_check_proto_init() }
+func file_check_proto_init() {
+	if File_check_proto != nil {
+		return
+	}
+	if !protoimpl.UnsafeEnabled {
+		file_check_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*CheckReq); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_check_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*CheckResp); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: file_check_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   2,
+			NumExtensions: 0,
+			NumServices:   1,
+		},
+		GoTypes:           file_check_proto_goTypes,
+		DependencyIndexes: file_check_proto_depIdxs,
+		MessageInfos:      file_check_proto_msgTypes,
+	}.Build()
+	File_check_proto = out.File
+	file_check_proto_rawDesc = nil
+	file_check_proto_goTypes = nil
+	file_check_proto_depIdxs = nil
+}
+
+// Reference imports to suppress errors if they are not otherwise used.
+var _ context.Context
+var _ grpc.ClientConnInterface
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the grpc package it is being compiled against.
+const _ = grpc.SupportPackageIsVersion6
+
+// CheckerClient is the client API for Checker service.
+//
+// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
+type CheckerClient interface {
+	Check(ctx context.Context, in *CheckReq, opts ...grpc.CallOption) (*CheckResp, error)
+}
+
+type checkerClient struct {
+	cc grpc.ClientConnInterface
+}
+
+func NewCheckerClient(cc grpc.ClientConnInterface) CheckerClient {
+	return &checkerClient{cc}
+}
+
+func (c *checkerClient) Check(ctx context.Context, in *CheckReq, opts ...grpc.CallOption) (*CheckResp, error) {
+	out := new(CheckResp)
+	err := c.cc.Invoke(ctx, "/check.checker/check", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+// CheckerServer is the server API for Checker service.
+type CheckerServer interface {
+	Check(context.Context, *CheckReq) (*CheckResp, error)
+}
+
+// UnimplementedCheckerServer can be embedded to have forward compatible implementations.
+type UnimplementedCheckerServer struct {
+}
+
+func (*UnimplementedCheckerServer) Check(context.Context, *CheckReq) (*CheckResp, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method Check not implemented")
+}
+
+func RegisterCheckerServer(s *grpc.Server, srv CheckerServer) {
+	s.RegisterService(&_Checker_serviceDesc, srv)
+}
+
+func _Checker_Check_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(CheckReq)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(CheckerServer).Check(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/check.checker/Check",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(CheckerServer).Check(ctx, req.(*CheckReq))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+var _Checker_serviceDesc = grpc.ServiceDesc{
+	ServiceName: "check.checker",
+	HandlerType: (*CheckerServer)(nil),
+	Methods: []grpc.MethodDesc{
+		{
+			MethodName: "check",
+			Handler:    _Checker_Check_Handler,
+		},
+	},
+	Streams:  []grpc.StreamDesc{},
+	Metadata: "check.proto",
+}

+ 38 - 0
bookstore/rpc/check/checker/checker.go

@@ -0,0 +1,38 @@
+// Code generated by goctl. DO NOT EDIT!
+// Source: check.proto
+
+//go:generate mockgen -destination ./checker_mock.go -package checker -source $GOFILE
+
+package checker
+
+import (
+	"context"
+
+	"bookstore/rpc/check/check"
+
+	"github.com/tal-tech/go-zero/zrpc"
+)
+
+type (
+	CheckReq  = check.CheckReq
+	CheckResp = check.CheckResp
+
+	Checker interface {
+		Check(ctx context.Context, in *CheckReq) (*CheckResp, error)
+	}
+
+	defaultChecker struct {
+		cli zrpc.Client
+	}
+)
+
+func NewChecker(cli zrpc.Client) Checker {
+	return &defaultChecker{
+		cli: cli,
+	}
+}
+
+func (m *defaultChecker) Check(ctx context.Context, in *CheckReq) (*CheckResp, error) {
+	client := check.NewCheckerClient(m.cli.Conn())
+	return client.Check(ctx, in)
+}

+ 10 - 0
bookstore/rpc/check/etc/check.yaml

@@ -0,0 +1,10 @@
+Name: check.rpc
+ListenOn: 127.0.0.1:8081
+Etcd:
+  Hosts:
+  - 127.0.0.1:2379
+  Key: check.rpc
+DataSource: root:@tcp(localhost:3306)/gozero
+Table: book
+Cache:
+  - Host: localhost:6379

+ 12 - 0
bookstore/rpc/check/internal/config/config.go

@@ -0,0 +1,12 @@
+package config
+
+import (
+	"github.com/tal-tech/go-zero/core/stores/cache"
+	"github.com/tal-tech/go-zero/zrpc"
+)
+
+type Config struct {
+	zrpc.RpcServerConf
+	DataSource string
+	Cache      cache.CacheConf
+}

+ 36 - 0
bookstore/rpc/check/internal/logic/checklogic.go

@@ -0,0 +1,36 @@
+package logic
+
+import (
+	"context"
+
+	check "bookstore/rpc/check/checker"
+	"bookstore/rpc/check/internal/svc"
+
+	"github.com/tal-tech/go-zero/core/logx"
+)
+
+type CheckLogic struct {
+	ctx    context.Context
+	svcCtx *svc.ServiceContext
+	logx.Logger
+}
+
+func NewCheckLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CheckLogic {
+	return &CheckLogic{
+		ctx:    ctx,
+		svcCtx: svcCtx,
+		Logger: logx.WithContext(ctx),
+	}
+}
+
+func (l *CheckLogic) Check(in *check.CheckReq) (*check.CheckResp, error) {
+	resp, err := l.svcCtx.Model.FindOne(in.Book)
+	if err != nil {
+		return nil, err
+	}
+
+	return &check.CheckResp{
+		Found: true,
+		Price: resp.Price,
+	}, nil
+}

+ 27 - 0
bookstore/rpc/check/internal/server/checkerserver.go

@@ -0,0 +1,27 @@
+// Code generated by goctl. DO NOT EDIT!
+// Source: check.proto
+
+package server
+
+import (
+	"context"
+
+	"bookstore/rpc/check/check"
+	"bookstore/rpc/check/internal/logic"
+	"bookstore/rpc/check/internal/svc"
+)
+
+type CheckerServer struct {
+	svcCtx *svc.ServiceContext
+}
+
+func NewCheckerServer(svcCtx *svc.ServiceContext) *CheckerServer {
+	return &CheckerServer{
+		svcCtx: svcCtx,
+	}
+}
+
+func (s *CheckerServer) Check(ctx context.Context, in *check.CheckReq) (*check.CheckResp, error) {
+	l := logic.NewCheckLogic(ctx, s.svcCtx)
+	return l.Check(in)
+}

+ 20 - 0
bookstore/rpc/check/internal/svc/servicecontext.go

@@ -0,0 +1,20 @@
+package svc
+
+import (
+	"bookstore/rpc/check/internal/config"
+	"bookstore/rpc/model"
+
+	"github.com/tal-tech/go-zero/core/stores/sqlx"
+)
+
+type ServiceContext struct {
+	c     config.Config
+	Model model.BookModel
+}
+
+func NewServiceContext(c config.Config) *ServiceContext {
+	return &ServiceContext{
+		c:     c,
+		Model: model.NewBookModel(sqlx.NewMysql(c.DataSource), c.Cache),
+	}
+}

+ 6 - 0
bookstore/rpc/model/book.sql

@@ -0,0 +1,6 @@
+CREATE TABLE `book`
+(
+  `book` varchar(255) NOT NULL COMMENT 'book name',
+  `price` int NOT NULL COMMENT 'book price',
+  PRIMARY KEY(`book`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

+ 100 - 0
bookstore/rpc/model/bookmodel.go

@@ -0,0 +1,100 @@
+package model
+
+import (
+	"database/sql"
+	"fmt"
+	"strings"
+
+	"github.com/tal-tech/go-zero/core/stores/cache"
+	"github.com/tal-tech/go-zero/core/stores/sqlc"
+	"github.com/tal-tech/go-zero/core/stores/sqlx"
+	"github.com/tal-tech/go-zero/core/stringx"
+	"github.com/tal-tech/go-zero/tools/goctl/model/sql/builderx"
+)
+
+var (
+	bookFieldNames          = builderx.FieldNames(&Book{})
+	bookRows                = strings.Join(bookFieldNames, ",")
+	bookRowsExpectAutoSet   = strings.Join(stringx.Remove(bookFieldNames, "create_time", "update_time"), ",")
+	bookRowsWithPlaceHolder = strings.Join(stringx.Remove(bookFieldNames, "book", "create_time", "update_time"), "=?,") + "=?"
+
+	cacheBookPrefix = "cache#Book#book#"
+)
+
+type (
+	BookModel interface {
+		Insert(data Book) (sql.Result, error)
+		FindOne(book string) (*Book, error)
+		Update(data Book) error
+		Delete(book string) error
+	}
+
+	defaultBookModel struct {
+		sqlc.CachedConn
+		table string
+	}
+
+	Book struct {
+		Book  string `db:"book"`  // book name
+		Price int64  `db:"price"` // book price
+	}
+)
+
+func NewBookModel(conn sqlx.SqlConn, c cache.CacheConf) BookModel {
+	return &defaultBookModel{
+		CachedConn: sqlc.NewConn(conn, c),
+		table:      "book",
+	}
+}
+
+func (m *defaultBookModel) Insert(data Book) (sql.Result, error) {
+	query := fmt.Sprintf("insert into %s (%s) values (?, ?)", m.table, bookRowsExpectAutoSet)
+	ret, err := m.ExecNoCache(query, data.Book, data.Price)
+
+	return ret, err
+}
+
+func (m *defaultBookModel) FindOne(book string) (*Book, error) {
+	bookKey := fmt.Sprintf("%s%v", cacheBookPrefix, book)
+	var resp Book
+	err := m.QueryRow(&resp, bookKey, func(conn sqlx.SqlConn, v interface{}) error {
+		query := fmt.Sprintf("select %s from %s where book = ? limit 1", bookRows, m.table)
+		return conn.QueryRow(v, query, book)
+	})
+	switch err {
+	case nil:
+		return &resp, nil
+	case sqlc.ErrNotFound:
+		return nil, ErrNotFound
+	default:
+		return nil, err
+	}
+}
+
+func (m *defaultBookModel) Update(data Book) error {
+	bookKey := fmt.Sprintf("%s%v", cacheBookPrefix, data.Book)
+	_, err := m.Exec(func(conn sqlx.SqlConn) (result sql.Result, err error) {
+		query := fmt.Sprintf("update %s set %s where book = ?", m.table, bookRowsWithPlaceHolder)
+		return conn.Exec(query, data.Price, data.Book)
+	}, bookKey)
+	return err
+}
+
+func (m *defaultBookModel) Delete(book string) error {
+
+	bookKey := fmt.Sprintf("%s%v", cacheBookPrefix, book)
+	_, err := m.Exec(func(conn sqlx.SqlConn) (result sql.Result, err error) {
+		query := fmt.Sprintf("delete from %s where book = ?", m.table)
+		return conn.Exec(query, book)
+	}, bookKey)
+	return err
+}
+
+func (m *defaultBookModel) formatPrimary(primary interface{}) string {
+	return fmt.Sprintf("%s%v", cacheBookPrefix, primary)
+}
+
+func (m *defaultBookModel) queryPrimary(conn sqlx.SqlConn, v, primary interface{}) error {
+	query := fmt.Sprintf("select %s from %s where book = ? limit 1", bookRows, m.table)
+	return conn.QueryRow(v, query, primary)
+}

+ 5 - 0
bookstore/rpc/model/vars.go

@@ -0,0 +1,5 @@
+package model
+
+import "github.com/tal-tech/go-zero/core/stores/sqlx"
+
+var ErrNotFound = sqlx.ErrNotFound

+ 139 - 0
breaker/main.go

@@ -0,0 +1,139 @@
+package main
+
+import (
+	"fmt"
+	"math/rand"
+	"os"
+	"sync"
+	"sync/atomic"
+	"time"
+
+	"github.com/tal-tech/go-zero/core/breaker"
+	"github.com/tal-tech/go-zero/core/lang"
+	"github.com/tal-tech/go-zero/core/logx"
+	"gopkg.in/cheggaaa/pb.v1"
+)
+
+const (
+	duration        = time.Minute * 5
+	breakRange      = 20
+	workRange       = 50
+	requestInterval = time.Millisecond
+	// multiply to make it visible in plot
+	stateFator = float64(time.Second/requestInterval) / 2
+)
+
+type (
+	server struct {
+		state int32
+	}
+
+	metric struct {
+		calls int64
+	}
+)
+
+func (m *metric) addCall() {
+	atomic.AddInt64(&m.calls, 1)
+}
+
+func (m *metric) reset() int64 {
+	return atomic.SwapInt64(&m.calls, 0)
+}
+
+func newServer() *server {
+	return &server{}
+}
+
+func (s *server) serve(m *metric) bool {
+	m.addCall()
+	return atomic.LoadInt32(&s.state) == 1
+}
+
+func (s *server) start() {
+	go func() {
+		r := rand.New(rand.NewSource(time.Now().UnixNano()))
+		var state int32
+		for {
+			var v int32
+			if state == 0 {
+				v = r.Int31n(breakRange)
+			} else {
+				v = r.Int31n(workRange)
+			}
+			time.Sleep(time.Second * time.Duration(v+1))
+			state ^= 1
+			atomic.StoreInt32(&s.state, state)
+		}
+	}()
+}
+
+func runBreaker(s *server, br breaker.Breaker, duration time.Duration, m *metric) {
+	ticker := time.NewTicker(requestInterval)
+	defer ticker.Stop()
+	done := make(chan lang.PlaceholderType)
+
+	go func() {
+		time.Sleep(duration)
+		close(done)
+	}()
+
+	for {
+		select {
+		case <-ticker.C:
+			_ = br.Do(func() error {
+				if s.serve(m) {
+					return nil
+				} else {
+					return breaker.ErrServiceUnavailable
+				}
+			})
+		case <-done:
+			return
+		}
+	}
+}
+
+func main() {
+	srv := newServer()
+	srv.start()
+
+	gb := breaker.NewBreaker()
+	fp, err := os.Create("result.csv")
+	logx.Must(err)
+	defer fp.Close()
+	fmt.Fprintln(fp, "seconds,state,googleCalls,netflixCalls")
+
+	var gm, nm metric
+	go func() {
+		ticker := time.NewTicker(time.Second)
+		defer ticker.Stop()
+		var seconds int
+		for range ticker.C {
+			seconds++
+			gcalls := gm.reset()
+			ncalls := nm.reset()
+			fmt.Fprintf(fp, "%d,%.2f,%d,%d\n",
+				seconds, float64(atomic.LoadInt32(&srv.state))*stateFator, gcalls, ncalls)
+		}
+	}()
+
+	var waitGroup sync.WaitGroup
+	waitGroup.Add(1)
+	go func() {
+		runBreaker(srv, gb, duration, &gm)
+		waitGroup.Done()
+	}()
+
+	go func() {
+		bar := pb.New(int(duration / time.Second)).Start()
+		ticker := time.NewTicker(time.Second)
+		defer ticker.Stop()
+		for range ticker.C {
+			bar.Increment()
+		}
+		bar.Finish()
+	}()
+
+	waitGroup.Wait()
+}

+ 15 - 0
breaker/plot.py

@@ -0,0 +1,15 @@
+import click
+import pandas as pd
+import matplotlib.pyplot as plt
+
+
+@click.command()
+@click.option("--csv", default="result.csv")
+def main(csv):
+    df = pd.read_csv(csv, index_col="seconds")
+    df.plot()
+    plt.show()
+
+
+if __name__ == "__main__":
+    main()

+ 98 - 0
chat/home.html

@@ -0,0 +1,98 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<title>Chat Example</title>
+<script type="text/javascript">
+window.onload = function () {
+    var conn;
+    var msg = document.getElementById("msg");
+    var log = document.getElementById("log");
+
+    function appendLog(item) {
+        var doScroll = log.scrollTop > log.scrollHeight - log.clientHeight - 1;
+        log.appendChild(item);
+        if (doScroll) {
+            log.scrollTop = log.scrollHeight - log.clientHeight;
+        }
+    }
+
+    document.getElementById("form").onsubmit = function () {
+        if (!conn) {
+            return false;
+        }
+        if (!msg.value) {
+            return false;
+        }
+        conn.send(msg.value);
+        msg.value = "";
+        return false;
+    };
+
+    if (window["WebSocket"]) {
+        conn = new WebSocket("ws://" + document.location.host + "/ws");
+        conn.onclose = function (evt) {
+            var item = document.createElement("div");
+            item.innerHTML = "<b>Connection closed.</b>";
+            appendLog(item);
+        };
+        conn.onmessage = function (evt) {
+            var messages = evt.data.split('\n');
+            for (var i = 0; i < messages.length; i++) {
+                var item = document.createElement("div");
+                item.innerText = messages[i];
+                appendLog(item);
+            }
+        };
+    } else {
+        var item = document.createElement("div");
+        item.innerHTML = "<b>Your browser does not support WebSockets.</b>";
+        appendLog(item);
+    }
+};
+</script>
+<style type="text/css">
+html {
+    overflow: hidden;
+}
+
+body {
+    overflow: hidden;
+    padding: 0;
+    margin: 0;
+    width: 100%;
+    height: 100%;
+    background: gray;
+}
+
+#log {
+    background: white;
+    margin: 0;
+    padding: 0.5em 0.5em 0.5em 0.5em;
+    position: absolute;
+    top: 0.5em;
+    left: 0.5em;
+    right: 0.5em;
+    bottom: 3em;
+    overflow: auto;
+}
+
+#form {
+    padding: 0 0.5em 0 0.5em;
+    margin: 0;
+    position: absolute;
+    bottom: 1em;
+    left: 0px;
+    width: 100%;
+    overflow: hidden;
+}
+
+</style>
+</head>
+<body>
+<div id="log"></div>
+<form id="form">
+    <input type="submit" value="Send" />
+    <input type="text" id="msg" size="64" autofocus />
+</form>
+</body>
+</html>

+ 142 - 0
chat/internal/client.go

@@ -0,0 +1,142 @@
+package internal
+
+import (
+	"bytes"
+	"log"
+	"net/http"
+	"time"
+
+	"github.com/gorilla/websocket"
+)
+
+const (
+	// Time allowed to write a message to the peer.
+	writeWait = 10 * time.Second
+
+	// Time allowed to read the next pong message from the peer.
+	pongWait = 60 * time.Second
+
+	// Send pings to peer with this period. Must be less than pongWait.
+	pingPeriod = (pongWait * 9) / 10
+
+	// Maximum message size allowed from peer.
+	maxMessageSize = 512
+
+	// send buffer size
+	bufSize = 256
+)
+
+var (
+	newline = []byte{'\n'}
+	space   = []byte{' '}
+)
+
+var upgrader = websocket.Upgrader{
+	ReadBufferSize:  1024,
+	WriteBufferSize: 1024,
+}
+
+// Client is a middleman between the websocket connection and the hub.
+type Client struct {
+	hub *Hub
+
+	// The websocket connection.
+	conn *websocket.Conn
+
+	// Buffered channel of outbound messages.
+	send chan []byte
+}
+
+// readPump pumps messages from the websocket connection to the hub.
+//
+// The application runs readPump in a per-connection goroutine. The application
+// ensures that there is at most one reader on a connection by executing all
+// reads from this goroutine.
+func (c *Client) readPump() {
+	defer func() {
+		c.hub.unregister <- c
+		c.conn.Close()
+	}()
+	c.conn.SetReadLimit(maxMessageSize)
+	c.conn.SetReadDeadline(time.Now().Add(pongWait))
+	c.conn.SetPongHandler(func(string) error { c.conn.SetReadDeadline(time.Now().Add(pongWait)); return nil })
+	for {
+		_, message, err := c.conn.ReadMessage()
+		if err != nil {
+			if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway, websocket.CloseAbnormalClosure) {
+				log.Printf("error: %v", err)
+			}
+			break
+		}
+		message = bytes.TrimSpace(bytes.Replace(message, newline, space, -1))
+		c.hub.broadcast <- message
+	}
+}
+
+// writePump pumps messages from the hub to the websocket connection.
+//
+// A goroutine running writePump is started for each connection. The
+// application ensures that there is at most one writer to a connection by
+// executing all writes from this goroutine.
+func (c *Client) writePump() {
+	ticker := time.NewTicker(pingPeriod)
+	defer func() {
+		ticker.Stop()
+		c.conn.Close()
+	}()
+
+	for {
+		select {
+		case message, ok := <-c.send:
+			c.conn.SetWriteDeadline(time.Now().Add(writeWait))
+			if !ok {
+				// The hub closed the channel.
+				c.conn.WriteMessage(websocket.CloseMessage, []byte{})
+				return
+			}
+
+			w, err := c.conn.NextWriter(websocket.TextMessage)
+			if err != nil {
+				return
+			}
+			w.Write(message)
+
+			// Add queued chat messages to the current websocket message.
+			n := len(c.send)
+			for i := 0; i < n; i++ {
+				w.Write(newline)
+				w.Write(<-c.send)
+			}
+
+			if err := w.Close(); err != nil {
+				return
+			}
+		case <-ticker.C:
+			c.conn.SetWriteDeadline(time.Now().Add(writeWait))
+			if err := c.conn.WriteMessage(websocket.PingMessage, nil); err != nil {
+				return
+			}
+		}
+	}
+}
+
+// ServeWs handles websocket requests from the peer.
+func ServeWs(hub *Hub, w http.ResponseWriter, r *http.Request) {
+	conn, err := upgrader.Upgrade(w, r, nil)
+	if err != nil {
+		log.Println(err)
+		return
+	}
+
+	client := &Client{
+		hub:  hub,
+		conn: conn,
+		send: make(chan []byte, bufSize),
+	}
+	client.hub.register <- client
+
+	// Allow collection of memory referenced by the caller by doing all work in
+	// new goroutines.
+	go client.writePump()
+	go client.readPump()
+}

+ 49 - 0
chat/internal/hub.go

@@ -0,0 +1,49 @@
+package internal
+
+// Hub maintains the set of active clients and broadcasts messages to the
+// clients.
+type Hub struct {
+	// Registered clients.
+	clients map[*Client]bool
+
+	// Inbound messages from the clients.
+	broadcast chan []byte
+
+	// Register requests from the clients.
+	register chan *Client
+
+	// Unregister requests from clients.
+	unregister chan *Client
+}
+
+func NewHub() *Hub {
+	return &Hub{
+		broadcast:  make(chan []byte),
+		register:   make(chan *Client),
+		unregister: make(chan *Client),
+		clients:    make(map[*Client]bool),
+	}
+}
+
+func (h *Hub) Run() {
+	for {
+		select {
+		case client := <-h.register:
+			h.clients[client] = true
+		case client := <-h.unregister:
+			if _, ok := h.clients[client]; ok {
+				delete(h.clients, client)
+				close(client.send)
+			}
+		case message := <-h.broadcast:
+			for client := range h.clients {
+				select {
+				case client.send <- message:
+				default:
+					close(client.send)
+					delete(h.clients, client)
+				}
+			}
+		}
+	}
+}

+ 65 - 0
chat/main.go

@@ -0,0 +1,65 @@
+package main
+
+import (
+	"flag"
+	"net/http"
+
+	"zero-examples/chat/internal"
+
+	"github.com/tal-tech/go-zero/core/logx"
+	"github.com/tal-tech/go-zero/core/service"
+	"github.com/tal-tech/go-zero/rest"
+)
+
+var (
+	port    = flag.Int("port", 3333, "the port to listen")
+	timeout = flag.Int64("timeout", 0, "timeout of milliseconds")
+	cpu     = flag.Int64("cpu", 500, "cpu threshold")
+)
+
+func main() {
+	flag.Parse()
+
+	logx.Disable()
+	engine := rest.MustNewServer(rest.RestConf{
+		ServiceConf: service.ServiceConf{
+			Log: logx.LogConf{
+				Mode: "console",
+			},
+		},
+		Port:         *port,
+		Timeout:      *timeout,
+		CpuThreshold: *cpu,
+	})
+	defer engine.Stop()
+
+	hub := internal.NewHub()
+	go hub.Run()
+
+	engine.AddRoute(rest.Route{
+		Method: http.MethodGet,
+		Path:   "/",
+		Handler: func(w http.ResponseWriter, r *http.Request) {
+			if r.URL.Path != "/" {
+				http.Error(w, "Not found", http.StatusNotFound)
+				return
+			}
+			if r.Method != "GET" {
+				http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
+				return
+			}
+
+			http.ServeFile(w, r, "home.html")
+		},
+	})
+
+	engine.AddRoute(rest.Route{
+		Method: http.MethodGet,
+		Path:   "/ws",
+		Handler: func(w http.ResponseWriter, r *http.Request) {
+			internal.ServeWs(hub, w, r)
+		},
+	})
+
+	engine.Start()
+}

+ 2 - 0
config/loadfromyaml/date.yml

@@ -0,0 +1,2 @@
+#date: "2019-06-20 00:00:00"
+date: "2019-06-19T16:00:00Z"

+ 21 - 0
config/loadfromyaml/main.go

@@ -0,0 +1,21 @@
+package main
+
+import (
+	"time"
+
+	"github.com/tal-tech/go-zero/core/conf"
+	"github.com/tal-tech/go-zero/core/logx"
+)
+
+type TimeHolder struct {
+	Date time.Time `json:"date"`
+}
+
+func main() {
+	th := &TimeHolder{}
+	err := conf.LoadConfig("./date.yml", th)
+	if err != nil {
+		logx.Error(err)
+	}
+	logx.Infof("%+v", th)
+}

+ 22 - 0
etcd/pub/Dockerfile

@@ -0,0 +1,22 @@
+FROM golang:1.13-alpine AS builder
+
+LABEL stage=gobuilder
+
+ENV CGO_ENABLED 0
+ENV GOOS linux
+ENV GOPROXY https://goproxy.cn,direct
+
+WORKDIR $GOPATH/src/zero
+COPY . .
+RUN go build -ldflags="-s -w" -o /app/pub example/etcd/pub/pub.go
+
+
+FROM alpine
+
+RUN apk add --no-cache tzdata
+ENV TZ Asia/Shanghai
+
+WORKDIR /app
+COPY --from=builder /app/pub /app/pub
+
+CMD ["./pub"]

+ 27 - 0
etcd/pub/pub.go

@@ -0,0 +1,27 @@
+package main
+
+import (
+	"flag"
+	"fmt"
+	"log"
+	"time"
+
+	"github.com/tal-tech/go-zero/core/discov"
+)
+
+var value = flag.String("v", "value", "the value")
+
+func main() {
+	flag.Parse()
+
+	client := discov.NewPublisher([]string{"etcd.discovery:2379"}, "028F2C35852D", *value)
+	if err := client.KeepAlive(); err != nil {
+		log.Fatal(err)
+	}
+	defer client.Stop()
+
+	for {
+		time.Sleep(time.Second)
+		fmt.Println(*value)
+	}
+}

+ 22 - 0
etcd/sub/Dockerfile

@@ -0,0 +1,22 @@
+FROM golang:1.13-alpine AS builder
+
+LABEL stage=gobuilder
+
+ENV CGO_ENABLED 0
+ENV GOOS linux
+ENV GOPROXY https://goproxy.cn,direct
+
+WORKDIR $GOPATH/src/zero
+COPY . .
+RUN go build -ldflags="-s -w" -o /app/sub example/etcd/sub/sub.go
+
+
+FROM alpine
+
+RUN apk add --no-cache tzdata
+ENV TZ Asia/Shanghai
+
+WORKDIR /app
+COPY --from=builder /app/sub /app/sub
+
+CMD ["./sub"]

+ 24 - 0
etcd/sub/sub.go

@@ -0,0 +1,24 @@
+package main
+
+import (
+	"fmt"
+	"time"
+
+	"github.com/tal-tech/go-zero/core/discov"
+	"github.com/tal-tech/go-zero/core/logx"
+)
+
+func main() {
+	sub, err := discov.NewSubscriber([]string{"etcd.discovery:2379"}, "028F2C35852D", discov.Exclusive())
+	logx.Must(err)
+
+	ticker := time.NewTicker(time.Second * 3)
+	defer ticker.Stop()
+
+	for {
+		select {
+		case <-ticker.C:
+			fmt.Println("values:", sub.Values())
+		}
+	}
+}

+ 139 - 0
filex/pread.go

@@ -0,0 +1,139 @@
+package main
+
+import (
+	"bufio"
+	"errors"
+	"flag"
+	"fmt"
+	"log"
+	"os"
+	"runtime"
+	"strconv"
+	"strings"
+	"time"
+
+	"github.com/tal-tech/go-zero/core/filex"
+	"github.com/tal-tech/go-zero/core/fx"
+	"github.com/tal-tech/go-zero/core/logx"
+	"gopkg.in/cheggaaa/pb.v1"
+)
+
+var (
+	file       = flag.String("f", "", "the input file")
+	concurrent = flag.Int("c", runtime.NumCPU(), "concurrent goroutines")
+	wordVecDic TXDictionary
+)
+
+type (
+	Vector []float64
+
+	TXDictionary struct {
+		EmbeddingCount int64
+		Dim            int64
+		Dict           map[string]Vector
+	}
+
+	pair struct {
+		key string
+		vec Vector
+	}
+)
+
+func FastLoad(filename string) error {
+	if filename == "" {
+		return errors.New("no available dictionary")
+	}
+
+	now := time.Now()
+	defer func() {
+		logx.Infof("article2vec init dictionary end used %v", time.Since(now))
+	}()
+
+	dicFile, err := os.Open(filename)
+	if err != nil {
+		return err
+	}
+	defer dicFile.Close()
+
+	header, err := filex.FirstLine(filename)
+	if err != nil {
+		return err
+	}
+
+	total := strings.Split(header, " ")
+	wordVecDic.EmbeddingCount, err = strconv.ParseInt(total[0], 10, 64)
+	if err != nil {
+		return err
+	}
+
+	wordVecDic.Dim, err = strconv.ParseInt(total[1], 10, 64)
+	if err != nil {
+		return err
+	}
+
+	wordVecDic.Dict = make(map[string]Vector, wordVecDic.EmbeddingCount)
+
+	ranges, err := filex.SplitLineChunks(filename, *concurrent)
+	if err != nil {
+		return err
+	}
+
+	info, err := os.Stat(filename)
+	if err != nil {
+		return err
+	}
+
+	bar := pb.New64(info.Size()).SetUnits(pb.U_BYTES).Start()
+	fx.From(func(source chan<- interface{}) {
+		for _, each := range ranges {
+			source <- each
+		}
+	}).Walk(func(item interface{}, pipe chan<- interface{}) {
+		offsetRange := item.(filex.OffsetRange)
+		scanner := bufio.NewScanner(filex.NewRangeReader(dicFile, offsetRange.Start, offsetRange.Stop))
+		scanner.Buffer([]byte{}, 1<<20)
+		reader := filex.NewProgressScanner(scanner, bar)
+		if offsetRange.Start == 0 {
+			// skip header
+			reader.Scan()
+		}
+		for reader.Scan() {
+			text := reader.Text()
+			elements := strings.Split(text, " ")
+			vec := make(Vector, wordVecDic.Dim)
+			for i, ele := range elements {
+				if i == 0 {
+					continue
+				}
+
+				v, err := strconv.ParseFloat(ele, 64)
+				if err != nil {
+					return
+				}
+
+				vec[i-1] = v
+			}
+			pipe <- pair{
+				key: elements[0],
+				vec: vec,
+			}
+		}
+	}).ForEach(func(item interface{}) {
+		p := item.(pair)
+		wordVecDic.Dict[p.key] = p.vec
+	})
+
+	return nil
+}
+
+func main() {
+	flag.Parse()
+
+	start := time.Now()
+	if err := FastLoad(*file); err != nil {
+		log.Fatal(err)
+	}
+
+	fmt.Println(len(wordVecDic.Dict))
+	fmt.Println(time.Since(start))
+}

+ 33 - 0
fx/fx_test.go

@@ -0,0 +1,33 @@
+package main
+
+import (
+	"fmt"
+	"testing"
+
+	"github.com/tal-tech/go-zero/core/fx"
+)
+
+func TestFxSplit(t *testing.T) {
+	fx.Just(1, 2, 3, 4, 5, 6, 7, 8, 9, 10).Split(4).ForEach(func(item interface{}) {
+		vals := item.([]interface{})
+		fmt.Println(len(vals))
+	})
+}
+
+func BenchmarkFx(b *testing.B) {
+	type Mixed struct {
+		Name   string
+		Age    int
+		Gender int
+	}
+	for i := 0; i < b.N; i++ {
+		var mx Mixed
+		fx.Parallel(func() {
+			mx.Name = "hello"
+		}, func() {
+			mx.Age = 20
+		}, func() {
+			mx.Gender = 1
+		})
+	}
+}

+ 35 - 0
fx/square.go

@@ -0,0 +1,35 @@
+package main
+
+import (
+	"fmt"
+
+	"github.com/tal-tech/go-zero/core/fx"
+)
+
+func main() {
+	result, err := fx.From(func(source chan<- interface{}) {
+		for i := 0; i < 10; i++ {
+			source <- i
+		}
+	}).Map(func(item interface{}) interface{} {
+		i := item.(int)
+		return i * i
+	}).Filter(func(item interface{}) bool {
+		i := item.(int)
+		return i%2 == 0
+	}).Distinct(func(item interface{}) interface{} {
+		return item
+	}).Reduce(func(pipe <-chan interface{}) (interface{}, error) {
+		var result int
+		for item := range pipe {
+			i := item.(int)
+			result += i
+		}
+		return result, nil
+	})
+	if err != nil {
+		fmt.Println(err)
+	} else {
+		fmt.Println(result)
+	}
+}

+ 18 - 0
go.mod

@@ -0,0 +1,18 @@
+module github.com/zeromicro/zero-examples
+
+go 1.15
+
+require (
+	github.com/dchest/siphash v1.2.2
+	github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8
+	github.com/golang/protobuf v1.4.2
+	github.com/google/gops v0.3.14
+	github.com/gorilla/websocket v1.4.2
+	github.com/stretchr/testify v1.7.0
+	github.com/tal-tech/go-zero v1.1.6
+	golang.org/x/net v0.0.0-20210119194325-5f4716e94777
+	google.golang.org/grpc v1.31.0
+	gopkg.in/cheggaaa/pb.v1 v1.0.28
+)
+
+replace google.golang.org/grpc => google.golang.org/grpc v1.29.1

+ 407 - 0
go.sum

@@ -0,0 +1,407 @@
+github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/ClickHouse/clickhouse-go v1.4.3/go.mod h1:EaI/sW7Azgz9UATzd5ZdZHRUhHgv5+JMS9NSr2smCJI=
+github.com/DATA-DOG/go-sqlmock v1.4.1/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
+github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
+github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
+github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
+github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
+github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
+github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a h1:HbKu58rmZpUGpz5+4FfNmIU+FmZg2P3Xaj2v2bfNWmk=
+github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc=
+github.com/alicebob/miniredis/v2 v2.14.1 h1:GjlbSeoJ24bzdLRs13HoMEeaRZx9kg5nHoRW7QV/nCs=
+github.com/alicebob/miniredis/v2 v2.14.1/go.mod h1:uS970Sw5Gs9/iK3yBg0l9Uj9s25wXxSpQUE9EaJ/Blg=
+github.com/antihax/optional v0.0.0-20180407024304-ca021399b1a6/go.mod h1:V8iCPQYkqmusNa815XgQio277wI47sdRh1dUOLdyC6Q=
+github.com/antlr/antlr4 v0.0.0-20210105212045-464bcbc32de2/go.mod h1:T7PbCXFs94rrTttyxjbyT5+/1V8T2TYDejxUfHJjw1Y=
+github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
+github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
+github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
+github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
+github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
+github.com/bkaradzic/go-lz4 v1.0.0/go.mod h1:0YdlkowM3VswSROI7qDxhRvJ3sLhlFrRRwjwegp5jy4=
+github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
+github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
+github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
+github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
+github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
+github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h4xcZ5GoxqC5SDxFQ8gwyZPKQoEzownBlhI80=
+github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
+github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa h1:OaNxuTZr7kxeODyLWsRMC+OD03aFUH+mW6r2d+MWa5Y=
+github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
+github.com/coreos/go-semver v0.2.0 h1:3Jm3tLmsgAYcjC+4Up7hJrFBPr+n7rAqYeSw/SZazuY=
+github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
+github.com/coreos/go-systemd/v22 v22.0.0 h1:XJIw/+VlJ+87J+doOxznsAWIdmWuViOVhkQamW5YV28=
+github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk=
+github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
+github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
+github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/dchest/siphash v1.2.2 h1:9DFz8tQwl9pTVt5iok/9zKyzA1Q6bRGiF3HPiEEVr9I=
+github.com/dchest/siphash v1.2.2/go.mod h1:q+IRvb2gOSrUnYoPqHiyHXS0FOBBOdl6tONBlVnOnt4=
+github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
+github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
+github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4 h1:qk/FSDDxo05wdJH28W+p5yivv7LuLYLRXPPD8KQCtZs=
+github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
+github.com/emicklei/proto v1.9.0/go.mod h1:rn1FgRS/FANiZdD2djyH7TMA9jdRDcYQ9IEN9yvjX0A=
+github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
+github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
+github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
+github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s=
+github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
+github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94=
+github.com/frankban/quicktest v1.7.2/go.mod h1:jaStnuzAqU1AJdCO0l53JDCJrVDKcS03DbaAcR7Ks/o=
+github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
+github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
+github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
+github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8 h1:DujepqpGd1hyOd7aW59XpK7Qymp8iy83xq74fLr21is=
+github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
+github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
+github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
+github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM=
+github.com/go-redis/redis v6.15.7+incompatible h1:3skhDh95XQMpnqeqNftPkQD9jL9e5e36z/1SUm6dy1U=
+github.com/go-redis/redis v6.15.7+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
+github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
+github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
+github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
+github.com/go-xorm/builder v0.3.4/go.mod h1:KxkQkNN1DpPKTedxXyTQcmH+rXfvk4LZ9SOOBoZBAxw=
+github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:56xuuqnHyryaerycW3BfssRdxQstACi0Epw/yC5E2xM=
+github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
+github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
+github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
+github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=
+github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
+github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
+github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY=
+github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/mock v1.4.3 h1:GV+pQPG/EUUbkh47niozDcADz6go/dUwhVzdUQHIVRw=
+github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
+github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
+github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
+github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
+github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
+github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
+github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
+github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
+github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo=
+github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
+github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w=
+github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/gops v0.3.14 h1:4Gpv4sABlEsVqrtKxiSynzD0//kzjTIUwUm5UgkGILI=
+github.com/google/gops v0.3.14/go.mod h1:zjT9F4XsKzazOvdVad3+Zwga79UHKziX3r9TN05rVN8=
+github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
+github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
+github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
+github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
+github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
+github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4 h1:z53tR0945TRRQO/fLEVPI6SMv7ZflF0TEaTAoU7tOzg=
+github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
+github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho=
+github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
+github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
+github.com/grpc-ecosystem/grpc-gateway v1.14.3 h1:OCJlWkOUoTnl0neNGlf4fUm3TmbEtguw7vR+nGtnDjY=
+github.com/grpc-ecosystem/grpc-gateway v1.14.3/go.mod h1:6CwZWGDSPRJidgKAtJVvND6soZe6fT7iteq8wDPdhb0=
+github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw=
+github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI=
+github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
+github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
+github.com/iancoleman/strcase v0.1.2/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE=
+github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
+github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks=
+github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo=
+github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
+github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
+github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns=
+github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
+github.com/justinas/alice v1.2.0 h1:+MHSA/vccVCF4Uq37S42jwlkvI2Xzl7zTPCN5BnZNVo=
+github.com/justinas/alice v1.2.0/go.mod h1:fN5HRH/reO/zrUflLfTN43t3vXvKzvZIENsNEe7i7qA=
+github.com/keybase/go-ps v0.0.0-20190827175125-91aafc93ba19/go.mod h1:hY+WOq6m2FpbvyrI93sMaypsttvaIL5nhVR92dTMUcQ=
+github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
+github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
+github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
+github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=
+github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
+github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs=
+github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
+github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
+github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
+github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
+github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
+github.com/mattn/go-colorable v0.1.6 h1:6Su7aK7lXmJ/U79bYtBjLNaha4Fs1Rg9plHpcH+vvnE=
+github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
+github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
+github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
+github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
+github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
+github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
+github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
+github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
+github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
+github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
+github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
+github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
+github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
+github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
+github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
+github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32 h1:W6apQkHrMkS0Muv8G/TipAy/FJl/rCYT0+EuS8+Z0z4=
+github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms=
+github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
+github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA=
+github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs=
+github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/gomega v1.5.0 h1:izbySO9zDPmjJ8rDjLvkA2zJHIo+HkYXHnf7eN7SSyo=
+github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
+github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
+github.com/pierrec/lz4 v2.5.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
+github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
+github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
+github.com/prometheus/client_golang v1.5.1 h1:bdHYieyGlH+6OLEk2YQha8THib30KP0/yD0YH9m6xcA=
+github.com/prometheus/client_golang v1.5.1/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=
+github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
+github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
+github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
+github.com/prometheus/common v0.9.1 h1:KOMtN28tlbam3/7ZKEYKHhKoJZYYj3gMH4uc62x7X7U=
+github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4=
+github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
+github.com/prometheus/procfs v0.0.8 h1:+fpWZdT24pJBiqJdAwYBjPSk+5YmQzYNPYzQsdzLkt8=
+github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
+github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
+github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
+github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
+github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
+github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
+github.com/shirou/gopsutil v2.20.4+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
+github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
+github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
+github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
+github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
+github.com/soheilhy/cmux v0.1.4 h1:0HKaf1o97UwFjHH9o5XsHUOF+tqmdA7KEzXLpiyaw0E=
+github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
+github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
+github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
+github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
+github.com/spf13/pflag v1.0.1 h1:aCvUg6QPl3ibpQUxyLkrEkCHtPqYJL4x9AuhqVqFis4=
+github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
+github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
+github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
+github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/tal-tech/go-zero v1.1.6 h1:Xnbx0t10zzT2dcbpWOxmhsSu3DOkYwj604BSdfSkJlM=
+github.com/tal-tech/go-zero v1.1.6/go.mod h1:LbN0C7/rbl2+LUWTSUYx5leXmgedeMWjt1jc3/8/zFA=
+github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
+github.com/tmc/grpc-websocket-proxy v0.0.0-20171017195756-830351dc03c6 h1:lYIiVDtZnyTWlNwiAxLj0bbpTcx1BWCFhXjfsvmPdNc=
+github.com/tmc/grpc-websocket-proxy v0.0.0-20171017195756-830351dc03c6/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
+github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
+github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
+github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8=
+github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
+github.com/xlab/treeprint v1.0.0/go.mod h1:IoImgRak9i3zJyuxOKUP1v4UZd1tMoKkq/Cimt1uhCg=
+github.com/xwb1989/sqlparser v0.0.0-20180606152119-120387863bf2/go.mod h1:hzfGeIUDq/j97IG+FhNqkowIyEcD88LrW6fyU3K3WqY=
+github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/gopher-lua v0.0.0-20191220021717-ab39c6098bdb h1:ZkM6LRnq40pR1Ox0hTHlnpkcOTuFIDQpZ1IN8rKKhX0=
+github.com/yuin/gopher-lua v0.0.0-20191220021717-ab39c6098bdb/go.mod h1:gqRgreBUhTSL0GeU64rtZ3Uq3wtjOa/TB2YfrtkCbVQ=
+go.etcd.io/bbolt v1.3.4 h1:hi1bXHMVrlQh6WwxAy+qZCV/SYIlqo+Ushwdpa4tAKg=
+go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
+go.etcd.io/etcd v0.0.0-20200402134248-51bdeb39e698 h1:jWtjCJX1qxhHISBMLRztWwR+EXkI7MJAF2HjHAE/x/I=
+go.etcd.io/etcd v0.0.0-20200402134248-51bdeb39e698/go.mod h1:YoUyTScD3Vcv2RBm3eGVOq7i1ULiz3OuXoQFWOirmAM=
+go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk=
+go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
+go.uber.org/automaxprocs v1.3.0 h1:II28aZoGdaglS5vVNnspf28lnZpXScxtIozx1lAjdb0=
+go.uber.org/automaxprocs v1.3.0/go.mod h1:9CWT6lKIep8U41DDaPiH6eFscnTyjfTANNQNx6LrIcA=
+go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A=
+go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
+go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4=
+go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
+go.uber.org/zap v1.14.1 h1:nYDKopTbvAPq/NrUVZwT15y2lpROBiLLyoRTbXOYWOo=
+go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc=
+golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
+golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
+golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k=
+golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
+golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
+golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
+golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ=
+golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20191002035440-2ec189313ef0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20210119194325-5f4716e94777 h1:003p0dJM77cxMSyCPFphvZf/Y5/NXf5fzg6ufd1/Oew=
+golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201207223542-d4d67f95c62d h1:MiWWjyhUzZ+jvhZvloX6ZrUsdEghn8a64Upd8EMHglE=
+golang.org/x/sys v0.0.0-20201207223542-d4d67f95c62d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs=
+golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
+golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200410132612-ae9902aceb98 h1:ibc1eDGW5ajwA4qzFTj0WHlD9eofMe1gAre+A0a3Vhs=
+golang.org/x/tools v0.0.0-20200410132612-ae9902aceb98/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20190927181202-20e1ac93f88c/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
+google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
+google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f h1:ohwtWcCwB/fZUxh/vjazHorYmBnua3NmY3CAjwC7mEA=
+google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/grpc v1.29.1 h1:EC2SB8S04d2r73uptxphDSUG+kTKVgjRPF+N3xpxRB4=
+google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
+google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
+google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
+google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
+google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
+google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
+google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
+google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
+google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
+gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
+gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
+gopkg.in/cheggaaa/pb.v1 v1.0.28 h1:n1tBJnnK2r7g9OW2btFH91V92STTUevLXYFb8gy9EMk=
+gopkg.in/cheggaaa/pb.v1 v1.0.28/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
+gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
+gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
+gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
+gopkg.in/h2non/gock.v1 v1.0.15 h1:SzLqcIlb/fDfg7UvukMpNcWsu7sI5tWwL+KCATZqks0=
+gopkg.in/h2non/gock.v1 v1.0.15/go.mod h1:sX4zAkdYX1TRGJ2JY156cFspQn4yRWn6p9EMdODlynE=
+gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
+gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
+gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
+gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
+honnef.co/go/tools v0.0.1-2020.1.4 h1:UoveltGrhghAA7ePc+e+QYDHXrBps2PqFZiHkGR/xK8=
+honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
+rsc.io/goversion v1.2.0/go.mod h1:Eih9y/uIBS3ulggl7KNJ09xGSLcuNaLgmvvqa07sgfo=
+rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
+rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
+sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
+sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=
+sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=

+ 26 - 0
graceful/dns/api/Dockerfile

@@ -0,0 +1,26 @@
+FROM golang:1.13 AS builder
+
+ENV CGO_ENABLED 0
+ENV GOOS linux
+
+RUN apt-get update
+RUN apt-get install -y apt-utils upx
+
+WORKDIR $GOPATH/src/zero
+COPY . .
+RUN go build -ldflags="-s -w" -o /app/graceful example/graceful/dns/api/graceful.go
+RUN upx /app/graceful
+
+
+FROM alpine
+
+RUN apk update --no-cache
+RUN apk add --no-cache ca-certificates
+RUN apk add --no-cache tzdata
+ENV TZ Asia/Shanghai
+
+WORKDIR /app
+COPY --from=builder /app/graceful /app/graceful
+COPY example/graceful/dns/api/etc/graceful-api.json /app/etc/config.json
+
+CMD ["./graceful", "-f", "etc/config.json"]

+ 11 - 0
graceful/dns/api/config/config.go

@@ -0,0 +1,11 @@
+package config
+
+import (
+	"github.com/tal-tech/go-zero/rest"
+	"github.com/tal-tech/go-zero/zrpc"
+)
+
+type Config struct {
+	rest.RestConf
+	Rpc zrpc.RpcClientConf
+}

+ 9 - 0
graceful/dns/api/etc/graceful-api.json

@@ -0,0 +1,9 @@
+{
+    "Name": "graceful-api",
+    "Host": "0.0.0.0",
+    "Port": 8888,
+    "MaxConns": 1000000,
+    "Rpc": {
+        "Server": "dns:///gracefulrpc:3456"
+    }
+}

+ 11 - 0
graceful/dns/api/graceful.api

@@ -0,0 +1,11 @@
+type Response {
+    Host string `json:"host"`
+    Time int64 `json:"time"`
+}
+
+service graceful-api {
+    @server(
+        handler: GracefulHandler
+    )
+    get /api/graceful() returns(Response)
+}

+ 32 - 0
graceful/dns/api/graceful.go

@@ -0,0 +1,32 @@
+package main
+
+import (
+	"flag"
+
+	"github.com/tal-tech/go-zero/core/conf"
+	"github.com/tal-tech/go-zero/rest"
+	"github.com/tal-tech/go-zero/zrpc"
+	"github.com/zeromicro/zero-examples/graceful/dns/api/config"
+	"github.com/zeromicro/zero-examples/graceful/dns/api/handler"
+	"github.com/zeromicro/zero-examples/graceful/dns/api/svc"
+)
+
+var configFile = flag.String("f", "etc/graceful-api.json", "the config file")
+
+func main() {
+	flag.Parse()
+
+	var c config.Config
+	conf.MustLoad(*configFile, &c)
+
+	client := zrpc.MustNewClient(c.Rpc)
+	ctx := &svc.ServiceContext{
+		Client: client,
+	}
+
+	engine := rest.MustNewServer(c.RestConf)
+	defer engine.Stop()
+
+	handler.RegisterHandlers(engine, ctx)
+	engine.Start()
+}

+ 43 - 0
graceful/dns/api/handler/gracefulhandler.go

@@ -0,0 +1,43 @@
+package handler
+
+import (
+	"context"
+	"fmt"
+	"net/http"
+	"os"
+	"time"
+
+	"github.com/tal-tech/go-zero/core/executors"
+	"github.com/tal-tech/go-zero/core/logx"
+	"github.com/tal-tech/go-zero/rest/httpx"
+	"github.com/zeromicro/zero-examples/graceful/dns/api/svc"
+	"github.com/zeromicro/zero-examples/graceful/dns/api/types"
+	"github.com/zeromicro/zero-examples/graceful/dns/rpc/graceful"
+)
+
+func gracefulHandler(ctx *svc.ServiceContext) http.HandlerFunc {
+	logger := executors.NewLessExecutor(time.Second)
+	return func(w http.ResponseWriter, r *http.Request) {
+		host, err := os.Hostname()
+		if err != nil {
+			http.Error(w, http.StatusText(http.StatusNotImplemented), http.StatusNotImplemented)
+			return
+		}
+
+		conn := ctx.Client.Conn()
+		client := graceful.NewGraceServiceClient(conn)
+		rp, err := client.Grace(context.Background(), &graceful.Request{From: host})
+		if err != nil {
+			logx.Error(err)
+			http.Error(w, http.StatusText(http.StatusBadGateway), http.StatusBadGateway)
+			return
+		}
+
+		var resp types.Response
+		resp.Host = rp.Host
+		logger.DoOrDiscard(func() {
+			fmt.Printf("%s from host: %s\n", time.Now().Format("15:04:05"), rp.Host)
+		})
+		httpx.OkJson(w, resp)
+	}
+}

+ 19 - 0
graceful/dns/api/handler/routes.go

@@ -0,0 +1,19 @@
+// Code generated by goctl. DO NOT EDIT.
+package handler
+
+import (
+	"net/http"
+
+	"github.com/tal-tech/go-zero/rest"
+	"github.com/zeromicro/zero-examples/graceful/dns/api/svc"
+)
+
+func RegisterHandlers(engine *rest.Server, ctx *svc.ServiceContext) {
+	engine.AddRoutes([]rest.Route{
+		{
+			Method:  http.MethodGet,
+			Path:    "/api/graceful",
+			Handler: gracefulHandler(ctx),
+		},
+	})
+}

+ 7 - 0
graceful/dns/api/svc/servicecontext.go

@@ -0,0 +1,7 @@
+package svc
+
+import "github.com/tal-tech/go-zero/zrpc"
+
+type ServiceContext struct {
+	Client zrpc.Client
+}

+ 7 - 0
graceful/dns/api/types/types.go

@@ -0,0 +1,7 @@
+// Code generated by goctl. DO NOT EDIT.
+package types
+
+type Response struct {
+	Host string `json:"host"`
+	Time int64  `json:"time"`
+}

+ 22 - 0
graceful/dns/rpc/Dockerfile

@@ -0,0 +1,22 @@
+FROM golang:1.13 AS builder
+
+ENV CGO_ENABLED 0
+ENV GOOS linux
+
+WORKDIR $GOPATH/src/zero
+COPY . .
+RUN go build -ldflags="-s -w" -o /app/gracefulrpc example/graceful/dns/rpc/gracefulrpc.go
+
+
+FROM alpine
+
+RUN apk update --no-cache
+RUN apk add --no-cache ca-certificates
+RUN apk add --no-cache tzdata
+ENV TZ Asia/Shanghai
+
+WORKDIR /app
+COPY --from=builder /app/gracefulrpc /app/gracefulrpc
+COPY example/graceful/dns/rpc/etc/config.json /app/etc/config.json
+
+CMD ["./gracefulrpc", "-f", "etc/config.json"]

+ 4 - 0
graceful/dns/rpc/etc/config.json

@@ -0,0 +1,4 @@
+{
+    "Name": "rpc.grace",
+    "ListenOn": "0.0.0.0:3456"
+}

+ 15 - 0
graceful/dns/rpc/graceful.proto

@@ -0,0 +1,15 @@
+syntax = "proto3";
+
+package graceful;
+
+message Request {
+    string from = 1;
+}
+
+message Response {
+    string host = 2;
+}
+
+service GraceService {
+    rpc grace(Request) returns(Response);
+}

+ 159 - 0
graceful/dns/rpc/graceful/graceful.pb.go

@@ -0,0 +1,159 @@
+// Code generated by protoc-gen-go.
+// source: graceful.proto
+// DO NOT EDIT!
+
+/*
+Package graceful is a generated protocol buffer package.
+
+It is generated from these files:
+	graceful.proto
+
+It has these top-level messages:
+	Request
+	Response
+*/
+package graceful
+
+import (
+	"fmt"
+	"math"
+
+	"github.com/golang/protobuf/proto"
+	"golang.org/x/net/context"
+	"google.golang.org/grpc"
+)
+
+// Reference imports to suppress errors if they are not otherwise used.
+var _ = proto.Marshal
+var _ = fmt.Errorf
+var _ = math.Inf
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the proto package it is being compiled against.
+// A compilation error at this line likely means your copy of the
+// proto package needs to be updated.
+const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
+
+type Request struct {
+	From string `protobuf:"bytes,1,opt,name=from" json:"from,omitempty"`
+}
+
+func (m *Request) Reset()                    { *m = Request{} }
+func (m *Request) String() string            { return proto.CompactTextString(m) }
+func (*Request) ProtoMessage()               {}
+func (*Request) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
+
+func (m *Request) GetFrom() string {
+	if m != nil {
+		return m.From
+	}
+	return ""
+}
+
+type Response struct {
+	Host string `protobuf:"bytes,2,opt,name=host" json:"host,omitempty"`
+}
+
+func (m *Response) Reset()                    { *m = Response{} }
+func (m *Response) String() string            { return proto.CompactTextString(m) }
+func (*Response) ProtoMessage()               {}
+func (*Response) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
+
+func (m *Response) GetHost() string {
+	if m != nil {
+		return m.Host
+	}
+	return ""
+}
+
+func init() {
+	proto.RegisterType((*Request)(nil), "graceful.Request")
+	proto.RegisterType((*Response)(nil), "graceful.Response")
+}
+
+// Reference imports to suppress errors if they are not otherwise used.
+var _ context.Context
+var _ grpc.ClientConn
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the grpc package it is being compiled against.
+const _ = grpc.SupportPackageIsVersion4
+
+// Client API for GraceService service
+
+type GraceServiceClient interface {
+	Grace(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error)
+}
+
+type graceServiceClient struct {
+	cc *grpc.ClientConn
+}
+
+func NewGraceServiceClient(cc *grpc.ClientConn) GraceServiceClient {
+	return &graceServiceClient{cc}
+}
+
+func (c *graceServiceClient) Grace(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error) {
+	out := new(Response)
+	err := grpc.Invoke(ctx, "/graceful.GraceService/grace", in, out, c.cc, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+// Server API for GraceService service
+
+type GraceServiceServer interface {
+	Grace(context.Context, *Request) (*Response, error)
+}
+
+func RegisterGraceServiceServer(s *grpc.Server, srv GraceServiceServer) {
+	s.RegisterService(&_GraceService_serviceDesc, srv)
+}
+
+func _GraceService_Grace_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(Request)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(GraceServiceServer).Grace(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/graceful.GraceService/Grace",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(GraceServiceServer).Grace(ctx, req.(*Request))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+var _GraceService_serviceDesc = grpc.ServiceDesc{
+	ServiceName: "graceful.GraceService",
+	HandlerType: (*GraceServiceServer)(nil),
+	Methods: []grpc.MethodDesc{
+		{
+			MethodName: "grace",
+			Handler:    _GraceService_Grace_Handler,
+		},
+	},
+	Streams:  []grpc.StreamDesc{},
+	Metadata: "graceful.proto",
+}
+
+func init() { proto.RegisterFile("graceful.proto", fileDescriptor0) }
+
+var fileDescriptor0 = []byte{
+	// 134 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe2, 0xe2, 0x4b, 0x2f, 0x4a, 0x4c,
+	0x4e, 0x4d, 0x2b, 0xcd, 0xd1, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0x80, 0xf1, 0x95, 0x64,
+	0xb9, 0xd8, 0x83, 0x52, 0x0b, 0x4b, 0x53, 0x8b, 0x4b, 0x84, 0x84, 0xb8, 0x58, 0xd2, 0x8a, 0xf2,
+	0x73, 0x25, 0x18, 0x15, 0x18, 0x35, 0x38, 0x83, 0xc0, 0x6c, 0x25, 0x39, 0x2e, 0x8e, 0xa0, 0xd4,
+	0xe2, 0x82, 0xfc, 0xbc, 0xe2, 0x54, 0x90, 0x7c, 0x46, 0x7e, 0x71, 0x89, 0x04, 0x13, 0x44, 0x1e,
+	0xc4, 0x36, 0xb2, 0xe3, 0xe2, 0x71, 0x07, 0x19, 0x15, 0x9c, 0x5a, 0x54, 0x96, 0x99, 0x9c, 0x2a,
+	0xa4, 0xc7, 0xc5, 0x0a, 0x36, 0x5a, 0x48, 0x50, 0x0f, 0x6e, 0x25, 0xd4, 0x7c, 0x29, 0x21, 0x64,
+	0x21, 0x88, 0x99, 0x49, 0x6c, 0x60, 0xf7, 0x18, 0x03, 0x02, 0x00, 0x00, 0xff, 0xff, 0x81, 0x87,
+	0xc8, 0xc1, 0xa1, 0x00, 0x00, 0x00,
+}

+ 50 - 0
graceful/dns/rpc/gracefulrpc.go

@@ -0,0 +1,50 @@
+package main
+
+import (
+	"context"
+	"flag"
+	"fmt"
+	"os"
+	"time"
+
+	"github.com/tal-tech/go-zero/core/conf"
+	"github.com/tal-tech/go-zero/zrpc"
+	"github.com/zeromicro/zero-examples/graceful/dns/rpc/graceful"
+	"google.golang.org/grpc"
+)
+
+var configFile = flag.String("f", "etc/config.json", "the config file")
+
+type GracefulServer struct{}
+
+func NewGracefulServer() *GracefulServer {
+	return &GracefulServer{}
+}
+
+func (gs *GracefulServer) Grace(ctx context.Context, req *graceful.Request) (*graceful.Response, error) {
+	fmt.Println("=>", req)
+
+	time.Sleep(time.Millisecond * 10)
+
+	hostname, err := os.Hostname()
+	if err != nil {
+		return nil, err
+	}
+
+	return &graceful.Response{
+		Host: hostname,
+	}, nil
+}
+
+func main() {
+	flag.Parse()
+
+	var c zrpc.RpcServerConf
+	conf.MustLoad(*configFile, &c)
+
+	server := zrpc.MustNewServer(c, func(grpcServer *grpc.Server) {
+		graceful.RegisterGraceServiceServer(grpcServer, NewGracefulServer())
+	})
+	defer server.Stop()
+	server.Start()
+}

+ 28 - 0
graceful/etcd/api/Dockerfile

@@ -0,0 +1,28 @@
+FROM golang:alpine AS builder
+
+LABEL stage=gobuilder
+
+ENV CGO_ENABLED 0
+ENV GOOS linux
+
+RUN apk update
+RUN apk add upx
+
+WORKDIR $GOPATH/src/zero
+COPY . .
+RUN go build -ldflags="-s -w" -o /app/graceful example/graceful/etcd/api/graceful.go
+RUN upx /app/graceful
+
+
+FROM alpine
+
+RUN apk update --no-cache
+RUN apk add --no-cache ca-certificates
+RUN apk add --no-cache tzdata
+ENV TZ Asia/Shanghai
+
+WORKDIR /app
+COPY --from=builder /app/graceful /app/graceful
+COPY example/graceful/etcd/api/etc/graceful-api.json /app/etc/config.json
+
+CMD ["./graceful", "-f", "etc/config.json"]

+ 11 - 0
graceful/etcd/api/config/config.go

@@ -0,0 +1,11 @@
+package config
+
+import (
+	"github.com/tal-tech/go-zero/rest"
+	"github.com/tal-tech/go-zero/zrpc"
+)
+
+type Config struct {
+	rest.RestConf
+	Rpc zrpc.RpcClientConf
+}

+ 12 - 0
graceful/etcd/api/etc/graceful-api.json

@@ -0,0 +1,12 @@
+{
+    "Name": "graceful-api",
+    "Host": "0.0.0.0",
+    "Port": 8888,
+    "MaxConns": 1000000,
+    "Rpc": {
+        "Etcd": {
+            "Hosts": ["etcd.discov:2379"],
+            "Key": "zrpc"
+        }
+    }
+}

+ 11 - 0
graceful/etcd/api/graceful.api

@@ -0,0 +1,11 @@
+type Response {
+    Host string `json:"host"`
+    Time int64 `json:"time"`
+}
+
+service graceful-api {
+    @server(
+        handler: GracefulHandler
+    )
+    get /api/graceful() returns(Response)
+}

+ 32 - 0
graceful/etcd/api/graceful.go

@@ -0,0 +1,32 @@
+package main
+
+import (
+	"flag"
+
+	"github.com/tal-tech/go-zero/core/conf"
+	"github.com/tal-tech/go-zero/rest"
+	"github.com/tal-tech/go-zero/zrpc"
+	"github.com/zeromicro/zero-examples/graceful/etcd/api/config"
+	"github.com/zeromicro/zero-examples/graceful/etcd/api/handler"
+	"github.com/zeromicro/zero-examples/graceful/etcd/api/svc"
+)
+
+var configFile = flag.String("f", "etc/graceful-api.json", "the config file")
+
+func main() {
+	flag.Parse()
+
+	var c config.Config
+	conf.MustLoad(*configFile, &c)
+
+	client := zrpc.MustNewClient(c.Rpc)
+	ctx := &svc.ServiceContext{
+		Client: client,
+	}
+
+	engine := rest.MustNewServer(c.RestConf)
+	defer engine.Stop()
+
+	handler.RegisterHandlers(engine, ctx)
+	engine.Start()
+}

+ 43 - 0
graceful/etcd/api/handler/gracefulhandler.go

@@ -0,0 +1,43 @@
+package handler
+
+import (
+	"context"
+	"fmt"
+	"net/http"
+	"os"
+	"time"
+
+	"github.com/tal-tech/go-zero/core/executors"
+	"github.com/tal-tech/go-zero/core/logx"
+	"github.com/tal-tech/go-zero/rest/httpx"
+	"github.com/zeromicro/zero-examples/graceful/etcd/api/svc"
+	"github.com/zeromicro/zero-examples/graceful/etcd/api/types"
+	"github.com/zeromicro/zero-examples/graceful/etcd/rpc/graceful"
+)
+
+func gracefulHandler(ctx *svc.ServiceContext) http.HandlerFunc {
+	logger := executors.NewLessExecutor(time.Second)
+	return func(w http.ResponseWriter, r *http.Request) {
+		host, err := os.Hostname()
+		if err != nil {
+			http.Error(w, http.StatusText(http.StatusNotImplemented), http.StatusNotImplemented)
+			return
+		}
+
+		conn := ctx.Client.Conn()
+		client := graceful.NewGraceServiceClient(conn)
+		rp, err := client.Grace(context.Background(), &graceful.Request{From: host})
+		if err != nil {
+			logx.Error(err)
+			http.Error(w, http.StatusText(http.StatusBadGateway), http.StatusBadGateway)
+			return
+		}
+
+		var resp types.Response
+		resp.Host = rp.Host
+		logger.DoOrDiscard(func() {
+			fmt.Printf("%s from host: %s\n", time.Now().Format("15:04:05"), rp.Host)
+		})
+		httpx.OkJson(w, resp)
+	}
+}

+ 19 - 0
graceful/etcd/api/handler/routes.go

@@ -0,0 +1,19 @@
+// Code generated by goctl. DO NOT EDIT.
+package handler
+
+import (
+	"net/http"
+
+	"github.com/tal-tech/go-zero/rest"
+	"github.com/zeromicro/zero-examples/graceful/etcd/api/svc"
+)
+
+func RegisterHandlers(engine *rest.Server, ctx *svc.ServiceContext) {
+	engine.AddRoutes([]rest.Route{
+		{
+			Method:  http.MethodGet,
+			Path:    "/api/graceful",
+			Handler: gracefulHandler(ctx),
+		},
+	})
+}

+ 7 - 0
graceful/etcd/api/svc/servicecontext.go

@@ -0,0 +1,7 @@
+package svc
+
+import "github.com/tal-tech/go-zero/zrpc"
+
+type ServiceContext struct {
+	Client zrpc.Client
+}

+ 7 - 0
graceful/etcd/api/types/types.go

@@ -0,0 +1,7 @@
+// Code generated by goctl. DO NOT EDIT.
+package types
+
+type Response struct {
+	Host string `json:"host"`
+	Time int64  `json:"time"`
+}

+ 4 - 0
graceful/etcd/discov/discov-namespace.yaml

@@ -0,0 +1,4 @@
+apiVersion: v1
+kind: Namespace
+metadata:
+  name: discov

+ 319 - 0
graceful/etcd/discov/etcd.yaml

@@ -0,0 +1,319 @@
+apiVersion: v1
+kind: Service
+metadata:
+  name: etcd
+  namespace: discov
+spec:
+  ports:
+  - name: etcd-port
+    port: 2379
+    protocol: TCP
+    targetPort: 2379
+  selector:
+    app: etcd
+
+---
+
+apiVersion: v1
+kind: Pod
+metadata:
+  labels:
+    app: etcd
+    etcd_node: etcd0
+  name: etcd0
+  namespace: discov
+spec:
+  containers:
+  - command:
+    - /usr/local/bin/etcd
+    - --name
+    - etcd0
+    - --initial-advertise-peer-urls
+    - http://etcd0:2380
+    - --listen-peer-urls
+    - http://0.0.0.0:2380
+    - --listen-client-urls
+    - http://0.0.0.0:2379
+    - --advertise-client-urls
+    - http://etcd0:2379
+    - --initial-cluster
+    - etcd0=http://etcd0:2380,etcd1=http://etcd1:2380,etcd2=http://etcd2:2380,etcd3=http://etcd3:2380,etcd4=http://etcd4:2380
+    - --initial-cluster-state
+    - new
+    image: quay.io/coreos/etcd:latest
+    name: etcd0
+    ports:
+    - containerPort: 2379
+      name: client
+      protocol: TCP
+    - containerPort: 2380
+      name: server
+      protocol: TCP
+  restartPolicy: Always
+
+---
+
+apiVersion: v1
+kind: Service
+metadata:
+  labels:
+    etcd_node: etcd0
+  name: etcd0
+  namespace: discov
+spec:
+  ports:
+  - name: client
+    port: 2379
+    protocol: TCP
+    targetPort: 2379
+  - name: server
+    port: 2380
+    protocol: TCP
+    targetPort: 2380
+  selector:
+    etcd_node: etcd0
+
+---
+
+apiVersion: v1
+kind: Pod
+metadata:
+  labels:
+    app: etcd
+    etcd_node: etcd1
+  name: etcd1
+  namespace: discov
+spec:
+  containers:
+  - command:
+    - /usr/local/bin/etcd
+    - --name
+    - etcd1
+    - --initial-advertise-peer-urls
+    - http://etcd1:2380
+    - --listen-peer-urls
+    - http://0.0.0.0:2380
+    - --listen-client-urls
+    - http://0.0.0.0:2379
+    - --advertise-client-urls
+    - http://etcd1:2379
+    - --initial-cluster
+    - etcd0=http://etcd0:2380,etcd1=http://etcd1:2380,etcd2=http://etcd2:2380,etcd3=http://etcd3:2380,etcd4=http://etcd4:2380
+    - --initial-cluster-state
+    - new
+    image: quay.io/coreos/etcd:latest
+    name: etcd1
+    ports:
+    - containerPort: 2379
+      name: client
+      protocol: TCP
+    - containerPort: 2380
+      name: server
+      protocol: TCP
+  restartPolicy: Always
+
+---
+
+apiVersion: v1
+kind: Service
+metadata:
+  labels:
+    etcd_node: etcd1
+  name: etcd1
+  namespace: discov
+spec:
+  ports:
+  - name: client
+    port: 2379
+    protocol: TCP
+    targetPort: 2379
+  - name: server
+    port: 2380
+    protocol: TCP
+    targetPort: 2380
+  selector:
+    etcd_node: etcd1
+
+---
+
+apiVersion: v1
+kind: Pod
+metadata:
+  labels:
+    app: etcd
+    etcd_node: etcd2
+  name: etcd2
+  namespace: discov
+spec:
+  containers:
+  - command:
+    - /usr/local/bin/etcd
+    - --name
+    - etcd2
+    - --initial-advertise-peer-urls
+    - http://etcd2:2380
+    - --listen-peer-urls
+    - http://0.0.0.0:2380
+    - --listen-client-urls
+    - http://0.0.0.0:2379
+    - --advertise-client-urls
+    - http://etcd2:2379
+    - --initial-cluster
+    - etcd0=http://etcd0:2380,etcd1=http://etcd1:2380,etcd2=http://etcd2:2380,etcd3=http://etcd3:2380,etcd4=http://etcd4:2380
+    - --initial-cluster-state
+    - new
+    image: quay.io/coreos/etcd:latest
+    name: etcd2
+    ports:
+    - containerPort: 2379
+      name: client
+      protocol: TCP
+    - containerPort: 2380
+      name: server
+      protocol: TCP
+  restartPolicy: Always
+
+---
+
+apiVersion: v1
+kind: Service
+metadata:
+  labels:
+    etcd_node: etcd2
+  name: etcd2
+  namespace: discov
+spec:
+  ports:
+  - name: client
+    port: 2379
+    protocol: TCP
+    targetPort: 2379
+  - name: server
+    port: 2380
+    protocol: TCP
+    targetPort: 2380
+  selector:
+    etcd_node: etcd2
+
+---
+
+apiVersion: v1
+kind: Pod
+metadata:
+  labels:
+    app: etcd
+    etcd_node: etcd3
+  name: etcd3
+  namespace: discov
+spec:
+  containers:
+  - command:
+    - /usr/local/bin/etcd
+    - --name
+    - etcd3
+    - --initial-advertise-peer-urls
+    - http://etcd3:2380
+    - --listen-peer-urls
+    - http://0.0.0.0:2380
+    - --listen-client-urls
+    - http://0.0.0.0:2379
+    - --advertise-client-urls
+    - http://etcd3:2379
+    - --initial-cluster
+    - etcd0=http://etcd0:2380,etcd1=http://etcd1:2380,etcd2=http://etcd2:2380,etcd3=http://etcd3:2380,etcd4=http://etcd4:2380
+    - --initial-cluster-state
+    - new
+    image: quay.io/coreos/etcd:latest
+    name: etcd3
+    ports:
+      - containerPort: 2379
+        name: client
+        protocol: TCP
+      - containerPort: 2380
+        name: server
+        protocol: TCP
+  restartPolicy: Always
+
+---
+
+apiVersion: v1
+kind: Service
+metadata:
+  labels:
+    etcd_node: etcd3
+  name: etcd3
+  namespace: discov
+spec:
+  ports:
+    - name: client
+      port: 2379
+      protocol: TCP
+      targetPort: 2379
+    - name: server
+      port: 2380
+      protocol: TCP
+      targetPort: 2380
+  selector:
+    etcd_node: etcd3
+
+---
+
+apiVersion: v1
+kind: Pod
+metadata:
+  labels:
+    app: etcd
+    etcd_node: etcd4
+  name: etcd4
+  namespace: discov
+spec:
+  containers:
+  - command:
+    - /usr/local/bin/etcd
+    - --name
+    - etcd4
+    - --initial-advertise-peer-urls
+    - http://etcd4:2380
+    - --listen-peer-urls
+    - http://0.0.0.0:2380
+    - --listen-client-urls
+    - http://0.0.0.0:2379
+    - --advertise-client-urls
+    - http://etcd4:2379
+    - --initial-cluster
+    - etcd0=http://etcd0:2380,etcd1=http://etcd1:2380,etcd2=http://etcd2:2380,etcd3=http://etcd3:2380,etcd4=http://etcd4:2380
+    - --initial-cluster-state
+    - new
+    image: quay.io/coreos/etcd:latest
+    name: etcd4
+    ports:
+      - containerPort: 2379
+        name: client
+        protocol: TCP
+      - containerPort: 2380
+        name: server
+        protocol: TCP
+  restartPolicy: Always
+
+---
+
+apiVersion: v1
+kind: Service
+metadata:
+  labels:
+    etcd_node: etcd4
+  name: etcd4
+  namespace: discov
+spec:
+  ports:
+    - name: client
+      port: 2379
+      protocol: TCP
+      targetPort: 2379
+    - name: server
+      port: 2380
+      protocol: TCP
+      targetPort: 2380
+  selector:
+    etcd_node: etcd4
+

+ 24 - 0
graceful/etcd/rpc/Dockerfile

@@ -0,0 +1,24 @@
+FROM golang:alpine AS builder
+
+LABEL stage=gobuilder
+
+ENV CGO_ENABLED 0
+ENV GOOS linux
+
+WORKDIR $GOPATH/src/zero
+COPY . .
+RUN go build -ldflags="-s -w" -o /app/gracefulrpc example/graceful/etcd/rpc/gracefulrpc.go
+
+
+FROM alpine
+
+RUN apk update --no-cache
+RUN apk add --no-cache ca-certificates
+RUN apk add --no-cache tzdata
+ENV TZ Asia/Shanghai
+
+WORKDIR /app
+COPY --from=builder /app/gracefulrpc /app/gracefulrpc
+COPY example/graceful/etcd/rpc/etc/graceful-rpc.json /app/etc/config.json
+
+CMD ["./gracefulrpc", "-f", "etc/config.json"]

+ 8 - 0
graceful/etcd/rpc/etc/graceful-rpc.json

@@ -0,0 +1,8 @@
+{
+    "Name": "rpc.grace",
+    "ListenOn": "0.0.0.0:3456",
+    "Etcd": {
+        "Hosts": ["etcd.discov:2379"],
+        "Key": "zrpc"
+    }
+}

+ 15 - 0
graceful/etcd/rpc/graceful.proto

@@ -0,0 +1,15 @@
+syntax = "proto3";
+
+package graceful;
+
+message Request {
+    string from = 1;
+}
+
+message Response {
+    string host = 2;
+}
+
+service GraceService {
+    rpc grace(Request) returns(Response);
+}

+ 159 - 0
graceful/etcd/rpc/graceful/graceful.pb.go

@@ -0,0 +1,159 @@
+// Code generated by protoc-gen-go.
+// source: graceful.proto
+// DO NOT EDIT!
+
+/*
+Package graceful is a generated protocol buffer package.
+
+It is generated from these files:
+	graceful.proto
+
+It has these top-level messages:
+	Request
+	Response
+*/
+package graceful
+
+import (
+	"fmt"
+	"math"
+
+	"github.com/golang/protobuf/proto"
+	"golang.org/x/net/context"
+	"google.golang.org/grpc"
+)
+
+// Reference imports to suppress errors if they are not otherwise used.
+var _ = proto.Marshal
+var _ = fmt.Errorf
+var _ = math.Inf
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the proto package it is being compiled against.
+// A compilation error at this line likely means your copy of the
+// proto package needs to be updated.
+const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
+
+type Request struct {
+	From string `protobuf:"bytes,1,opt,name=from" json:"from,omitempty"`
+}
+
+func (m *Request) Reset()                    { *m = Request{} }
+func (m *Request) String() string            { return proto.CompactTextString(m) }
+func (*Request) ProtoMessage()               {}
+func (*Request) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
+
+func (m *Request) GetFrom() string {
+	if m != nil {
+		return m.From
+	}
+	return ""
+}
+
+type Response struct {
+	Host string `protobuf:"bytes,2,opt,name=host" json:"host,omitempty"`
+}
+
+func (m *Response) Reset()                    { *m = Response{} }
+func (m *Response) String() string            { return proto.CompactTextString(m) }
+func (*Response) ProtoMessage()               {}
+func (*Response) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
+
+func (m *Response) GetHost() string {
+	if m != nil {
+		return m.Host
+	}
+	return ""
+}
+
+func init() {
+	proto.RegisterType((*Request)(nil), "graceful.Request")
+	proto.RegisterType((*Response)(nil), "graceful.Response")
+}
+
+// Reference imports to suppress errors if they are not otherwise used.
+var _ context.Context
+var _ grpc.ClientConn
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the grpc package it is being compiled against.
+const _ = grpc.SupportPackageIsVersion4
+
+// Client API for GraceService service
+
+type GraceServiceClient interface {
+	Grace(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error)
+}
+
+type graceServiceClient struct {
+	cc *grpc.ClientConn
+}
+
+func NewGraceServiceClient(cc *grpc.ClientConn) GraceServiceClient {
+	return &graceServiceClient{cc}
+}
+
+func (c *graceServiceClient) Grace(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error) {
+	out := new(Response)
+	err := grpc.Invoke(ctx, "/graceful.GraceService/grace", in, out, c.cc, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+// Server API for GraceService service
+
+type GraceServiceServer interface {
+	Grace(context.Context, *Request) (*Response, error)
+}
+
+func RegisterGraceServiceServer(s *grpc.Server, srv GraceServiceServer) {
+	s.RegisterService(&_GraceService_serviceDesc, srv)
+}
+
+func _GraceService_Grace_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(Request)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(GraceServiceServer).Grace(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/graceful.GraceService/Grace",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(GraceServiceServer).Grace(ctx, req.(*Request))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+var _GraceService_serviceDesc = grpc.ServiceDesc{
+	ServiceName: "graceful.GraceService",
+	HandlerType: (*GraceServiceServer)(nil),
+	Methods: []grpc.MethodDesc{
+		{
+			MethodName: "grace",
+			Handler:    _GraceService_Grace_Handler,
+		},
+	},
+	Streams:  []grpc.StreamDesc{},
+	Metadata: "graceful.proto",
+}
+
+func init() { proto.RegisterFile("graceful.proto", fileDescriptor0) }
+
+var fileDescriptor0 = []byte{
+	// 134 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe2, 0xe2, 0x4b, 0x2f, 0x4a, 0x4c,
+	0x4e, 0x4d, 0x2b, 0xcd, 0xd1, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0x80, 0xf1, 0x95, 0x64,
+	0xb9, 0xd8, 0x83, 0x52, 0x0b, 0x4b, 0x53, 0x8b, 0x4b, 0x84, 0x84, 0xb8, 0x58, 0xd2, 0x8a, 0xf2,
+	0x73, 0x25, 0x18, 0x15, 0x18, 0x35, 0x38, 0x83, 0xc0, 0x6c, 0x25, 0x39, 0x2e, 0x8e, 0xa0, 0xd4,
+	0xe2, 0x82, 0xfc, 0xbc, 0xe2, 0x54, 0x90, 0x7c, 0x46, 0x7e, 0x71, 0x89, 0x04, 0x13, 0x44, 0x1e,
+	0xc4, 0x36, 0xb2, 0xe3, 0xe2, 0x71, 0x07, 0x19, 0x15, 0x9c, 0x5a, 0x54, 0x96, 0x99, 0x9c, 0x2a,
+	0xa4, 0xc7, 0xc5, 0x0a, 0x36, 0x5a, 0x48, 0x50, 0x0f, 0x6e, 0x25, 0xd4, 0x7c, 0x29, 0x21, 0x64,
+	0x21, 0x88, 0x99, 0x49, 0x6c, 0x60, 0xf7, 0x18, 0x03, 0x02, 0x00, 0x00, 0xff, 0xff, 0x81, 0x87,
+	0xc8, 0xc1, 0xa1, 0x00, 0x00, 0x00,
+}

+ 50 - 0
graceful/etcd/rpc/gracefulrpc.go

@@ -0,0 +1,50 @@
+package main
+
+import (
+	"context"
+	"flag"
+	"fmt"
+	"os"
+	"time"
+
+	"github.com/tal-tech/go-zero/core/conf"
+	"github.com/tal-tech/go-zero/zrpc"
+	"github.com/zeromicro/zero-examples/graceful/etcd/rpc/graceful"
+	"google.golang.org/grpc"
+)
+
+var configFile = flag.String("f", "etc/config.json", "the config file")
+
+type GracefulServer struct{}
+
+func NewGracefulServer() *GracefulServer {
+	return &GracefulServer{}
+}
+
+func (gs *GracefulServer) Grace(ctx context.Context, req *graceful.Request) (*graceful.Response, error) {
+	fmt.Println("=>", req)
+
+	time.Sleep(time.Millisecond * 10)
+
+	hostname, err := os.Hostname()
+	if err != nil {
+		return nil, err
+	}
+
+	return &graceful.Response{
+		Host: hostname,
+	}, nil
+}
+
+func main() {
+	flag.Parse()
+
+	var c zrpc.RpcServerConf
+	conf.MustLoad(*configFile, &c)
+
+	server := zrpc.MustNewServer(c, func(grpcServer *grpc.Server) {
+		graceful.RegisterGraceServiceServer(grpcServer, NewGracefulServer())
+	})
+	defer server.Stop()
+	server.Start()
+}

+ 170 - 0
http/breaker/client/client.go

@@ -0,0 +1,170 @@
+package main
+
+import (
+	"flag"
+	"fmt"
+	"net/http"
+	"os"
+	"sync"
+	"time"
+
+	"github.com/tal-tech/go-zero/core/lang"
+	"github.com/tal-tech/go-zero/core/logx"
+	"github.com/tal-tech/go-zero/core/threading"
+	"gopkg.in/cheggaaa/pb.v1"
+)
+
+var (
+	freq     = flag.Int("freq", 100, "frequency")
+	duration = flag.String("duration", "10s", "duration")
+)
+
+type (
+	counting struct {
+		ok      int
+		fail    int
+		reject  int
+		errs    int
+		unknown int
+	}
+
+	metric struct {
+		counting
+		lock sync.Mutex
+	}
+)
+
+func (m *metric) addOk() {
+	m.lock.Lock()
+	m.ok++
+	m.lock.Unlock()
+}
+
+func (m *metric) addFail() {
+	m.lock.Lock()
+	m.ok++
+	m.lock.Unlock()
+}
+
+func (m *metric) addReject() {
+	m.lock.Lock()
+	m.ok++
+	m.lock.Unlock()
+}
+
+func (m *metric) addErrs() {
+	m.lock.Lock()
+	m.errs++
+	m.lock.Unlock()
+}
+
+func (m *metric) addUnknown() {
+	m.lock.Lock()
+	m.unknown++
+	m.lock.Unlock()
+}
+
+func (m *metric) reset() counting {
+	m.lock.Lock()
+	result := counting{
+		ok:      m.ok,
+		fail:    m.fail,
+		reject:  m.reject,
+		errs:    m.errs,
+		unknown: m.unknown,
+	}
+
+	m.ok = 0
+	m.fail = 0
+	m.reject = 0
+	m.errs = 0
+	m.unknown = 0
+	m.lock.Unlock()
+
+	return result
+}
+
+func runRequests(url string, frequency int, metrics *metric, done <-chan lang.PlaceholderType) {
+	ticker := time.NewTicker(time.Second / time.Duration(frequency))
+	defer ticker.Stop()
+
+	for {
+		select {
+		case <-ticker.C:
+			go func() {
+				resp, err := http.Get(url)
+				if err != nil {
+					metrics.addErrs()
+					return
+				}
+				defer resp.Body.Close()
+
+				switch resp.StatusCode {
+				case http.StatusOK:
+					metrics.addOk()
+				case http.StatusInternalServerError:
+					metrics.addFail()
+				case http.StatusServiceUnavailable:
+					metrics.addReject()
+				default:
+					metrics.addUnknown()
+				}
+			}()
+		case <-done:
+			return
+		}
+	}
+}
+
+func main() {
+	flag.Parse()
+
+	fp, err := os.Create("result.csv")
+	logx.Must(err)
+	defer fp.Close()
+	fmt.Fprintln(fp, "seconds,goodOk,goodFail,goodReject,goodErrs,goodUnknowns,goodDropRatio,"+
+		"heavyOk,heavyFail,heavyReject,heavyErrs,heavyUnknowns,heavyDropRatio")
+
+	var gm, hm metric
+	dur, err := time.ParseDuration(*duration)
+	logx.Must(err)
+	done := make(chan lang.PlaceholderType)
+	group := threading.NewRoutineGroup()
+	group.RunSafe(func() {
+		runRequests("http://localhost:8080/heavy", *freq, &hm, done)
+	})
+	group.RunSafe(func() {
+		runRequests("http://localhost:8080/good", *freq, &gm, done)
+	})
+
+	go func() {
+		ticker := time.NewTicker(time.Second)
+		defer ticker.Stop()
+		var seconds int
+		for range ticker.C {
+			seconds++
+			g := gm.reset()
+			h := hm.reset()
+			fmt.Fprintf(fp, "%d,%d,%d,%d,%d,%d,%.1f,%d,%d,%d,%d,%d,%.1f\n",
+				seconds, g.ok, g.fail, g.reject, g.errs, g.unknown,
+				float32(g.reject)/float32(g.ok+g.fail+g.reject+g.unknown),
+				h.ok, h.fail, h.reject, h.errs, h.unknown,
+				float32(h.reject)/float32(h.ok+h.fail+h.reject+h.unknown))
+		}
+	}()
+
+	go func() {
+		bar := pb.New(int(dur / time.Second)).Start()
+		ticker := time.NewTicker(time.Second)
+		defer ticker.Stop()
+		for range ticker.C {
+			bar.Increment()
+		}
+		bar.Finish()
+	}()
+
+	<-time.After(dur)
+	close(done)
+	group.Wait()
+	time.Sleep(time.Millisecond * 900)
+}

+ 3 - 0
http/breaker/good.sh

@@ -0,0 +1,3 @@
+#!/bin/bash
+
+hey -z 60s http://localhost:8080/good

+ 3 - 0
http/breaker/heavy.sh

@@ -0,0 +1,3 @@
+#!/bin/bash
+
+hey -z 60s http://localhost:8080/heavy

+ 59 - 0
http/breaker/server.go

@@ -0,0 +1,59 @@
+package main
+
+import (
+	"net/http"
+	"runtime"
+	"time"
+
+	"github.com/tal-tech/go-zero/core/logx"
+	"github.com/tal-tech/go-zero/core/service"
+	"github.com/tal-tech/go-zero/core/stat"
+	"github.com/tal-tech/go-zero/core/syncx"
+	"github.com/tal-tech/go-zero/rest"
+)
+
+func main() {
+	logx.Disable()
+	stat.SetReporter(nil)
+	server := rest.MustNewServer(rest.RestConf{
+		ServiceConf: service.ServiceConf{
+			Name: "breaker",
+			Log: logx.LogConf{
+				Mode: "console",
+			},
+		},
+		Host:     "0.0.0.0",
+		Port:     8080,
+		MaxConns: 1000,
+		Timeout:  3000,
+	})
+	latch := syncx.NewLimit(10)
+	server.AddRoute(rest.Route{
+		Method: http.MethodGet,
+		Path:   "/heavy",
+		Handler: func(w http.ResponseWriter, r *http.Request) {
+			if latch.TryBorrow() {
+				defer latch.Return()
+				runtime.LockOSThread()
+				defer runtime.UnlockOSThread()
+				begin := time.Now()
+				for {
+					if time.Now().Sub(begin) > time.Millisecond*50 {
+						break
+					}
+				}
+			} else {
+				w.WriteHeader(http.StatusInternalServerError)
+			}
+		},
+	})
+	server.AddRoute(rest.Route{
+		Method: http.MethodGet,
+		Path:   "/good",
+		Handler: func(w http.ResponseWriter, r *http.Request) {
+			w.WriteHeader(http.StatusOK)
+		},
+	})
+	defer server.Stop()
+	server.Start()
+}

+ 5 - 0
http/breaker/start.sh

@@ -0,0 +1,5 @@
+#!/bin/bash
+
+GOOS=linux go build -ldflags="-s -w" server.go
+docker run --rm -it --cpus=1 -p 8080:8080 -v `pwd`:/app -w /app alpine /app/server
+rm -f server

+ 70 - 0
http/demo/main.go

@@ -0,0 +1,70 @@
+package main
+
+import (
+	"flag"
+	"net/http"
+
+	"github.com/tal-tech/go-zero/core/logx"
+	"github.com/tal-tech/go-zero/core/service"
+	"github.com/tal-tech/go-zero/rest"
+	"github.com/tal-tech/go-zero/rest/httpx"
+)
+
+var (
+	port    = flag.Int("port", 3333, "the port to listen")
+	timeout = flag.Int64("timeout", 0, "timeout of milliseconds")
+)
+
+type Request struct {
+	User string `form:"user,options=a|b"`
+}
+
+func first(next http.HandlerFunc) http.HandlerFunc {
+	return func(w http.ResponseWriter, r *http.Request) {
+		w.Header().Add("X-Middleware", "first")
+		next(w, r)
+	}
+}
+
+func second(next http.HandlerFunc) http.HandlerFunc {
+	return func(w http.ResponseWriter, r *http.Request) {
+		w.Header().Add("X-Middleware", "second")
+		next(w, r)
+	}
+}
+
+func handle(w http.ResponseWriter, r *http.Request) {
+	var req Request
+	err := httpx.Parse(r, &req)
+	if err != nil {
+		http.Error(w, err.Error(), http.StatusBadRequest)
+		return
+	}
+
+	httpx.OkJson(w, "helllo, "+req.User)
+}
+
+func main() {
+	flag.Parse()
+
+	engine := rest.MustNewServer(rest.RestConf{
+		ServiceConf: service.ServiceConf{
+			Log: logx.LogConf{
+				Mode: "console",
+			},
+		},
+		Port:     *port,
+		Timeout:  *timeout,
+		MaxConns: 500,
+	}, rest.WithNotAllowedHandler(rest.CorsHandler()))
+	defer engine.Stop()
+
+	engine.Use(first)
+	engine.Use(second)
+	engine.AddRoute(rest.Route{
+		Method:  http.MethodGet,
+		Path:    "/",
+		Handler: handle,
+	})
+	engine.Start()
+}

+ 65 - 0
http/post/main.go

@@ -0,0 +1,65 @@
+package main
+
+import (
+	"flag"
+	"fmt"
+	"net/http"
+
+	"github.com/tal-tech/go-zero/core/logx"
+	"github.com/tal-tech/go-zero/core/service"
+	"github.com/tal-tech/go-zero/rest"
+	"github.com/tal-tech/go-zero/rest/httpx"
+)
+
+var (
+	port    = flag.Int("port", 3333, "the port to listen")
+	timeout = flag.Int64("timeout", 0, "timeout of milliseconds")
+)
+
+type Request struct {
+	User string `json:"user"`
+}
+
+func handleGet(w http.ResponseWriter, r *http.Request) {
+}
+
+func handlePost(w http.ResponseWriter, r *http.Request) {
+	var req Request
+	err := httpx.Parse(r, &req)
+	if err != nil {
+		http.Error(w, err.Error(), http.StatusBadRequest)
+		return
+	}
+
+	httpx.OkJson(w, fmt.Sprintf("Content-Length: %d, UserLen: %d", r.ContentLength, len(req.User)))
+}
+
+func main() {
+	flag.Parse()
+
+	engine := rest.MustNewServer(rest.RestConf{
+		ServiceConf: service.ServiceConf{
+			Log: logx.LogConf{
+				Mode: "console",
+			},
+		},
+		Port:         *port,
+		Timeout:      *timeout,
+		MaxConns:     500,
+		MaxBytes:     50,
+		CpuThreshold: 500,
+	})
+	defer engine.Stop()
+
+	engine.AddRoute(rest.Route{
+		Method:  http.MethodGet,
+		Path:    "/",
+		Handler: handleGet,
+	})
+	engine.AddRoute(rest.Route{
+		Method:  http.MethodPost,
+		Path:    "/",
+		Handler: handlePost,
+	})
+	engine.Start()
+}

+ 11 - 0
http/shedding/Dockerfile

@@ -0,0 +1,11 @@
+FROM alpine
+
+RUN apk update --no-cache
+RUN apk add --no-cache ca-certificates
+RUN apk add --no-cache tzdata
+ENV TZ Asia/Shanghai
+
+WORKDIR /app
+COPY main /app/main
+
+CMD ["./main"]

+ 63 - 0
http/shedding/main.go

@@ -0,0 +1,63 @@
+package main
+
+import (
+	"flag"
+	"math"
+	"net/http"
+	"time"
+
+	"github.com/tal-tech/go-zero/core/logx"
+	"github.com/tal-tech/go-zero/core/service"
+	"github.com/tal-tech/go-zero/rest"
+	"github.com/tal-tech/go-zero/rest/httpx"
+)
+
+var (
+	port    = flag.Int("port", 3333, "the port to listen")
+	timeout = flag.Int64("timeout", 1000, "timeout of milliseconds")
+	cpu     = flag.Int64("cpu", 500, "cpu threshold")
+)
+
+type Request struct {
+	User string `form:"user,optional"`
+}
+
+func handle(w http.ResponseWriter, r *http.Request) {
+	var req Request
+	err := httpx.Parse(r, &req)
+	if err != nil {
+		http.Error(w, err.Error(), http.StatusBadRequest)
+		return
+	}
+
+	var result float64
+	for i := 0; i < 30000; i++ {
+		result += math.Sqrt(float64(i))
+	}
+	time.Sleep(time.Millisecond * 5)
+	httpx.OkJson(w, result)
+}
+
+func main() {
+	flag.Parse()
+
+	logx.Disable()
+	engine := rest.MustNewServer(rest.RestConf{
+		ServiceConf: service.ServiceConf{
+			Log: logx.LogConf{
+				Mode: "console",
+			},
+		},
+		Port:         *port,
+		Timeout:      *timeout,
+		CpuThreshold: *cpu,
+	})
+	defer engine.Stop()
+
+	engine.AddRoute(rest.Route{
+		Method:  http.MethodGet,
+		Path:    "/",
+		Handler: handle,
+	})
+	engine.Start()
+}

+ 67 - 0
limit/period/periodlimit.go

@@ -0,0 +1,67 @@
+package main
+
+import (
+	"flag"
+	"fmt"
+	"log"
+	"runtime"
+	"strconv"
+	"sync"
+	"sync/atomic"
+	"time"
+
+	"github.com/tal-tech/go-zero/core/limit"
+	"github.com/tal-tech/go-zero/core/stores/redis"
+)
+
+const seconds = 5
+
+var (
+	rdx     = flag.String("redis", "localhost:6379", "the redis, default localhost:6379")
+	rdxType = flag.String("redisType", "node", "the redis type, default node")
+	rdxPass = flag.String("redisPass", "", "the redis password")
+	rdxKey  = flag.String("redisKey", "rate", "the redis key, default rate")
+	threads = flag.Int("threads", runtime.NumCPU(), "the concurrent threads, default to cores")
+)
+
+func main() {
+	flag.Parse()
+
+	store := redis.NewRedis(*rdx, *rdxType, *rdxPass)
+	fmt.Println(store.Ping())
+	lmt := limit.NewPeriodLimit(seconds, 5, store, *rdxKey)
+	timer := time.NewTimer(time.Second * seconds)
+	quit := make(chan struct{})
+	defer timer.Stop()
+	go func() {
+		<-timer.C
+		close(quit)
+	}()
+
+	var allowed, denied int32
+	var wait sync.WaitGroup
+	for i := 0; i < *threads; i++ {
+		i := i
+		wait.Add(1)
+		go func() {
+			for {
+				select {
+				case <-quit:
+					wait.Done()
+					return
+				default:
+					if v, err := lmt.Take(strconv.FormatInt(int64(i), 10)); err == nil && v == limit.Allowed {
+						atomic.AddInt32(&allowed, 1)
+					} else if err != nil {
+						log.Fatal(err)
+					} else {
+						atomic.AddInt32(&denied, 1)
+					}
+				}
+			}
+		}()
+	}
+
+	wait.Wait()
+	fmt.Printf("allowed: %d, denied: %d, qps: %d\n", allowed, denied, (allowed+denied)/seconds)
+}

+ 66 - 0
limit/token/tokenlimit.go

@@ -0,0 +1,66 @@
+package main
+
+import (
+	"flag"
+	"fmt"
+	"runtime"
+	"sync"
+	"sync/atomic"
+	"time"
+
+	"github.com/tal-tech/go-zero/core/limit"
+	"github.com/tal-tech/go-zero/core/stores/redis"
+)
+
+const (
+	burst   = 100
+	rate    = 100
+	seconds = 5
+)
+
+var (
+	rdx     = flag.String("redis", "localhost:6379", "the redis, default localhost:6379")
+	rdxType = flag.String("redisType", "node", "the redis type, default node")
+	rdxKey  = flag.String("redisKey", "rate", "the redis key, default rate")
+	rdxPass = flag.String("redisPass", "", "the redis password")
+	threads = flag.Int("threads", runtime.NumCPU(), "the concurrent threads, default to cores")
+)
+
+func main() {
+	flag.Parse()
+
+	store := redis.NewRedis(*rdx, *rdxType, *rdxPass)
+	fmt.Println(store.Ping())
+	limit := limit.NewTokenLimiter(rate, burst, store, *rdxKey)
+	timer := time.NewTimer(time.Second * seconds)
+	quit := make(chan struct{})
+	defer timer.Stop()
+	go func() {
+		<-timer.C
+		close(quit)
+	}()
+
+	var allowed, denied int32
+	var wait sync.WaitGroup
+	for i := 0; i < *threads; i++ {
+		wait.Add(1)
+		go func() {
+			for {
+				select {
+				case <-quit:
+					wait.Done()
+					return
+				default:
+					if limit.Allow() {
+						atomic.AddInt32(&allowed, 1)
+					} else {
+						atomic.AddInt32(&denied, 1)
+					}
+				}
+			}
+		}()
+	}
+
+	wait.Wait()
+	fmt.Printf("allowed: %d, denied: %d, qps: %d\n", allowed, denied, (allowed+denied)/seconds)
+}

+ 148 - 0
load/main.go

@@ -0,0 +1,148 @@
+package main
+
+import (
+	"flag"
+	"fmt"
+	"io"
+	"math"
+	"math/rand"
+	"os"
+	"sync"
+	"sync/atomic"
+	"time"
+
+	"github.com/tal-tech/go-zero/core/collection"
+	"github.com/tal-tech/go-zero/core/executors"
+	"github.com/tal-tech/go-zero/core/logx"
+	"github.com/tal-tech/go-zero/core/syncx"
+	"gopkg.in/cheggaaa/pb.v1"
+)
+
+const (
+	beta     = 0.9
+	total    = 400
+	interval = time.Second
+	factor   = 5
+)
+
+var (
+	seconds             = flag.Int("d", 400, "duration to go")
+	flying              uint64
+	avgFlyingAggressive float64
+	aggressiveLock      syncx.SpinLock
+	avgFlyingLazy       float64
+	lazyLock            syncx.SpinLock
+	avgFlyingBoth       float64
+	bothLock            syncx.SpinLock
+	lessWriter          *executors.LessExecutor
+	passCounter         = collection.NewRollingWindow(50, time.Millisecond*100)
+	rtCounter           = collection.NewRollingWindow(50, time.Millisecond*100)
+	index               int32
+)
+
+func main() {
+	flag.Parse()
+
+	// only log 100 records
+	lessWriter = executors.NewLessExecutor(interval * total / 100)
+
+	fp, err := os.Create("result.csv")
+	logx.Must(err)
+	defer fp.Close()
+	fmt.Fprintln(fp, "second,maxFlight,flying,agressiveAvgFlying,lazyAvgFlying,bothAvgFlying")
+
+	ticker := time.NewTicker(interval)
+	defer ticker.Stop()
+	bar := pb.New(*seconds * 2).Start()
+	var waitGroup sync.WaitGroup
+	batchRequests := func(i int) {
+		<-ticker.C
+		requests := (i + 1) * factor
+		func() {
+			it := time.NewTicker(interval / time.Duration(requests))
+			defer it.Stop()
+			for j := 0; j < requests; j++ {
+				<-it.C
+				waitGroup.Add(1)
+				go func() {
+					issueRequest(fp, atomic.AddInt32(&index, 1))
+					waitGroup.Done()
+				}()
+			}
+			bar.Increment()
+		}()
+	}
+	for i := 0; i < *seconds; i++ {
+		batchRequests(i)
+	}
+	for i := *seconds; i > 0; i-- {
+		batchRequests(i)
+	}
+	bar.Finish()
+	waitGroup.Wait()
+}
+
+func issueRequest(writer io.Writer, idx int32) {
+	v := atomic.AddUint64(&flying, 1)
+	aggressiveLock.Lock()
+	af := avgFlyingAggressive*beta + float64(v)*(1-beta)
+	avgFlyingAggressive = af
+	aggressiveLock.Unlock()
+	bothLock.Lock()
+	bf := avgFlyingBoth*beta + float64(v)*(1-beta)
+	avgFlyingBoth = bf
+	bothLock.Unlock()
+	duration := time.Millisecond * time.Duration(rand.Int63n(10)+1)
+	job(duration)
+	passCounter.Add(1)
+	rtCounter.Add(float64(duration) / float64(time.Millisecond))
+	v1 := atomic.AddUint64(&flying, ^uint64(0))
+	lazyLock.Lock()
+	lf := avgFlyingLazy*beta + float64(v1)*(1-beta)
+	avgFlyingLazy = lf
+	lazyLock.Unlock()
+	bothLock.Lock()
+	bf = avgFlyingBoth*beta + float64(v1)*(1-beta)
+	avgFlyingBoth = bf
+	bothLock.Unlock()
+	lessWriter.DoOrDiscard(func() {
+		fmt.Fprintf(writer, "%d,%d,%d,%.2f,%.2f,%.2f\n", idx, maxFlight(), v, af, lf, bf)
+	})
+}
+
+func job(duration time.Duration) {
+	time.Sleep(duration)
+}
+
+func maxFlight() int64 {
+	return int64(math.Max(1, float64(maxPass()*10)*(minRt()/1e3)))
+}
+
+func maxPass() int64 {
+	var result float64 = 1
+
+	passCounter.Reduce(func(b *collection.Bucket) {
+		if b.Sum > result {
+			result = b.Sum
+		}
+	})
+
+	return int64(result)
+}
+
+func minRt() float64 {
+	var result float64 = 1000
+
+	rtCounter.Reduce(func(b *collection.Bucket) {
+		if b.Count <= 0 {
+			return
+		}
+
+		avg := math.Round(b.Sum / float64(b.Count))
+		if avg < result {
+			result = avg
+		}
+	})
+
+	return result
+}

+ 14 - 0
load/plot.py

@@ -0,0 +1,14 @@
+import click
+import pandas as pd
+import matplotlib.pyplot as plt
+
+@click.command()
+@click.option("--csv", default="result.csv")
+def main(csv):
+    df = pd.read_csv(csv, index_col="second")
+    df.drop(["agressiveAvgFlying", "bothAvgFlying"], axis=1, inplace=True)
+    df.plot()
+    plt.show()
+
+if __name__ == "__main__":
+    main()

+ 95 - 0
load/simulate/client/main.go

@@ -0,0 +1,95 @@
+package main
+
+import (
+	"errors"
+	"flag"
+	"fmt"
+	"io"
+	"net/http"
+	"os"
+	"sync/atomic"
+	"time"
+
+	"github.com/tal-tech/go-zero/core/fx"
+	"github.com/tal-tech/go-zero/core/logx"
+)
+
+var (
+	errServiceUnavailable = errors.New("service unavailable")
+	total                 int64
+	pass                  int64
+	fail                  int64
+	drop                  int64
+	seconds               int64 = 1
+)
+
+func main() {
+	flag.Parse()
+
+	fp, err := os.Create("result.csv")
+	logx.Must(err)
+	defer fp.Close()
+	fmt.Fprintln(fp, "seconds,total,pass,fail,drop")
+
+	go func() {
+		ticker := time.NewTicker(time.Second)
+		defer ticker.Stop()
+		for range ticker.C {
+			reset(fp)
+		}
+	}()
+
+	for i := 0; ; i++ {
+		it := time.NewTicker(time.Second / time.Duration(atomic.LoadInt64(&seconds)))
+		func() {
+			for j := 0; j < int(seconds); j++ {
+				<-it.C
+				go issueRequest()
+			}
+		}()
+		it.Stop()
+
+		cur := atomic.AddInt64(&seconds, 1)
+		fmt.Println(cur)
+	}
+}
+
+func issueRequest() {
+	atomic.AddInt64(&total, 1)
+	err := fx.DoWithTimeout(func() error {
+		return job()
+	}, time.Second)
+	switch err {
+	case nil:
+		atomic.AddInt64(&pass, 1)
+	case errServiceUnavailable:
+		atomic.AddInt64(&drop, 1)
+	default:
+		atomic.AddInt64(&fail, 1)
+	}
+}
+
+func job() error {
+	resp, err := http.Get("http://localhost:3333/")
+	if err != nil {
+		return err
+	}
+
+	defer resp.Body.Close()
+	switch resp.StatusCode {
+	case http.StatusOK:
+		return nil
+	default:
+		return errServiceUnavailable
+	}
+}
+
+func reset(writer io.Writer) {
+	fmt.Fprintf(writer, "%d,%d,%d,%d,%d\n",
+		atomic.LoadInt64(&seconds),
+		atomic.SwapInt64(&total, 0),
+		atomic.SwapInt64(&pass, 0),
+		atomic.SwapInt64(&fail, 0),
+		atomic.SwapInt64(&drop, 0),
+	)
+}

+ 13 - 0
load/simulate/client/plot.py

@@ -0,0 +1,13 @@
+import click
+import pandas as pd
+import matplotlib.pyplot as plt
+
+@click.command()
+@click.option("--csv", default="result.csv")
+def main(csv):
+    df = pd.read_csv(csv, index_col="seconds")
+    df.plot()
+    plt.show()
+
+if __name__ == "__main__":
+    main()

+ 26 - 0
load/simulate/cpu/Dockerfile

@@ -0,0 +1,26 @@
+FROM golang:alpine AS builder
+
+LABEL stage=gobuilder
+
+ENV CGO_ENABLED 0
+ENV GOOS linux
+ENV GOPROXY https://goproxy.cn,direct
+
+WORKDIR $GOPATH/src/zero
+COPY . .
+RUN go build -ldflags="-s -w" -o /app/main example/load/simulate/cpu/main.go
+
+
+FROM alpine
+
+RUN apk add --no-cache tzdata
+ENV TZ Asia/Shanghai
+
+RUN apk add git
+RUN go get github.com/vikyd/go-cpu-load
+
+RUN mkdir /app
+COPY --from=builder /app/main /app/main
+
+WORKDIR /app
+CMD ["/app/main"]

Bu fark içinde çok fazla dosya değişikliği olduğu için bazı dosyalar gösterilmiyor