├── .gitattributes ├── .gitignore ├── .golangci.yml ├── .goreleaser.yml ├── Dockerfile ├── LICENSE ├── Makefile ├── README.md ├── benchmark ├── README.md ├── _backup │ ├── README.md │ ├── micro_client.go │ ├── micro_mclient.go │ └── micro_server.go ├── go.mod ├── grpc_grpc │ ├── client.go │ └── server.go ├── grpc_rpc │ ├── client.go │ └── server.go ├── proto │ ├── micro_benchmark.micro.go │ ├── micro_benchmark.pb.go │ └── micro_benchmark.proto ├── service │ ├── client.go │ ├── codec.go │ └── server.go ├── tcp_rpc │ ├── client.go │ └── server.go └── utp_rpc │ ├── client.go │ └── server.go ├── cmd └── micro │ ├── main.go │ ├── server │ ├── auth.go │ ├── plugin.go │ ├── proxy.go │ └── server.go │ ├── service │ ├── api │ │ ├── api.go │ │ └── auth.go │ └── service.go │ └── web │ ├── README.md │ ├── html │ ├── assets │ │ ├── jquery.min.js │ │ ├── mu.css │ │ ├── mu.js │ │ └── mu.png │ └── template.go │ └── web.go ├── doc └── img │ ├── micro-istio.png │ └── micro.jpg ├── go.mod ├── go.sum ├── manifests ├── buildpacks │ └── project.toml ├── charts │ ├── micro │ │ ├── .helmignore │ │ ├── Chart.yaml │ │ ├── templates │ │ │ ├── NOTES.txt │ │ │ ├── _helpers.tpl │ │ │ ├── deployment.yaml │ │ │ ├── hpa.yaml │ │ │ ├── ingress.yaml │ │ │ ├── service.yaml │ │ │ ├── serviceaccount.yaml │ │ │ └── tests │ │ │ │ └── test-connection.yaml │ │ └── values.yaml │ └── service │ │ ├── .helmignore │ │ ├── Chart.yaml │ │ ├── templates │ │ ├── _helpers.tpl │ │ ├── deployment.yaml │ │ ├── hpa.yaml │ │ ├── service.yaml │ │ ├── serviceaccount.yaml │ │ └── tests │ │ │ └── test-connection.yaml │ │ └── values.yaml ├── kubevela │ └── application.yml └── tekton │ ├── README.md │ ├── buildpacks │ ├── pipeline.yml │ └── run.yml │ ├── kaniko │ ├── pipeline.yml │ └── run.yml │ └── trigger-template.yml ├── pkg ├── file │ ├── file_slice.go │ └── walk_dir.go ├── service │ └── service.go └── tools │ └── proto │ └── batch.go ├── profile └── profile.go └── service ├── auth └── noop │ └── noop.go └── greeting ├── .goreleaser.yml ├── Dockerfile ├── LICENSE ├── Makefile ├── README.md ├── conf ├── auth_key ├── auth_key.pub ├── casbin_model.conf ├── casbin_policy.csv └── type.go ├── domain ├── model │ └── greeting.go ├── repository │ └── greeting.go └── usecase │ └── greeting.go ├── generate.go ├── main.go ├── proto └── greeting │ ├── greeting.pb.go │ ├── greeting.pb.micro.go │ └── greeting.proto ├── registry └── container.go ├── repo ├── gorm │ ├── .gitkeep │ ├── db.go │ └── greeting_repository.go └── memory │ └── memory.go ├── server └── handler.go └── service └── greeting.go /.gitattributes: -------------------------------------------------------------------------------- 1 | console/web/vue-admin-template/* linguist-vendored 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.dll 4 | *.so 5 | *.dylib 6 | 7 | go.sum 8 | 9 | # Test binary, build with `go test -c` 10 | *.test 11 | 12 | # Output of the go coverage tool, specifically when used with LiteIDE 13 | *.out 14 | 15 | # Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736 16 | .glide/ 17 | 18 | .idea 19 | bin 20 | build 21 | dist 22 | vendor 23 | -------------------------------------------------------------------------------- /.golangci.yml: -------------------------------------------------------------------------------- 1 | # options for analysis running 2 | run: 3 | deadline: 10m 4 | skip-dirs: 5 | - benchmark 6 | 7 | # default is true. Enables skipping of directories: 8 | # vendor$, third_party$, testdata$, examples$, Godeps$, builtin$ 9 | skip-dirs-use-default: true 10 | 11 | linters: 12 | disable-all: false 13 | enable-all: false 14 | enable: 15 | - megacheck 16 | - staticcheck 17 | - deadcode 18 | - varcheck 19 | - gosimple 20 | - unused 21 | - prealloc 22 | - scopelint 23 | - goimports 24 | - unconvert 25 | - govet 26 | - nakedret 27 | - structcheck 28 | - gosec 29 | disable: 30 | - maligned 31 | - interfacer 32 | - typecheck 33 | - dupl 34 | - gocritic 35 | linters-settings: 36 | govet: 37 | check-shadowing: true 38 | issues: 39 | # Excluding configuration per-path, per-linter, per-text and per-source 40 | exclude-rules: 41 | # Exclude known linters from partially hard-vendored code, 42 | # which is impossible to exclude via "nolint" comments. 43 | - text: "weak cryptographic primitive" 44 | linters: 45 | - gosec 46 | # Independently from option `exclude` we use default exclude patterns, 47 | # it can be disabled by this option. To list all 48 | # excluded by default patterns execute `golangci-lint run --help`. 49 | # Default value for this option is true. 50 | exclude-use-default: false 51 | -------------------------------------------------------------------------------- /.goreleaser.yml: -------------------------------------------------------------------------------- 1 | # This is an example goreleaser.yaml file with some sane defaults. 2 | # Make sure to check the documentation at http://goreleaser.com 3 | project_name: "micro" 4 | before: 5 | hooks: 6 | # You may remove this if you don't use go modules. 7 | - go mod download 8 | 9 | builds: 10 | - # ID of the build. 11 | # Defaults to the project name. 12 | id: "micro" 13 | 14 | # Path to project's (sub)directory containing Go code. 15 | # This is the working directory for the Go build command(s). 16 | # Default is `.`. 17 | dir: ./cmd/micro 18 | 19 | # Path to main.go file or main package. 20 | # Default is `.`. 21 | main: . 22 | 23 | # Binary name. 24 | # Can be a path (e.g. `bin/app`) to wrap the binary in a directory. 25 | # Default is the name of the project directory. 26 | binary: bin/{{ .ProjectName }} 27 | 28 | # Custom flags templates. 29 | # Default is empty. 30 | #flags: 31 | 32 | # Custom ldflags templates. 33 | # Default is `-s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}} -X main.builtBy=goreleaser`. 34 | ldflags: 35 | - -s -w -X main.version={{ .Version }} -X main.commit={{ .ShortCommit }} -X main.date={{ .Date }} -X main.builtBy=hbchen.com 36 | 37 | # Custom environment variables to be set during the builds. 38 | # Default is empty. 39 | #env: 40 | 41 | # GOOS list to build for. 42 | # For more info refer to: https://golang.org/doc/install/source#environment 43 | # Defaults are darwin and linux. 44 | goos: 45 | - linux 46 | - darwin 47 | #- windows 48 | 49 | # GOARCH to build for. 50 | # For more info refer to: https://golang.org/doc/install/source#environment 51 | # Defaults are 386 and amd64. 52 | goarch: 53 | - amd64 54 | #- 386 55 | - arm64 56 | 57 | archives: 58 | - # ID of this archive. 59 | # Defaults to `default`. 60 | id: micro 61 | 62 | #replacements: 63 | # darwin: Darwin 64 | # linux: Linux 65 | # windows: Windows 66 | # 386: i386 67 | # amd64: x86_64 68 | 69 | # Archive name template. 70 | # Defaults: 71 | # - if format is `tar.gz`, `tar.xz`, `gz` or `zip`: 72 | # - `{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}{{ if .Mips }}_{{ .Mips }}{{ end }}` 73 | # - if format is `binary`: 74 | # - `{{ .Binary }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}{{ if .Mips }}_{{ .Mips }}{{ end }}` 75 | name_template: "{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}{{ if .Mips }}_{{ .Mips }}{{ end }}" 76 | format: tar.gz 77 | files: 78 | - README.md 79 | - LICENSE 80 | - doc 81 | - manifests 82 | 83 | # Set to true, if you want all files in the archive to be in a single directory. 84 | # If set to true and you extract the archive 'goreleaser_Linux_arm64.tar.gz', 85 | # you get a folder 'goreleaser_Linux_arm64'. 86 | # If set to false, all files are extracted separately. 87 | # You can also set it to a custom folder name (templating is supported). 88 | # Default is false. 89 | wrap_in_directory: true 90 | 91 | # Disables the binary count check. 92 | # Default: false 93 | allow_different_binary_count: true 94 | snapshot: 95 | # Allows you to change the name of the generated snapshot 96 | # 97 | # Note that some pipes require this to be semantic version compliant (nfpm, 98 | # for example). 99 | # 100 | # Default is `{{ .Tag }}-SNAPSHOT-{{.ShortCommit}}`. 101 | name_template: '{{ .Version }}-SNAPSHOT-{{ .ShortCommit }}' 102 | checksum: 103 | name_template: 'checksums.txt' 104 | changelog: 105 | sort: asc 106 | filters: 107 | exclude: 108 | - '^docs:' 109 | - '^test:' 110 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:3.10 2 | 3 | ADD dist/micro_linux_amd64_v1/bin/micro /opt/service/micro 4 | 5 | EXPOSE 8080 6 | WORKDIR /opt/service 7 | 8 | CMD [ "./micro"] 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Hobo Go 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | GOOS=$(shell go env GOOS) 3 | GOARCH=$(shell go env GOARCH) 4 | 5 | ifeq ($(OS),Windows_NT) 6 | uname_S := Windows 7 | else 8 | uname_S := $(shell uname -s) 9 | endif 10 | 11 | # Goreleaser config 12 | ifeq ($(uname_S), Darwin) 13 | goreleaser_config = .goreleaser.yml 14 | else 15 | goreleaser_config = .goreleaser.yml 16 | endif 17 | 18 | .PHONY: micro 19 | micro: 20 | ./dist/micro_$(GOOS)_$(GOARCH)/bin/micro --profile starter-local server 21 | 22 | .PHONY: example 23 | example: 24 | ./dist/example_$(GOOS)_$(GOARCH)/bin/example --profile starter-local 25 | 26 | .PHONY: release 27 | release: 28 | goreleaser release --config $(goreleaser_config) --skip-validate --skip-publish --rm-dist 29 | 30 | .PHONY: snapshot 31 | snapshot: 32 | goreleaser release --config $(goreleaser_config) --skip-publish --snapshot --rm-dist 33 | 34 | .PHONY: test 35 | test: 36 | go test -race -cover -v ./cmd/... ./service/... ./profile/... ./pkg/... 37 | 38 | .PHONY: lint 39 | lint: 40 | golangci-lint run ./cmd/... ./service/... ./profile/... ./pkg/... 41 | 42 | .PHONY: pack_build 43 | pack_build: 44 | pack build micro \ 45 | --builder paketobuildpacks/builder:tiny \ 46 | --descriptor manifests/buildpacks/project.toml \ 47 | --tag registry.cn-hangzhou.aliyuncs.com/hb-chen/micro-starter-micro:latest 48 | 49 | .PHONY: run 50 | run: 51 | docker run micro --profile starter-local server -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Micro [github.com/micro](http://github.com/micro) 2 | 3 | [![Slack](https://img.shields.io/badge/slack-join-D60051.svg)](https://hbchen.slack.com/messages/CE68CJ60Z) 4 | 5 | ![go-micro](/doc/img/micro.jpg "go-micro") 6 | 7 | ## Local 8 | 9 | Build micro cmd 10 | ```shell script 11 | go build -o bin/micro cmd/micro/main.go 12 | ``` 13 | 14 | Start registry & api with server runtime 15 | ```shell script 16 | ./bin/micro --profile starter-local server 17 | ``` 18 | 19 |
20 | Start registry & api with service command 21 | Run registry service 22 | ```shell script 23 | ./bin/micro --profile starter-local service registry 24 | ``` 25 | 26 | Run API service 27 | ```shell script 28 | ./bin/micro --profile starter-local service api 29 | ``` 30 |
31 | 32 | Run example service 33 | ```shell script 34 | # Greeting 35 | cd service/greeting 36 | CGO_ENABLED=0 go run main.go --profile starter-local 37 | ``` 38 | 39 | Test example service 40 | ```shell script 41 | # Greeting 42 | curl "http://localhost:8080/greeting/call?msg=helloworld" 43 | {"id":"1","msg":"helloworld"} 44 | 45 | curl "http://localhost:8080/greeting/list?page=1&size=10" 46 | {"items":[{"id":"1","msg":"helloworld"}]} 47 | ``` 48 | 49 | ## Kubernetes 50 | 51 | ```shell 52 | $ make snapshot 53 | 54 | $ docker build ./ -f Dockerfile --platform=linux/amd64 -t registry.cn-hangzhou.aliyuncs.com/hb-chen/micro-starter-micro:latest 55 | ``` 56 | 57 | > Attention: default ingress class=nginx, host=api.micro.hbchen.com 58 | 59 | ```shell 60 | helm install -n micro micro-server manifests/charts/micro \ 61 | --set ingress.enabled=true 62 | 63 | # Digest 64 | helm install -n micro micro-server manifests/charts/micro \ 65 | --set image.tag="latest@sha256:aceabd67ac333dcd19bde3524c54e7a556b8651cf049495ab6e086d45bb7ad77" \ 66 | --set ingress.enabled=true 67 | ``` 68 | 69 | ```shell 70 | helm install -n micro micro-example manifests/charts/service 71 | 72 | # Digest 73 | helm install -n micro micro-example manifests/charts/service \ 74 | --set image.tag="latest@sha256:a2af30ff9a0a66ade77672e01679a2b02ead3b2b0f27bd7092d726d75fd069e0" 75 | ``` 76 | 77 | ```shell 78 | curl "http://api.micro.hbchen.com/greeting/call?msg=helloworld" 79 | ``` -------------------------------------------------------------------------------- /benchmark/README.md: -------------------------------------------------------------------------------- 1 | # Benchmark 2 | >ref:[rpcx-benchmark](https://github.com/rpcx-ecosystem/rpcx-benchmark) 3 | 4 | 测试影响`go-micro`服务间通信效率的三个组件:`transport`、`server`以及`codec`,主要做不同插件间的横向对比。 5 | 6 | **测试环境** 7 | 8 | - MBP 9 | - go **1.12.5** 10 | - go-micro **v1.2.0** 11 | - go-plugins **v1.1.0** 12 | 13 | ## Transport + Server对比 14 | 15 | `transport`和`server`的对比使用`100`并发,完成`10W`请求进行测试 16 | 17 | ### 结果对比 18 | 从结果看`tcp`+`rpc`吞吐量最高,分别比较: 19 | 20 | - `transport`比较结果`tcp`>`grpc`>`utp` 21 | - `server`比较结果`rpc`>`grpc` 22 | 23 | T+S|平均
(ms)|中位
(ms)|最大
(ms)|最小
(ms)|P90
(ms)|P99
(ms)|TPS 24 | ---|---|---|---|---|---|---|--- 25 | tcp+rpc|7.236|5.629|101.506|0.177|13.338|35.880|13192 26 | grpc+rpc|8.668|7.964|101.280|0.251|12.744|21.672|11166 27 | utp+rpc|11.824|11.600|53.183|0.204|15.575|21.334|8252 28 | grpc+grpc|8.924|8.181|134.434|0.286|13.211|22.973|10845 29 | 30 | > 在开始的测试中有个误区,`grpc`服务并不使用`transport`,包括`http`服务,`transport`仅在使用`go-micro`的`rpc`服务时有效 31 | 32 | ## Codec对比 33 | `transport`和`server`分别使用`tcp`和`rpc`对比不同`codec`性能,因为并发`100`时不同`codec`的失败率差别比较大,所以使用`50`并发,完成`10W`请求进行测试 34 | 35 | ### 结果对比 36 | 对比结果:`protobuf`>`proto-rpc`>`grpc`>`json`>`grpc+json`>`json-rpc`>`bsonrpc` 37 | 38 | CODEC|平均
(ms)|中位
(ms)|最大
(ms)|最小
(ms)|P90
(ms)|P99
(ms)|TPS 39 | -----|------|------|------|------|------|------|------ 40 | grpc|3.937|2.979|90.004|0.180|7.184|19.355|12310 41 | grpc+json|6.085|4.694|149.861|0.342|10.365|31.837|8000 42 | protobuf|3.661|2.707|96.636|0.156|6.542|20.261|13150 43 | json|5.402|4.122|122.360|0.225|9.186|30.474|8896 44 | json-rpc|6.380|4.878|115.141|0.288|11.150|33.395|7631 45 | proto-rpc|3.692|2.729|101.010|0.180|6.701|19.454|13041 46 | bsonrpc|7.912|5.979|132.041|0.354|14.789|40.414|6145 47 | 48 | 默认`chdec`如下 49 | ```go 50 | DefaultCodecs = map[string]codec.NewCodec{ 51 | "application/grpc": grpc.NewCodec, 52 | "application/grpc+json": grpc.NewCodec, 53 | "application/grpc+proto": grpc.NewCodec, 54 | "application/json": json.NewCodec, 55 | "application/json-rpc": jsonrpc.NewCodec, 56 | "application/protobuf": proto.NewCodec, 57 | "application/proto-rpc": protorpc.NewCodec, 58 | "application/octet-stream": raw.NewCodec, 59 | } 60 | ``` 61 | 62 | 另外`go-plugins`提供三个`codec`插件,在`server`和`client`初始化时自定义添加 63 | ```go 64 | server.Codec("application/msgpackrpc", msgpackrpc.NewCodec), 65 | server.Codec("application/bsonrpc", bsonrpc.NewCodec), 66 | server.Codec("application/jsonrpc2", jsonrpc2.NewCodec), 67 | 68 | client.Codec("application/msgpackrpc", msgpackrpc.NewCodec), 69 | client.Codec("application/bsonrpc", bsonrpc.NewCodec), 70 | client.Codec("application/jsonrpc2", jsonrpc2.NewCodec), 71 | ``` 72 | 73 | 实际测试时由于不同原因`raw` 、`msgpackrpc`和`jsonrpc2`运行失败未测试,`grpc+proto`与`grpc`实现一致未测试 74 | 75 | >raw.NewCodec
error:{"id":"go.micro.client.codec","code":500,"detail":"failed to write: field1:……
76 | msgpackrpc.NewCodec,需要实现EncodeMsg(*Writer)
error:{"id":"go.micro.client.codec","code":500,"detail":"Not encodable","status":"Internal Server Error"}
77 | jsonrpc2.NewCodec
error:{"id":"go.micro.client.transport","code":500,"detail":"EOF","status":"Internal Server Error"} 78 | 79 | ## 详细数据 80 | 81 | ### Transport + Server 82 | 83 | #### 测试命令 84 | ```bash 85 | $ go run server.go 86 | $ go run client.go -c 100 -n 100000 87 | ``` 88 | 89 | **tcp + rpc** 90 | ```bash 91 | took (ms) : 7580 92 | sent requests : 100000 93 | received requests : 100000 94 | received requests_OK : 99999 95 | throughput (TPS) : 13192 96 | 97 | concurrency mean median max min p90 p99 TPS 98 | 100 7235584ns 5629000ns 101506000ns 177000ns 13338000ns 35880000ns 13192 99 | 100 7.236ms 5.629ms 101.506ms 0.177ms 13.338ms 35.880ms 13192 100 | 101 | ``` 102 | 103 | **tcp + grpc** 104 | ```bash 105 | took (ms) : 9295 106 | sent requests : 100000 107 | received requests : 100000 108 | received requests_OK : 99994 109 | throughput (TPS) : 10758 110 | 111 | concurrency mean median max min p90 p99 TPS 112 | 100 9005583ns 8171000ns 110580000ns 300000ns 13510000ns 24317000ns 10758 113 | 100 9.006ms 8.171ms 110.580ms 0.300ms 13.510ms 24.317ms 10758 114 | ``` 115 | 116 | **grpc + rpc** 117 | ```bash 118 | took (ms) : 8955 119 | sent requests : 100000 120 | received requests : 100000 121 | received requests_OK : 99999 122 | throughput (TPS) : 11166 123 | 124 | concurrency mean median max min p90 p99 TPS 125 | 100 8668191ns 7964000ns 101280000ns 251000ns 12744000ns 21672000ns 11166 126 | 100 8.668ms 7.964ms 101.280ms 0.251ms 12.744ms 21.672ms 11166 127 | ``` 128 | 129 | 130 | **grpc + gRPC** 131 | ```bash 132 | took (ms) : 9220 133 | sent requests : 100000 134 | received requests : 100000 135 | received requests_OK : 99995 136 | throughput (TPS) : 10845 137 | 138 | concurrency mean median max min p90 p99 TPS 139 | 100 8924043ns 8181000ns 134434000ns 286000ns 13211000ns 22973000ns 10845 140 | 100 8.924ms 8.181ms 134.434ms 0.286ms 13.211ms 22.973ms 10845 141 | ``` 142 | 143 | 144 | **utp + rpc** 145 | ```bash 146 | took (ms) : 12117 147 | sent requests : 100000 148 | received requests : 100000 149 | received requests_OK : 100000 150 | throughput (TPS) : 8252 151 | 152 | concurrency mean median max min p90 p99 TPS 153 | 100 11823520ns 11600000ns 53183000ns 204000ns 15575000ns 21334000ns 8252 154 | 100 11.824ms 11.600ms 53.183ms 0.204ms 15.575ms 21.334ms 8252 155 | ``` 156 | 157 | **utp + grpc** 158 | ```bash 159 | took (ms) : 9367 160 | sent requests : 100000 161 | received requests : 100000 162 | received requests_OK : 99999 163 | throughput (TPS) : 10675 164 | 165 | concurrency mean median max min p90 p99 TPS 166 | 100 9063046ns 8213000ns 102052000ns 289000ns 13553000ns 23920000ns 10675 167 | 100 9.063ms 8.213ms 102.052ms 0.289ms 13.553ms 23.920ms 10675 168 | ``` 169 | 170 | ### Codec 171 | 172 | #### 测试命令 173 | 174 | ```bash 175 | $ cd benchmark/tcp_rpc 176 | $ go run server.go 177 | $ go run client.go -c 50 -n 100000 -ct grpc 178 | $ go run client.go -c 50 -n 100000 -ct grpc+json 179 | $ go run client.go -c 50 -n 100000 -ct protobuf 180 | $ go run client.go -c 50 -n 100000 -ct json 181 | $ go run client.go -c 50 -n 100000 -ct json-rpc 182 | $ go run client.go -c 50 -n 100000 -ct proto-rpc 183 | $ go run client.go -c 50 -n 100000 -ct bsonrpc 184 | ``` 185 | 186 | **grpc** 187 | ```bash 188 | took (ms) : 8123 189 | sent requests : 100000 190 | received requests : 100000 191 | received requests_OK : 100000 192 | throughput (TPS) : 12310 193 | 194 | concurrency mean median max min p90 p99 TPS 195 | 50 3936652ns 2979000ns 90004000ns 180000ns 7184000ns 19355000ns 12310 196 | 50 3.937ms 2.979ms 90.004ms 0.180ms 7.184ms 19.355ms 12310 197 | ``` 198 | 199 | **grpc+json** 200 | ```bash 201 | took (ms) : 12500 202 | sent requests : 100000 203 | received requests : 100000 204 | received requests_OK : 99961 205 | throughput (TPS) : 8000 206 | 207 | concurrency mean median max min p90 p99 TPS 208 | 50 6084709ns 4694000ns 149861000ns 342000ns 10365000ns 31837000ns 8000 209 | 50 6.085ms 4.694ms 149.861ms 0.342ms 10.365ms 31.837ms 8000 210 | ``` 211 | 212 | **protobuf** 213 | ```bash 214 | took (ms) : 7604 215 | sent requests : 100000 216 | received requests : 100000 217 | received requests_OK : 100000 218 | throughput (TPS) : 13150 219 | 220 | concurrency mean median max min p90 p99 TPS 221 | 50 3660854ns 2707000ns 96636000ns 156000ns 6542000ns 20261000ns 13150 222 | 50 3.661ms 2.707ms 96.636ms 0.156ms 6.542ms 20.261ms 13150 223 | ``` 224 | 225 | **json** 226 | ```bash 227 | took (ms) : 11241 228 | sent requests : 100000 229 | received requests : 100000 230 | received requests_OK : 99922 231 | throughput (TPS) : 8896 232 | 233 | concurrency mean median max min p90 p99 TPS 234 | 50 5401532ns 4121500ns 122360000ns 225000ns 9186000ns 30474000ns 8896 235 | 50 5.402ms 4.122ms 122.360ms 0.225ms 9.186ms 30.474ms 8896 236 | ``` 237 | 238 | **json-rpc** 239 | ```bash 240 | took (ms) : 13103 241 | sent requests : 100000 242 | received requests : 100000 243 | received requests_OK : 99971 244 | throughput (TPS) : 7631 245 | 246 | concurrency mean median max min p90 p99 TPS 247 | 50 6380308ns 4878000ns 115141000ns 288000ns 11150000ns 33395000ns 7631 248 | 50 6.380ms 4.878ms 115.141ms 0.288ms 11.150ms 33.395ms 7631 249 | ``` 250 | 251 | **proto-rpc** 252 | ```bash 253 | took (ms) : 7668 254 | sent requests : 100000 255 | received requests : 100000 256 | received requests_OK : 99998 257 | throughput (TPS) : 13041 258 | 259 | concurrency mean median max min p90 p99 TPS 260 | 50 3692281ns 2729000ns 101010000ns 180000ns 6701000ns 19454000ns 13041 261 | 50 3.692ms 2.729ms 101.010ms 0.180ms 6.701ms 19.454ms 13041 262 | ``` 263 | 264 | **bsonrpc** 265 | ```bash 266 | took (ms) : 16272 267 | sent requests : 100000 268 | received requests : 100000 269 | received requests_OK : 99933 270 | throughput (TPS) : 6145 271 | 272 | concurrency mean median max min p90 p99 TPS 273 | 50 7911887ns 5979000ns 132041000ns 354000ns 14789000ns 40414000ns 6145 274 | 50 7.912ms 5.979ms 132.041ms 0.354ms 14.789ms 40.414ms 6145 275 | ``` -------------------------------------------------------------------------------- /benchmark/_backup/README.md: -------------------------------------------------------------------------------- 1 | # Benchmark 2 | [rpcx-benchmark](https://github.com/rpcx-ecosystem/rpcx-benchmark) 3 | 4 | - MBP开发环境,不限流&不熔断 5 | ```bash 6 | go run micro_mclient.go -c 100 -n 50000 7 | 2018/06/27 17:48:00 Servers: [127.0.0.1:8972] 8 | 9 | 2018/06/27 17:51:28 concurrency: 100 10 | requests per client: 500 11 | 12 | 2018/06/27 17:51:32 took 3885 ms for 50000 requests 13 | 2018/06/27 17:51:32 sent requests : 50000 14 | 2018/06/27 17:51:32 received requests : 50000 15 | 2018/06/27 17:51:32 received requests_OK : 50000 16 | 2018/06/27 17:51:32 throughput (TPS) : 12870 17 | 2018/06/27 17:51:32 mean: 5376750 ns, median: 4338000 ns, max: 96008000 ns, min: 156000 ns, p99: 45684000 ns 18 | 2018/06/27 17:51:32 mean: 5 ms, median: 4 ms, max: 96 ms, min: 0 ms, p99: 45 ms 19 | ``` 20 | 21 | - 限流 22 | ```go 23 | helloClient := client.NewClient( 24 | client.Transport(tcp.NewTransport()), 25 | client.ContentType("application/proto-rpc"), 26 | client.Selector(cache.NewSelector(cache.TTL(time.Second*3000))), 27 | client.Retries(1), 28 | client.PoolSize(100), 29 | client.RequestTimeout(time.Millisecond*1000), 30 | client.Wrap(ratelimit.NewClientWrapper(1)), 31 | ) 32 | ``` 33 | ```bash 34 | # client.Wrap(ratelimit.NewClientWrapper(1)) 35 | 36 | ➜ benchmark git:(master) ✗ go run micro_client.go -c 50 -n 1000 37 | 2018/07/06 21:27:13 concurrency: 50 38 | requests per client: 20 39 | 40 | 2018/07/06 21:27:37 took 24018 ms for 1000 requests 41 | 2018/07/06 21:27:37 sent requests : 1000 42 | 2018/07/06 21:27:37 received requests : 1000 43 | 2018/07/06 21:27:37 received requests_OK : 1000 44 | 2018/07/06 21:27:37 throughput (TPS) : 41 45 | 2018/07/06 21:27:37 mean: 1000159226 ns, median: 999944000 ns, max: 1009774000 ns, min: 992741000 ns, p99: 1009760500 ns 46 | 2018/07/06 21:27:37 mean: 1000 ms, median: 999 ms, max: 1009 ms, min: 992 ms, p99: 1009 ms 47 | 48 | # client.Wrap(ratelimit.NewClientWrapper(10)) 49 | ➜ benchmark git:(master) ✗ go run micro_client.go -c 50 -n 1000 50 | 2018/07/06 21:27:53 concurrency: 50 51 | requests per client: 20 52 | 53 | 2018/07/06 21:27:56 took 2414 ms for 1000 requests 54 | 2018/07/06 21:27:56 sent requests : 1000 55 | 2018/07/06 21:27:56 received requests : 1000 56 | 2018/07/06 21:27:56 received requests_OK : 1000 57 | 2018/07/06 21:27:56 throughput (TPS) : 414 58 | 2018/07/06 21:27:56 mean: 100238663 ns, median: 99990000 ns, max: 109895000 ns, min: 93010000 ns, p99: 109669000 ns 59 | 2018/07/06 21:27:56 mean: 100 ms, median: 99 ms, max: 109 ms, min: 93 ms, p99: 109 ms 60 | 61 | # client.Wrap(ratelimit.NewClientWrapper(100)) 62 | ➜ benchmark git:(master) ✗ go run micro_client.go -c 50 -n 1000 63 | 2018/07/06 21:28:18 concurrency: 50 64 | requests per client: 20 65 | 66 | 2018/07/06 21:28:18 took 267 ms for 1000 requests 67 | 2018/07/06 21:28:18 sent requests : 1000 68 | 2018/07/06 21:28:18 received requests : 1000 69 | 2018/07/06 21:28:18 received requests_OK : 1000 70 | 2018/07/06 21:28:18 throughput (TPS) : 3745 71 | 2018/07/06 21:28:18 mean: 8221555 ns, median: 8683500 ns, max: 29595000 ns, min: 204000 ns, p99: 29448500 ns 72 | 2018/07/06 21:28:18 mean: 8 ms, median: 8 ms, max: 29 ms, min: 0 ms, p99: 29 ms 73 | 74 | ``` -------------------------------------------------------------------------------- /benchmark/_backup/micro_client.go: -------------------------------------------------------------------------------- 1 | package _backup 2 | 3 | import ( 4 | "context" 5 | "flag" 6 | "reflect" 7 | "sync" 8 | "sync/atomic" 9 | "time" 10 | 11 | "github.com/afex/hystrix-go/hystrix" 12 | "github.com/micro/go-micro/client/selector" 13 | "github.com/montanaflynn/stats" 14 | 15 | "github.com/micro/go-micro/util/log" 16 | // micro "github.com/micro/go-micro" 17 | "github.com/micro/go-micro/client" 18 | "github.com/micro/go-plugins/transport/tcp" 19 | breaker "github.com/micro/go-plugins/wrapper/breaker/hystrix" 20 | "github.com/micro/go-plugins/wrapper/ratelimiter/uber" 21 | 22 | "github.com/hb-go/micro/benchmark/proto" 23 | ) 24 | 25 | var concurrency = flag.Int("c", 1, "concurrency") 26 | var total = flag.Int("n", 1, "total requests for all clients") 27 | var host = flag.String("s", "127.0.0.1:8972", "listened ip and port") 28 | 29 | func main() { 30 | flag.Parse() 31 | n := *concurrency 32 | m := *total / n 33 | 34 | log.Logf("concurrency: %d\nrequests per client: %d\n\n", n, m) 35 | 36 | args := prepareArgs() 37 | 38 | // Hystrix配置 39 | hystrix.ConfigureCommand("hello.Hello.Say", hystrix.CommandConfig{ 40 | MaxConcurrentRequests: hystrix.DefaultMaxConcurrent * 2, 41 | }) 42 | 43 | // b, _ := proto.Marshal(args) 44 | // log.Logf("message size: %d bytes\n\n", len(b)) 45 | 46 | var wg sync.WaitGroup 47 | wg.Add(n * m) 48 | 49 | var trans uint64 50 | var transOK uint64 51 | 52 | d := make([][]int64, n, n) 53 | 54 | // it contains warmup time but we can ignore it 55 | totalT := time.Now().UnixNano() 56 | for i := 0; i < n; i++ { 57 | dt := make([]int64, 0, m) 58 | d = append(d, dt) 59 | 60 | go func(i int) { 61 | // service := micro.NewService( 62 | // micro.Name("hello.client"), 63 | // micro.Transport(tcp.NewTransport()), 64 | // micro.Selector(cache.NewSelector(cache.TTL(time.Second*3000))), 65 | // 66 | // ) 67 | // c := proto.NewHelloService("hello", service.Client()) 68 | 69 | cache := selector.NewSelector(func(o *selector.Options) { 70 | o.Context = context.WithValue(o.Context, "selector_ttl", time.Second*30) 71 | }) 72 | 73 | helloClient := client.NewClient( 74 | client.Transport(tcp.NewTransport()), 75 | // client.ContentType("application/protobuf"), 76 | client.Selector(cache), 77 | client.Retries(1), 78 | client.PoolSize(10), 79 | client.RequestTimeout(time.Millisecond*100), 80 | client.Wrap(breaker.NewClientWrapper()), 81 | client.Wrap(ratelimit.NewClientWrapper(10)), 82 | ) 83 | c := proto.NewHelloService("hello", helloClient) 84 | 85 | // warmup 86 | for j := 0; j < 5; j++ { 87 | c.Say(context.Background(), args) 88 | } 89 | 90 | for j := 0; j < m; j++ { 91 | t := time.Now().UnixNano() 92 | reply, err := c.Say(context.Background(), args) 93 | t = time.Now().UnixNano() - t 94 | 95 | d[i] = append(d[i], t) 96 | 97 | if err == nil && *reply.Field1 == "OK" { 98 | atomic.AddUint64(&transOK, 1) 99 | } else { 100 | log.Logf("error:%v", err) 101 | } 102 | 103 | atomic.AddUint64(&trans, 1) 104 | wg.Done() 105 | } 106 | }(i) 107 | 108 | } 109 | 110 | wg.Wait() 111 | totalT = time.Now().UnixNano() - totalT 112 | totalT = totalT / 1000000 113 | log.Logf("took %d ms for %d requests\n", totalT, n*m) 114 | 115 | totalD := make([]int64, 0, n*m) 116 | for _, k := range d { 117 | totalD = append(totalD, k...) 118 | } 119 | totalD2 := make([]float64, 0, n*m) 120 | for _, k := range totalD { 121 | totalD2 = append(totalD2, float64(k)) 122 | } 123 | 124 | mean, _ := stats.Mean(totalD2) 125 | median, _ := stats.Median(totalD2) 126 | max, _ := stats.Max(totalD2) 127 | min, _ := stats.Min(totalD2) 128 | p99, _ := stats.Percentile(totalD2, 99.9) 129 | 130 | log.Logf("sent requests : %d\n", n*m) 131 | log.Logf("received requests : %d\n", atomic.LoadUint64(&trans)) 132 | log.Logf("received requests_OK : %d\n", atomic.LoadUint64(&transOK)) 133 | log.Logf("throughput (TPS) : %d\n", int64(n*m)*1000/totalT) 134 | log.Logf("mean: %.f ns, median: %.f ns, max: %.f ns, min: %.f ns, p99: %.f ns\n", mean, median, max, min, p99) 135 | log.Logf("mean: %d ms, median: %d ms, max: %d ms, min: %d ms, p99: %d ms\n", int64(mean/1000000), int64(median/1000000), int64(max/1000000), int64(min/1000000), int64(p99/1000000)) 136 | 137 | } 138 | 139 | func prepareArgs() *proto.BenchmarkMessage { 140 | b := true 141 | var i int32 = 100000 142 | var i64 int64 = 100000 143 | var s = "许多往事在眼前一幕一幕,变的那麼模糊" 144 | 145 | var args proto.BenchmarkMessage 146 | 147 | v := reflect.ValueOf(&args).Elem() 148 | num := v.NumField() 149 | for k := 0; k < num; k++ { 150 | field := v.Field(k) 151 | if field.Type().Kind() == reflect.Ptr { 152 | switch v.Field(k).Type().Elem().Kind() { 153 | case reflect.Int, reflect.Int32: 154 | field.Set(reflect.ValueOf(&i)) 155 | case reflect.Int64: 156 | field.Set(reflect.ValueOf(&i64)) 157 | case reflect.Bool: 158 | field.Set(reflect.ValueOf(&b)) 159 | case reflect.String: 160 | field.Set(reflect.ValueOf(&s)) 161 | } 162 | } else { 163 | switch field.Kind() { 164 | case reflect.Int, reflect.Int32, reflect.Int64: 165 | field.SetInt(100000) 166 | case reflect.Bool: 167 | field.SetBool(true) 168 | case reflect.String: 169 | field.SetString(s) 170 | } 171 | } 172 | 173 | } 174 | return &args 175 | } 176 | -------------------------------------------------------------------------------- /benchmark/_backup/micro_mclient.go: -------------------------------------------------------------------------------- 1 | package _backup 2 | 3 | import ( 4 | "context" 5 | "flag" 6 | "reflect" 7 | "strings" 8 | "sync" 9 | "sync/atomic" 10 | "time" 11 | 12 | "github.com/afex/hystrix-go/hystrix" 13 | "github.com/micro/go-micro/client/selector" 14 | "github.com/montanaflynn/stats" 15 | 16 | "github.com/micro/go-micro/util/log" 17 | // micro "github.com/micro/go-micro" 18 | "github.com/micro/go-micro/client" 19 | "github.com/micro/go-plugins/transport/tcp" 20 | breaker "github.com/micro/go-plugins/wrapper/breaker/hystrix" 21 | "github.com/micro/go-plugins/wrapper/ratelimiter/uber" 22 | 23 | "github.com/hb-go/micro/benchmark/proto" 24 | ) 25 | 26 | var concurrency = flag.Int("c", 1, "concurrency") 27 | var total = flag.Int("n", 1, "total requests for all clients") 28 | var host = flag.String("s", "127.0.0.1:8972", "server ip and port") 29 | 30 | func main() { 31 | flag.Parse() 32 | n := *concurrency 33 | m := *total / n 34 | 35 | selected := -1 36 | servers := strings.Split(*host, ",") 37 | sNum := len(servers) 38 | 39 | log.Logf("Servers: %+v\n\n", servers) 40 | 41 | log.Logf("concurrency: %d\nrequests per client: %d\n\n", n, m) 42 | 43 | args := prepareArgs() 44 | 45 | // Hystrix配置 46 | hystrix.ConfigureCommand("hello.Hello.Say", hystrix.CommandConfig{ 47 | MaxConcurrentRequests: hystrix.DefaultMaxConcurrent * 2, 48 | }) 49 | 50 | // b, _ := proto.Marshal(args) 51 | // log.Logf("message size: %d bytes\n\n", len(b)) 52 | 53 | var wg sync.WaitGroup 54 | wg.Add(n * m) 55 | 56 | var trans uint64 57 | var transOK uint64 58 | 59 | d := make([][]int64, n, n) 60 | 61 | // it contains warmup time but we can ignore it 62 | totalT := time.Now().UnixNano() 63 | for i := 0; i < n; i++ { 64 | dt := make([]int64, 0, m) 65 | d = append(d, dt) 66 | selected = (selected + 1) % sNum 67 | 68 | go func(i int, selected int) { 69 | // service := micro.NewService( 70 | // micro.Name("hello.client"), 71 | // micro.Transport(tcp.NewTransport()), 72 | // micro.Selector(cache.NewSelector(cache.TTL(time.Second*3000))), 73 | // ) 74 | // c := proto.NewHelloService("hello", service.Client()) 75 | 76 | cache := selector.NewSelector(func(o *selector.Options) { 77 | o.Context = context.WithValue(o.Context, "selector_ttl", time.Second*30) 78 | }) 79 | 80 | helloClient := client.NewClient( 81 | client.Transport(tcp.NewTransport()), 82 | // client.ContentType("application/protobuf"), 83 | client.Selector(cache), 84 | client.Retries(1), 85 | client.PoolSize(10), 86 | client.RequestTimeout(time.Millisecond*100), 87 | client.Wrap(breaker.NewClientWrapper()), 88 | client.Wrap(ratelimit.NewClientWrapper(10)), 89 | ) 90 | c := proto.NewHelloService("hello", helloClient) 91 | 92 | // warmup 93 | for j := 0; j < 5; j++ { 94 | c.Say(context.Background(), args) 95 | } 96 | 97 | for j := 0; j < m; j++ { 98 | t := time.Now().UnixNano() 99 | reply, err := c.Say(context.Background(), args) 100 | t = time.Now().UnixNano() - t 101 | 102 | d[i] = append(d[i], t) 103 | 104 | if err == nil && *reply.Field1 == "OK" { 105 | atomic.AddUint64(&transOK, 1) 106 | } else { 107 | log.Logf("error:%v", err) 108 | } 109 | 110 | atomic.AddUint64(&trans, 1) 111 | wg.Done() 112 | } 113 | 114 | // c.Close() 115 | 116 | }(i, selected) 117 | 118 | } 119 | 120 | wg.Wait() 121 | totalT = time.Now().UnixNano() - totalT 122 | totalT = totalT / 1000000 123 | log.Logf("took %d ms for %d requests\n", totalT, n*m) 124 | 125 | totalD := make([]int64, 0, n*m) 126 | for _, k := range d { 127 | totalD = append(totalD, k...) 128 | } 129 | totalD2 := make([]float64, 0, n*m) 130 | for _, k := range totalD { 131 | totalD2 = append(totalD2, float64(k)) 132 | } 133 | 134 | mean, _ := stats.Mean(totalD2) 135 | median, _ := stats.Median(totalD2) 136 | max, _ := stats.Max(totalD2) 137 | min, _ := stats.Min(totalD2) 138 | p99, _ := stats.Percentile(totalD2, 99.9) 139 | 140 | log.Logf("sent requests : %d\n", n*m) 141 | log.Logf("received requests : %d\n", atomic.LoadUint64(&trans)) 142 | log.Logf("received requests_OK : %d\n", atomic.LoadUint64(&transOK)) 143 | log.Logf("throughput (TPS) : %d\n", int64(n*m)*1000/totalT) 144 | log.Logf("mean: %.f ns, median: %.f ns, max: %.f ns, min: %.f ns, p99: %.f ns\n", mean, median, max, min, p99) 145 | log.Logf("mean: %d ms, median: %d ms, max: %d ms, min: %d ms, p99: %d ms\n", int64(mean/1000000), int64(median/1000000), int64(max/1000000), int64(min/1000000), int64(p99/1000000)) 146 | 147 | } 148 | 149 | func prepareArgs() *proto.BenchmarkMessage { 150 | b := true 151 | var i int32 = 100000 152 | var i64 int64 = 100000 153 | var s = "许多往事在眼前一幕一幕,变的那麼模糊" 154 | 155 | var args proto.BenchmarkMessage 156 | 157 | v := reflect.ValueOf(&args).Elem() 158 | num := v.NumField() 159 | for k := 0; k < num; k++ { 160 | field := v.Field(k) 161 | if field.Type().Kind() == reflect.Ptr { 162 | switch v.Field(k).Type().Elem().Kind() { 163 | case reflect.Int, reflect.Int32: 164 | field.Set(reflect.ValueOf(&i)) 165 | case reflect.Int64: 166 | field.Set(reflect.ValueOf(&i64)) 167 | case reflect.Bool: 168 | field.Set(reflect.ValueOf(&b)) 169 | case reflect.String: 170 | field.Set(reflect.ValueOf(&s)) 171 | } 172 | } else { 173 | switch field.Kind() { 174 | case reflect.Int, reflect.Int32, reflect.Int64: 175 | field.SetInt(100000) 176 | case reflect.Bool: 177 | field.SetBool(true) 178 | case reflect.String: 179 | field.SetString(s) 180 | } 181 | } 182 | 183 | } 184 | return &args 185 | } 186 | -------------------------------------------------------------------------------- /benchmark/_backup/micro_server.go: -------------------------------------------------------------------------------- 1 | package _backup 2 | 3 | import ( 4 | "context" 5 | "flag" 6 | "fmt" 7 | "time" 8 | 9 | "github.com/micro/go-micro" 10 | "github.com/micro/go-plugins/transport/tcp" 11 | "github.com/micro/go-plugins/wrapper/ratelimiter/uber" 12 | 13 | "github.com/hb-go/micro/benchmark/proto" 14 | ) 15 | 16 | type HelloS struct{} 17 | 18 | func (t *HelloS) Say(ctx context.Context, args *proto.BenchmarkMessage, reply *proto.BenchmarkMessage) error { 19 | s := "OK" 20 | var i int32 = 100 21 | args.Field1 = &s 22 | args.Field2 = &i 23 | *reply = *args 24 | if *delay > 0 { 25 | time.Sleep(*delay) 26 | } 27 | return nil 28 | } 29 | 30 | // var host = flag.String("s", "127.0.0.1:8972", "listened ip and port") 31 | 32 | var delay = flag.Duration("delay", 0, "delay to mock business processing") 33 | 34 | func main() { 35 | flag.Parse() 36 | 37 | service := micro.NewService( 38 | micro.Name("hello"), 39 | micro.Version("latest"), 40 | micro.Transport(tcp.NewTransport()), 41 | ) 42 | 43 | service.Init( 44 | // handler wrap 45 | micro.WrapHandler( 46 | ratelimit.NewHandlerWrapper(100), 47 | ), 48 | ) 49 | 50 | proto.RegisterHelloHandler(service.Server(), &HelloS{}) 51 | 52 | // Run the server 53 | if err := service.Run(); err != nil { 54 | fmt.Println(err) 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /benchmark/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/hb-chen/micro/benchmark 2 | 3 | go 1.15 4 | -------------------------------------------------------------------------------- /benchmark/grpc_grpc/client.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "flag" 6 | "time" 7 | 8 | "github.com/micro/go-micro/client" 9 | "github.com/micro/go-micro/client/selector" 10 | "github.com/micro/go-plugins/client/grpc" 11 | trans "github.com/micro/go-plugins/transport/grpc" 12 | 13 | "github.com/hb-go/micro/benchmark/service" 14 | ) 15 | 16 | var concurrency = flag.Int("c", 1, "concurrency") 17 | var total = flag.Int("n", 1, "total requests for all clients") 18 | var contentType = flag.String("ct", "application/protobuf", "content type") 19 | 20 | func main() { 21 | flag.Parse() 22 | serviceName := "hello.grpc.grpc" 23 | service.ClientWith( 24 | serviceName, 25 | func() client.Client { 26 | cache := selector.NewSelector(func(o *selector.Options) { 27 | o.Context = context.WithValue(o.Context, "selector_ttl", time.Minute*3) 28 | }) 29 | return grpc.NewClient( 30 | client.Transport(trans.NewTransport()), 31 | client.ContentType(*contentType), 32 | client.Selector(cache), 33 | client.Retries(1), 34 | client.PoolSize(*concurrency*2), 35 | client.RequestTimeout(time.Millisecond*100), 36 | // client.Wrap(breaker.NewClientWrapper()), 37 | // client.Wrap(ratelimit.NewClientWrapper(10000)), 38 | ) 39 | }, 40 | *concurrency, 41 | *total, 42 | ) 43 | 44 | } 45 | -------------------------------------------------------------------------------- /benchmark/grpc_grpc/server.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | 6 | "github.com/micro/go-micro" 7 | "github.com/micro/go-plugins/server/grpc" 8 | trans "github.com/micro/go-plugins/transport/grpc" 9 | 10 | "github.com/hb-go/micro/benchmark/service" 11 | ) 12 | 13 | var delay = flag.Duration("delay", 0, "delay to mock business processing") 14 | 15 | func main() { 16 | flag.Parse() 17 | 18 | serviceName := "hello.grpc.grpc" 19 | service.ServeWith( 20 | serviceName, 21 | micro.Server(grpc.NewServer()), 22 | micro.Transport(trans.NewTransport()), 23 | *delay, 24 | ) 25 | } 26 | -------------------------------------------------------------------------------- /benchmark/grpc_rpc/client.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "flag" 6 | "time" 7 | 8 | "github.com/micro/go-micro/client" 9 | "github.com/micro/go-micro/client/selector" 10 | "github.com/micro/go-plugins/transport/grpc" 11 | 12 | "github.com/hb-go/micro/benchmark/service" 13 | ) 14 | 15 | var concurrency = flag.Int("c", 1, "concurrency") 16 | var total = flag.Int("n", 1, "total requests for all clients") 17 | var contentType = flag.String("ct", "application/protobuf", "content type") 18 | 19 | func main() { 20 | flag.Parse() 21 | serviceName := "hello.grpc.rpc" 22 | service.ClientWith( 23 | serviceName, 24 | func() client.Client { 25 | cache := selector.NewSelector(func(o *selector.Options) { 26 | o.Context = context.WithValue(o.Context, "selector_ttl", time.Minute*3) 27 | }) 28 | return client.NewClient( 29 | client.Transport(grpc.NewTransport()), 30 | client.ContentType(*contentType), 31 | client.Selector(cache), 32 | client.Retries(1), 33 | client.PoolSize(*concurrency*2), 34 | client.RequestTimeout(time.Millisecond*100), 35 | // client.Wrap(breaker.NewClientWrapper()), 36 | // client.Wrap(ratelimit.NewClientWrapper(10000)), 37 | ) 38 | }, 39 | *concurrency, 40 | *total, 41 | ) 42 | 43 | } 44 | -------------------------------------------------------------------------------- /benchmark/grpc_rpc/server.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | 6 | "github.com/micro/go-micro" 7 | "github.com/micro/go-micro/server" 8 | "github.com/micro/go-plugins/transport/grpc" 9 | 10 | "github.com/hb-go/micro/benchmark/service" 11 | ) 12 | 13 | var delay = flag.Duration("delay", 0, "delay to mock business processing") 14 | 15 | func main() { 16 | flag.Parse() 17 | 18 | serviceName := "hello.grpc.rpc" 19 | service.ServeWith( 20 | serviceName, 21 | micro.Server(server.DefaultServer), 22 | micro.Transport(grpc.NewTransport()), 23 | *delay, 24 | ) 25 | } 26 | -------------------------------------------------------------------------------- /benchmark/proto/micro_benchmark.micro.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-micro. DO NOT EDIT. 2 | // source: benchmark/proto/micro_benchmark.proto 3 | 4 | package proto 5 | 6 | import ( 7 | fmt "fmt" 8 | proto "github.com/golang/protobuf/proto" 9 | math "math" 10 | ) 11 | 12 | import ( 13 | context "context" 14 | client "github.com/micro/go-micro/client" 15 | server "github.com/micro/go-micro/server" 16 | ) 17 | 18 | // Reference imports to suppress errors if they are not otherwise used. 19 | var _ = proto.Marshal 20 | var _ = fmt.Errorf 21 | var _ = math.Inf 22 | 23 | // This is a compile-time assertion to ensure that this generated file 24 | // is compatible with the proto package it is being compiled against. 25 | // A compilation error at this line likely means your copy of the 26 | // proto package needs to be updated. 27 | const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package 28 | 29 | // Reference imports to suppress errors if they are not otherwise used. 30 | var _ context.Context 31 | var _ client.Option 32 | var _ server.Option 33 | 34 | // Client API for Hello service 35 | 36 | type HelloService interface { 37 | // Sends a greeting 38 | Say(ctx context.Context, in *BenchmarkMessage, opts ...client.CallOption) (*BenchmarkMessage, error) 39 | } 40 | 41 | type helloService struct { 42 | c client.Client 43 | name string 44 | } 45 | 46 | func NewHelloService(name string, c client.Client) HelloService { 47 | if c == nil { 48 | c = client.NewClient() 49 | } 50 | if len(name) == 0 { 51 | name = "proto" 52 | } 53 | return &helloService{ 54 | c: c, 55 | name: name, 56 | } 57 | } 58 | 59 | func (c *helloService) Say(ctx context.Context, in *BenchmarkMessage, opts ...client.CallOption) (*BenchmarkMessage, error) { 60 | req := c.c.NewRequest(c.name, "Hello.Say", in) 61 | out := new(BenchmarkMessage) 62 | err := c.c.Call(ctx, req, out, opts...) 63 | if err != nil { 64 | return nil, err 65 | } 66 | return out, nil 67 | } 68 | 69 | // Server API for Hello service 70 | 71 | type HelloHandler interface { 72 | // Sends a greeting 73 | Say(context.Context, *BenchmarkMessage, *BenchmarkMessage) error 74 | } 75 | 76 | func RegisterHelloHandler(s server.Server, hdlr HelloHandler, opts ...server.HandlerOption) error { 77 | type hello interface { 78 | Say(ctx context.Context, in *BenchmarkMessage, out *BenchmarkMessage) error 79 | } 80 | type Hello struct { 81 | hello 82 | } 83 | h := &helloHandler{hdlr} 84 | return s.Handle(s.NewHandler(&Hello{h}, opts...)) 85 | } 86 | 87 | type helloHandler struct { 88 | HelloHandler 89 | } 90 | 91 | func (h *helloHandler) Say(ctx context.Context, in *BenchmarkMessage, out *BenchmarkMessage) error { 92 | return h.HelloHandler.Say(ctx, in, out) 93 | } 94 | -------------------------------------------------------------------------------- /benchmark/proto/micro_benchmark.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. DO NOT EDIT. 2 | // source: benchmark/proto/micro_benchmark.proto 3 | 4 | package proto 5 | 6 | import ( 7 | fmt "fmt" 8 | proto "github.com/golang/protobuf/proto" 9 | math "math" 10 | ) 11 | 12 | // Reference imports to suppress errors if they are not otherwise used. 13 | var _ = proto.Marshal 14 | var _ = fmt.Errorf 15 | var _ = math.Inf 16 | 17 | // This is a compile-time assertion to ensure that this generated file 18 | // is compatible with the proto package it is being compiled against. 19 | // A compilation error at this line likely means your copy of the 20 | // proto package needs to be updated. 21 | const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package 22 | 23 | type BenchmarkMessage struct { 24 | Field1 *string `protobuf:"bytes,1,req,name=field1" json:"field1,omitempty"` 25 | Field9 *string `protobuf:"bytes,9,opt,name=field9" json:"field9,omitempty"` 26 | Field18 *string `protobuf:"bytes,18,opt,name=field18" json:"field18,omitempty"` 27 | Field80 *bool `protobuf:"varint,80,opt,name=field80,def=0" json:"field80,omitempty"` 28 | Field81 *bool `protobuf:"varint,81,opt,name=field81,def=1" json:"field81,omitempty"` 29 | Field2 *int32 `protobuf:"varint,2,req,name=field2" json:"field2,omitempty"` 30 | Field3 *int32 `protobuf:"varint,3,req,name=field3" json:"field3,omitempty"` 31 | Field280 *int32 `protobuf:"varint,280,opt,name=field280" json:"field280,omitempty"` 32 | Field6 *int32 `protobuf:"varint,6,opt,name=field6,def=0" json:"field6,omitempty"` 33 | Field22 *int64 `protobuf:"varint,22,opt,name=field22" json:"field22,omitempty"` 34 | Field4 *string `protobuf:"bytes,4,opt,name=field4" json:"field4,omitempty"` 35 | Field5 []uint64 `protobuf:"fixed64,5,rep,name=field5" json:"field5,omitempty"` 36 | Field59 *bool `protobuf:"varint,59,opt,name=field59,def=0" json:"field59,omitempty"` 37 | Field7 *string `protobuf:"bytes,7,opt,name=field7" json:"field7,omitempty"` 38 | Field16 *int32 `protobuf:"varint,16,opt,name=field16" json:"field16,omitempty"` 39 | Field130 *int32 `protobuf:"varint,130,opt,name=field130,def=0" json:"field130,omitempty"` 40 | Field12 *bool `protobuf:"varint,12,opt,name=field12,def=1" json:"field12,omitempty"` 41 | Field17 *bool `protobuf:"varint,17,opt,name=field17,def=1" json:"field17,omitempty"` 42 | Field13 *bool `protobuf:"varint,13,opt,name=field13,def=1" json:"field13,omitempty"` 43 | Field14 *bool `protobuf:"varint,14,opt,name=field14,def=1" json:"field14,omitempty"` 44 | Field104 *int32 `protobuf:"varint,104,opt,name=field104,def=0" json:"field104,omitempty"` 45 | Field100 *int32 `protobuf:"varint,100,opt,name=field100,def=0" json:"field100,omitempty"` 46 | Field101 *int32 `protobuf:"varint,101,opt,name=field101,def=0" json:"field101,omitempty"` 47 | Field102 *string `protobuf:"bytes,102,opt,name=field102" json:"field102,omitempty"` 48 | Field103 *string `protobuf:"bytes,103,opt,name=field103" json:"field103,omitempty"` 49 | Field29 *int32 `protobuf:"varint,29,opt,name=field29,def=0" json:"field29,omitempty"` 50 | Field30 *bool `protobuf:"varint,30,opt,name=field30,def=0" json:"field30,omitempty"` 51 | Field60 *int32 `protobuf:"varint,60,opt,name=field60,def=-1" json:"field60,omitempty"` 52 | Field271 *int32 `protobuf:"varint,271,opt,name=field271,def=-1" json:"field271,omitempty"` 53 | Field272 *int32 `protobuf:"varint,272,opt,name=field272,def=-1" json:"field272,omitempty"` 54 | Field150 *int32 `protobuf:"varint,150,opt,name=field150" json:"field150,omitempty"` 55 | Field23 *int32 `protobuf:"varint,23,opt,name=field23,def=0" json:"field23,omitempty"` 56 | Field24 *bool `protobuf:"varint,24,opt,name=field24,def=0" json:"field24,omitempty"` 57 | Field25 *int32 `protobuf:"varint,25,opt,name=field25,def=0" json:"field25,omitempty"` 58 | Field78 *bool `protobuf:"varint,78,opt,name=field78" json:"field78,omitempty"` 59 | Field67 *int32 `protobuf:"varint,67,opt,name=field67,def=0" json:"field67,omitempty"` 60 | Field68 *int32 `protobuf:"varint,68,opt,name=field68" json:"field68,omitempty"` 61 | Field128 *int32 `protobuf:"varint,128,opt,name=field128,def=0" json:"field128,omitempty"` 62 | Field129 *string `protobuf:"bytes,129,opt,name=field129,def=xxxxxxxxxxxxxxxxxxxxx" json:"field129,omitempty"` 63 | Field131 *int32 `protobuf:"varint,131,opt,name=field131,def=0" json:"field131,omitempty"` 64 | XXX_NoUnkeyedLiteral struct{} `json:"-"` 65 | XXX_unrecognized []byte `json:"-"` 66 | XXX_sizecache int32 `json:"-"` 67 | } 68 | 69 | func (m *BenchmarkMessage) Reset() { *m = BenchmarkMessage{} } 70 | func (m *BenchmarkMessage) String() string { return proto.CompactTextString(m) } 71 | func (*BenchmarkMessage) ProtoMessage() {} 72 | func (*BenchmarkMessage) Descriptor() ([]byte, []int) { 73 | return fileDescriptor_9ec8442d33902ef2, []int{0} 74 | } 75 | 76 | func (m *BenchmarkMessage) XXX_Unmarshal(b []byte) error { 77 | return xxx_messageInfo_BenchmarkMessage.Unmarshal(m, b) 78 | } 79 | func (m *BenchmarkMessage) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 80 | return xxx_messageInfo_BenchmarkMessage.Marshal(b, m, deterministic) 81 | } 82 | func (m *BenchmarkMessage) XXX_Merge(src proto.Message) { 83 | xxx_messageInfo_BenchmarkMessage.Merge(m, src) 84 | } 85 | func (m *BenchmarkMessage) XXX_Size() int { 86 | return xxx_messageInfo_BenchmarkMessage.Size(m) 87 | } 88 | func (m *BenchmarkMessage) XXX_DiscardUnknown() { 89 | xxx_messageInfo_BenchmarkMessage.DiscardUnknown(m) 90 | } 91 | 92 | var xxx_messageInfo_BenchmarkMessage proto.InternalMessageInfo 93 | 94 | const Default_BenchmarkMessage_Field80 bool = false 95 | const Default_BenchmarkMessage_Field81 bool = true 96 | const Default_BenchmarkMessage_Field6 int32 = 0 97 | const Default_BenchmarkMessage_Field59 bool = false 98 | const Default_BenchmarkMessage_Field130 int32 = 0 99 | const Default_BenchmarkMessage_Field12 bool = true 100 | const Default_BenchmarkMessage_Field17 bool = true 101 | const Default_BenchmarkMessage_Field13 bool = true 102 | const Default_BenchmarkMessage_Field14 bool = true 103 | const Default_BenchmarkMessage_Field104 int32 = 0 104 | const Default_BenchmarkMessage_Field100 int32 = 0 105 | const Default_BenchmarkMessage_Field101 int32 = 0 106 | const Default_BenchmarkMessage_Field29 int32 = 0 107 | const Default_BenchmarkMessage_Field30 bool = false 108 | const Default_BenchmarkMessage_Field60 int32 = -1 109 | const Default_BenchmarkMessage_Field271 int32 = -1 110 | const Default_BenchmarkMessage_Field272 int32 = -1 111 | const Default_BenchmarkMessage_Field23 int32 = 0 112 | const Default_BenchmarkMessage_Field24 bool = false 113 | const Default_BenchmarkMessage_Field25 int32 = 0 114 | const Default_BenchmarkMessage_Field67 int32 = 0 115 | const Default_BenchmarkMessage_Field128 int32 = 0 116 | const Default_BenchmarkMessage_Field129 string = "xxxxxxxxxxxxxxxxxxxxx" 117 | const Default_BenchmarkMessage_Field131 int32 = 0 118 | 119 | func (m *BenchmarkMessage) GetField1() string { 120 | if m != nil && m.Field1 != nil { 121 | return *m.Field1 122 | } 123 | return "" 124 | } 125 | 126 | func (m *BenchmarkMessage) GetField9() string { 127 | if m != nil && m.Field9 != nil { 128 | return *m.Field9 129 | } 130 | return "" 131 | } 132 | 133 | func (m *BenchmarkMessage) GetField18() string { 134 | if m != nil && m.Field18 != nil { 135 | return *m.Field18 136 | } 137 | return "" 138 | } 139 | 140 | func (m *BenchmarkMessage) GetField80() bool { 141 | if m != nil && m.Field80 != nil { 142 | return *m.Field80 143 | } 144 | return Default_BenchmarkMessage_Field80 145 | } 146 | 147 | func (m *BenchmarkMessage) GetField81() bool { 148 | if m != nil && m.Field81 != nil { 149 | return *m.Field81 150 | } 151 | return Default_BenchmarkMessage_Field81 152 | } 153 | 154 | func (m *BenchmarkMessage) GetField2() int32 { 155 | if m != nil && m.Field2 != nil { 156 | return *m.Field2 157 | } 158 | return 0 159 | } 160 | 161 | func (m *BenchmarkMessage) GetField3() int32 { 162 | if m != nil && m.Field3 != nil { 163 | return *m.Field3 164 | } 165 | return 0 166 | } 167 | 168 | func (m *BenchmarkMessage) GetField280() int32 { 169 | if m != nil && m.Field280 != nil { 170 | return *m.Field280 171 | } 172 | return 0 173 | } 174 | 175 | func (m *BenchmarkMessage) GetField6() int32 { 176 | if m != nil && m.Field6 != nil { 177 | return *m.Field6 178 | } 179 | return Default_BenchmarkMessage_Field6 180 | } 181 | 182 | func (m *BenchmarkMessage) GetField22() int64 { 183 | if m != nil && m.Field22 != nil { 184 | return *m.Field22 185 | } 186 | return 0 187 | } 188 | 189 | func (m *BenchmarkMessage) GetField4() string { 190 | if m != nil && m.Field4 != nil { 191 | return *m.Field4 192 | } 193 | return "" 194 | } 195 | 196 | func (m *BenchmarkMessage) GetField5() []uint64 { 197 | if m != nil { 198 | return m.Field5 199 | } 200 | return nil 201 | } 202 | 203 | func (m *BenchmarkMessage) GetField59() bool { 204 | if m != nil && m.Field59 != nil { 205 | return *m.Field59 206 | } 207 | return Default_BenchmarkMessage_Field59 208 | } 209 | 210 | func (m *BenchmarkMessage) GetField7() string { 211 | if m != nil && m.Field7 != nil { 212 | return *m.Field7 213 | } 214 | return "" 215 | } 216 | 217 | func (m *BenchmarkMessage) GetField16() int32 { 218 | if m != nil && m.Field16 != nil { 219 | return *m.Field16 220 | } 221 | return 0 222 | } 223 | 224 | func (m *BenchmarkMessage) GetField130() int32 { 225 | if m != nil && m.Field130 != nil { 226 | return *m.Field130 227 | } 228 | return Default_BenchmarkMessage_Field130 229 | } 230 | 231 | func (m *BenchmarkMessage) GetField12() bool { 232 | if m != nil && m.Field12 != nil { 233 | return *m.Field12 234 | } 235 | return Default_BenchmarkMessage_Field12 236 | } 237 | 238 | func (m *BenchmarkMessage) GetField17() bool { 239 | if m != nil && m.Field17 != nil { 240 | return *m.Field17 241 | } 242 | return Default_BenchmarkMessage_Field17 243 | } 244 | 245 | func (m *BenchmarkMessage) GetField13() bool { 246 | if m != nil && m.Field13 != nil { 247 | return *m.Field13 248 | } 249 | return Default_BenchmarkMessage_Field13 250 | } 251 | 252 | func (m *BenchmarkMessage) GetField14() bool { 253 | if m != nil && m.Field14 != nil { 254 | return *m.Field14 255 | } 256 | return Default_BenchmarkMessage_Field14 257 | } 258 | 259 | func (m *BenchmarkMessage) GetField104() int32 { 260 | if m != nil && m.Field104 != nil { 261 | return *m.Field104 262 | } 263 | return Default_BenchmarkMessage_Field104 264 | } 265 | 266 | func (m *BenchmarkMessage) GetField100() int32 { 267 | if m != nil && m.Field100 != nil { 268 | return *m.Field100 269 | } 270 | return Default_BenchmarkMessage_Field100 271 | } 272 | 273 | func (m *BenchmarkMessage) GetField101() int32 { 274 | if m != nil && m.Field101 != nil { 275 | return *m.Field101 276 | } 277 | return Default_BenchmarkMessage_Field101 278 | } 279 | 280 | func (m *BenchmarkMessage) GetField102() string { 281 | if m != nil && m.Field102 != nil { 282 | return *m.Field102 283 | } 284 | return "" 285 | } 286 | 287 | func (m *BenchmarkMessage) GetField103() string { 288 | if m != nil && m.Field103 != nil { 289 | return *m.Field103 290 | } 291 | return "" 292 | } 293 | 294 | func (m *BenchmarkMessage) GetField29() int32 { 295 | if m != nil && m.Field29 != nil { 296 | return *m.Field29 297 | } 298 | return Default_BenchmarkMessage_Field29 299 | } 300 | 301 | func (m *BenchmarkMessage) GetField30() bool { 302 | if m != nil && m.Field30 != nil { 303 | return *m.Field30 304 | } 305 | return Default_BenchmarkMessage_Field30 306 | } 307 | 308 | func (m *BenchmarkMessage) GetField60() int32 { 309 | if m != nil && m.Field60 != nil { 310 | return *m.Field60 311 | } 312 | return Default_BenchmarkMessage_Field60 313 | } 314 | 315 | func (m *BenchmarkMessage) GetField271() int32 { 316 | if m != nil && m.Field271 != nil { 317 | return *m.Field271 318 | } 319 | return Default_BenchmarkMessage_Field271 320 | } 321 | 322 | func (m *BenchmarkMessage) GetField272() int32 { 323 | if m != nil && m.Field272 != nil { 324 | return *m.Field272 325 | } 326 | return Default_BenchmarkMessage_Field272 327 | } 328 | 329 | func (m *BenchmarkMessage) GetField150() int32 { 330 | if m != nil && m.Field150 != nil { 331 | return *m.Field150 332 | } 333 | return 0 334 | } 335 | 336 | func (m *BenchmarkMessage) GetField23() int32 { 337 | if m != nil && m.Field23 != nil { 338 | return *m.Field23 339 | } 340 | return Default_BenchmarkMessage_Field23 341 | } 342 | 343 | func (m *BenchmarkMessage) GetField24() bool { 344 | if m != nil && m.Field24 != nil { 345 | return *m.Field24 346 | } 347 | return Default_BenchmarkMessage_Field24 348 | } 349 | 350 | func (m *BenchmarkMessage) GetField25() int32 { 351 | if m != nil && m.Field25 != nil { 352 | return *m.Field25 353 | } 354 | return Default_BenchmarkMessage_Field25 355 | } 356 | 357 | func (m *BenchmarkMessage) GetField78() bool { 358 | if m != nil && m.Field78 != nil { 359 | return *m.Field78 360 | } 361 | return false 362 | } 363 | 364 | func (m *BenchmarkMessage) GetField67() int32 { 365 | if m != nil && m.Field67 != nil { 366 | return *m.Field67 367 | } 368 | return Default_BenchmarkMessage_Field67 369 | } 370 | 371 | func (m *BenchmarkMessage) GetField68() int32 { 372 | if m != nil && m.Field68 != nil { 373 | return *m.Field68 374 | } 375 | return 0 376 | } 377 | 378 | func (m *BenchmarkMessage) GetField128() int32 { 379 | if m != nil && m.Field128 != nil { 380 | return *m.Field128 381 | } 382 | return Default_BenchmarkMessage_Field128 383 | } 384 | 385 | func (m *BenchmarkMessage) GetField129() string { 386 | if m != nil && m.Field129 != nil { 387 | return *m.Field129 388 | } 389 | return Default_BenchmarkMessage_Field129 390 | } 391 | 392 | func (m *BenchmarkMessage) GetField131() int32 { 393 | if m != nil && m.Field131 != nil { 394 | return *m.Field131 395 | } 396 | return Default_BenchmarkMessage_Field131 397 | } 398 | 399 | func init() { 400 | proto.RegisterType((*BenchmarkMessage)(nil), "proto.BenchmarkMessage") 401 | } 402 | 403 | func init() { 404 | proto.RegisterFile("benchmark/proto/micro_benchmark.proto", fileDescriptor_9ec8442d33902ef2) 405 | } 406 | 407 | var fileDescriptor_9ec8442d33902ef2 = []byte{ 408 | // 515 bytes of a gzipped FileDescriptorProto 409 | 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x94, 0xcd, 0x6e, 0xd3, 0x40, 410 | 0x14, 0x85, 0xb1, 0x53, 0xa7, 0x8d, 0x05, 0xa8, 0x8c, 0x44, 0x7b, 0x5a, 0x68, 0x6a, 0x55, 0x42, 411 | 0xf2, 0x86, 0x76, 0x7e, 0xfc, 0x1b, 0x58, 0x05, 0x16, 0xdd, 0x80, 0xc0, 0x3c, 0x00, 0x0a, 0xad, 412 | 0xd3, 0x56, 0xa4, 0x04, 0x25, 0x45, 0x82, 0x1d, 0x3f, 0x0f, 0x00, 0x2b, 0xc4, 0x73, 0xf0, 0x84, 413 | 0xc8, 0x8e, 0xe7, 0x7a, 0xea, 0xa1, 0xd9, 0x44, 0xf7, 0x7c, 0xf7, 0xd8, 0xf7, 0xce, 0x1c, 0xd9, 414 | 0x7f, 0xf4, 0xae, 0xfc, 0x70, 0x72, 0x7e, 0x39, 0x59, 0xbc, 0x3f, 0xfa, 0xb8, 0x98, 0x5f, 0xcd, 415 | 0x8f, 0x2e, 0x2f, 0x4e, 0x16, 0xf3, 0xb7, 0xa4, 0x1e, 0xd6, 0x2a, 0xf3, 0xea, 0xbf, 0x83, 0xbf, 416 | 0x03, 0x7f, 0x73, 0xac, 0xd1, 0x8b, 0x72, 0xb9, 0x9c, 0x9c, 0x95, 0x6c, 0xcb, 0xef, 0x4f, 0x2f, 417 | 0xca, 0xd9, 0xa9, 0x80, 0x13, 0xb8, 0xe1, 0xa0, 0x68, 0x2a, 0xd2, 0x73, 0x0c, 0x02, 0x87, 0xf4, 418 | 0x9c, 0xc1, 0x5f, 0x5f, 0x75, 0x64, 0x60, 0x35, 0xd0, 0x25, 0xdb, 0x6f, 0x48, 0xc6, 0xf1, 0x2a, 419 | 0x70, 0xc2, 0x8d, 0x91, 0x37, 0x9d, 0xcc, 0x96, 0x65, 0xa1, 0x55, 0x36, 0xd4, 0x0d, 0x02, 0xaf, 420 | 0xeb, 0x86, 0xb5, 0xab, 0xc5, 0x27, 0xe2, 0xed, 0x2b, 0x25, 0xdc, 0xc0, 0x0d, 0xbd, 0xe6, 0x95, 421 | 0x92, 0x74, 0x85, 0x9e, 0xa1, 0x2b, 0xf6, 0xc0, 0xdf, 0x58, 0x75, 0x64, 0x1c, 0x7f, 0xdc, 0xc0, 422 | 0x09, 0xbd, 0x82, 0x04, 0xb6, 0xd3, 0x98, 0x12, 0xf4, 0x2b, 0x32, 0x72, 0x78, 0xe3, 0x4b, 0x68, 423 | 0x05, 0x29, 0xb1, 0x15, 0x38, 0x61, 0xaf, 0xd0, 0x25, 0xbd, 0x29, 0xc2, 0x9a, 0xb1, 0x74, 0x44, 424 | 0x7a, 0x0c, 0x2f, 0xe8, 0x85, 0xfd, 0x46, 0x8f, 0x69, 0xe5, 0x38, 0xc7, 0x13, 0x7b, 0xe5, 0x38, 425 | 0x27, 0x63, 0x8a, 0x75, 0xe3, 0x81, 0x69, 0x7b, 0x8a, 0x09, 0x36, 0xeb, 0xc1, 0x75, 0xc9, 0x86, 426 | 0xcd, 0x52, 0x42, 0x71, 0x7c, 0x77, 0xf4, 0xe8, 0xa4, 0xd1, 0x21, 0x0a, 0x89, 0xdb, 0xd6, 0x21, 427 | 0x0a, 0xd9, 0xf2, 0x14, 0xf7, 0x6c, 0x9e, 0xb6, 0x5c, 0xe1, 0x8e, 0xcd, 0x55, 0xcb, 0x23, 0xdc, 428 | 0xb5, 0x79, 0xc4, 0xf6, 0xf4, 0x7c, 0x3c, 0xc2, 0x79, 0x67, 0x3c, 0x6e, 0x62, 0x8e, 0xd3, 0x2e, 429 | 0xe6, 0x06, 0x16, 0x28, 0xbb, 0x58, 0xb0, 0x5d, 0xc2, 0x12, 0xd3, 0xfa, 0xc0, 0xa8, 0x36, 0x98, 430 | 0xc2, 0xd9, 0x35, 0x56, 0x25, 0xa1, 0xb9, 0xc2, 0x1c, 0x7b, 0xfa, 0xa9, 0x5a, 0xa1, 0x4b, 0x52, 431 | 0x1c, 0x43, 0xfb, 0x92, 0x14, 0x67, 0x0f, 0x9b, 0x86, 0x84, 0xe3, 0x69, 0xed, 0x76, 0x1f, 0x8b, 432 | 0x42, 0x4b, 0x6c, 0x5f, 0xa7, 0x2c, 0x15, 0xf8, 0xe9, 0x12, 0x27, 0xd1, 0x68, 0x90, 0xf8, 0x65, 433 | 0x37, 0x48, 0xca, 0xa9, 0x88, 0x39, 0x7e, 0x3b, 0x46, 0x4e, 0x45, 0xcc, 0xdb, 0xd1, 0x15, 0xb6, 434 | 0x3b, 0xa3, 0x2b, 0x1a, 0x5d, 0x46, 0x80, 0x3d, 0xba, 0x8c, 0x5a, 0x77, 0x8c, 0x9d, 0x8e, 0x3b, 435 | 0xa6, 0x90, 0xa5, 0x19, 0x5e, 0x56, 0xee, 0x42, 0x97, 0x64, 0x4b, 0x52, 0x3c, 0xbb, 0x6e, 0x4b, 436 | 0xda, 0x6c, 0x26, 0x19, 0x9e, 0x1b, 0xd9, 0x4c, 0xb2, 0x36, 0x9b, 0x32, 0xc3, 0xd7, 0x6e, 0x36, 437 | 0x65, 0xc6, 0x24, 0xf1, 0x1c, 0xdf, 0x2a, 0x3e, 0x18, 0xdd, 0xff, 0xfc, 0xbf, 0x1f, 0x79, 0x72, 438 | 0x23, 0xef, 0x02, 0x3f, 0xac, 0xbc, 0x0b, 0x39, 0xf6, 0xbd, 0xe3, 0x72, 0x36, 0x9b, 0xb3, 0xdc, 439 | 0xef, 0xbd, 0x99, 0x7c, 0x61, 0xdb, 0xab, 0x6f, 0xda, 0x61, 0xf7, 0x43, 0xb6, 0x7b, 0x13, 0x38, 440 | 0xb8, 0x35, 0x76, 0x8f, 0x9d, 0x7f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x8d, 0xaf, 0xf5, 0x75, 0x2b, 441 | 0x05, 0x00, 0x00, 442 | } 443 | -------------------------------------------------------------------------------- /benchmark/proto/micro_benchmark.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto2"; 2 | 3 | package proto; 4 | 5 | option optimize_for = SPEED; 6 | 7 | service Hello { 8 | // Sends a greeting 9 | rpc Say (BenchmarkMessage) returns (BenchmarkMessage) { 10 | } 11 | } 12 | 13 | 14 | message BenchmarkMessage { 15 | required string field1 = 1; 16 | optional string field9 = 9; 17 | optional string field18 = 18; 18 | optional bool field80 = 80 [default = false]; 19 | optional bool field81 = 81 [default = true]; 20 | required int32 field2 = 2; 21 | required int32 field3 = 3; 22 | optional int32 field280 = 280; 23 | optional int32 field6 = 6 [default = 0]; 24 | optional int64 field22 = 22; 25 | optional string field4 = 4; 26 | repeated fixed64 field5 = 5; 27 | optional bool field59 = 59 [default = false]; 28 | optional string field7 = 7; 29 | optional int32 field16 = 16; 30 | optional int32 field130 = 130 [default = 0]; 31 | optional bool field12 = 12 [default = true]; 32 | optional bool field17 = 17 [default = true]; 33 | optional bool field13 = 13 [default = true]; 34 | optional bool field14 = 14 [default = true]; 35 | optional int32 field104 = 104 [default = 0]; 36 | optional int32 field100 = 100 [default = 0]; 37 | optional int32 field101 = 101 [default = 0]; 38 | optional string field102 = 102; 39 | optional string field103 = 103; 40 | optional int32 field29 = 29 [default = 0]; 41 | optional bool field30 = 30 [default = false]; 42 | optional int32 field60 = 60 [default = -1]; 43 | optional int32 field271 = 271 [default = -1]; 44 | optional int32 field272 = 272 [default = -1]; 45 | optional int32 field150 = 150; 46 | optional int32 field23 = 23 [default = 0]; 47 | optional bool field24 = 24 [default = false]; 48 | optional int32 field25 = 25 [default = 0]; 49 | optional bool field78 = 78; 50 | optional int32 field67 = 67 [default = 0]; 51 | optional int32 field68 = 68; 52 | optional int32 field128 = 128 [default = 0]; 53 | optional string field129 = 129 [default = "xxxxxxxxxxxxxxxxxxxxx"]; 54 | optional int32 field131 = 131 [default = 0]; 55 | } -------------------------------------------------------------------------------- /benchmark/service/client.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "context" 5 | "flag" 6 | "fmt" 7 | "os" 8 | "reflect" 9 | "sync" 10 | "sync/atomic" 11 | "text/tabwriter" 12 | "time" 13 | 14 | "github.com/micro/go-micro/client" 15 | "github.com/micro/go-micro/util/log" 16 | "github.com/montanaflynn/stats" 17 | 18 | "github.com/hb-go/micro/benchmark/proto" 19 | ) 20 | 21 | type NewClient func() client.Client 22 | 23 | func ClientWith(serviceName string, nc NewClient, concurrency, total int) { 24 | flag.Parse() 25 | n := concurrency 26 | m := total / n 27 | 28 | log.Logf("service: %s testing", serviceName) 29 | log.Logf("concurrency: %d, requests per client: %d \n", n, m) 30 | 31 | args := prepareArgs() 32 | 33 | // Hystrix配置 34 | // hystrix.ConfigureCommand(serviceName+".Hello.Say", hystrix.CommandConfig{ 35 | // MaxConcurrentRequests: hystrix.DefaultMaxConcurrent * 100, 36 | // }) 37 | 38 | var wg sync.WaitGroup 39 | wg.Add(n * m) 40 | 41 | var trans uint64 42 | var transOK uint64 43 | 44 | d := make([][]int64, n, n) 45 | 46 | // it contains warmup time but we can ignore it 47 | totalT := time.Now().UnixNano() 48 | for i := 0; i < n; i++ { 49 | dt := make([]int64, 0, m) 50 | d = append(d, dt) 51 | 52 | go func(i int) { 53 | helloClient := nc() 54 | c := proto.NewHelloService(serviceName, helloClient) 55 | 56 | // warmup 57 | for j := 0; j < 5; j++ { 58 | c.Say(context.Background(), args) 59 | } 60 | 61 | for j := 0; j < m; j++ { 62 | t := time.Now().UnixNano() 63 | reply, err := c.Say(context.Background(), args) 64 | t = time.Now().UnixNano() - t 65 | 66 | d[i] = append(d[i], t) 67 | 68 | if err == nil && *reply.Field1 == "OK" { 69 | atomic.AddUint64(&transOK, 1) 70 | } else { 71 | // log.Logf("error:%v", err) 72 | } 73 | 74 | atomic.AddUint64(&trans, 1) 75 | wg.Done() 76 | } 77 | }(i) 78 | 79 | } 80 | 81 | wg.Wait() 82 | totalT = time.Now().UnixNano() - totalT 83 | totalT = totalT / 1000000 84 | 85 | totalD := make([]int64, 0, n*m) 86 | for _, k := range d { 87 | totalD = append(totalD, k...) 88 | } 89 | totalD2 := make([]float64, 0, n*m) 90 | for _, k := range totalD { 91 | totalD2 = append(totalD2, float64(k)) 92 | } 93 | 94 | mean, _ := stats.Mean(totalD2) 95 | median, _ := stats.Median(totalD2) 96 | max, _ := stats.Max(totalD2) 97 | min, _ := stats.Min(totalD2) 98 | p90, _ := stats.Percentile(totalD2, 90) 99 | p99, _ := stats.Percentile(totalD2, 99) 100 | tps := int64(n*m) * 1000 / totalT 101 | 102 | w := tabwriter.NewWriter(os.Stdout, 10, 0, 1, ' ', 0) 103 | 104 | fmt.Println() 105 | fmt.Fprintf(w, "took\t(ms)\t: %d\n", totalT) 106 | fmt.Fprintf(w, "sent\trequests\t: %d\n", n*m) 107 | fmt.Fprintf(w, "received\trequests\t: %d\n", atomic.LoadUint64(&trans)) 108 | fmt.Fprintf(w, "received\trequests_OK\t: %d\n", atomic.LoadUint64(&transOK)) 109 | fmt.Fprintf(w, "throughput\t(TPS)\t: %d\n", tps) 110 | w.Flush() 111 | 112 | fmt.Println() 113 | fmt.Fprintf(w, "concurrency\tmean\tmedian\tmax\tmin\tp90\tp99\tTPS\n") 114 | fmt.Fprintf(w, "%d\t%.fns\t%.fns\t%.fns\t%.fns\t%.fns\t%.fns\t%d\n", concurrency, mean, median, max, min, p90, p99, tps) 115 | fmt.Fprintf(w, "%d\t%.3fms\t%.3fms\t%.3fms\t%.3fms\t%.3fms\t%.3fms\t%d\n", concurrency, mean/1000000, median/1000000, max/1000000, min/1000000, p90/1000000, p99/1000000, tps) 116 | w.Flush() 117 | } 118 | 119 | func prepareArgs() *proto.BenchmarkMessage { 120 | b := true 121 | var i int32 = 100000 122 | var i64 int64 = 100000 123 | var s = "许多往事在眼前一幕一幕,变的那麼模糊" 124 | 125 | var args proto.BenchmarkMessage 126 | 127 | v := reflect.ValueOf(&args).Elem() 128 | num := v.NumField() 129 | for k := 0; k < num; k++ { 130 | field := v.Field(k) 131 | if field.Type().Kind() == reflect.Ptr { 132 | switch v.Field(k).Type().Elem().Kind() { 133 | case reflect.Int, reflect.Int32: 134 | field.Set(reflect.ValueOf(&i)) 135 | case reflect.Int64: 136 | field.Set(reflect.ValueOf(&i64)) 137 | case reflect.Bool: 138 | field.Set(reflect.ValueOf(&b)) 139 | case reflect.String: 140 | field.Set(reflect.ValueOf(&s)) 141 | } 142 | } else { 143 | switch field.Kind() { 144 | case reflect.Int, reflect.Int32, reflect.Int64: 145 | field.SetInt(100000) 146 | case reflect.Bool: 147 | field.SetBool(true) 148 | case reflect.String: 149 | field.SetString(s) 150 | } 151 | } 152 | 153 | } 154 | return &args 155 | } 156 | -------------------------------------------------------------------------------- /benchmark/service/codec.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "github.com/golang/protobuf/proto" 5 | ) 6 | 7 | // gRPC codec options 8 | type ProtoCodec struct{} 9 | 10 | func (ProtoCodec) Marshal(v interface{}) ([]byte, error) { 11 | return proto.Marshal(v.(proto.Message)) 12 | } 13 | 14 | func (ProtoCodec) Unmarshal(data []byte, v interface{}) error { 15 | return proto.Unmarshal(data, v.(proto.Message)) 16 | } 17 | 18 | func (ProtoCodec) Name() string { 19 | return "proto" 20 | } 21 | -------------------------------------------------------------------------------- /benchmark/service/server.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "context" 5 | "time" 6 | 7 | "github.com/micro/go-micro" 8 | "github.com/micro/go-micro/util/log" 9 | 10 | "github.com/hb-go/micro/benchmark/proto" 11 | ) 12 | 13 | type HelloS struct{} 14 | 15 | func (t *HelloS) Say(ctx context.Context, args *proto.BenchmarkMessage, reply *proto.BenchmarkMessage) error { 16 | s := "OK" 17 | var i int32 = 100 18 | args.Field1 = &s 19 | args.Field2 = &i 20 | *reply = *args 21 | if delay > 0 { 22 | time.Sleep(delay) 23 | } 24 | return nil 25 | } 26 | 27 | var delay = time.Duration(0) 28 | 29 | func ServeWith(serviceName string, serverOpt, transOpt micro.Option, d time.Duration) { 30 | delay = d 31 | service := micro.NewService( 32 | serverOpt, 33 | micro.Name(serviceName), 34 | micro.Version("latest"), 35 | transOpt, 36 | ) 37 | 38 | service.Init( 39 | // handler wrap 40 | // micro.WrapHandler( 41 | // ratelimit.NewHandlerWrapper(10000), 42 | // ), 43 | ) 44 | 45 | proto.RegisterHelloHandler(service.Server(), &HelloS{}) 46 | 47 | log.Logf("service: %s start", serviceName) 48 | 49 | // Run the server 50 | if err := service.Run(); err != nil { 51 | log.Log(err) 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /benchmark/tcp_rpc/client.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "flag" 6 | "time" 7 | 8 | "github.com/micro/go-micro/client" 9 | "github.com/micro/go-micro/client/selector" 10 | "github.com/micro/go-plugins/codec/bsonrpc" 11 | "github.com/micro/go-plugins/codec/jsonrpc2" 12 | "github.com/micro/go-plugins/codec/msgpackrpc" 13 | "github.com/micro/go-plugins/transport/tcp" 14 | 15 | "github.com/hb-go/micro/benchmark/service" 16 | ) 17 | 18 | var concurrency = flag.Int("c", 1, "concurrency") 19 | var total = flag.Int("n", 1, "total requests for all clients") 20 | var contentType = flag.String("ct", "protobuf", "content type") 21 | 22 | // "application/grpc": grpc.NewCodec, // TPS:9990 23 | // "application/protobuf": proto.NewCodec, // TPS:11037 24 | // "application/json": json.NewCodec, // TPS:7782 25 | // "application/json-rpc": jsonrpc.NewCodec, // TPS:6544 26 | // "application/proto-rpc": protorpc.NewCodec, // TPS:10869 27 | // "application/octet-stream": raw.NewCodec, // error:{"id":"go.micro.client.codec","code":500,"detail":"failed to write: field1: 28 | // "application/msgpackrpc", msgpackrpc.NewCodec, // 需要实现EncodeMsg(*Writer) error,error:{"id":"go.micro.client.codec","code":500,"detail":"Not encodable","status":"Internal Server Error"} 29 | // "application/bsonrpc", bsonrpc.NewCodec, // TPS:4970 30 | // "application/jsonrpc2", jsonrpc2.NewCodec, // error:{"id":"go.micro.client.transport","code":500,"detail":"EOF","status":"Internal Server Error"} 31 | 32 | func main() { 33 | flag.Parse() 34 | serviceName := "hello.tcp.rpc" 35 | service.ClientWith( 36 | serviceName, 37 | func() client.Client { 38 | cache := selector.NewSelector(func(o *selector.Options) { 39 | o.Context = context.WithValue(o.Context, "selector_ttl", time.Minute*3) 40 | }) 41 | return client.NewClient( 42 | client.Codec("application/msgpackrpc", msgpackrpc.NewCodec), 43 | client.Codec("application/bsonrpc", bsonrpc.NewCodec), 44 | client.Codec("application/jsonrpc2", jsonrpc2.NewCodec), 45 | client.Transport(tcp.NewTransport()), 46 | client.ContentType("application/"+*contentType), 47 | client.Selector(cache), 48 | client.Retries(1), 49 | client.PoolSize(*concurrency*2), 50 | client.RequestTimeout(time.Millisecond*100), 51 | // client.Wrap(breaker.NewClientWrapper()), 52 | // client.Wrap(ratelimit.NewClientWrapper(10000)), 53 | ) 54 | }, 55 | *concurrency, 56 | *total, 57 | ) 58 | 59 | } 60 | -------------------------------------------------------------------------------- /benchmark/tcp_rpc/server.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | 6 | "github.com/micro/go-micro" 7 | "github.com/micro/go-micro/server" 8 | "github.com/micro/go-plugins/codec/bsonrpc" 9 | "github.com/micro/go-plugins/codec/jsonrpc2" 10 | "github.com/micro/go-plugins/codec/msgpackrpc" 11 | "github.com/micro/go-plugins/transport/tcp" 12 | 13 | "github.com/hb-go/micro/benchmark/service" 14 | ) 15 | 16 | var delay = flag.Duration("delay", 0, "delay to mock business processing") 17 | 18 | func main() { 19 | flag.Parse() 20 | 21 | serviceName := "hello.tcp.rpc" 22 | service.ServeWith( 23 | serviceName, 24 | micro.Server( 25 | server.NewServer( 26 | server.Codec("application/msgpackrpc", msgpackrpc.NewCodec), 27 | server.Codec("application/bsonrpc", bsonrpc.NewCodec), 28 | server.Codec("application/jsonrpc2", jsonrpc2.NewCodec), 29 | )), 30 | micro.Transport(tcp.NewTransport()), 31 | *delay, 32 | ) 33 | } 34 | -------------------------------------------------------------------------------- /benchmark/utp_rpc/client.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "flag" 6 | "time" 7 | 8 | "github.com/micro/go-micro/client" 9 | "github.com/micro/go-micro/client/selector" 10 | "github.com/micro/go-plugins/transport/utp" 11 | 12 | "github.com/hb-go/micro/benchmark/service" 13 | ) 14 | 15 | var concurrency = flag.Int("c", 1, "concurrency") 16 | var total = flag.Int("n", 1, "total requests for all clients") 17 | var contentType = flag.String("ct", "application/protobuf", "content type") 18 | 19 | func main() { 20 | flag.Parse() 21 | serviceName := "hello.utp.rpc" 22 | service.ClientWith( 23 | serviceName, 24 | func() client.Client { 25 | cache := selector.NewSelector(func(o *selector.Options) { 26 | o.Context = context.WithValue(o.Context, "selector_ttl", time.Minute*3) 27 | }) 28 | return client.NewClient( 29 | client.Transport(utp.NewTransport()), 30 | client.ContentType(*contentType), 31 | client.Selector(cache), 32 | client.Retries(1), 33 | client.PoolSize(*concurrency*2), 34 | client.RequestTimeout(time.Millisecond*100), 35 | // client.Wrap(breaker.NewClientWrapper()), 36 | // client.Wrap(ratelimit.NewClientWrapper(10000)), 37 | ) 38 | }, 39 | *concurrency, 40 | *total, 41 | ) 42 | 43 | } 44 | -------------------------------------------------------------------------------- /benchmark/utp_rpc/server.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | 6 | "github.com/micro/go-micro" 7 | "github.com/micro/go-micro/server" 8 | "github.com/micro/go-plugins/transport/utp" 9 | 10 | "github.com/hb-go/micro/benchmark/service" 11 | ) 12 | 13 | var delay = flag.Duration("delay", 0, "delay to mock business processing") 14 | 15 | func main() { 16 | flag.Parse() 17 | 18 | serviceName := "hello.utp.rpc" 19 | service.ServeWith( 20 | serviceName, 21 | micro.Server(server.DefaultServer), 22 | micro.Transport(utp.NewTransport()), 23 | *delay, 24 | ) 25 | } 26 | -------------------------------------------------------------------------------- /cmd/micro/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | //go:generate ./scripts/generate.sh 4 | 5 | import ( 6 | "micro.dev/v4/cmd" 7 | 8 | _ "github.com/hb-chen/micro-starter/cmd/micro/server" 9 | _ "github.com/hb-chen/micro-starter/cmd/micro/service" 10 | _ "github.com/hb-chen/micro-starter/cmd/micro/web" 11 | _ "github.com/hb-chen/micro-starter/profile" 12 | ) 13 | 14 | func main() { 15 | cmd.Run() 16 | } 17 | -------------------------------------------------------------------------------- /cmd/micro/server/auth.go: -------------------------------------------------------------------------------- 1 | package server 2 | 3 | import ( 4 | "context" 5 | "strings" 6 | 7 | "micro.dev/v4/service/auth" 8 | metadata "micro.dev/v4/service/context" 9 | "micro.dev/v4/service/errors" 10 | "micro.dev/v4/service/server" 11 | inauth "micro.dev/v4/util/auth" 12 | "micro.dev/v4/util/namespace" 13 | ) 14 | 15 | // authHandler wraps a server handler to perform auth 16 | func authHandler() server.HandlerWrapper { 17 | return func(h server.HandlerFunc) server.HandlerFunc { 18 | return func(ctx context.Context, req server.Request, rsp interface{}) error { 19 | // Extract the token if the header is present. We will inspect the token regardless of if it's 20 | // present or not since noop auth will return a blank account upon Inspecting a blank token. 21 | var token string 22 | if header, ok := metadata.Get(ctx, "Authorization"); ok { 23 | // Ensure the correct scheme is being used 24 | if !strings.HasPrefix(header, inauth.BearerScheme) { 25 | return errors.Unauthorized(req.Service(), "invalid authorization header. expected Bearer schema") 26 | } 27 | 28 | // Strip the bearer scheme prefix 29 | token = strings.TrimPrefix(header, inauth.BearerScheme) 30 | } 31 | 32 | // Inspect the token and decode an account 33 | account, _ := auth.Inspect(token) 34 | 35 | // Extract the namespace header 36 | ns, ok := metadata.Get(ctx, "Micro-Namespace") 37 | if !ok && account != nil { 38 | ns = account.Issuer 39 | ctx = metadata.Set(ctx, "Micro-Namespace", ns) 40 | } else if !ok { 41 | ns = namespace.DefaultNamespace 42 | ctx = metadata.Set(ctx, "Micro-Namespace", ns) 43 | } 44 | 45 | // construct the resource 46 | res := &auth.Resource{ 47 | Type: "service", 48 | Name: req.Service(), 49 | Endpoint: req.Endpoint(), 50 | } 51 | 52 | // Verify the caller has access to the resource. 53 | err := auth.Verify(account, res, auth.VerifyNamespace(ns)) 54 | if err == auth.ErrForbidden && account != nil { 55 | return errors.Forbidden(req.Service(), "Forbidden call made to %v:%v by %v", req.Service(), req.Endpoint(), account.ID) 56 | } else if err == auth.ErrForbidden { 57 | return errors.Unauthorized(req.Service(), "Unauthorized call made to %v:%v", req.Service(), req.Endpoint()) 58 | } else if err != nil { 59 | return errors.InternalServerError("proxy", "Error authorizing request: %v", err) 60 | } 61 | 62 | // The user is authorised, allow the call 63 | return h(ctx, req, rsp) 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /cmd/micro/server/plugin.go: -------------------------------------------------------------------------------- 1 | //go:build ignore 2 | 3 | package server 4 | 5 | import ( 6 | "fmt" 7 | "plugin" 8 | // "micro.dev/v4/plugin" 9 | ) 10 | 11 | var ( 12 | defaultManager = plugin.NewManager() 13 | ) 14 | 15 | // Plugins lists the server plugins 16 | func Plugins() []plugin.Plugin { 17 | return defaultManager.Plugins() 18 | } 19 | 20 | // Register registers an server plugin 21 | func Register(pl plugin.Plugin) error { 22 | if plugin.IsRegistered(pl) { 23 | return fmt.Errorf("%s registered globally", pl.String()) 24 | } 25 | return defaultManager.Register(pl) 26 | } 27 | -------------------------------------------------------------------------------- /cmd/micro/server/proxy.go: -------------------------------------------------------------------------------- 1 | package server 2 | 3 | import ( 4 | "github.com/urfave/cli/v2" 5 | bmem "micro.dev/v4/service/broker/memory" 6 | "micro.dev/v4/service/client" 7 | log "micro.dev/v4/service/logger" 8 | "micro.dev/v4/service/registry/noop" 9 | "micro.dev/v4/service/server" 10 | sgrpc "micro.dev/v4/service/server/grpc" 11 | "micro.dev/v4/util/proxy" 12 | "micro.dev/v4/util/proxy/grpc" 13 | ) 14 | 15 | func runProxy(ctx *cli.Context, wait chan bool) error { 16 | addr := ctx.String("proxy_address") 17 | 18 | // set the context 19 | popts := []proxy.Option{ 20 | proxy.WithClient(client.DefaultClient), 21 | } 22 | 23 | serverOpts := []server.Option{ 24 | server.Address(addr), 25 | server.Registry(noop.NewRegistry()), 26 | server.Broker(bmem.NewBroker()), 27 | } 28 | 29 | // default to the grpc proxy 30 | p := grpc.NewProxy(popts...) 31 | 32 | // wrap the proxy using the proxy's authHandler 33 | authOpt := server.WrapHandler(authHandler()) 34 | serverOpts = append(serverOpts, authOpt) 35 | serverOpts = append(serverOpts, server.WithRouter(p)) 36 | 37 | // create a new grpc server 38 | srv := sgrpc.NewServer(serverOpts...) 39 | 40 | // Start the proxy server 41 | if err := srv.Start(); err != nil { 42 | log.Fatal(err) 43 | } 44 | 45 | <-wait 46 | 47 | // Stop the server 48 | if err := srv.Stop(); err != nil { 49 | log.Fatal(err) 50 | } 51 | 52 | return nil 53 | } 54 | -------------------------------------------------------------------------------- /cmd/micro/server/server.go: -------------------------------------------------------------------------------- 1 | // Package server is the micro server which runs the whole system 2 | package server 3 | 4 | import ( 5 | "os" 6 | "os/signal" 7 | "strings" 8 | "syscall" 9 | "time" 10 | 11 | "github.com/hb-chen/micro-starter/cmd/micro/service/api" 12 | "github.com/urfave/cli/v2" 13 | "micro.dev/v4/cmd" 14 | "micro.dev/v4/service/client" 15 | log "micro.dev/v4/service/logger" 16 | "micro.dev/v4/service/runtime" 17 | "micro.dev/v4/service/runtime/local" 18 | ) 19 | 20 | var ( 21 | // list of services managed 22 | services = []string{ 23 | "registry", // :8000 24 | "broker", // :8003 25 | "network", // :8443 26 | // "runtime", // :8088 27 | "config", // :8001 28 | // "store", // :8002 29 | // "events", // :8005 30 | // "auth", // :8010 31 | } 32 | ) 33 | 34 | func init() { 35 | command := &cli.Command{ 36 | Name: "server", 37 | Usage: "Run the micro server", 38 | Description: "Launch the micro server", 39 | Flags: []cli.Flag{ 40 | &cli.StringFlag{ 41 | Name: "address", 42 | Usage: "Set the micro api address", 43 | EnvVars: []string{"MICRO_API_ADDRESS"}, 44 | Value: ":8080", 45 | }, 46 | &cli.StringFlag{ 47 | Name: "proxy_address", 48 | Usage: "Set the micro proxy address", 49 | EnvVars: []string{"MICRO_PROXY_ADDRESS"}, 50 | Value: ":8081", 51 | }, 52 | }, 53 | Action: func(ctx *cli.Context) error { 54 | Run(ctx) 55 | return nil 56 | }, 57 | } 58 | 59 | cmd.Register(command) 60 | } 61 | 62 | func setNetwork() { 63 | client.DefaultClient.Init( 64 | client.Network("127.0.0.1:8443"), 65 | ) 66 | } 67 | 68 | // Run runs the entire platform 69 | func Run(context *cli.Context) error { 70 | if context.Args().Len() > 0 { 71 | cli.ShowSubcommandHelp(context) 72 | os.Exit(1) 73 | } 74 | 75 | log.Info("Starting server") 76 | 77 | // parse the env vars 78 | var envvars []string 79 | for _, val := range os.Environ() { 80 | comps := strings.Split(val, "=") 81 | if len(comps) != 2 { 82 | continue 83 | } 84 | 85 | // only process MICRO_ values 86 | if !strings.HasPrefix(comps[0], "MICRO_") { 87 | continue 88 | } 89 | 90 | // skip the profile and proxy, that's set below since it can be service specific 91 | if comps[0] == "MICRO_SERVICE_PROFILE" || comps[0] == "MICRO_SERVICE_NETWORK" { 92 | continue 93 | } 94 | 95 | envvars = append(envvars, val) 96 | } 97 | 98 | // save the runtime 99 | runtimeServer := local.NewRuntime() 100 | 101 | // start the services 102 | for _, service := range services { 103 | // all things run by the server are `micro service [name]` 104 | var cmdArgs []string 105 | 106 | profile := "server" 107 | 108 | env := envvars 109 | env = append(env, "MICRO_SERVICE_NAME="+service) 110 | env = append(env, "MICRO_SERVICE_PROFILE="+profile) 111 | 112 | // we want to pass through the global args so go up one level in the context lineage 113 | if len(context.Lineage()) > 1 { 114 | globCtx := context.Lineage()[1] 115 | for _, f := range globCtx.FlagNames() { 116 | cmdArgs = append(cmdArgs, "--"+f, context.String(f)) 117 | } 118 | } 119 | cmdArgs = append(cmdArgs, "service", service) 120 | 121 | // runtime based on environment we run the service in 122 | args := []runtime.CreateOption{ 123 | runtime.WithCommand(os.Args[0]), 124 | runtime.WithArgs(cmdArgs...), 125 | runtime.WithEnv(env), 126 | runtime.WithPort("0"), 127 | runtime.WithRetries(10), 128 | } 129 | 130 | log.Infof("Registering %s, args: %v", service, cmdArgs) 131 | 132 | // NOTE: we use Version right now to check for the latest release 133 | muService := &runtime.Service{Name: service, Version: "latest"} 134 | if err := runtimeServer.Create(muService, args...); err != nil { 135 | log.Errorf("Failed to create runtime environment: %v", err) 136 | return err 137 | } 138 | } 139 | 140 | log.Info("Starting runtime") 141 | 142 | // start the runtime 143 | if err := runtimeServer.Start(); err != nil { 144 | log.Fatal(err) 145 | return err 146 | } 147 | 148 | // start the proxy 149 | wait := make(chan bool) 150 | 151 | setNetwork() 152 | 153 | // run the proxy 154 | go runProxy(context, wait) 155 | 156 | // run the api 157 | apiCmd := api.NewAPI(wait) 158 | go apiCmd.Run(context) 159 | 160 | ch := make(chan os.Signal, 1) 161 | signal.Notify(ch, syscall.SIGTERM, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGKILL) 162 | <-ch 163 | 164 | log.Info("Stopping server") 165 | 166 | // close wait chan 167 | close(wait) 168 | 169 | // stop the runtime 170 | runtimeServer.Stop() 171 | 172 | // just wait 1 sec 173 | <-time.After(time.Second) 174 | 175 | return nil 176 | } 177 | -------------------------------------------------------------------------------- /cmd/micro/service/api/api.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | "os" 7 | "os/signal" 8 | "syscall" 9 | 10 | "github.com/gorilla/mux" 11 | "github.com/urfave/cli/v2" 12 | "micro.dev/v4/service/api" 13 | "micro.dev/v4/service/api/handler" 14 | "micro.dev/v4/service/api/handler/rpc" 15 | "micro.dev/v4/service/api/router" 16 | regRouter "micro.dev/v4/service/api/router/registry" 17 | httpapi "micro.dev/v4/service/api/server/http" 18 | "micro.dev/v4/service/client" 19 | "micro.dev/v4/service/logger" 20 | "micro.dev/v4/service/registry" 21 | ) 22 | 23 | type API struct { 24 | wait chan bool 25 | } 26 | 27 | func NewAPI(wait chan bool) *API { 28 | return &API{ 29 | wait: wait, 30 | } 31 | } 32 | 33 | func Run(ctx *cli.Context) error { 34 | // start the proxy 35 | wait := make(chan bool) 36 | 37 | apiCmd := NewAPI(wait) 38 | 39 | go func() { 40 | if err := apiCmd.Run(ctx); err != nil { 41 | logger.Fatal(err) 42 | } 43 | }() 44 | 45 | ch := make(chan os.Signal, 1) 46 | signal.Notify(ch, syscall.SIGTERM, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGKILL) 47 | <-ch 48 | 49 | // close wait chan 50 | close(wait) 51 | 52 | return nil 53 | } 54 | 55 | func (a *API) Run(ctx *cli.Context) error { 56 | addr := ctx.String("address") 57 | 58 | // Init API 59 | var opts []api.Option 60 | 61 | opts = append(opts, api.EnableCORS(true)) 62 | 63 | // create the router 64 | var h http.Handler 65 | r := mux.NewRouter() 66 | h = r 67 | 68 | // return version and list of services 69 | r.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { 70 | if r.Method == "OPTIONS" { 71 | return 72 | } 73 | 74 | response := fmt.Sprintf(`{"version": "%s"}`, ctx.App.Version) 75 | w.Write([]byte(response)) 76 | }) 77 | 78 | // strip favicon.ico 79 | r.HandleFunc("/favicon.ico", func(w http.ResponseWriter, r *http.Request) {}) 80 | rt := regRouter.NewRouter(router.WithRegistry(registry.DefaultRegistry)) 81 | r.PathPrefix("/").Handler(rpc.NewHandler( 82 | handler.WithClient(client.DefaultClient), 83 | handler.WithRouter(rt), 84 | )) 85 | 86 | // create a new api server with wrappers 87 | api := httpapi.NewServer(addr) 88 | 89 | // initialise 90 | api.Init(opts...) 91 | // register the http handler 92 | api.Handle("/", authWrapper()(h)) 93 | 94 | // Start API 95 | if err := api.Start(); err != nil { 96 | logger.Fatal(err) 97 | } 98 | 99 | // wait to stop 100 | <-a.wait 101 | 102 | // Stop API 103 | if err := api.Stop(); err != nil { 104 | logger.Fatal(err) 105 | } 106 | 107 | return nil 108 | } 109 | -------------------------------------------------------------------------------- /cmd/micro/service/api/auth.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "context" 5 | "net/http" 6 | "strings" 7 | 8 | "micro.dev/v4/service/api" 9 | "micro.dev/v4/service/api/router/registry" 10 | "micro.dev/v4/service/auth" 11 | "micro.dev/v4/service/logger" 12 | inauth "micro.dev/v4/util/auth" 13 | "micro.dev/v4/util/ctx" 14 | "micro.dev/v4/util/namespace" 15 | ) 16 | 17 | func authWrapper() api.Wrapper { 18 | resolver := registry.NewResolver() 19 | 20 | return func(h http.Handler) http.Handler { 21 | return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { 22 | // Determine the name of the service being requested 23 | endpoint := resolver.Resolve(req) 24 | ctrx := context.WithValue(req.Context(), registry.Endpoint{}, endpoint) 25 | *req = *req.Clone(ctrx) 26 | 27 | // Set the metadata so we can access it in micro api / web 28 | req = req.WithContext(ctx.FromRequest(req)) 29 | 30 | // Extract the token from the request 31 | var token string 32 | if header := req.Header.Get("Authorization"); len(header) > 0 { 33 | // Extract the auth token from the request 34 | if strings.HasPrefix(header, inauth.BearerScheme) { 35 | token = header[len(inauth.BearerScheme):] 36 | } 37 | } else { 38 | // Get the token out the cookies if not provided in headers 39 | if c, err := req.Cookie("micro-token"); err == nil && c != nil { 40 | token = strings.TrimPrefix(c.Value, inauth.TokenCookieName+"=") 41 | req.Header.Set("Authorization", inauth.BearerScheme+token) 42 | } 43 | } 44 | 45 | // Get the account using the token, some are unauthenticated, so the lack of an 46 | // account doesn't necessarily mean a forbidden request 47 | acc, err := auth.Inspect(token) 48 | if err == nil { 49 | // inject into the context 50 | ctx := auth.ContextWithAccount(req.Context(), acc) 51 | *req = *req.Clone(ctx) 52 | } 53 | 54 | // Determine the namespace and set it in the header. If the user passed auth creds 55 | // on the request, use the namespace that issued the account, otherwise check for 56 | // the domain of the resolved endpoint. 57 | ns := req.Header.Get(namespace.NamespaceKey) 58 | if len(ns) == 0 && acc != nil { 59 | ns = acc.Issuer 60 | req.Header.Set(namespace.NamespaceKey, ns) 61 | } else if len(ns) == 0 { 62 | ns = endpoint.Domain 63 | req.Header.Set(namespace.NamespaceKey, ns) 64 | } 65 | 66 | // Ensure accounts only issued by the namespace are valid. 67 | if acc != nil && acc.Issuer != ns { 68 | acc = nil 69 | } 70 | 71 | // construct the resource name, e.g. home => foo.api.home 72 | resName := endpoint.Name 73 | resEndpoint := endpoint.Method 74 | 75 | // Options to use when verifying the request 76 | verifyOpts := []auth.VerifyOption{ 77 | auth.VerifyContext(req.Context()), 78 | auth.VerifyNamespace(ns), 79 | } 80 | 81 | logger.Debugf("Resolving %v %v", resName, resEndpoint) 82 | 83 | // Perform the verification check to see if the account has access to 84 | // the resource they're requesting 85 | res := &auth.Resource{Type: "service", Name: resName, Endpoint: resEndpoint} 86 | if err := auth.Verify(acc, res, verifyOpts...); err == nil { 87 | // The account has the necessary permissions to access the resource 88 | h.ServeHTTP(w, req) 89 | return 90 | } else if err != auth.ErrForbidden { 91 | http.Error(w, err.Error(), http.StatusInternalServerError) 92 | return 93 | } 94 | 95 | // The account is set, but they don't have enough permissions, hence 96 | // we return a forbidden error. 97 | if acc != nil { 98 | http.Error(w, "Forbidden request", http.StatusForbidden) 99 | return 100 | } 101 | 102 | http.Error(w, "unauthorized request", http.StatusUnauthorized) 103 | return 104 | }) 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /cmd/micro/service/service.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "github.com/hb-chen/micro-starter/cmd/micro/service/api" 5 | "github.com/urfave/cli/v2" 6 | "micro.dev/v4/cmd" 7 | 8 | // services 9 | auth "micro.dev/v4/service/auth/server" 10 | broker "micro.dev/v4/service/broker/server" 11 | config "micro.dev/v4/service/config/server" 12 | events "micro.dev/v4/service/events/server" 13 | network "micro.dev/v4/service/network/server" 14 | registry "micro.dev/v4/service/registry/server" 15 | runtime "micro.dev/v4/service/runtime/server" 16 | store "micro.dev/v4/service/store/server" 17 | ) 18 | 19 | type srvCommand struct { 20 | Name string 21 | Command cli.ActionFunc 22 | After cli.AfterFunc 23 | Flags []cli.Flag 24 | } 25 | 26 | var apiCmd = func(*cli.Context) error { 27 | return nil 28 | } 29 | var srvCommands = []srvCommand{ 30 | { 31 | Name: "api", 32 | Command: api.Run, 33 | }, 34 | { 35 | Name: "auth", 36 | Command: auth.Run, 37 | }, 38 | { 39 | Name: "broker", 40 | Command: broker.Run, 41 | }, 42 | { 43 | Name: "config", 44 | Command: config.Run, 45 | Flags: config.Flags, 46 | }, 47 | { 48 | Name: "events", 49 | Command: events.Run, 50 | }, 51 | { 52 | Name: "network", 53 | Command: network.Run, 54 | Flags: network.Flags, 55 | }, 56 | { 57 | Name: "registry", 58 | Command: registry.Run, 59 | }, 60 | { 61 | Name: "runtime", 62 | Command: runtime.Run, 63 | }, 64 | { 65 | Name: "store", 66 | Command: store.Run, 67 | }, 68 | } 69 | 70 | func init() { 71 | flags := []cli.Flag{ 72 | &cli.StringFlag{ 73 | Name: "name", 74 | Usage: "Name of the service", 75 | EnvVars: []string{"MICRO_SERVICE_NAME"}, 76 | Value: "service", 77 | }, 78 | &cli.StringFlag{ 79 | Name: "address", 80 | Usage: "Address of the service", 81 | EnvVars: []string{"MICRO_SERVICE_ADDRESS"}, 82 | }, 83 | } 84 | 85 | subcommands := make([]*cli.Command, len(srvCommands)) 86 | 87 | for i, c := range srvCommands { 88 | // construct the command 89 | command := &cli.Command{ 90 | Name: c.Name, 91 | Flags: c.Flags, 92 | Action: c.Command, 93 | After: c.After, 94 | } 95 | 96 | // set the command 97 | subcommands[i] = command 98 | } 99 | 100 | command := &cli.Command{ 101 | Name: "service", 102 | Usage: "Run the micro service", 103 | Flags: flags, 104 | Subcommands: subcommands, 105 | } 106 | 107 | cmd.Register(command) 108 | } 109 | -------------------------------------------------------------------------------- /cmd/micro/web/README.md: -------------------------------------------------------------------------------- 1 | # Micro Web 2 | 3 | A web app for Micro 4 | 5 | ## Usage 6 | 7 | Specify the API Address (Defaults to localhost:8080) 8 | 9 | ``` 10 | MICRO_API_ADDRESS=https://api.m3o.com 11 | ``` 12 | 13 | Run the dashboard 14 | 15 | ``` 16 | micro web 17 | ``` 18 | 19 | Go to `localhost:8082` 20 | -------------------------------------------------------------------------------- /cmd/micro/web/html/assets/mu.css: -------------------------------------------------------------------------------- 1 | html, body { 2 | font-size: 14px; 3 | font-family: arial, sans-serif; 4 | } 5 | #header,#container,#footer { 6 | max-width: 1400px; 7 | margin: 0 auto; 8 | padding: 2em; 9 | } 10 | #container { 11 | max-width: 1024px; 12 | } 13 | a { color: #333333; text-decoration: none; } 14 | a:hover { text-decoration: underline; } 15 | #error { 16 | color: red; 17 | } 18 | #login, #error { 19 | margin: 0 auto; 20 | max-width: 400px; 21 | } 22 | #logo { 23 | font-size: 2em; 24 | font-weight: 600; 25 | text-decoration: none; 26 | } 27 | #links { 28 | float: right; 29 | font-size: 0.8em; 30 | font-weight: normal; 31 | } 32 | #menu { 33 | float: right; 34 | list-style: none; 35 | } 36 | #menu li { 37 | display: inline-block; 38 | margin-left: 10px; 39 | } 40 | #heading { 41 | margin-bottom: 10px; 42 | font-size: 1.5em; 43 | text-transform: capitalize; 44 | } 45 | button:hover { 46 | cursor: pointer; 47 | } 48 | .response { 49 | margin-bottom: 10px; 50 | overflow-wrap: break-word; 51 | } 52 | .search { 53 | width: 100%; 54 | position: relative; 55 | margin: 0 auto; 56 | border-radius: 0; 57 | border: 0; 58 | box-shadow: none; 59 | border-bottom: 1px solid #ccc; 60 | } 61 | .search:focus { 62 | border-color: transparent; 63 | outline: 0; 64 | box-shadow: none; 65 | border-bottom: 1px solid #ccc; 66 | } 67 | #services { 68 | height: calc(100vh - 250px); 69 | width: 100%; 70 | max-width: 1024px; 71 | position: absolute; 72 | overflow: auto; 73 | background: white; 74 | z-index: 1; 75 | } 76 | .field { 77 | margin-bottom: 3px; 78 | } 79 | .key, .title { 80 | text-transform: capitalize; 81 | } 82 | .key { 83 | color: grey; 84 | } 85 | .table>tbody>tr>th, .table>tbody>tr>td { 86 | border-top: none; 87 | } 88 | .endpoint, .service, .query { 89 | margin-bottom: 5px; 90 | cursor: pointer; 91 | display: block; 92 | } 93 | .bold { 94 | font-weight: bold; 95 | } 96 | .user { 97 | padding: 15px; 98 | } 99 | form { 100 | display: flex; 101 | flex-direction: column; 102 | } 103 | .form-control { 104 | border: 1px solid #ccc; 105 | } 106 | .form-group { 107 | margin-bottom: 0px; 108 | } 109 | input { 110 | margin-bottom: 10px; 111 | outline: none; 112 | height: 25px; 113 | } 114 | label { 115 | margin-bottom: 3px; 116 | } 117 | pre { 118 | padding: 20px; 119 | border: 1px solid #ccc; 120 | overflow: auto; 121 | word-wrap: break-word; 122 | } 123 | textarea#request { 124 | margin-bottom: 10px; 125 | } 126 | @media only screen and (max-width: 500px) { 127 | } 128 | -------------------------------------------------------------------------------- /cmd/micro/web/html/assets/mu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hb-chen/micro-starter/045d1f4f99d50c96857b34fb1eced2c419eb6507/cmd/micro/web/html/assets/mu.png -------------------------------------------------------------------------------- /cmd/micro/web/html/template.go: -------------------------------------------------------------------------------- 1 | package html 2 | 3 | var ( 4 | LoginTemplate = ` 5 | {{define "title"}}Login{{end}} 6 | {{define "heading"}}{{end}} 7 | {{define "style" }}{{end}} 8 | {{define "content"}} 9 |
{{ .error }}
10 |
11 | {{end}} 12 | {{define "script"}}{{end}} 13 | ` 14 | 15 | LayoutTemplate = ` 16 | {{define "layout"}} 17 | 18 | 19 | {{ template "title" . }} | Micro 20 | 21 | 22 | 25 | {{ template "head" . }} 26 | 27 | 28 | 38 |
39 |
{{ template "heading" . }}
40 |
{{ template "content" . }}
41 |
42 | 43 | 44 | 45 | 63 | {{template "script" . }} 64 | 65 | 66 | {{end}} 67 | {{ define "style" }}{{end}} 68 | {{ define "head" }}{{end}} 69 | {{ define "script" }}{{end}} 70 | {{ define "title" }}Web{{end}} 71 | {{ define "heading" }}

 

{{end}} 72 | ` 73 | IndexTemplate = ` 74 | {{define "title"}}Home{{end}} 75 | {{define "heading"}}{{end}} 76 | {{define "style" }}{{end}} 77 | {{define "content"}} 78 |
79 | {{end}} 80 | {{define "script"}} 81 | 82 | {{end}} 83 | ` 84 | NotFoundTemplate = ` 85 | {{define "title"}}404: Not Found{{end}} 86 | {{define "heading"}}

404: Not Found

{{end}} 87 | {{define "content"}}

The requested page could not be found

{{end}}` 88 | ) 89 | -------------------------------------------------------------------------------- /cmd/micro/web/web.go: -------------------------------------------------------------------------------- 1 | // Package web is a web dashboard 2 | package web 3 | 4 | import ( 5 | "context" 6 | "embed" 7 | "html/template" 8 | "io/fs" 9 | "log" 10 | "net/http" 11 | "net/url" 12 | "os" 13 | "path/filepath" 14 | "strings" 15 | "sync" 16 | "time" 17 | 18 | "github.com/gorilla/mux" 19 | "github.com/urfave/cli/v2" 20 | "micro.dev/v4/cmd" 21 | "micro.dev/v4/cmd/web/html" 22 | ) 23 | 24 | // Meta Fields of micro web 25 | var ( 26 | Name = "web" 27 | API = "http://localhost:8080" 28 | Address = ":8082" 29 | Namespace = "micro" 30 | LoginURL = "/login" 31 | // Host name the web dashboard is served on 32 | Host, _ = os.Hostname() 33 | // Token cookie name 34 | TokenCookieName = "micro-token" 35 | 36 | // create a session store 37 | mtx sync.RWMutex 38 | sessions = map[string]*session{} 39 | ) 40 | 41 | type srv struct { 42 | *mux.Router 43 | } 44 | 45 | type session struct { 46 | // token used for the session 47 | Token string 48 | } 49 | 50 | //go:embed html/* html/assets/* 51 | var content embed.FS 52 | 53 | func init() { 54 | cmd.Register( 55 | &cli.Command{ 56 | Name: "web", 57 | Usage: "Run the micro web UI", 58 | Action: Run, 59 | Flags: Flags, 60 | }, 61 | ) 62 | } 63 | 64 | // ServeHTTP serves the web dashboard and proxies where appropriate 65 | func (s *srv) ServeHTTP(w http.ResponseWriter, r *http.Request) { 66 | if strings.HasPrefix(r.URL.Path, "/assets/") { 67 | s.Router.ServeHTTP(w, r) 68 | return 69 | } 70 | 71 | // check if authenticated 72 | if r.URL.Path != LoginURL { 73 | c, err := r.Cookie(TokenCookieName) 74 | if err != nil || c == nil { 75 | http.Redirect(w, r, LoginURL, 302) 76 | return 77 | } 78 | 79 | // check the token is valid 80 | token := strings.TrimPrefix(c.Value, TokenCookieName+"=") 81 | if len(token) == 0 { 82 | http.Redirect(w, r, LoginURL, 302) 83 | return 84 | } 85 | 86 | // if we have a session retrieve it 87 | mtx.RLock() 88 | sess, ok := sessions[token] 89 | mtx.RUnlock() 90 | 91 | // no session, go get the account 92 | if !ok { 93 | // save the session 94 | mtx.Lock() 95 | sess = &session{ 96 | Token: token, 97 | } 98 | sessions[token] = sess 99 | mtx.Unlock() 100 | } 101 | 102 | // create a new context 103 | ctx := context.WithValue(r.Context(), session{}, sess) 104 | 105 | // redefine request with context 106 | r = r.Clone(ctx) 107 | } 108 | 109 | // set defaults on the request 110 | if len(r.URL.Host) == 0 { 111 | r.URL.Host = r.Host 112 | } 113 | if len(r.URL.Scheme) == 0 { 114 | r.URL.Scheme = "http" 115 | } 116 | 117 | s.Router.ServeHTTP(w, r) 118 | } 119 | 120 | func faviconHandler(w http.ResponseWriter, r *http.Request) { 121 | return 122 | } 123 | 124 | func (s *srv) notFoundHandler(w http.ResponseWriter, r *http.Request) { 125 | w.WriteHeader(http.StatusNotFound) 126 | s.render(w, r, html.NotFoundTemplate, nil) 127 | } 128 | 129 | func (s *srv) indexHandler(w http.ResponseWriter, r *http.Request) { 130 | if r.Method == "OPTIONS" { 131 | return 132 | } 133 | s.render(w, r, html.IndexTemplate, struct{}{}) 134 | } 135 | 136 | func (s *srv) loginHandler(w http.ResponseWriter, req *http.Request) { 137 | s.render(w, req, html.LoginTemplate, struct{}{}) 138 | } 139 | 140 | func (s *srv) logoutHandler(w http.ResponseWriter, req *http.Request) { 141 | http.SetCookie(w, &http.Cookie{ 142 | Name: TokenCookieName, 143 | Value: "", 144 | Expires: time.Unix(0, 0), 145 | Secure: true, 146 | }) 147 | 148 | http.Redirect(w, req, "/", 302) 149 | } 150 | 151 | type templateValue struct { 152 | Key string 153 | Value interface{} 154 | } 155 | 156 | func (s *srv) render(w http.ResponseWriter, r *http.Request, tmpl string, data interface{}, vals ...templateValue) { 157 | t, err := template.New("template").Funcs(template.FuncMap{ 158 | "Title": strings.Title, 159 | "First": func(s string) string { 160 | if len(s) == 0 { 161 | return s 162 | } 163 | return strings.Title(string(s[0])) 164 | }, 165 | "Endpoint": func(ep string) string { 166 | return strings.Replace(ep, ".", "/", -1) 167 | }, 168 | }).Parse(html.LayoutTemplate) 169 | if err != nil { 170 | http.Error(w, "Error occurred:"+err.Error(), 500) 171 | return 172 | } 173 | t, err = t.Parse(tmpl) 174 | if err != nil { 175 | http.Error(w, "Error occurred:"+err.Error(), 500) 176 | return 177 | } 178 | 179 | apiURL := API 180 | 181 | // set api from the hdear if available 182 | if v := r.Header.Get("Micro-API"); len(v) > 0 { 183 | apiURL = v 184 | } 185 | 186 | u, err := url.Parse(apiURL) 187 | if err != nil { 188 | http.Error(w, "Error occurred:"+err.Error(), 500) 189 | return 190 | } 191 | 192 | filepath.Join(u.Path, r.URL.Path) 193 | 194 | var token string 195 | 196 | sess, ok := r.Context().Value(session{}).(*session) 197 | if ok { 198 | token = sess.Token 199 | } 200 | 201 | templateData := map[string]interface{}{ 202 | "ApiURL": template.URL(apiURL), 203 | "Token": token, 204 | "Results": data, 205 | "Namespace": Namespace, 206 | } 207 | 208 | // add extra values 209 | for _, val := range vals { 210 | templateData[val.Key] = val.Value 211 | } 212 | 213 | if err := t.ExecuteTemplate(w, "layout", 214 | templateData, 215 | ); err != nil { 216 | http.Error(w, "Error occurred:"+err.Error(), 500) 217 | } 218 | } 219 | 220 | func Run(ctx *cli.Context) error { 221 | if len(ctx.String("api_address")) > 0 { 222 | API = ctx.String("api_address") 223 | } 224 | if len(ctx.String("server_name")) > 0 { 225 | Name = ctx.String("server_name") 226 | } 227 | if len(ctx.String("web_address")) > 0 { 228 | Address = ctx.String("web_address") 229 | } 230 | if len(ctx.String("web_namespace")) > 0 { 231 | Namespace = ctx.String("web_namespace") 232 | } 233 | if len(ctx.String("web_host")) > 0 { 234 | Host = ctx.String("web_host") 235 | } 236 | if len(ctx.String("namespace")) > 0 { 237 | // remove the service type from the namespace to allow for 238 | // backwards compatability 239 | Namespace = ctx.String("namespace") 240 | } 241 | // Setup auth redirect 242 | if len(ctx.String("login_url")) > 0 { 243 | LoginURL = ctx.String("login_url") 244 | } 245 | 246 | srv := &srv{ 247 | Router: mux.NewRouter(), 248 | } 249 | 250 | htmlContent, err := fs.Sub(content, "html") 251 | if err != nil { 252 | log.Fatal(err) 253 | } 254 | 255 | // the web handler itself 256 | srv.HandleFunc("/favicon.ico", faviconHandler) 257 | srv.HandleFunc("/404", srv.notFoundHandler) 258 | srv.HandleFunc("/login", srv.loginHandler) 259 | srv.HandleFunc("/logout", srv.logoutHandler) 260 | srv.PathPrefix("/assets/").Handler(http.FileServer(http.FS(htmlContent))) 261 | srv.HandleFunc("/", srv.indexHandler) 262 | srv.HandleFunc("/services", srv.indexHandler) 263 | srv.HandleFunc("/{service}", srv.indexHandler) 264 | srv.HandleFunc("/{service}/{endpoint}", srv.indexHandler) 265 | srv.HandleFunc("/{service}/{endpoint}/{method}", srv.indexHandler) 266 | 267 | // create new http server 268 | server := &http.Server{ 269 | Addr: Address, 270 | Handler: srv, 271 | } 272 | 273 | if err := server.ListenAndServe(); err != nil { 274 | log.Fatal(err) 275 | } 276 | 277 | return nil 278 | } 279 | 280 | var ( 281 | Flags = []cli.Flag{ 282 | &cli.StringFlag{ 283 | Name: "api_address", 284 | Usage: "Set the api address to call e.g http://localhost:8080", 285 | EnvVars: []string{"MICRO_API_ADDRESS"}, 286 | }, 287 | &cli.StringFlag{ 288 | Name: "web_address", 289 | Usage: "Set the web UI address e.g 0.0.0.0:8082", 290 | EnvVars: []string{"MICRO_WEB_ADDRESS"}, 291 | }, 292 | &cli.StringFlag{ 293 | Name: "namespace", 294 | Usage: "Set the namespace used by the Web proxy e.g. com.example.web", 295 | EnvVars: []string{"MICRO_WEB_NAMESPACE"}, 296 | }, 297 | &cli.StringFlag{ 298 | Name: "login_url", 299 | EnvVars: []string{"MICRO_WEB_LOGIN_URL"}, 300 | Usage: "The relative URL where a user can login", 301 | }, 302 | } 303 | ) 304 | -------------------------------------------------------------------------------- /doc/img/micro-istio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hb-chen/micro-starter/045d1f4f99d50c96857b34fb1eced2c419eb6507/doc/img/micro-istio.png -------------------------------------------------------------------------------- /doc/img/micro.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hb-chen/micro-starter/045d1f4f99d50c96857b34fb1eced2c419eb6507/doc/img/micro.jpg -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/hb-chen/micro-starter 2 | 3 | go 1.20 4 | 5 | require ( 6 | github.com/go-sql-driver/mysql v1.7.0 7 | github.com/golang/protobuf v1.5.3 8 | github.com/google/uuid v1.3.0 9 | github.com/gorilla/mux v1.7.3 10 | github.com/urfave/cli/v2 v2.3.0 11 | go.uber.org/dig v1.13.0 12 | google.golang.org/protobuf v1.28.1 13 | gorm.io/driver/mysql v1.4.5 14 | gorm.io/gorm v1.24.3 15 | gorm.io/plugin/dbresolver v1.4.0 16 | micro.dev/v4 v4.3.1 17 | ) 18 | 19 | require ( 20 | github.com/bitly/go-simplejson v0.5.0 // indirect 21 | github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect 22 | github.com/davecgh/go-spew v1.1.1 // indirect 23 | github.com/evanphx/json-patch/v5 v5.5.0 // indirect 24 | github.com/felixge/httpsnoop v1.0.1 // indirect 25 | github.com/golang-jwt/jwt v0.0.0-20210529014511-0f726ea0e725 // indirect 26 | github.com/gorilla/handlers v1.5.1 // indirect 27 | github.com/gorilla/websocket v1.4.2 // indirect 28 | github.com/hpcloud/tail v1.0.0 // indirect 29 | github.com/jackc/chunkreader/v2 v2.0.1 // indirect 30 | github.com/jackc/pgconn v1.13.0 // indirect 31 | github.com/jackc/pgio v1.0.0 // indirect 32 | github.com/jackc/pgpassfile v1.0.0 // indirect 33 | github.com/jackc/pgproto3/v2 v2.3.1 // indirect 34 | github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect 35 | github.com/jackc/pgtype v1.12.0 // indirect 36 | github.com/jackc/pgx/v4 v4.17.2 // indirect 37 | github.com/jinzhu/inflection v1.0.0 // indirect 38 | github.com/jinzhu/now v1.1.5 // indirect 39 | github.com/mattn/go-sqlite3 v1.14.15 // indirect 40 | github.com/nightlyone/lockfile v1.0.0 // indirect 41 | github.com/onsi/gomega v1.27.6 // indirect 42 | github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c // indirect 43 | github.com/patrickmn/go-cache v2.1.0+incompatible // indirect 44 | github.com/pkg/errors v0.9.1 // indirect 45 | github.com/pmezard/go-difflib v1.0.0 // indirect 46 | github.com/rogpeppe/go-internal v1.9.0 // indirect 47 | github.com/russross/blackfriday/v2 v2.0.1 // indirect 48 | github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect 49 | github.com/stretchr/objx v0.5.0 // indirect 50 | github.com/stretchr/testify v1.8.1 // indirect 51 | github.com/teris-io/shortid v0.0.0-20171029131806-771a37caa5cf // indirect 52 | go.etcd.io/bbolt v1.3.5 // indirect 53 | golang.org/x/crypto v0.4.0 // indirect 54 | golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 // indirect 55 | golang.org/x/net v0.10.0 // indirect 56 | golang.org/x/sys v0.8.0 // indirect 57 | golang.org/x/text v0.9.0 // indirect 58 | golang.org/x/tools v0.9.1 // indirect 59 | google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect 60 | google.golang.org/grpc v1.54.1 // indirect 61 | gopkg.in/fsnotify.v1 v1.4.7 // indirect 62 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect 63 | gopkg.in/yaml.v3 v3.0.1 // indirect 64 | gorm.io/driver/postgres v1.4.5 // indirect 65 | gorm.io/driver/sqlite v1.4.3 // indirect 66 | ) 67 | 68 | replace micro.dev/v4 => github.com/micro/micro/v4 v4.3.1 69 | -------------------------------------------------------------------------------- /manifests/buildpacks/project.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | id = "com.hbchen.micro" 3 | name = "Micro" 4 | version = "3.8.0" 5 | 6 | [build] 7 | exclude = [ 8 | "../../README.md", 9 | "../../LICENSE" 10 | ] 11 | 12 | [[build.buildpacks]] 13 | uri = "paketobuildpacks/go:4" 14 | 15 | [[ build.env ]] 16 | name="BP_GO_VERSION" 17 | value="1.20" 18 | 19 | [[ build.env ]] 20 | name="BP_GO_TARGETS" 21 | value="./cmd/micro" 22 | 23 | [[ build.env ]] 24 | name="BP_GO_BUILD_LDFLAGS" 25 | value="-s -w" 26 | 27 | [[ build.env ]] 28 | name="GOPROXY" 29 | value="https://mirrors.aliyun.com/goproxy/,direct" -------------------------------------------------------------------------------- /manifests/charts/micro/.helmignore: -------------------------------------------------------------------------------- 1 | # Patterns to ignore when building packages. 2 | # This supports shell glob matching, relative path matching, and 3 | # negation (prefixed with !). Only one pattern per line. 4 | .DS_Store 5 | # Common VCS dirs 6 | .git/ 7 | .gitignore 8 | .bzr/ 9 | .bzrignore 10 | .hg/ 11 | .hgignore 12 | .svn/ 13 | # Common backup files 14 | *.swp 15 | *.bak 16 | *.tmp 17 | *.orig 18 | *~ 19 | # Various IDEs 20 | .project 21 | .idea/ 22 | *.tmproj 23 | .vscode/ 24 | -------------------------------------------------------------------------------- /manifests/charts/micro/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v2 2 | name: micro 3 | description: A Helm chart for Kubernetes 4 | 5 | # A chart can be either an 'application' or a 'library' chart. 6 | # 7 | # Application charts are a collection of templates that can be packaged into versioned archives 8 | # to be deployed. 9 | # 10 | # Library charts provide useful utilities or functions for the chart developer. They're included as 11 | # a dependency of application charts to inject those utilities and functions into the rendering 12 | # pipeline. Library charts do not define any templates and therefore cannot be deployed. 13 | type: application 14 | 15 | # This is the chart version. This version number should be incremented each time you make changes 16 | # to the chart and its templates, including the app version. 17 | # Versions are expected to follow Semantic Versioning (https://semver.org/) 18 | version: 0.1.0 19 | 20 | # This is the version number of the application being deployed. This version number should be 21 | # incremented each time you make changes to the application. Versions are not expected to 22 | # follow Semantic Versioning. They should reflect the version the application is using. 23 | # It is recommended to use it with quotes. 24 | appVersion: "1.16.0" 25 | -------------------------------------------------------------------------------- /manifests/charts/micro/templates/NOTES.txt: -------------------------------------------------------------------------------- 1 | 1. Get the application URL by running these commands: 2 | {{- if .Values.ingress.enabled }} 3 | {{- range $host := .Values.ingress.hosts }} 4 | {{- range .paths }} 5 | http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }} 6 | {{- end }} 7 | {{- end }} 8 | {{- else if contains "NodePort" .Values.service.type }} 9 | export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "micro.fullname" . }}) 10 | export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") 11 | echo http://$NODE_IP:$NODE_PORT 12 | {{- else if contains "LoadBalancer" .Values.service.type }} 13 | NOTE: It may take a few minutes for the LoadBalancer IP to be available. 14 | You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "micro.fullname" . }}' 15 | export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "micro.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") 16 | echo http://$SERVICE_IP:{{ .Values.service.port }} 17 | {{- else if contains "ClusterIP" .Values.service.type }} 18 | export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "micro.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") 19 | export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}") 20 | echo "Visit http://127.0.0.1:8080 to use your application" 21 | kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT 22 | {{- end }} 23 | -------------------------------------------------------------------------------- /manifests/charts/micro/templates/_helpers.tpl: -------------------------------------------------------------------------------- 1 | {{/* 2 | Expand the name of the chart. 3 | */}} 4 | {{- define "micro.name" -}} 5 | {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} 6 | {{- end }} 7 | 8 | {{/* 9 | Create a default fully qualified app name. 10 | We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). 11 | If release name contains chart name it will be used as a full name. 12 | */}} 13 | {{- define "micro.fullname" -}} 14 | {{- if .Values.fullnameOverride }} 15 | {{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} 16 | {{- else }} 17 | {{- $name := default .Chart.Name .Values.nameOverride }} 18 | {{- if contains $name .Release.Name }} 19 | {{- .Release.Name | trunc 63 | trimSuffix "-" }} 20 | {{- else }} 21 | {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} 22 | {{- end }} 23 | {{- end }} 24 | {{- end }} 25 | 26 | {{/* 27 | Create chart name and version as used by the chart label. 28 | */}} 29 | {{- define "micro.chart" -}} 30 | {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} 31 | {{- end }} 32 | 33 | {{/* 34 | Common labels 35 | */}} 36 | {{- define "micro.labels" -}} 37 | helm.sh/chart: {{ include "micro.chart" . }} 38 | {{ include "micro.selectorLabels" . }} 39 | {{- if .Chart.AppVersion }} 40 | app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} 41 | {{- end }} 42 | app.kubernetes.io/managed-by: {{ .Release.Service }} 43 | {{- end }} 44 | 45 | {{/* 46 | Selector labels 47 | */}} 48 | {{- define "micro.selectorLabels" -}} 49 | app.kubernetes.io/name: {{ include "micro.name" . }} 50 | app.kubernetes.io/instance: {{ .Release.Name }} 51 | {{- end }} 52 | 53 | {{/* 54 | Create the name of the service account to use 55 | */}} 56 | {{- define "micro.serviceAccountName" -}} 57 | {{- if .Values.serviceAccount.create }} 58 | {{- default (include "micro.fullname" .) .Values.serviceAccount.name }} 59 | {{- else }} 60 | {{- default "default" .Values.serviceAccount.name }} 61 | {{- end }} 62 | {{- end }} 63 | -------------------------------------------------------------------------------- /manifests/charts/micro/templates/deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: {{ include "micro.fullname" . }} 5 | labels: 6 | {{- include "micro.labels" . | nindent 4 }} 7 | spec: 8 | {{- if not .Values.autoscaling.enabled }} 9 | replicas: {{ .Values.replicaCount }} 10 | {{- end }} 11 | selector: 12 | matchLabels: 13 | {{- include "micro.selectorLabels" . | nindent 6 }} 14 | template: 15 | metadata: 16 | {{- with .Values.podAnnotations }} 17 | annotations: 18 | {{- toYaml . | nindent 8 }} 19 | {{- end }} 20 | labels: 21 | {{- include "micro.selectorLabels" . | nindent 8 }} 22 | spec: 23 | {{- with .Values.imagePullSecrets }} 24 | imagePullSecrets: 25 | {{- toYaml . | nindent 8 }} 26 | {{- end }} 27 | serviceAccountName: {{ include "micro.serviceAccountName" . }} 28 | securityContext: 29 | {{- toYaml .Values.podSecurityContext | nindent 8 }} 30 | containers: 31 | - name: {{ .Chart.Name }} 32 | securityContext: 33 | {{- toYaml .Values.securityContext | nindent 12 }} 34 | image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" 35 | imagePullPolicy: {{ .Values.image.pullPolicy }} 36 | env: 37 | - name: MICRO_SERVICE_PROFILE 38 | value: starter-kubernetes 39 | - name: MICRO_API_ADDRESS 40 | value: :8080 41 | - name: MICRO_PROXY_ADDRESS 42 | value: :8081 43 | command: 44 | - "./micro" 45 | args: 46 | - --profile 47 | - starter-kubernetes 48 | - server 49 | ports: 50 | - name: http 51 | containerPort: 8080 52 | protocol: TCP 53 | - name: registry 54 | containerPort: 8000 55 | protocol: TCP 56 | livenessProbe: 57 | httpGet: 58 | path: / 59 | port: http 60 | readinessProbe: 61 | httpGet: 62 | path: / 63 | port: http 64 | resources: 65 | {{- toYaml .Values.resources | nindent 12 }} 66 | {{- with .Values.nodeSelector }} 67 | nodeSelector: 68 | {{- toYaml . | nindent 8 }} 69 | {{- end }} 70 | {{- with .Values.affinity }} 71 | affinity: 72 | {{- toYaml . | nindent 8 }} 73 | {{- end }} 74 | {{- with .Values.tolerations }} 75 | tolerations: 76 | {{- toYaml . | nindent 8 }} 77 | {{- end }} 78 | -------------------------------------------------------------------------------- /manifests/charts/micro/templates/hpa.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.autoscaling.enabled }} 2 | apiVersion: autoscaling/v2beta1 3 | kind: HorizontalPodAutoscaler 4 | metadata: 5 | name: {{ include "micro.fullname" . }} 6 | labels: 7 | {{- include "micro.labels" . | nindent 4 }} 8 | spec: 9 | scaleTargetRef: 10 | apiVersion: apps/v1 11 | kind: Deployment 12 | name: {{ include "micro.fullname" . }} 13 | minReplicas: {{ .Values.autoscaling.minReplicas }} 14 | maxReplicas: {{ .Values.autoscaling.maxReplicas }} 15 | metrics: 16 | {{- if .Values.autoscaling.targetCPUUtilizationPercentage }} 17 | - type: Resource 18 | resource: 19 | name: cpu 20 | targetAverageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }} 21 | {{- end }} 22 | {{- if .Values.autoscaling.targetMemoryUtilizationPercentage }} 23 | - type: Resource 24 | resource: 25 | name: memory 26 | targetAverageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }} 27 | {{- end }} 28 | {{- end }} 29 | -------------------------------------------------------------------------------- /manifests/charts/micro/templates/ingress.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.ingress.enabled -}} 2 | {{- $fullName := include "micro.fullname" . -}} 3 | {{- $svcPort := .Values.service.port -}} 4 | {{- if and .Values.ingress.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }} 5 | {{- if not (hasKey .Values.ingress.annotations "kubernetes.io/ingress.class") }} 6 | {{- $_ := set .Values.ingress.annotations "kubernetes.io/ingress.class" .Values.ingress.className}} 7 | {{- end }} 8 | {{- end }} 9 | {{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}} 10 | apiVersion: networking.k8s.io/v1 11 | {{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}} 12 | apiVersion: networking.k8s.io/v1beta1 13 | {{- else -}} 14 | apiVersion: extensions/v1beta1 15 | {{- end }} 16 | kind: Ingress 17 | metadata: 18 | name: {{ $fullName }} 19 | labels: 20 | {{- include "micro.labels" . | nindent 4 }} 21 | {{- with .Values.ingress.annotations }} 22 | annotations: 23 | {{- toYaml . | nindent 4 }} 24 | {{- end }} 25 | spec: 26 | {{- if and .Values.ingress.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }} 27 | ingressClassName: {{ .Values.ingress.className }} 28 | {{- end }} 29 | {{- if .Values.ingress.tls }} 30 | tls: 31 | {{- range .Values.ingress.tls }} 32 | - hosts: 33 | {{- range .hosts }} 34 | - {{ . | quote }} 35 | {{- end }} 36 | secretName: {{ .secretName }} 37 | {{- end }} 38 | {{- end }} 39 | rules: 40 | {{- range .Values.ingress.hosts }} 41 | - host: {{ .host | quote }} 42 | http: 43 | paths: 44 | {{- range .paths }} 45 | - path: {{ .path }} 46 | {{- if and .pathType (semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion) }} 47 | pathType: {{ .pathType }} 48 | {{- end }} 49 | backend: 50 | {{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }} 51 | service: 52 | name: {{ $fullName }} 53 | port: 54 | number: {{ $svcPort }} 55 | {{- else }} 56 | serviceName: {{ $fullName }} 57 | servicePort: {{ $svcPort }} 58 | {{- end }} 59 | {{- end }} 60 | {{- end }} 61 | {{- end }} 62 | -------------------------------------------------------------------------------- /manifests/charts/micro/templates/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: {{ include "micro.fullname" . }} 5 | labels: 6 | {{- include "micro.labels" . | nindent 4 }} 7 | spec: 8 | type: {{ .Values.service.type }} 9 | ports: 10 | - port: {{ .Values.service.port }} 11 | targetPort: http 12 | protocol: TCP 13 | name: http 14 | - port: 8000 15 | targetPort: registry 16 | protocol: TCP 17 | name: registry 18 | selector: 19 | {{- include "micro.selectorLabels" . | nindent 4 }} 20 | -------------------------------------------------------------------------------- /manifests/charts/micro/templates/serviceaccount.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.serviceAccount.create -}} 2 | apiVersion: v1 3 | kind: ServiceAccount 4 | metadata: 5 | name: {{ include "micro.serviceAccountName" . }} 6 | labels: 7 | {{- include "micro.labels" . | nindent 4 }} 8 | {{- with .Values.serviceAccount.annotations }} 9 | annotations: 10 | {{- toYaml . | nindent 4 }} 11 | {{- end }} 12 | {{- end }} 13 | -------------------------------------------------------------------------------- /manifests/charts/micro/templates/tests/test-connection.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.tests.enabled -}} 2 | apiVersion: v1 3 | kind: Pod 4 | metadata: 5 | name: "{{ include "micro.fullname" . }}-test-connection" 6 | labels: 7 | {{- include "micro.labels" . | nindent 4 }} 8 | annotations: 9 | "helm.sh/hook": test 10 | spec: 11 | containers: 12 | - name: wget 13 | image: busybox 14 | command: ['wget'] 15 | args: ['{{ include "micro.fullname" . }}:{{ .Values.service.port }}'] 16 | restartPolicy: Never 17 | {{- end }} -------------------------------------------------------------------------------- /manifests/charts/micro/values.yaml: -------------------------------------------------------------------------------- 1 | # Default values for micro. 2 | # This is a YAML-formatted file. 3 | # Declare variables to be passed into your templates. 4 | 5 | replicaCount: 1 6 | 7 | image: 8 | repository: registry.cn-hangzhou.aliyuncs.com/hb-chen/micro-starter-micro 9 | pullPolicy: IfNotPresent 10 | # Overrides the image tag whose default is the chart appVersion. 11 | tag: "latest" 12 | 13 | imagePullSecrets: [] 14 | nameOverride: "" 15 | fullnameOverride: "" 16 | 17 | serviceAccount: 18 | # Specifies whether a service account should be created 19 | create: true 20 | # Annotations to add to the service account 21 | annotations: {} 22 | # The name of the service account to use. 23 | # If not set and create is true, a name is generated using the fullname template 24 | name: "" 25 | 26 | podAnnotations: {} 27 | 28 | podSecurityContext: {} 29 | # fsGroup: 2000 30 | 31 | securityContext: {} 32 | # capabilities: 33 | # drop: 34 | # - ALL 35 | # readOnlyRootFilesystem: true 36 | # runAsNonRoot: true 37 | # runAsUser: 1000 38 | 39 | service: 40 | type: ClusterIP 41 | port: 8080 42 | 43 | ingress: 44 | enabled: false 45 | className: "nginx" 46 | annotations: {} 47 | # kubernetes.io/ingress.class: nginx 48 | # kubernetes.io/tls-acme: "true" 49 | hosts: 50 | - host: api.micro.hbchen.com 51 | paths: 52 | - path: / 53 | pathType: ImplementationSpecific 54 | tls: [] 55 | # - secretName: chart-example-tls 56 | # hosts: 57 | # - chart-example.local 58 | 59 | resources: {} 60 | # We usually recommend not to specify default resources and to leave this as a conscious 61 | # choice for the user. This also increases chances charts run on environments with little 62 | # resources, such as Minikube. If you do want to specify resources, uncomment the following 63 | # lines, adjust them as necessary, and remove the curly braces after 'resources:'. 64 | # limits: 65 | # cpu: 100m 66 | # memory: 128Mi 67 | # requests: 68 | # cpu: 100m 69 | # memory: 128Mi 70 | 71 | autoscaling: 72 | enabled: false 73 | minReplicas: 1 74 | maxReplicas: 100 75 | targetCPUUtilizationPercentage: 80 76 | # targetMemoryUtilizationPercentage: 80 77 | 78 | nodeSelector: {} 79 | 80 | tolerations: [] 81 | 82 | affinity: {} 83 | 84 | tests: 85 | enabled: false 86 | -------------------------------------------------------------------------------- /manifests/charts/service/.helmignore: -------------------------------------------------------------------------------- 1 | # Patterns to ignore when building packages. 2 | # This supports shell glob matching, relative path matching, and 3 | # negation (prefixed with !). Only one pattern per line. 4 | .DS_Store 5 | # Common VCS dirs 6 | .git/ 7 | .gitignore 8 | .bzr/ 9 | .bzrignore 10 | .hg/ 11 | .hgignore 12 | .svn/ 13 | # Common backup files 14 | *.swp 15 | *.bak 16 | *.tmp 17 | *.orig 18 | *~ 19 | # Various IDEs 20 | .project 21 | .idea/ 22 | *.tmproj 23 | .vscode/ 24 | -------------------------------------------------------------------------------- /manifests/charts/service/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v2 2 | name: service 3 | description: A Helm chart for Kubernetes 4 | 5 | # A chart can be either an 'application' or a 'library' chart. 6 | # 7 | # Application charts are a collection of templates that can be packaged into versioned archives 8 | # to be deployed. 9 | # 10 | # Library charts provide useful utilities or functions for the chart developer. They're included as 11 | # a dependency of application charts to inject those utilities and functions into the rendering 12 | # pipeline. Library charts do not define any templates and therefore cannot be deployed. 13 | type: application 14 | 15 | # This is the chart version. This version number should be incremented each time you make changes 16 | # to the chart and its templates, including the app version. 17 | # Versions are expected to follow Semantic Versioning (https://semver.org/) 18 | version: 0.1.0 19 | 20 | # This is the version number of the application being deployed. This version number should be 21 | # incremented each time you make changes to the application. Versions are not expected to 22 | # follow Semantic Versioning. They should reflect the version the application is using. 23 | # It is recommended to use it with quotes. 24 | appVersion: "1.16.0" 25 | -------------------------------------------------------------------------------- /manifests/charts/service/templates/_helpers.tpl: -------------------------------------------------------------------------------- 1 | {{/* 2 | Expand the name of the chart. 3 | */}} 4 | {{- define "service.name" -}} 5 | {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} 6 | {{- end }} 7 | 8 | {{/* 9 | Create a default fully qualified app name. 10 | We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). 11 | If release name contains chart name it will be used as a full name. 12 | */}} 13 | {{- define "service.fullname" -}} 14 | {{- if .Values.fullnameOverride }} 15 | {{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} 16 | {{- else }} 17 | {{- $name := default .Chart.Name .Values.nameOverride }} 18 | {{- if contains $name .Release.Name }} 19 | {{- .Release.Name | trunc 63 | trimSuffix "-" }} 20 | {{- else }} 21 | {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} 22 | {{- end }} 23 | {{- end }} 24 | {{- end }} 25 | 26 | {{/* 27 | Create chart name and version as used by the chart label. 28 | */}} 29 | {{- define "service.chart" -}} 30 | {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} 31 | {{- end }} 32 | 33 | {{/* 34 | Common labels 35 | */}} 36 | {{- define "service.labels" -}} 37 | helm.sh/chart: {{ include "service.chart" . }} 38 | {{ include "service.selectorLabels" . }} 39 | {{- if .Chart.AppVersion }} 40 | app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} 41 | {{- end }} 42 | app.kubernetes.io/managed-by: {{ .Release.Service }} 43 | {{- end }} 44 | 45 | {{/* 46 | Selector labels 47 | */}} 48 | {{- define "service.selectorLabels" -}} 49 | app.kubernetes.io/name: {{ include "service.name" . }} 50 | app.kubernetes.io/instance: {{ .Release.Name }} 51 | {{- end }} 52 | 53 | {{/* 54 | Create the name of the service account to use 55 | */}} 56 | {{- define "service.serviceAccountName" -}} 57 | {{- if .Values.serviceAccount.create }} 58 | {{- default (include "service.fullname" .) .Values.serviceAccount.name }} 59 | {{- else }} 60 | {{- default "default" .Values.serviceAccount.name }} 61 | {{- end }} 62 | {{- end }} 63 | -------------------------------------------------------------------------------- /manifests/charts/service/templates/deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: {{ include "service.fullname" . }} 5 | labels: 6 | {{- include "service.labels" . | nindent 4 }} 7 | spec: 8 | {{- if not .Values.autoscaling.enabled }} 9 | replicas: {{ .Values.replicaCount }} 10 | {{- end }} 11 | selector: 12 | matchLabels: 13 | {{- include "service.selectorLabels" . | nindent 6 }} 14 | template: 15 | metadata: 16 | {{- with .Values.podAnnotations }} 17 | annotations: 18 | {{- toYaml . | nindent 8 }} 19 | {{- end }} 20 | labels: 21 | {{- include "service.selectorLabels" . | nindent 8 }} 22 | spec: 23 | {{- with .Values.imagePullSecrets }} 24 | imagePullSecrets: 25 | {{- toYaml . | nindent 8 }} 26 | {{- end }} 27 | serviceAccountName: {{ include "service.serviceAccountName" . }} 28 | securityContext: 29 | {{- toYaml .Values.podSecurityContext | nindent 8 }} 30 | containers: 31 | - name: {{ .Chart.Name }} 32 | securityContext: 33 | {{- toYaml .Values.securityContext | nindent 12 }} 34 | image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" 35 | imagePullPolicy: {{ .Values.image.pullPolicy }} 36 | env: 37 | - name: MICRO_SERVICE_PROFILE 38 | value: starter-kubernetes 39 | - name: MICRO_SERVICE_ADDRESS 40 | value: :8080 41 | ports: 42 | - name: http 43 | containerPort: 8080 44 | protocol: TCP 45 | livenessProbe: 46 | tcpSocket: 47 | port: http 48 | readinessProbe: 49 | tcpSocket: 50 | port: http 51 | resources: 52 | {{- toYaml .Values.resources | nindent 12 }} 53 | {{- with .Values.nodeSelector }} 54 | nodeSelector: 55 | {{- toYaml . | nindent 8 }} 56 | {{- end }} 57 | {{- with .Values.affinity }} 58 | affinity: 59 | {{- toYaml . | nindent 8 }} 60 | {{- end }} 61 | {{- with .Values.tolerations }} 62 | tolerations: 63 | {{- toYaml . | nindent 8 }} 64 | {{- end }} 65 | -------------------------------------------------------------------------------- /manifests/charts/service/templates/hpa.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.autoscaling.enabled }} 2 | apiVersion: autoscaling/v2beta1 3 | kind: HorizontalPodAutoscaler 4 | metadata: 5 | name: {{ include "service.fullname" . }} 6 | labels: 7 | {{- include "service.labels" . | nindent 4 }} 8 | spec: 9 | scaleTargetRef: 10 | apiVersion: apps/v1 11 | kind: Deployment 12 | name: {{ include "service.fullname" . }} 13 | minReplicas: {{ .Values.autoscaling.minReplicas }} 14 | maxReplicas: {{ .Values.autoscaling.maxReplicas }} 15 | metrics: 16 | {{- if .Values.autoscaling.targetCPUUtilizationPercentage }} 17 | - type: Resource 18 | resource: 19 | name: cpu 20 | targetAverageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }} 21 | {{- end }} 22 | {{- if .Values.autoscaling.targetMemoryUtilizationPercentage }} 23 | - type: Resource 24 | resource: 25 | name: memory 26 | targetAverageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }} 27 | {{- end }} 28 | {{- end }} 29 | -------------------------------------------------------------------------------- /manifests/charts/service/templates/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: {{ include "service.fullname" . }} 5 | labels: 6 | {{- include "service.labels" . | nindent 4 }} 7 | spec: 8 | type: {{ .Values.service.type }} 9 | ports: 10 | - port: {{ .Values.service.port }} 11 | targetPort: http 12 | protocol: TCP 13 | name: http 14 | selector: 15 | {{- include "service.selectorLabels" . | nindent 4 }} 16 | -------------------------------------------------------------------------------- /manifests/charts/service/templates/serviceaccount.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.serviceAccount.create -}} 2 | apiVersion: v1 3 | kind: ServiceAccount 4 | metadata: 5 | name: {{ include "service.serviceAccountName" . }} 6 | labels: 7 | {{- include "service.labels" . | nindent 4 }} 8 | {{- with .Values.serviceAccount.annotations }} 9 | annotations: 10 | {{- toYaml . | nindent 4 }} 11 | {{- end }} 12 | {{- end }} 13 | -------------------------------------------------------------------------------- /manifests/charts/service/templates/tests/test-connection.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.tests.enabled -}} 2 | apiVersion: v1 3 | kind: Pod 4 | metadata: 5 | name: "{{ include "service.fullname" . }}-test-connection" 6 | labels: 7 | {{- include "service.labels" . | nindent 4 }} 8 | annotations: 9 | "helm.sh/hook": test 10 | spec: 11 | containers: 12 | - name: wget 13 | image: busybox 14 | command: ['wget'] 15 | args: ['{{ include "service.fullname" . }}:{{ .Values.service.port }}'] 16 | restartPolicy: Never 17 | {{- end }} -------------------------------------------------------------------------------- /manifests/charts/service/values.yaml: -------------------------------------------------------------------------------- 1 | # Default values for service. 2 | # This is a YAML-formatted file. 3 | # Declare variables to be passed into your templates. 4 | 5 | replicaCount: 1 6 | 7 | image: 8 | repository: registry.cn-hangzhou.aliyuncs.com/hb-chen/micro-starter-example 9 | pullPolicy: IfNotPresent 10 | # Overrides the image tag whose default is the chart appVersion. 11 | tag: "latest" 12 | 13 | imagePullSecrets: [] 14 | nameOverride: "" 15 | fullnameOverride: "" 16 | 17 | serviceAccount: 18 | # Specifies whether a service account should be created 19 | create: true 20 | # Annotations to add to the service account 21 | annotations: {} 22 | # The name of the service account to use. 23 | # If not set and create is true, a name is generated using the fullname template 24 | name: "" 25 | 26 | podAnnotations: {} 27 | 28 | podSecurityContext: {} 29 | # fsGroup: 2000 30 | 31 | securityContext: {} 32 | # capabilities: 33 | # drop: 34 | # - ALL 35 | # readOnlyRootFilesystem: true 36 | # runAsNonRoot: true 37 | # runAsUser: 1000 38 | 39 | service: 40 | type: ClusterIP 41 | port: 8080 42 | 43 | resources: {} 44 | # We usually recommend not to specify default resources and to leave this as a conscious 45 | # choice for the user. This also increases chances charts run on environments with little 46 | # resources, such as Minikube. If you do want to specify resources, uncomment the following 47 | # lines, adjust them as necessary, and remove the curly braces after 'resources:'. 48 | # limits: 49 | # cpu: 100m 50 | # memory: 128Mi 51 | # requests: 52 | # cpu: 100m 53 | # memory: 128Mi 54 | 55 | autoscaling: 56 | enabled: false 57 | minReplicas: 1 58 | maxReplicas: 100 59 | targetCPUUtilizationPercentage: 80 60 | # targetMemoryUtilizationPercentage: 80 61 | 62 | nodeSelector: {} 63 | 64 | tolerations: [] 65 | 66 | affinity: {} 67 | 68 | tests: 69 | enabled: false -------------------------------------------------------------------------------- /manifests/kubevela/application.yml: -------------------------------------------------------------------------------- 1 | apiVersion: core.oam.dev/v1beta1 2 | kind: Application 3 | metadata: 4 | name: micro-starter 5 | spec: 6 | components: 7 | - name: micro-server 8 | properties: 9 | chart: ./manifests/charts/micro 10 | git: 11 | branch: main 12 | installTimeout: 10m 13 | pullInterval: 5m 14 | releaseName: micro-server 15 | repoType: git 16 | targetNamespace: micro 17 | url: https://github.com/hb-chen/micro-starter 18 | values: 19 | image: 20 | repository: registry.cn-hangzhou.aliyuncs.com/hb-chen/micro-starter-micro 21 | tag: latest 22 | ingress: 23 | annotations: 24 | kubernetes.io/ingress.class: nginx 25 | enabled: 'true' 26 | service: 27 | port: '8080' 28 | version: '*' 29 | type: helm 30 | policies: 31 | - name: env-bindings-dev 32 | properties: 33 | envs: 34 | - name: micro 35 | patch: {} 36 | placement: 37 | clusterSelector: 38 | name: local 39 | namespaceSelector: 40 | name: micro 41 | type: env-binding 42 | workflow: 43 | steps: 44 | - name: micro 45 | properties: 46 | env: micro 47 | policy: env-bindings-dev 48 | type: deploy2env -------------------------------------------------------------------------------- /manifests/tekton/README.md: -------------------------------------------------------------------------------- 1 | # Tekton CICD 2 | 3 | > `TODO` CD 使用 KubeVela Task 4 | 5 | - Tekton 环境搭建参考 [hb-chen/tekton-practice](https://github.com/hb-chen/tekton-practice) 6 | - 需要完成 `Install` `Task` 和 `Config` 三个步骤 7 | - microt-starter 提供了两种方式构建镜像 `buildpacks` 和 `kaniko` 8 | - `TriggerTemplate` 默认使用的 `buildpacks` 9 | - Trigger 的 `EventListener` 配置在 [hb-chen/tekton-practice/example/trigger.yml](https://github.com/hb-chen/tekton-practice/blob/main/example/trigger.yml) -------------------------------------------------------------------------------- /manifests/tekton/buildpacks/pipeline.yml: -------------------------------------------------------------------------------- 1 | apiVersion: tekton.dev/v1beta1 2 | kind: Pipeline 3 | metadata: 4 | name: micro-starter-buildpacks-pipeline 5 | spec: 6 | params: 7 | - name: url 8 | type: string 9 | - default: master 10 | name: revision 11 | type: string 12 | - description: image URL to push 13 | name: image 14 | type: string 15 | tasks: 16 | - name: fetch-repository 17 | params: 18 | - name: url 19 | value: $(params.url) 20 | - name: revision 21 | value: $(params.revision) 22 | - name: subdirectory 23 | value: micro-starter 24 | - name: deleteExisting 25 | value: 'true' 26 | taskRef: 27 | kind: Task 28 | name: git-clone 29 | workspaces: 30 | - name: output 31 | workspace: shared-workspace 32 | - name: buildpacks 33 | params: 34 | - name: APP_IMAGE 35 | value: $(params.image) 36 | - name: SOURCE_SUBPATH 37 | value: micro-starter 38 | - name: BUILDER_IMAGE 39 | value: 'paketobuildpacks/builder:tiny' 40 | - name: ENV_VARS 41 | value: 42 | - GOPROXY=https://mirrors.aliyun.com/goproxy/,direct 43 | runAfter: 44 | - fetch-repository 45 | taskRef: 46 | kind: Task 47 | name: buildpacks 48 | workspaces: 49 | - name: source 50 | workspace: shared-workspace 51 | - name: cache 52 | workspace: shared-workspace 53 | - name: dockerconfig 54 | workspace: dockerconfig 55 | workspaces: 56 | - name: shared-workspace 57 | - name: dockerconfig 58 | - name: kubeconfig -------------------------------------------------------------------------------- /manifests/tekton/buildpacks/run.yml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: tekton.dev/v1beta1 3 | kind: PipelineRun 4 | metadata: 5 | # name: micro-starter-buildpacks-pipeline-run 6 | generateName: micro-starter-buildpacks-pipeline-run- 7 | spec: 8 | serviceAccountName: build-bot 9 | pipelineRef: 10 | name: micro-starter-buildpacks-pipeline 11 | params: 12 | - name: url 13 | value: https://github.com/hb-chen/micro-starter 14 | - name: revision 15 | value: main 16 | - name: image 17 | value: registry.cn-hangzhou.aliyuncs.com/hb-chen/micro-starter-micro 18 | workspaces: 19 | - name: shared-workspace 20 | persistentvolumeclaim: 21 | claimName: golang-source-pvc 22 | - name: dockerconfig 23 | secret: 24 | secretName: dockerconfig 25 | - name: kubeconfig 26 | secret: 27 | secretName: k8s-kubeconfig 28 | -------------------------------------------------------------------------------- /manifests/tekton/kaniko/pipeline.yml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: tekton.dev/v1beta1 3 | kind: Pipeline 4 | metadata: 5 | name: micro-starter-pipeline 6 | spec: 7 | workspaces: 8 | - name: shared-workspace 9 | - name: dockerconfig 10 | - name: kubeconfig 11 | params: 12 | - name: url 13 | - name: revision 14 | default: master 15 | tasks: 16 | - name: fetch-repository 17 | taskRef: 18 | name: git-clone 19 | workspaces: 20 | - name: output 21 | workspace: shared-workspace 22 | params: 23 | - name: url 24 | value: $(params.url) 25 | - name: revision 26 | value: $(params.revision) 27 | - name: subdirectory 28 | value: "micro-starter" 29 | - name: deleteExisting 30 | value: "true" 31 | # - name: run-test 32 | # taskRef: 33 | # name: golang-test 34 | # runAfter: 35 | # - fetch-repository 36 | # workspaces: 37 | # - name: source 38 | # workspace: shared-workspace 39 | # params: 40 | # - name: package 41 | # value: github.com/hb-chen/micro-starter 42 | # - name: subdirectory 43 | # value: "micro-starter" 44 | # - name: version 45 | # value: 1.14.15 46 | - name: run-build 47 | taskRef: 48 | name: golang-build 49 | runAfter: 50 | - fetch-repository 51 | workspaces: 52 | - name: source 53 | workspace: shared-workspace 54 | params: 55 | - name: package 56 | value: github.com/hb-chen/micro-starter 57 | - name: packages 58 | value: "./cmd/micro/main.go" 59 | - name: subdirectory 60 | value: "micro-starter" 61 | - name: version 62 | value: 1.15.11 63 | - name: flags 64 | value: -v -o $(workspaces.source.path)/micro-starter/dist/micro_linux_amd64/bin/micro 65 | - name: docker-build 66 | taskRef: 67 | name: kaniko 68 | runAfter: 69 | - run-build 70 | workspaces: 71 | - name: source 72 | workspace: shared-workspace 73 | - name: dockerconfig 74 | workspace: dockerconfig 75 | params: 76 | - name: IMAGE 77 | value: registry.cn-hangzhou.aliyuncs.com/hb-chen/micro-starter-micro:latest 78 | - name: DOCKERFILE 79 | value: ./micro-starter/Dockerfile 80 | - name: CONTEXT 81 | value: ./micro-starter/ 82 | - name: EXTRA_ARGS 83 | value: 84 | - "--skip-tls-verify" 85 | - "--insecure-registry=registry.cn-hangzhou.aliyuncs.com" 86 | # - name: helm-kubectl-deploy 87 | # taskRef: 88 | # name: helm-kubectl-deploy 89 | # runAfter: 90 | # - docker-build 91 | # workspaces: 92 | # - name: source 93 | # workspace: shared-workspace 94 | # - name: kubeconfig 95 | # workspace: kubeconfig 96 | # params: 97 | # - name: commands 98 | # value: | 99 | # helm template \ 100 | # --release-name micro-starter \ 101 | # --no-hooks \ 102 | # --set image.repository=registry.cn-hangzhou.aliyuncs.com/hb-chen/micro-starter-micro \ 103 | # --set image.tag=latest \ 104 | # --set image.digest=@$(tasks.docker-build.results.IMAGE-DIGEST) \ 105 | # ./micro-starter/manifests/helm | kubectl apply -n micro-starter -f - 106 | - name: run-build-service 107 | taskRef: 108 | name: golang-build 109 | runAfter: 110 | - fetch-repository 111 | workspaces: 112 | - name: source 113 | workspace: shared-workspace 114 | params: 115 | - name: package 116 | value: github.com/hb-chen/micro-starter 117 | - name: packages 118 | value: "./service/account/main.go" 119 | - name: subdirectory 120 | value: "micro-starter" 121 | - name: version 122 | value: 1.15.11 123 | - name: flags 124 | value: -v -o $(workspaces.source.path)/micro-starter/dist/micro_linux_amd64/bin/example 125 | - name: docker-build-service 126 | taskRef: 127 | name: kaniko 128 | runAfter: 129 | - run-build 130 | workspaces: 131 | - name: source 132 | workspace: shared-workspace 133 | - name: dockerconfig 134 | workspace: dockerconfig 135 | params: 136 | - name: IMAGE 137 | value: registry.cn-hangzhou.aliyuncs.com/hb-chen/micro-starter-example:latest 138 | - name: DOCKERFILE 139 | value: ./micro-starter/service/account/Dockerfile 140 | - name: CONTEXT 141 | value: ./micro-starter/ 142 | - name: EXTRA_ARGS 143 | value: 144 | - "--skip-tls-verify" 145 | - "--insecure-registry=registry.cn-hangzhou.aliyuncs.com" -------------------------------------------------------------------------------- /manifests/tekton/kaniko/run.yml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: tekton.dev/v1beta1 3 | kind: PipelineRun 4 | metadata: 5 | # name: micro-starter-pipeline-run 6 | generateName: micro-starter-pipeline-run- 7 | spec: 8 | serviceAccountName: build-bot 9 | pipelineRef: 10 | name: micro-starter-pipeline 11 | params: 12 | - name: url 13 | value: https://github.com/hb-chen/micro-starter 14 | - name: revision 15 | value: main 16 | workspaces: 17 | - name: shared-workspace 18 | persistentvolumeclaim: 19 | claimName: golang-source-pvc 20 | - name: dockerconfig 21 | secret: 22 | secretName: dockerconfig 23 | - name: kubeconfig 24 | secret: 25 | secretName: k8s-kubeconfig 26 | -------------------------------------------------------------------------------- /manifests/tekton/trigger-template.yml: -------------------------------------------------------------------------------- 1 | apiVersion: triggers.tekton.dev/v1alpha1 2 | kind: TriggerTemplate 3 | metadata: 4 | name: micro-starter-pipeline-template 5 | spec: 6 | params: 7 | - name: gitrevision 8 | description: The git revision 9 | default: master 10 | - name: gitrepositoryurl 11 | description: The git repository url 12 | resourcetemplates: 13 | - apiVersion: tekton.dev/v1beta1 14 | kind: PipelineRun 15 | metadata: 16 | generateName: micro-starter-pipeline-run- 17 | spec: 18 | serviceAccountName: build-bot 19 | pipelineRef: 20 | name: micro-starter-buildpacks-pipeline 21 | workspaces: 22 | - name: shared-workspace 23 | persistentvolumeclaim: 24 | claimName: golang-source-pvc 25 | - name: dockerconfig 26 | secret: 27 | secretName: dockerconfig 28 | - name: kubeconfig 29 | secret: 30 | secretName: k8s-kubeconfig 31 | params: 32 | - name: url 33 | value: $(tt.params.gitrepositoryurl) 34 | - name: revision 35 | value: $(tt.params.gitrevision) 36 | -------------------------------------------------------------------------------- /pkg/file/file_slice.go: -------------------------------------------------------------------------------- 1 | package file 2 | 3 | import ( 4 | "os" 5 | ) 6 | 7 | type FileInfo struct { 8 | os.FileInfo 9 | Path string 10 | } 11 | 12 | type FileSlice []FileInfo 13 | 14 | // ModTime升序 15 | // sort.Interface 16 | // Len is the number of elements in the collection. 17 | func (files FileSlice) Len() int { 18 | return len(files) 19 | } 20 | 21 | // Less reports whether the element with 22 | // index i should sort before the element with index j. 23 | func (files FileSlice) Less(i, j int) bool { 24 | a := files[i] 25 | b := files[j] 26 | if a.ModTime().UnixNano() < b.ModTime().UnixNano() { 27 | return true 28 | } 29 | return false 30 | } 31 | 32 | // Swap swaps the elements with indexes i and j. 33 | func (files FileSlice) Swap(i, j int) { 34 | files[i], files[j] = files[j], files[i] 35 | } 36 | -------------------------------------------------------------------------------- /pkg/file/walk_dir.go: -------------------------------------------------------------------------------- 1 | package file 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "os" 7 | "path" 8 | "path/filepath" 9 | "sync" 10 | ) 11 | 12 | // sema is a counting semaphore for limiting concurrency in dirents 13 | var sema = make(chan struct{}, 20) 14 | 15 | // 读取目录dir下的文件信息 16 | func dirents(dir string) []os.FileInfo { 17 | sema <- struct{}{} 18 | defer func() { <-sema }() 19 | entries, err := ioutil.ReadDir(dir) 20 | if err != nil { 21 | fmt.Fprintf(os.Stderr, "du: %v\n", err) 22 | return nil 23 | } 24 | return entries 25 | } 26 | 27 | // 获取目录dir下的文件 28 | func walkDir(dir, suffix string, wg *sync.WaitGroup, fileInfos chan<- FileInfo) { 29 | defer wg.Done() 30 | for _, entry := range dirents(dir) { 31 | subDir := filepath.Join(dir, entry.Name()) 32 | if entry.IsDir() { // 目录 33 | wg.Add(1) 34 | go walkDir(subDir, suffix, wg, fileInfos) 35 | } else { 36 | if suffix == "" || suffix == path.Ext(entry.Name()) { 37 | fi := FileInfo{ 38 | FileInfo: entry, 39 | Path: subDir, 40 | } 41 | fileInfos <- fi 42 | } 43 | } 44 | } 45 | } 46 | 47 | func WalkDirs(roots []string, suffix string, files *FileSlice, nbytes *int64) { 48 | fileInfos := make(chan FileInfo) 49 | var wg sync.WaitGroup 50 | for _, root := range roots { 51 | wg.Add(1) 52 | go walkDir(root, suffix, &wg, fileInfos) 53 | } 54 | go func() { 55 | wg.Wait() // 等待goroutine结束 56 | close(fileInfos) 57 | }() 58 | 59 | loop: 60 | for { 61 | select { 62 | case fi, ok := <-fileInfos: 63 | if !ok { 64 | break loop 65 | } 66 | 67 | *files = append(*files, fi) 68 | *nbytes += fi.Size() 69 | } 70 | } 71 | 72 | return 73 | } 74 | -------------------------------------------------------------------------------- /pkg/service/service.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "github.com/urfave/cli/v2" 5 | "micro.dev/v4/cmd" 6 | "micro.dev/v4/service" 7 | "micro.dev/v4/service/profile" 8 | ) 9 | 10 | // New returns a new Micro Service 11 | func New(opts ...service.Option) *service.Service { 12 | // setup micro, this triggers the Before 13 | // function which parses CLI flags. 14 | c := cmd.New( 15 | cmd.Service(), 16 | cmd.Flags( 17 | &cli.StringFlag{ 18 | Name: "address", 19 | Usage: "Set the micro service address", 20 | EnvVars: []string{"MICRO_SERVICE_ADDRESS"}, 21 | Value: ":0", 22 | }, 23 | ), 24 | cmd.Before(func(ctx *cli.Context) error { 25 | addr := ctx.String("address") 26 | opts = append(opts, service.Address(addr)) 27 | return nil 28 | }), 29 | ) 30 | 31 | err := c.Run() 32 | if err != nil { 33 | return nil 34 | } 35 | 36 | // setup auth 37 | profile.SetupAccount(nil) 38 | 39 | // return a new service 40 | svc := &service.Service{} 41 | svc.Init(opts...) 42 | return svc 43 | } 44 | -------------------------------------------------------------------------------- /pkg/tools/proto/batch.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "flag" 6 | "fmt" 7 | "os" 8 | "os/exec" 9 | "strings" 10 | 11 | "github.com/hb-chen/micro-starter/pkg/file" 12 | ) 13 | 14 | var ( 15 | cmdHelp = flag.Bool("h", false, "帮助") 16 | root = flag.String("r", "", "需要查找.proto文件的路径,多路径使用\":\"分隔") 17 | ) 18 | 19 | func init() { 20 | flag.Parse() 21 | } 22 | 23 | func main() { 24 | if *cmdHelp { 25 | flag.PrintDefaults() 26 | return 27 | } 28 | 29 | roots := strings.Split(*root, ":") 30 | if *root == "" || len(roots) <= 0 { 31 | fmt.Println("-r 请输入正确的路径") 32 | return 33 | } 34 | 35 | files := file.FileSlice{} 36 | nbytes := int64(0) 37 | file.WalkDirs(roots, ".proto", &files, &nbytes) 38 | 39 | fmt.Printf("proto files count:%d, size:%.3f kb\n", files.Len(), float64(nbytes)/1e3) 40 | 41 | arg := []string{} 42 | 43 | arg = append(arg, "-I="+os.Getenv("GOPATH")+"/src:.") 44 | arg = append(arg, "--micro_out=.", "--go_out=.") 45 | 46 | var out bytes.Buffer 47 | var stderr bytes.Buffer 48 | for _, v := range files { 49 | fmt.Println("proto file path:" + v.Path) 50 | 51 | cmd := exec.Command("protoc", append(arg, v.Path)...) 52 | cmd.Stdout = &out 53 | cmd.Stderr = &stderr 54 | 55 | err := cmd.Run() 56 | if err != nil { 57 | fmt.Printf("exec cmd error:" + fmt.Sprint(err) + "\n" + stderr.String()) 58 | continue 59 | } 60 | 61 | fmt.Println("exec cmd success\n" + out.String()) 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /profile/profile.go: -------------------------------------------------------------------------------- 1 | // Package profile is for specific profiles 2 | // @todo this package is the definition of cruft and 3 | // should be rewritten in a more elegant way 4 | package profile 5 | 6 | import ( 7 | "path/filepath" 8 | 9 | "github.com/hb-chen/micro-starter/service/auth/noop" 10 | "github.com/urfave/cli/v2" 11 | microAuth "micro.dev/v4/service/auth" 12 | "micro.dev/v4/service/broker" 13 | memBroker "micro.dev/v4/service/broker/memory" 14 | "micro.dev/v4/service/config" 15 | storeConfig "micro.dev/v4/service/config/store" 16 | microEvents "micro.dev/v4/service/events" 17 | evStore "micro.dev/v4/service/events/store" 18 | memStream "micro.dev/v4/service/events/stream/memory" 19 | "micro.dev/v4/service/logger" 20 | "micro.dev/v4/service/model" 21 | "micro.dev/v4/service/model/sql" 22 | "micro.dev/v4/service/profile" 23 | "micro.dev/v4/service/registry" 24 | memRegistry "micro.dev/v4/service/registry/memory" 25 | microRuntime "micro.dev/v4/service/runtime" 26 | "micro.dev/v4/service/runtime/local" 27 | microStore "micro.dev/v4/service/store" 28 | "micro.dev/v4/service/store/file" 29 | mem "micro.dev/v4/service/store/memory" 30 | "micro.dev/v4/util/user" 31 | ) 32 | 33 | func init() { 34 | if err := profile.Register("starter-local", Local); err != nil { 35 | logger.Fatalf("Error profile register: %v", err) 36 | } 37 | 38 | if err := profile.Register("starter-kubernetes", Kubernetes); err != nil { 39 | logger.Fatalf("Error profile register: %v", err) 40 | } 41 | 42 | if err := profile.Register("starter-test", Kubernetes); err != nil { 43 | logger.Fatalf("Error profile register: %v", err) 44 | } 45 | } 46 | 47 | // Local profile to run locally 48 | var Local = &profile.Profile{ 49 | Name: "starter-local", 50 | Setup: func(ctx *cli.Context) error { 51 | // catch all 52 | profile.SetupDefaults() 53 | 54 | microAuth.DefaultAuth = noop.NewAuth() 55 | microStore.DefaultStore = file.NewStore(file.WithDir(filepath.Join(user.Dir, "server", "store"))) 56 | profile.SetupConfigSecretKey() 57 | config.DefaultConfig, _ = storeConfig.NewConfig(microStore.DefaultStore, "") 58 | profile.SetupJWT() 59 | 60 | // the registry service uses the memory registry, the other core services will use the default 61 | // rpc client and call the registry service 62 | if ctx.Args().Get(1) == "registry" { 63 | profile.SetupRegistry(memRegistry.NewRegistry()) 64 | } else { 65 | // set the registry address 66 | registry.DefaultRegistry.Init( 67 | registry.Addrs("localhost:8000"), 68 | ) 69 | 70 | profile.SetupRegistry(registry.DefaultRegistry) 71 | } 72 | 73 | // the broker service uses the memory broker, the other core services will use the default 74 | // rpc client and call the broker service 75 | if ctx.Args().Get(1) == "broker" { 76 | profile.SetupBroker(memBroker.NewBroker()) 77 | } else { 78 | broker.DefaultBroker.Init( 79 | broker.Addrs("localhost:8003"), 80 | ) 81 | profile.SetupBroker(broker.DefaultBroker) 82 | } 83 | 84 | // set the store in the model 85 | // TODO sql model 86 | model.DefaultModel = sql.NewModel() 87 | 88 | // use the local runtime, note: the local runtime is designed to run source code directly so 89 | // the runtime builder should NOT be set when using this implementation 90 | microRuntime.DefaultRuntime = local.NewRuntime() 91 | 92 | var err error 93 | microEvents.DefaultStream, err = memStream.NewStream() 94 | if err != nil { 95 | logger.Fatalf("Error configuring stream: %v", err) 96 | } 97 | microEvents.DefaultStore = evStore.NewStore( 98 | evStore.WithStore(microStore.DefaultStore), 99 | ) 100 | 101 | microStore.DefaultBlobStore, err = file.NewBlobStore() 102 | if err != nil { 103 | logger.Fatalf("Error configuring file blob store: %v", err) 104 | } 105 | 106 | // Configure tracing with Jaeger (forced tracing): 107 | tracingServiceName := ctx.Args().Get(1) 108 | if len(tracingServiceName) == 0 { 109 | tracingServiceName = "Micro" 110 | } 111 | // openTracer, _, err := jaeger.New( 112 | // opentelemetry.WithServiceName(tracingServiceName), 113 | // opentelemetry.WithSamplingRate(1), 114 | // ) 115 | // if err != nil { 116 | // logger.Fatalf("Error configuring opentracing: %v", err) 117 | // } 118 | // opentelemetry.DefaultOpenTracer = openTracer 119 | 120 | return nil 121 | }, 122 | } 123 | 124 | // Kubernetes profile to run on kubernetes with zero deps. Designed for use with the micro helm chart 125 | var Kubernetes = &profile.Profile{ 126 | Name: "starter-kubernetes", 127 | Setup: func(ctx *cli.Context) (err error) { 128 | // catch all 129 | profile.SetupDefaults() 130 | 131 | microAuth.DefaultAuth = noop.NewAuth() 132 | 133 | microRuntime.DefaultRuntime = local.NewRuntime() 134 | 135 | microEvents.DefaultStream, err = memStream.NewStream() 136 | if err != nil { 137 | logger.Fatalf("Error configuring stream: %v", err) 138 | } 139 | 140 | microStore.DefaultStore = file.NewStore(file.WithDir("/store")) 141 | microStore.DefaultBlobStore, err = file.NewBlobStore(file.WithDir("/store/blob")) 142 | if err != nil { 143 | logger.Fatalf("Error configuring file blob store: %v", err) 144 | } 145 | 146 | // set the store in the model 147 | // TODO sql model 148 | model.DefaultModel = sql.NewModel() 149 | 150 | // the registry service uses the memory registry, the other core services will use the default 151 | // rpc client and call the registry service 152 | if ctx.Args().Get(1) == "registry" { 153 | profile.SetupRegistry(memRegistry.NewRegistry()) 154 | } else { 155 | // set the registry address 156 | registry.DefaultRegistry.Init( 157 | registry.Addrs("micro-server.micro.svc.cluster.local:8000"), 158 | ) 159 | 160 | profile.SetupRegistry(registry.DefaultRegistry) 161 | } 162 | 163 | // the broker service uses the memory broker, the other core services will use the default 164 | // rpc client and call the broker service 165 | if ctx.Args().Get(1) == "broker" { 166 | profile.SetupBroker(memBroker.NewBroker()) 167 | } else { 168 | broker.DefaultBroker.Init( 169 | broker.Addrs("micro-server.micro.svc.cluster.local:8003"), 170 | ) 171 | profile.SetupBroker(broker.DefaultBroker) 172 | } 173 | 174 | config.DefaultConfig, err = storeConfig.NewConfig(microStore.DefaultStore, "") 175 | if err != nil { 176 | logger.Fatalf("Error configuring config: %v", err) 177 | } 178 | profile.SetupConfigSecretKey() 179 | 180 | // Configure tracing with Jaeger: 181 | tracingServiceName := ctx.Args().Get(1) 182 | if len(tracingServiceName) == 0 { 183 | tracingServiceName = "Micro" 184 | } 185 | // openTracer, _, err := jaeger.New( 186 | // opentelemetry.WithServiceName(tracingServiceName), 187 | // opentelemetry.WithTraceReporterAddress("localhost:6831"), 188 | // ) 189 | // if err != nil { 190 | // logger.Fatalf("Error configuring opentracing: %v", err) 191 | // } 192 | // opentelemetry.DefaultOpenTracer = openTracer 193 | 194 | return nil 195 | }, 196 | } 197 | 198 | // Test profile is used for the go test suite 199 | var Test = &profile.Profile{ 200 | Name: "starter-test", 201 | Setup: func(ctx *cli.Context) error { 202 | // catch all 203 | profile.SetupDefaults() 204 | 205 | microAuth.DefaultAuth = noop.NewAuth() 206 | microStore.DefaultStore = mem.NewStore() 207 | microStore.DefaultBlobStore, _ = file.NewBlobStore() 208 | config.DefaultConfig, _ = storeConfig.NewConfig(microStore.DefaultStore, "") 209 | profile.SetupRegistry(memRegistry.NewRegistry()) 210 | // set the store in the model 211 | // TODO sql model 212 | model.DefaultModel = sql.NewModel() 213 | return nil 214 | }, 215 | } 216 | -------------------------------------------------------------------------------- /service/auth/noop/noop.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Asim Aslam 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // 15 | // Original source: github.com/micro/go-micro/v3/auth/noop/noop.go 16 | 17 | package noop 18 | 19 | import ( 20 | "github.com/google/uuid" 21 | "micro.dev/v4/service/auth" 22 | ) 23 | 24 | func NewAuth(opts ...auth.Option) auth.Auth { 25 | var options auth.Options 26 | for _, o := range opts { 27 | o(&options) 28 | } 29 | 30 | return &noop{ 31 | opts: options, 32 | } 33 | } 34 | 35 | type noop struct { 36 | opts auth.Options 37 | } 38 | 39 | // String returns the name of the implementation 40 | func (n *noop) String() string { 41 | return "noop" 42 | } 43 | 44 | // Init the auth 45 | func (n *noop) Init(opts ...auth.Option) { 46 | for _, o := range opts { 47 | o(&n.opts) 48 | } 49 | } 50 | 51 | // Options set for auth 52 | func (n *noop) Options() auth.Options { 53 | return n.opts 54 | } 55 | 56 | // Generate a new account 57 | func (n *noop) Generate(id string, opts ...auth.GenerateOption) (*auth.Account, error) { 58 | options := auth.NewGenerateOptions(opts...) 59 | name := options.Name 60 | if name == "" { 61 | name = id 62 | } 63 | return &auth.Account{ 64 | ID: id, 65 | Secret: options.Secret, 66 | Metadata: options.Metadata, 67 | Scopes: options.Scopes, 68 | Issuer: n.Options().Issuer, 69 | Name: name, 70 | }, nil 71 | } 72 | 73 | // Grant access to a resource 74 | func (n *noop) Grant(rule *auth.Rule) error { 75 | return nil 76 | } 77 | 78 | // Revoke access to a resource 79 | func (n *noop) Revoke(rule *auth.Rule) error { 80 | return nil 81 | } 82 | 83 | // Rules used to verify requests 84 | func (n *noop) Rules(opts ...auth.RulesOption) ([]*auth.Rule, error) { 85 | return []*auth.Rule{}, nil 86 | } 87 | 88 | // Verify an account has access to a resource 89 | func (n *noop) Verify(acc *auth.Account, res *auth.Resource, opts ...auth.VerifyOption) error { 90 | return nil 91 | } 92 | 93 | // Inspect a token 94 | func (n *noop) Inspect(token string) (*auth.Account, error) { 95 | return &auth.Account{ 96 | ID: uuid.New().String(), 97 | Type: "service", 98 | Issuer: n.Options().Issuer, 99 | Scopes: []string{"service"}, 100 | }, nil 101 | } 102 | 103 | // Token generation using an account id and secret 104 | func (n *noop) Token(opts ...auth.TokenOption) (*auth.AccountToken, error) { 105 | return &auth.AccountToken{}, nil 106 | } 107 | -------------------------------------------------------------------------------- /service/greeting/.goreleaser.yml: -------------------------------------------------------------------------------- 1 | # This is an example goreleaser.yaml file with some sane defaults. 2 | # Make sure to check the documentation at http://goreleaser.com 3 | project_name: "greeting" 4 | before: 5 | hooks: 6 | # You may remove this if you don't use go modules. 7 | - go mod download 8 | 9 | builds: 10 | - # ID of the build. 11 | # Defaults to the project name. 12 | id: "service" 13 | 14 | # Path to project's (sub)directory containing Go code. 15 | # This is the working directory for the Go build command(s). 16 | # Default is `.`. 17 | dir: . 18 | 19 | # Path to main.go file or main package. 20 | # Default is `.`. 21 | main: . 22 | 23 | # Binary name. 24 | # Can be a path (e.g. `bin/app`) to wrap the binary in a directory. 25 | # Default is the name of the project directory. 26 | binary: bin/main 27 | 28 | # Custom flags templates. 29 | # Default is empty. 30 | flags: 31 | 32 | # Custom ldflags templates. 33 | # Default is `-s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}} -X main.builtBy=goreleaser`. 34 | ldflags: 35 | - -s -w -X main.version={{ .Version }} -X main.commit={{ .ShortCommit }} -X main.date={{ .Date }} -X main.builtBy=hbchen.com 36 | 37 | # Custom environment variables to be set during the builds. 38 | # Default is empty. 39 | env: 40 | 41 | # GOOS list to build for. 42 | # For more info refer to: https://golang.org/doc/install/source#environment 43 | # Defaults are darwin and linux. 44 | goos: 45 | - linux 46 | - darwin 47 | #- windows 48 | 49 | # GOARCH to build for. 50 | # For more info refer to: https://golang.org/doc/install/source#environment 51 | # Defaults are 386 and amd64. 52 | goarch: 53 | - amd64 54 | #- 386 55 | - arm64 56 | 57 | archives: 58 | - # ID of this archive. 59 | # Defaults to `default`. 60 | id: service 61 | 62 | # Archive name template. 63 | # Defaults: 64 | # - if format is `tar.gz`, `tar.xz`, `gz` or `zip`: 65 | # - `{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}{{ if .Mips }}_{{ .Mips }}{{ end }}` 66 | # - if format is `binary`: 67 | # - `{{ .Binary }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}{{ if .Mips }}_{{ .Mips }}{{ end }}` 68 | name_template: "{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}{{ if .Mips }}_{{ .Mips }}{{ end }}" 69 | format: tar.gz 70 | files: 71 | - README.md 72 | - LICENSE 73 | 74 | # Set to true, if you want all files in the archive to be in a single directory. 75 | # If set to true and you extract the archive 'goreleaser_Linux_arm64.tar.gz', 76 | # you get a folder 'goreleaser_Linux_arm64'. 77 | # If set to false, all files are extracted separately. 78 | # You can also set it to a custom folder name (templating is supported). 79 | # Default is false. 80 | wrap_in_directory: true 81 | 82 | # Disables the binary count check. 83 | # Default: false 84 | allow_different_binary_count: true 85 | snapshot: 86 | # Allows you to change the name of the generated snapshot 87 | # 88 | # Note that some pipes require this to be semantic version compliant (nfpm, 89 | # for example). 90 | # 91 | # Default is `{{ .Tag }}-SNAPSHOT-{{.ShortCommit}}`. 92 | name_template: '{{ .Version }}-SNAPSHOT-{{ .ShortCommit }}' 93 | checksum: 94 | name_template: 'checksums.txt' 95 | changelog: 96 | sort: asc 97 | filters: 98 | exclude: 99 | - '^docs:' 100 | - '^test:' 101 | -------------------------------------------------------------------------------- /service/greeting/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:3.10 2 | 3 | ADD dist/service_linux_amd64_v1/bin/main /opt/service/main 4 | 5 | WORKDIR /opt/service 6 | 7 | CMD [ "./main" ] 8 | -------------------------------------------------------------------------------- /service/greeting/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Hobo Go 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /service/greeting/Makefile: -------------------------------------------------------------------------------- 1 | 2 | GOPATH:=$(shell go env GOPATH) 3 | 4 | ifeq ($(OS),Windows_NT) 5 | uname_S := Windows 6 | else 7 | uname_S := $(shell uname -s) 8 | endif 9 | 10 | # Goreleaser config 11 | ifeq ($(uname_S), Darwin) 12 | goreleaser_config = .goreleaser.yml 13 | else 14 | goreleaser_config = .goreleaser.yml 15 | endif 16 | 17 | .PHONY: init 18 | init: 19 | go get -u github.com/golang/protobuf/proto 20 | go get -u github.com/golang/protobuf/protoc-gen-go 21 | go get github.com/micro/micro/v3/cmd/protoc-gen-micro 22 | go get github.com/micro/micro/v3/cmd/protoc-gen-openapi 23 | 24 | .PHONY: api 25 | api: 26 | protoc --proto_path=${GOPATH}/src/ --openapi_out=. github.com/hb-chen/micro-starter/service/greeting/proto/greeting/greeting.proto 27 | 28 | .PHONY: proto 29 | proto: 30 | protoc --proto_path=${GOPATH}/src/ --micro_out=. --go_out=. github.com/hb-chen/micro-starter/service/greeting/proto/greeting/greeting.proto 31 | 32 | .PHONY: build 33 | build: proto 34 | go build -o bin/console main.go plugin.go 35 | 36 | .PHONY: test 37 | test: 38 | go test -v ./... -cover 39 | 40 | .PHONY: docker 41 | docker: 42 | docker build . -t example-srv:latest 43 | 44 | .PHONY: release 45 | release: 46 | goreleaser release --config $(goreleaser_config) --skip-validate --skip-publish --rm-dist 47 | 48 | .PHONY: snapshot 49 | snapshot: 50 | goreleaser release --config $(goreleaser_config) --skip-publish --snapshot --rm-dist -------------------------------------------------------------------------------- /service/greeting/README.md: -------------------------------------------------------------------------------- 1 | # Greeting Service 2 | 3 | This is the Greeting service 4 | 5 | ## Usage 6 | 7 | Generate the proto code 8 | 9 | ``` 10 | make proto 11 | ``` 12 | 13 | Run the service 14 | 15 | ``` 16 | go run main.go --profile starter-local 17 | ``` 18 | 19 | Call service 20 | 21 | ```shell script 22 | curl "http://localhost:8080/greeting/call?msg=helloworld" 23 | {"id":"1","msg":"helloworld"} 24 | ``` 25 | 26 | ## Image 27 | 28 | ```shell 29 | $ make snapshot 30 | 31 | $ docker build ./ -f Dockerfile --platform=linux/amd64 -t registry.cn-hangzhou.aliyuncs.com/hb-chen/micro-starter-example:latest 32 | ``` 33 | 34 | -------------------------------------------------------------------------------- /service/greeting/conf/auth_key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEowIBAAKCAQEA4f5wg5l2hKsTeNem/V41fGnJm6gOdrj8ym3rFkEU/wT8RDtn 3 | SgFEZOQpHEgQ7JL38xUfU0Y3g6aYw9QT0hJ7mCpz9Er5qLaMXJwZxzHzAahlfA0i 4 | cqabvJOMvQtzD6uQv6wPEyZtDTWiQi9AXwBpHssPnpYGIn20ZZuNlX2BrClciHhC 5 | PUIIZOQn/MmqTD31jSyjoQoV7MhhMTATKJx2XrHhR+1DcKJzQBSTAGnpYVaqpsAR 6 | ap+nwRipr3nUTuxyGohBTSmjJ2usSeQXHI3bODIRe1AuTyHceAbewn8b462yEWKA 7 | Rdpd9AjQW5SIVPfdsz5B6GlYQ5LdYKtznTuy7wIDAQABAoIBAQCwia1k7+2oZ2d3 8 | n6agCAbqIE1QXfCmh41ZqJHbOY3oRQG3X1wpcGH4Gk+O+zDVTV2JszdcOt7E5dAy 9 | MaomETAhRxB7hlIOnEN7WKm+dGNrKRvV0wDU5ReFMRHg31/Lnu8c+5BvGjZX+ky9 10 | POIhFFYJqwCRlopGSUIxmVj5rSgtzk3iWOQXr+ah1bjEXvlxDOWkHN6YfpV5ThdE 11 | KdBIPGEVqa63r9n2h+qazKrtiRqJqGnOrHzOECYbRFYhexsNFz7YT02xdfSHn7gM 12 | IvabDDP/Qp0PjE1jdouiMaFHYnLBbgvlnZW9yuVf/rpXTUq/njxIXMmvmEyyvSDn 13 | FcFikB8pAoGBAPF77hK4m3/rdGT7X8a/gwvZ2R121aBcdPwEaUhvj/36dx596zvY 14 | mEOjrWfZhF083/nYWE2kVquj2wjs+otCLfifEEgXcVPTnEOPO9Zg3uNSL0nNQghj 15 | FuD3iGLTUBCtM66oTe0jLSslHe8gLGEQqyMzHOzYxNqibxcOZIe8Qt0NAoGBAO+U 16 | I5+XWjWEgDmvyC3TrOSf/KCGjtu0TSv30ipv27bDLMrpvPmD/5lpptTFwcxvVhCs 17 | 2b+chCjlghFSWFbBULBrfci2FtliClOVMYrlNBdUSJhf3aYSG2Doe6Bgt1n2CpNn 18 | /iu37Y3NfemZBJA7hNl4dYe+f+uzM87cdQ214+jrAoGAXA0XxX8ll2+ToOLJsaNT 19 | OvNB9h9Uc5qK5X5w+7G7O998BN2PC/MWp8H+2fVqpXgNENpNXttkRm1hk1dych86 20 | EunfdPuqsX+as44oCyJGFHVBnWpm33eWQw9YqANRI+pCJzP08I5WK3osnPiwshd+ 21 | hR54yjgfYhBFNI7B95PmEQkCgYBzFSz7h1+s34Ycr8SvxsOBWxymG5zaCsUbPsL0 22 | 4aCgLScCHb9J+E86aVbbVFdglYa5Id7DPTL61ixhl7WZjujspeXZGSbmq0Kcnckb 23 | mDgqkLECiOJW2NHP/j0McAkDLL4tysF8TLDO8gvuvzNC+WQ6drO2ThrypLVZQ+ry 24 | eBIPmwKBgEZxhqa0gVvHQG/7Od69KWj4eJP28kq13RhKay8JOoN0vPmspXJo1HY3 25 | CKuHRG+AP579dncdUnOMvfXOtkdM4vk0+hWASBQzM9xzVcztCa+koAugjVaLS9A+ 26 | 9uQoqEeVNTckxx0S2bYevRy7hGQmUJTyQm3j1zEUR5jpdbL83Fbq 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /service/greeting/conf/auth_key.pub: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4f5wg5l2hKsTeNem/V41 3 | fGnJm6gOdrj8ym3rFkEU/wT8RDtnSgFEZOQpHEgQ7JL38xUfU0Y3g6aYw9QT0hJ7 4 | mCpz9Er5qLaMXJwZxzHzAahlfA0icqabvJOMvQtzD6uQv6wPEyZtDTWiQi9AXwBp 5 | HssPnpYGIn20ZZuNlX2BrClciHhCPUIIZOQn/MmqTD31jSyjoQoV7MhhMTATKJx2 6 | XrHhR+1DcKJzQBSTAGnpYVaqpsARap+nwRipr3nUTuxyGohBTSmjJ2usSeQXHI3b 7 | ODIRe1AuTyHceAbewn8b462yEWKARdpd9AjQW5SIVPfdsz5B6GlYQ5LdYKtznTuy 8 | 7wIDAQAB 9 | -----END PUBLIC KEY----- 10 | -------------------------------------------------------------------------------- /service/greeting/conf/casbin_model.conf: -------------------------------------------------------------------------------- 1 | [request_definition] 2 | r = sub, obj, act 3 | 4 | [policy_definition] 5 | p = sub, obj, act 6 | 7 | [policy_effect] 8 | e = some(where (p.eft == allow)) 9 | 10 | [matchers] 11 | m = r.sub == p.sub && keyMatch(r.obj, p.obj) && regexMatch(r.act, p.act) 12 | -------------------------------------------------------------------------------- /service/greeting/conf/casbin_policy.csv: -------------------------------------------------------------------------------- 1 | p, public, /, GET 2 | p, public, /stats, GET 3 | 4 | p, alice, /alice_data/*, GET 5 | p, alice, /alice_data/resource1, POST 6 | 7 | p, bob, /alice_data/resource2, GET 8 | p, bob, /bob_data/*, POST 9 | 10 | p, cathy, /cathy_data, (GET)|(POST) 11 | -------------------------------------------------------------------------------- /service/greeting/conf/type.go: -------------------------------------------------------------------------------- 1 | package conf 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | var BASE_PATH = "./conf/" 8 | 9 | type Database struct { 10 | Engine string 11 | Host string 12 | Port string 13 | User string 14 | Password string 15 | Name string 16 | 17 | MaxOpenConns int 18 | MaxIdleConns int 19 | ConnMaxLifetime time.Duration 20 | } 21 | -------------------------------------------------------------------------------- /service/greeting/domain/model/greeting.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type Msg struct { 4 | Id int64 `xorm:"bigint pk autoincr" gorm:"primary_key"` 5 | Msg string `xorm:"varchar(128) unique" gorm:"type:varchar(128);unique_index"` 6 | } 7 | -------------------------------------------------------------------------------- /service/greeting/domain/repository/greeting.go: -------------------------------------------------------------------------------- 1 | package repository 2 | 3 | import ( 4 | "github.com/hb-chen/micro-starter/service/greeting/domain/model" 5 | ) 6 | 7 | type GreetingRepository interface { 8 | FindById(id int64) (*model.Msg, error) 9 | FindByMsg(msg string) (*model.Msg, error) 10 | Add(msg *model.Msg) error 11 | List(page, size int) ([]*model.Msg, error) 12 | } 13 | -------------------------------------------------------------------------------- /service/greeting/domain/usecase/greeting.go: -------------------------------------------------------------------------------- 1 | package usecase 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/hb-chen/micro-starter/service/greeting/domain/model" 7 | "github.com/hb-chen/micro-starter/service/greeting/domain/repository" 8 | ) 9 | 10 | type GreetingUsecase interface { 11 | Add(msg string) (*model.Msg, error) 12 | List(page, size int) ([]*model.Msg, error) 13 | Duplicated(msg string) error 14 | } 15 | 16 | type greetingUsecase struct { 17 | repo repository.GreetingRepository 18 | } 19 | 20 | func NewGreetingUsecase(repo repository.GreetingRepository) GreetingUsecase { 21 | return &greetingUsecase{ 22 | repo: repo, 23 | } 24 | } 25 | 26 | func (s *greetingUsecase) Add(msg string) (*model.Msg, error) { 27 | item, err := s.repo.FindByMsg(msg) 28 | if err != nil { 29 | return nil, err 30 | } 31 | 32 | if item != nil { 33 | return item, nil 34 | } 35 | 36 | u := model.Msg{ 37 | Msg: msg, 38 | } 39 | err = s.repo.Add(&u) 40 | if err != nil { 41 | return nil, err 42 | } 43 | 44 | return &u, nil 45 | } 46 | 47 | func (s *greetingUsecase) List(page, size int) ([]*model.Msg, error) { 48 | items, err := s.repo.List(page, size) 49 | if err != nil { 50 | return nil, err 51 | } 52 | 53 | return items, nil 54 | } 55 | 56 | func (s *greetingUsecase) Duplicated(msg string) error { 57 | item, err := s.repo.FindByMsg(msg) 58 | if item != nil { 59 | return fmt.Errorf("msg duplicated: %s", item.Msg) 60 | } 61 | if err != nil { 62 | return err 63 | } 64 | return nil 65 | } 66 | -------------------------------------------------------------------------------- /service/greeting/generate.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | //go:generate make proto 4 | -------------------------------------------------------------------------------- /service/greeting/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "micro.dev/v4/service" 5 | "micro.dev/v4/service/logger" 6 | 7 | svc "github.com/hb-chen/micro-starter/pkg/service" 8 | _ "github.com/hb-chen/micro-starter/profile" 9 | "github.com/hb-chen/micro-starter/service/greeting/registry" 10 | "github.com/hb-chen/micro-starter/service/greeting/server" 11 | ) 12 | 13 | func main() { 14 | // New Service 15 | srv := svc.New( 16 | service.Name("greeting"), 17 | service.Version("latest"), 18 | ) 19 | 20 | c, err := registry.NewContainer() 21 | if err != nil { 22 | logger.Fatal(err) 23 | } 24 | 25 | // Register Handler 26 | server.Apply(srv.Server(), c) 27 | 28 | // Run service 29 | if err := srv.Run(); err != nil { 30 | logger.Fatal(err) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /service/greeting/proto/greeting/greeting.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. DO NOT EDIT. 2 | // versions: 3 | // protoc-gen-go v1.26.0 4 | // protoc v3.21.12 5 | // source: github.com/hb-chen/micro-starter/service/greeting/proto/greeting/greeting.proto 6 | 7 | package greeting 8 | 9 | import ( 10 | protoreflect "google.golang.org/protobuf/reflect/protoreflect" 11 | protoimpl "google.golang.org/protobuf/runtime/protoimpl" 12 | reflect "reflect" 13 | sync "sync" 14 | ) 15 | 16 | const ( 17 | // Verify that this generated code is sufficiently up-to-date. 18 | _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) 19 | // Verify that runtime/protoimpl is sufficiently up-to-date. 20 | _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) 21 | ) 22 | 23 | type CallRequest struct { 24 | state protoimpl.MessageState 25 | sizeCache protoimpl.SizeCache 26 | unknownFields protoimpl.UnknownFields 27 | 28 | Msg string `protobuf:"bytes,1,opt,name=msg,proto3" json:"msg,omitempty"` 29 | } 30 | 31 | func (x *CallRequest) Reset() { 32 | *x = CallRequest{} 33 | if protoimpl.UnsafeEnabled { 34 | mi := &file_github_com_hb_chen_micro_starter_service_greeting_proto_greeting_greeting_proto_msgTypes[0] 35 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 36 | ms.StoreMessageInfo(mi) 37 | } 38 | } 39 | 40 | func (x *CallRequest) String() string { 41 | return protoimpl.X.MessageStringOf(x) 42 | } 43 | 44 | func (*CallRequest) ProtoMessage() {} 45 | 46 | func (x *CallRequest) ProtoReflect() protoreflect.Message { 47 | mi := &file_github_com_hb_chen_micro_starter_service_greeting_proto_greeting_greeting_proto_msgTypes[0] 48 | if protoimpl.UnsafeEnabled && x != nil { 49 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 50 | if ms.LoadMessageInfo() == nil { 51 | ms.StoreMessageInfo(mi) 52 | } 53 | return ms 54 | } 55 | return mi.MessageOf(x) 56 | } 57 | 58 | // Deprecated: Use CallRequest.ProtoReflect.Descriptor instead. 59 | func (*CallRequest) Descriptor() ([]byte, []int) { 60 | return file_github_com_hb_chen_micro_starter_service_greeting_proto_greeting_greeting_proto_rawDescGZIP(), []int{0} 61 | } 62 | 63 | func (x *CallRequest) GetMsg() string { 64 | if x != nil { 65 | return x.Msg 66 | } 67 | return "" 68 | } 69 | 70 | type CallResponse struct { 71 | state protoimpl.MessageState 72 | sizeCache protoimpl.SizeCache 73 | unknownFields protoimpl.UnknownFields 74 | 75 | Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` 76 | Msg string `protobuf:"bytes,2,opt,name=msg,proto3" json:"msg,omitempty"` 77 | } 78 | 79 | func (x *CallResponse) Reset() { 80 | *x = CallResponse{} 81 | if protoimpl.UnsafeEnabled { 82 | mi := &file_github_com_hb_chen_micro_starter_service_greeting_proto_greeting_greeting_proto_msgTypes[1] 83 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 84 | ms.StoreMessageInfo(mi) 85 | } 86 | } 87 | 88 | func (x *CallResponse) String() string { 89 | return protoimpl.X.MessageStringOf(x) 90 | } 91 | 92 | func (*CallResponse) ProtoMessage() {} 93 | 94 | func (x *CallResponse) ProtoReflect() protoreflect.Message { 95 | mi := &file_github_com_hb_chen_micro_starter_service_greeting_proto_greeting_greeting_proto_msgTypes[1] 96 | if protoimpl.UnsafeEnabled && x != nil { 97 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 98 | if ms.LoadMessageInfo() == nil { 99 | ms.StoreMessageInfo(mi) 100 | } 101 | return ms 102 | } 103 | return mi.MessageOf(x) 104 | } 105 | 106 | // Deprecated: Use CallResponse.ProtoReflect.Descriptor instead. 107 | func (*CallResponse) Descriptor() ([]byte, []int) { 108 | return file_github_com_hb_chen_micro_starter_service_greeting_proto_greeting_greeting_proto_rawDescGZIP(), []int{1} 109 | } 110 | 111 | func (x *CallResponse) GetId() int64 { 112 | if x != nil { 113 | return x.Id 114 | } 115 | return 0 116 | } 117 | 118 | func (x *CallResponse) GetMsg() string { 119 | if x != nil { 120 | return x.Msg 121 | } 122 | return "" 123 | } 124 | 125 | type ListResponse struct { 126 | state protoimpl.MessageState 127 | sizeCache protoimpl.SizeCache 128 | unknownFields protoimpl.UnknownFields 129 | 130 | Items []*CallResponse `protobuf:"bytes,1,rep,name=items,proto3" json:"items,omitempty"` 131 | } 132 | 133 | func (x *ListResponse) Reset() { 134 | *x = ListResponse{} 135 | if protoimpl.UnsafeEnabled { 136 | mi := &file_github_com_hb_chen_micro_starter_service_greeting_proto_greeting_greeting_proto_msgTypes[2] 137 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 138 | ms.StoreMessageInfo(mi) 139 | } 140 | } 141 | 142 | func (x *ListResponse) String() string { 143 | return protoimpl.X.MessageStringOf(x) 144 | } 145 | 146 | func (*ListResponse) ProtoMessage() {} 147 | 148 | func (x *ListResponse) ProtoReflect() protoreflect.Message { 149 | mi := &file_github_com_hb_chen_micro_starter_service_greeting_proto_greeting_greeting_proto_msgTypes[2] 150 | if protoimpl.UnsafeEnabled && x != nil { 151 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 152 | if ms.LoadMessageInfo() == nil { 153 | ms.StoreMessageInfo(mi) 154 | } 155 | return ms 156 | } 157 | return mi.MessageOf(x) 158 | } 159 | 160 | // Deprecated: Use ListResponse.ProtoReflect.Descriptor instead. 161 | func (*ListResponse) Descriptor() ([]byte, []int) { 162 | return file_github_com_hb_chen_micro_starter_service_greeting_proto_greeting_greeting_proto_rawDescGZIP(), []int{2} 163 | } 164 | 165 | func (x *ListResponse) GetItems() []*CallResponse { 166 | if x != nil { 167 | return x.Items 168 | } 169 | return nil 170 | } 171 | 172 | type Page struct { 173 | state protoimpl.MessageState 174 | sizeCache protoimpl.SizeCache 175 | unknownFields protoimpl.UnknownFields 176 | 177 | Page int64 `protobuf:"varint,1,opt,name=page,proto3" json:"page,omitempty"` 178 | Size int64 `protobuf:"varint,2,opt,name=size,proto3" json:"size,omitempty"` 179 | } 180 | 181 | func (x *Page) Reset() { 182 | *x = Page{} 183 | if protoimpl.UnsafeEnabled { 184 | mi := &file_github_com_hb_chen_micro_starter_service_greeting_proto_greeting_greeting_proto_msgTypes[3] 185 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 186 | ms.StoreMessageInfo(mi) 187 | } 188 | } 189 | 190 | func (x *Page) String() string { 191 | return protoimpl.X.MessageStringOf(x) 192 | } 193 | 194 | func (*Page) ProtoMessage() {} 195 | 196 | func (x *Page) ProtoReflect() protoreflect.Message { 197 | mi := &file_github_com_hb_chen_micro_starter_service_greeting_proto_greeting_greeting_proto_msgTypes[3] 198 | if protoimpl.UnsafeEnabled && x != nil { 199 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 200 | if ms.LoadMessageInfo() == nil { 201 | ms.StoreMessageInfo(mi) 202 | } 203 | return ms 204 | } 205 | return mi.MessageOf(x) 206 | } 207 | 208 | // Deprecated: Use Page.ProtoReflect.Descriptor instead. 209 | func (*Page) Descriptor() ([]byte, []int) { 210 | return file_github_com_hb_chen_micro_starter_service_greeting_proto_greeting_greeting_proto_rawDescGZIP(), []int{3} 211 | } 212 | 213 | func (x *Page) GetPage() int64 { 214 | if x != nil { 215 | return x.Page 216 | } 217 | return 0 218 | } 219 | 220 | func (x *Page) GetSize() int64 { 221 | if x != nil { 222 | return x.Size 223 | } 224 | return 0 225 | } 226 | 227 | var File_github_com_hb_chen_micro_starter_service_greeting_proto_greeting_greeting_proto protoreflect.FileDescriptor 228 | 229 | var file_github_com_hb_chen_micro_starter_service_greeting_proto_greeting_greeting_proto_rawDesc = []byte{ 230 | 0x0a, 0x4f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x62, 0x2d, 231 | 0x63, 0x68, 0x65, 0x6e, 0x2f, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x2d, 0x73, 0x74, 0x61, 0x72, 0x74, 232 | 0x65, 0x72, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2f, 0x67, 0x72, 0x65, 0x65, 0x74, 233 | 0x69, 0x6e, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x72, 0x65, 0x65, 0x74, 0x69, 234 | 0x6e, 0x67, 0x2f, 0x67, 0x72, 0x65, 0x65, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 235 | 0x6f, 0x12, 0x15, 0x67, 0x6f, 0x2e, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x2e, 0x73, 0x72, 0x76, 0x2e, 236 | 0x67, 0x72, 0x65, 0x65, 0x74, 0x69, 0x6e, 0x67, 0x22, 0x1f, 0x0a, 0x0b, 0x43, 0x61, 0x6c, 0x6c, 237 | 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x73, 0x67, 0x18, 0x01, 238 | 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6d, 0x73, 0x67, 0x22, 0x30, 0x0a, 0x0c, 0x43, 0x61, 0x6c, 239 | 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 240 | 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x02, 0x69, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x73, 0x67, 241 | 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6d, 0x73, 0x67, 0x22, 0x49, 0x0a, 0x0c, 0x4c, 242 | 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x39, 0x0a, 0x05, 0x69, 243 | 0x74, 0x65, 0x6d, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x67, 0x6f, 0x2e, 244 | 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x2e, 0x73, 0x72, 0x76, 0x2e, 0x67, 0x72, 0x65, 0x65, 0x74, 0x69, 245 | 0x6e, 0x67, 0x2e, 0x43, 0x61, 0x6c, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 246 | 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x22, 0x2e, 0x0a, 0x04, 0x50, 0x61, 0x67, 0x65, 0x12, 0x12, 247 | 0x0a, 0x04, 0x70, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x70, 0x61, 248 | 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 249 | 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x32, 0xa9, 0x01, 0x0a, 0x08, 0x47, 0x72, 0x65, 0x65, 0x74, 250 | 0x69, 0x6e, 0x67, 0x12, 0x51, 0x0a, 0x04, 0x43, 0x61, 0x6c, 0x6c, 0x12, 0x22, 0x2e, 0x67, 0x6f, 251 | 0x2e, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x2e, 0x73, 0x72, 0x76, 0x2e, 0x67, 0x72, 0x65, 0x65, 0x74, 252 | 0x69, 0x6e, 0x67, 0x2e, 0x43, 0x61, 0x6c, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 253 | 0x23, 0x2e, 0x67, 0x6f, 0x2e, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x2e, 0x73, 0x72, 0x76, 0x2e, 0x67, 254 | 0x72, 0x65, 0x65, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x43, 0x61, 0x6c, 0x6c, 0x52, 0x65, 0x73, 0x70, 255 | 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x4a, 0x0a, 0x04, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x1b, 256 | 0x2e, 0x67, 0x6f, 0x2e, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x2e, 0x73, 0x72, 0x76, 0x2e, 0x67, 0x72, 257 | 0x65, 0x65, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x50, 0x61, 0x67, 0x65, 0x1a, 0x23, 0x2e, 0x67, 0x6f, 258 | 0x2e, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x2e, 0x73, 0x72, 0x76, 0x2e, 0x67, 0x72, 0x65, 0x65, 0x74, 259 | 0x69, 0x6e, 0x67, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 260 | 0x22, 0x00, 0x42, 0x1b, 0x5a, 0x19, 0x2e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x72, 261 | 0x65, 0x65, 0x74, 0x69, 0x6e, 0x67, 0x3b, 0x67, 0x72, 0x65, 0x65, 0x74, 0x69, 0x6e, 0x67, 0x62, 262 | 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 263 | } 264 | 265 | var ( 266 | file_github_com_hb_chen_micro_starter_service_greeting_proto_greeting_greeting_proto_rawDescOnce sync.Once 267 | file_github_com_hb_chen_micro_starter_service_greeting_proto_greeting_greeting_proto_rawDescData = file_github_com_hb_chen_micro_starter_service_greeting_proto_greeting_greeting_proto_rawDesc 268 | ) 269 | 270 | func file_github_com_hb_chen_micro_starter_service_greeting_proto_greeting_greeting_proto_rawDescGZIP() []byte { 271 | file_github_com_hb_chen_micro_starter_service_greeting_proto_greeting_greeting_proto_rawDescOnce.Do(func() { 272 | file_github_com_hb_chen_micro_starter_service_greeting_proto_greeting_greeting_proto_rawDescData = protoimpl.X.CompressGZIP(file_github_com_hb_chen_micro_starter_service_greeting_proto_greeting_greeting_proto_rawDescData) 273 | }) 274 | return file_github_com_hb_chen_micro_starter_service_greeting_proto_greeting_greeting_proto_rawDescData 275 | } 276 | 277 | var file_github_com_hb_chen_micro_starter_service_greeting_proto_greeting_greeting_proto_msgTypes = make([]protoimpl.MessageInfo, 4) 278 | var file_github_com_hb_chen_micro_starter_service_greeting_proto_greeting_greeting_proto_goTypes = []interface{}{ 279 | (*CallRequest)(nil), // 0: go.micro.srv.greeting.CallRequest 280 | (*CallResponse)(nil), // 1: go.micro.srv.greeting.CallResponse 281 | (*ListResponse)(nil), // 2: go.micro.srv.greeting.ListResponse 282 | (*Page)(nil), // 3: go.micro.srv.greeting.Page 283 | } 284 | var file_github_com_hb_chen_micro_starter_service_greeting_proto_greeting_greeting_proto_depIdxs = []int32{ 285 | 1, // 0: go.micro.srv.greeting.ListResponse.items:type_name -> go.micro.srv.greeting.CallResponse 286 | 0, // 1: go.micro.srv.greeting.Greeting.Call:input_type -> go.micro.srv.greeting.CallRequest 287 | 3, // 2: go.micro.srv.greeting.Greeting.List:input_type -> go.micro.srv.greeting.Page 288 | 1, // 3: go.micro.srv.greeting.Greeting.Call:output_type -> go.micro.srv.greeting.CallResponse 289 | 2, // 4: go.micro.srv.greeting.Greeting.List:output_type -> go.micro.srv.greeting.ListResponse 290 | 3, // [3:5] is the sub-list for method output_type 291 | 1, // [1:3] is the sub-list for method input_type 292 | 1, // [1:1] is the sub-list for extension type_name 293 | 1, // [1:1] is the sub-list for extension extendee 294 | 0, // [0:1] is the sub-list for field type_name 295 | } 296 | 297 | func init() { 298 | file_github_com_hb_chen_micro_starter_service_greeting_proto_greeting_greeting_proto_init() 299 | } 300 | func file_github_com_hb_chen_micro_starter_service_greeting_proto_greeting_greeting_proto_init() { 301 | if File_github_com_hb_chen_micro_starter_service_greeting_proto_greeting_greeting_proto != nil { 302 | return 303 | } 304 | if !protoimpl.UnsafeEnabled { 305 | file_github_com_hb_chen_micro_starter_service_greeting_proto_greeting_greeting_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { 306 | switch v := v.(*CallRequest); i { 307 | case 0: 308 | return &v.state 309 | case 1: 310 | return &v.sizeCache 311 | case 2: 312 | return &v.unknownFields 313 | default: 314 | return nil 315 | } 316 | } 317 | file_github_com_hb_chen_micro_starter_service_greeting_proto_greeting_greeting_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { 318 | switch v := v.(*CallResponse); i { 319 | case 0: 320 | return &v.state 321 | case 1: 322 | return &v.sizeCache 323 | case 2: 324 | return &v.unknownFields 325 | default: 326 | return nil 327 | } 328 | } 329 | file_github_com_hb_chen_micro_starter_service_greeting_proto_greeting_greeting_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { 330 | switch v := v.(*ListResponse); i { 331 | case 0: 332 | return &v.state 333 | case 1: 334 | return &v.sizeCache 335 | case 2: 336 | return &v.unknownFields 337 | default: 338 | return nil 339 | } 340 | } 341 | file_github_com_hb_chen_micro_starter_service_greeting_proto_greeting_greeting_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { 342 | switch v := v.(*Page); i { 343 | case 0: 344 | return &v.state 345 | case 1: 346 | return &v.sizeCache 347 | case 2: 348 | return &v.unknownFields 349 | default: 350 | return nil 351 | } 352 | } 353 | } 354 | type x struct{} 355 | out := protoimpl.TypeBuilder{ 356 | File: protoimpl.DescBuilder{ 357 | GoPackagePath: reflect.TypeOf(x{}).PkgPath(), 358 | RawDescriptor: file_github_com_hb_chen_micro_starter_service_greeting_proto_greeting_greeting_proto_rawDesc, 359 | NumEnums: 0, 360 | NumMessages: 4, 361 | NumExtensions: 0, 362 | NumServices: 1, 363 | }, 364 | GoTypes: file_github_com_hb_chen_micro_starter_service_greeting_proto_greeting_greeting_proto_goTypes, 365 | DependencyIndexes: file_github_com_hb_chen_micro_starter_service_greeting_proto_greeting_greeting_proto_depIdxs, 366 | MessageInfos: file_github_com_hb_chen_micro_starter_service_greeting_proto_greeting_greeting_proto_msgTypes, 367 | }.Build() 368 | File_github_com_hb_chen_micro_starter_service_greeting_proto_greeting_greeting_proto = out.File 369 | file_github_com_hb_chen_micro_starter_service_greeting_proto_greeting_greeting_proto_rawDesc = nil 370 | file_github_com_hb_chen_micro_starter_service_greeting_proto_greeting_greeting_proto_goTypes = nil 371 | file_github_com_hb_chen_micro_starter_service_greeting_proto_greeting_greeting_proto_depIdxs = nil 372 | } 373 | -------------------------------------------------------------------------------- /service/greeting/proto/greeting/greeting.pb.micro.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-micro. DO NOT EDIT. 2 | // source: github.com/hb-chen/micro-starter/service/greeting/proto/greeting/greeting.proto 3 | 4 | package greeting 5 | 6 | import ( 7 | fmt "fmt" 8 | proto "github.com/golang/protobuf/proto" 9 | math "math" 10 | ) 11 | 12 | import ( 13 | context "context" 14 | api "micro.dev/v4/service/api" 15 | client "micro.dev/v4/service/client" 16 | server "micro.dev/v4/service/server" 17 | ) 18 | 19 | // Reference imports to suppress errors if they are not otherwise used. 20 | var _ = proto.Marshal 21 | var _ = fmt.Errorf 22 | var _ = math.Inf 23 | 24 | // This is a compile-time assertion to ensure that this generated file 25 | // is compatible with the proto package it is being compiled against. 26 | // A compilation error at this line likely means your copy of the 27 | // proto package needs to be updated. 28 | const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package 29 | 30 | // Reference imports to suppress errors if they are not otherwise used. 31 | var _ api.Endpoint 32 | var _ context.Context 33 | var _ client.Option 34 | var _ server.Option 35 | 36 | // Api Endpoints for Greeting service 37 | 38 | func NewGreetingEndpoints() []*api.Endpoint { 39 | return []*api.Endpoint{} 40 | } 41 | 42 | // Client API for Greeting service 43 | 44 | type GreetingService interface { 45 | Call(ctx context.Context, in *CallRequest, opts ...client.CallOption) (*CallResponse, error) 46 | List(ctx context.Context, in *Page, opts ...client.CallOption) (*ListResponse, error) 47 | } 48 | 49 | type greetingService struct { 50 | c client.Client 51 | name string 52 | } 53 | 54 | func NewGreetingService(name string, c client.Client) GreetingService { 55 | return &greetingService{ 56 | c: c, 57 | name: name, 58 | } 59 | } 60 | 61 | func (c *greetingService) Call(ctx context.Context, in *CallRequest, opts ...client.CallOption) (*CallResponse, error) { 62 | req := c.c.NewRequest(c.name, "Greeting.Call", in) 63 | out := new(CallResponse) 64 | err := c.c.Call(ctx, req, out, opts...) 65 | if err != nil { 66 | return nil, err 67 | } 68 | return out, nil 69 | } 70 | 71 | func (c *greetingService) List(ctx context.Context, in *Page, opts ...client.CallOption) (*ListResponse, error) { 72 | req := c.c.NewRequest(c.name, "Greeting.List", in) 73 | out := new(ListResponse) 74 | err := c.c.Call(ctx, req, out, opts...) 75 | if err != nil { 76 | return nil, err 77 | } 78 | return out, nil 79 | } 80 | 81 | // Server API for Greeting service 82 | 83 | type GreetingHandler interface { 84 | Call(context.Context, *CallRequest, *CallResponse) error 85 | List(context.Context, *Page, *ListResponse) error 86 | } 87 | 88 | func RegisterGreetingHandler(s server.Server, hdlr GreetingHandler, opts ...server.HandlerOption) error { 89 | type greeting interface { 90 | Call(ctx context.Context, in *CallRequest, out *CallResponse) error 91 | List(ctx context.Context, in *Page, out *ListResponse) error 92 | } 93 | type Greeting struct { 94 | greeting 95 | } 96 | h := &greetingHandler{hdlr} 97 | return s.Handle(s.NewHandler(&Greeting{h}, opts...)) 98 | } 99 | 100 | type greetingHandler struct { 101 | GreetingHandler 102 | } 103 | 104 | func (h *greetingHandler) Call(ctx context.Context, in *CallRequest, out *CallResponse) error { 105 | return h.GreetingHandler.Call(ctx, in, out) 106 | } 107 | 108 | func (h *greetingHandler) List(ctx context.Context, in *Page, out *ListResponse) error { 109 | return h.GreetingHandler.List(ctx, in, out) 110 | } 111 | -------------------------------------------------------------------------------- /service/greeting/proto/greeting/greeting.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package go.micro.srv.greeting; 4 | 5 | option go_package = "./proto/greeting;greeting"; 6 | 7 | service Greeting { 8 | rpc Call (CallRequest) returns (CallResponse) { 9 | } 10 | rpc List (Page)returns(ListResponse){ 11 | } 12 | } 13 | 14 | message CallRequest { 15 | string msg = 1; 16 | } 17 | 18 | message CallResponse { 19 | int64 id = 1; 20 | string msg = 2; 21 | } 22 | 23 | message ListResponse { 24 | repeated CallResponse items = 1; 25 | } 26 | 27 | message Page { 28 | int64 page = 1; 29 | int64 size = 2; 30 | } 31 | -------------------------------------------------------------------------------- /service/greeting/registry/container.go: -------------------------------------------------------------------------------- 1 | package registry 2 | 3 | import ( 4 | _ "github.com/go-sql-driver/mysql" 5 | "github.com/hb-chen/micro-starter/service/greeting/repo/gorm" 6 | "github.com/hb-chen/micro-starter/service/greeting/repo/memory" 7 | "go.uber.org/dig" 8 | "micro.dev/v4/service/config" 9 | 10 | "github.com/hb-chen/micro-starter/service/greeting/domain/usecase" 11 | "github.com/hb-chen/micro-starter/service/greeting/service" 12 | ) 13 | 14 | func NewContainer() (*dig.Container, error) { 15 | c := dig.New() 16 | 17 | err := build(c) 18 | if err != nil { 19 | return nil, err 20 | } 21 | 22 | return c, nil 23 | } 24 | 25 | func build(c *dig.Container) error { 26 | conf, _ := config.Get("persistence") 27 | persistence := conf.String("") 28 | 29 | // ORM选择,gorm、xorm... 30 | switch persistence { 31 | case "xorm": 32 | case "gorm": 33 | // DB初始化 34 | err := c.Provide(gorm.NewDB) 35 | if err != nil { 36 | return err 37 | } 38 | err = c.Provide(gorm.NewGreetingRepository) 39 | if err != nil { 40 | return err 41 | } 42 | default: 43 | // 默认memory作为mock 44 | err := c.Provide(memory.NewGreetingRepository) 45 | if err != nil { 46 | return err 47 | } 48 | } 49 | 50 | err := c.Provide(usecase.NewGreetingUsecase) 51 | if err != nil { 52 | return err 53 | } 54 | err = c.Provide(service.NewGreetingService) 55 | if err != nil { 56 | return err 57 | } 58 | 59 | return nil 60 | } 61 | -------------------------------------------------------------------------------- /service/greeting/repo/gorm/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hb-chen/micro-starter/045d1f4f99d50c96857b34fb1eced2c419eb6507/service/greeting/repo/gorm/.gitkeep -------------------------------------------------------------------------------- /service/greeting/repo/gorm/db.go: -------------------------------------------------------------------------------- 1 | package gorm 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/hb-chen/micro-starter/service/greeting/domain/model" 7 | "gorm.io/driver/mysql" 8 | "gorm.io/gorm" 9 | "gorm.io/plugin/dbresolver" 10 | "micro.dev/v4/service/config" 11 | log "micro.dev/v4/service/logger" 12 | 13 | "github.com/hb-chen/micro-starter/service/greeting/conf" 14 | ) 15 | 16 | func NewDB() (*gorm.DB, error) { 17 | dbConf := conf.Database{} 18 | cv, err := config.Get("database") 19 | if err != nil { 20 | log.Fatal(err) 21 | } 22 | if err := cv.Scan(&dbConf); err != nil { 23 | log.Fatal(err) 24 | } 25 | 26 | dsn := dbConf.User + ":" + dbConf.Password + "@tcp(" + dbConf.Host + ":" + dbConf.Port + ")/" + dbConf.Name + "?charset=utf8mb4&parseTime=True&loc=Local" 27 | db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{}) 28 | if err != nil { 29 | log.Error(err) 30 | return nil, err 31 | } 32 | 33 | err = db.Use( 34 | dbresolver.Register(dbresolver.Config{}). 35 | SetConnMaxIdleTime(time.Hour). 36 | SetConnMaxLifetime(dbConf.ConnMaxLifetime). 37 | SetMaxIdleConns(dbConf.MaxIdleConns). 38 | SetMaxOpenConns(dbConf.MaxOpenConns), 39 | ) 40 | if err != nil { 41 | log.Error(err) 42 | return nil, err 43 | } 44 | 45 | return db, nil 46 | } 47 | 48 | func Migrate() error { 49 | db, err := NewDB() 50 | if err != nil { 51 | return err 52 | } 53 | 54 | err = db.AutoMigrate(&model.Msg{}) 55 | if err != nil { 56 | return err 57 | } 58 | 59 | return nil 60 | } 61 | -------------------------------------------------------------------------------- /service/greeting/repo/gorm/greeting_repository.go: -------------------------------------------------------------------------------- 1 | package gorm 2 | 3 | import ( 4 | "errors" 5 | 6 | "gorm.io/gorm" 7 | 8 | "github.com/hb-chen/micro-starter/service/greeting/domain/model" 9 | "github.com/hb-chen/micro-starter/service/greeting/domain/repository" 10 | ) 11 | 12 | type greetingRepository struct { 13 | db *gorm.DB 14 | } 15 | 16 | func NewGreetingRepository(db *gorm.DB) repository.GreetingRepository { 17 | return &greetingRepository{ 18 | db: db, 19 | } 20 | } 21 | 22 | func (r *greetingRepository) FindById(id int64) (*model.Msg, error) { 23 | item := model.Msg{} 24 | if result := r.db.Where("id = ?", id).First(&item); result.Error != nil { 25 | if errors.Is(result.Error, gorm.ErrRecordNotFound) { 26 | return nil, nil 27 | } else { 28 | return nil, result.Error 29 | } 30 | } else { 31 | return &item, nil 32 | } 33 | } 34 | 35 | func (r *greetingRepository) FindByMsg(msg string) (*model.Msg, error) { 36 | item := model.Msg{} 37 | if result := r.db.Where("msg = ?", msg).First(&item); result.Error != nil { 38 | if errors.Is(result.Error, gorm.ErrRecordNotFound) { 39 | return nil, nil 40 | } else { 41 | return nil, result.Error 42 | } 43 | } else { 44 | return &item, nil 45 | } 46 | } 47 | 48 | func (r *greetingRepository) Add(msg *model.Msg) error { 49 | err := r.db.Create(msg).Error 50 | if err != nil { 51 | return err 52 | } 53 | 54 | return nil 55 | } 56 | 57 | func (r *greetingRepository) List(page, size int) ([]*model.Msg, error) { 58 | list := make([]*model.Msg, 0) 59 | err := r.db.Order("id DESC").Offset((page - 1) * size).Limit(size).Find(&list).Error 60 | 61 | return list, err 62 | } 63 | -------------------------------------------------------------------------------- /service/greeting/repo/memory/memory.go: -------------------------------------------------------------------------------- 1 | package memory 2 | 3 | import ( 4 | "sync" 5 | 6 | "github.com/hb-chen/micro-starter/service/greeting/domain/model" 7 | "github.com/hb-chen/micro-starter/service/greeting/domain/repository" 8 | ) 9 | 10 | type greetingRepository struct { 11 | mu *sync.Mutex 12 | items []*model.Msg 13 | } 14 | 15 | func (r *greetingRepository) FindById(id int64) (*model.Msg, error) { 16 | r.mu.Lock() 17 | defer r.mu.Unlock() 18 | 19 | for _, item := range r.items { 20 | if item.Id == id { 21 | return item, nil 22 | } 23 | } 24 | return nil, nil 25 | } 26 | 27 | func (r *greetingRepository) FindByMsg(msg string) (*model.Msg, error) { 28 | r.mu.Lock() 29 | defer r.mu.Unlock() 30 | 31 | for _, item := range r.items { 32 | if item.Msg == msg { 33 | return item, nil 34 | } 35 | } 36 | return nil, nil 37 | } 38 | 39 | func (r *greetingRepository) Add(item *model.Msg) error { 40 | r.mu.Lock() 41 | defer r.mu.Unlock() 42 | 43 | id := int64(len(r.items) + 1) 44 | item.Id = id 45 | 46 | r.items = append(r.items, item) 47 | 48 | return nil 49 | } 50 | 51 | func (r *greetingRepository) List(page, size int) ([]*model.Msg, error) { 52 | idx := (page - 1) * size 53 | offset := idx + size 54 | 55 | if offset > len(r.items) { 56 | offset = len(r.items) 57 | } 58 | 59 | if offset <= idx { 60 | return []*model.Msg{}, nil 61 | } 62 | 63 | items := make([]*model.Msg, 0, offset-idx) 64 | for _, item := range r.items[idx:offset] { 65 | items = append(items, item) 66 | } 67 | return items, nil 68 | } 69 | 70 | func NewGreetingRepository() repository.GreetingRepository { 71 | items := make([]*model.Msg, 0) 72 | 73 | return &greetingRepository{ 74 | mu: &sync.Mutex{}, 75 | items: items, 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /service/greeting/server/handler.go: -------------------------------------------------------------------------------- 1 | package server 2 | 3 | import ( 4 | "go.uber.org/dig" 5 | log "micro.dev/v4/service/logger" 6 | "micro.dev/v4/service/server" 7 | 8 | pb "github.com/hb-chen/micro-starter/service/greeting/proto/greeting" 9 | ) 10 | 11 | func Apply(server server.Server, c *dig.Container) { 12 | err := c.Invoke(func(svc pb.GreetingHandler) { 13 | err := pb.RegisterGreetingHandler(server, svc) 14 | if err != nil { 15 | log.Error(err) 16 | return 17 | } 18 | }) 19 | if err != nil { 20 | log.Error(err) 21 | return 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /service/greeting/service/greeting.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/hb-chen/micro-starter/service/greeting/domain/repository" 7 | "github.com/hb-chen/micro-starter/service/greeting/domain/usecase" 8 | "github.com/hb-chen/micro-starter/service/greeting/proto/greeting" 9 | ) 10 | 11 | type Msg struct { 12 | Id int64 `json:"id"` 13 | Msg string `json:"msg"` 14 | } 15 | 16 | var _ greeting.GreetingHandler = &greetingService{} 17 | 18 | type greetingService struct { 19 | repo repository.GreetingRepository 20 | greetingUsecase usecase.GreetingUsecase 21 | } 22 | 23 | func (g *greetingService) Call(ctx context.Context, req *greeting.CallRequest, resp *greeting.CallResponse) error { 24 | result, err := g.greetingUsecase.Add(req.Msg) 25 | if err != nil { 26 | return err 27 | } 28 | 29 | resp.Id = result.Id 30 | resp.Msg = result.Msg 31 | 32 | return nil 33 | } 34 | 35 | func (g *greetingService) List(ctx context.Context, page *greeting.Page, resp *greeting.ListResponse) error { 36 | items, err := g.greetingUsecase.List(int(page.Page), int(page.Size)) 37 | if err != nil { 38 | return err 39 | } 40 | 41 | for _, item := range items { 42 | 43 | resp.Items = append(resp.Items, 44 | &greeting.CallResponse{ 45 | Id: item.Id, 46 | Msg: item.Msg, 47 | }) 48 | } 49 | 50 | return nil 51 | } 52 | 53 | func NewGreetingService(repo repository.GreetingRepository, us usecase.GreetingUsecase) greeting.GreetingHandler { 54 | return &greetingService{ 55 | repo: repo, 56 | greetingUsecase: us, 57 | } 58 | } 59 | --------------------------------------------------------------------------------