Golang微服務實踐


背景

在之前的文章《漫談微服務》我已經簡單的介紹過微服務,微服務特性是輕量級跨平台和跨語言的服務,也列舉了比較了集中微服務通信的手段的利弊,本文將通過RPC通信的方式實現一個增刪查Redis的輕量級微服務示例,大部分內容翻譯自文章《Microservice in golang, using Redis and gRPC》,中間加上自己的實踐和理解。

 

實驗環境

Mac OS

go version go1.12.4 darwin/amd64

Docker version 18.09.2, build 6247962

 

代碼倉庫

https://github.com/felipeinfantino/microservice-golang

 

微服務實踐

gRPC代碼生成

選用gRPC的原因是因為gRPC本身是一款開源且高性能的RPC框架,支持跨平台,支持golang,java,c,C++ 等10多種編程語言。因為我們要實現一個通過gRPC通信的基於Redis 數據庫的增刪改微服務,所以我們首先需要定義一個gRPC的通信描述文件server.proto:

syntax = "proto3";

package proto;

// Server Requests
message SetRequest{
    string key = 1;
    string value = 2;
}

message GetRequest{
    string key = 1;
}

message DeleteRequest{
    string key = 1;
}

// Server Response
message ServerResponse{
    bool success = 1;
    string value = 2;
    string error = 3;
}

// Define service
service BasicService{
    rpc Set(SetRequest) returns (ServerResponse);
    rpc Get(GetRequest) returns (ServerResponse);
    rpc Delete(DeleteRequest) returns (ServerResponse);
}  

 

想要將上面的server.proto文件轉換為golang代碼需要安裝protocol buffer的編譯器:

1.下載https://github.com/protocolbuffers/protobuf/releases/tag/v3.11.0中的protoc-3.11.0-osx-x86_64.zip包。

2.解壓拷貝里面的二進制protoc及google子目錄到該示例工程目錄下。

3.通過上面定義的server.proto 生成golang代碼,可以看到proto目錄下生成了service.pb.go文件。

./protoc --proto_path=proto --proto_path=google --go_out=plugins=grpc:proto service.proto

如果還不行可以參考protocol buffer官方安裝詳細步驟 https://github.com/protocolbuffers/protobuf

工程代碼目錄結構如下:

.
├── Dockerfile
├── README.md
├── database
│   ├── database.model.go
│   ├── errors.go
│   └── redis.go
├── docker-compose.yml
├── go.mod
├── go.sum
├── google
│   └── protobuf
│       ├── any.proto
│       ├── api.proto
│       ├── compiler
│       │   └── plugin.proto
│       ├── descriptor.proto
│       ├── duration.proto
│       ├── empty.proto
│       ├── field_mask.proto
│       ├── source_context.proto
│       ├── struct.proto
│       ├── timestamp.proto
│       ├── type.proto
│       └── wrappers.proto
├── main
├── main.go
├── proto
│   ├── service.pb.go
│   └── service.proto
└── protoc

Redis服務

package database

// Database abstraction
type Database interface {
	Set(key string, value string) (string, error)
	Get(key string) (string, error)
	Delete(key string) (string, error)
}

// Factory looks up acording to the databaseName the database implementation
func Factory(databaseName string) (Database, error) {
	switch databaseName {
	case "redis":
		return createRedisDatabase()
	default:
		return nil, &NotImplementedDatabaseError{databaseName}
	}
}  

定義了一個Database的接口,里面含有增刪查三種方法,只要實現了這三種方法的數據庫都可以作為該微服務的數據庫,所以提供一個工廠函數供用戶后續擴展,目前只實現了Redis一種存儲。Redis的實現直接引用了開源第三方Redis操作用github/go-redis/redis 然后封裝了上面增刪查三種方法。這里就不展開講redis實現了。

主程序

然后就是我們的golang主程序,程序邏輯為開啟gRPC服務端,提供增刪查三個接口及響應。代碼如下:

func main() {
	listener, err := net.Listen("tcp", ":4040")
	if err != nil {
		panic(err) // The port may be on use
	}
	srv := grpc.NewServer()
	databaseImplementation := os.Args[1]
	db, err = database.Factory(databaseImplementation)
	if err != nil {
		panic(err)
	}
	proto.RegisterBasicServiceServer(srv, &server{})
	fmt.Println("Prepare to serve")
	if e := srv.Serve(listener); e != nil {
		panic(err)
	}
}
func (s *server) Set(ctx context.Context, in *proto.SetRequest) (*proto.ServerResponse, error) {
	value, err := db.Set(in.GetKey(), in.GetValue())
	return generateResponse(value, err)
}
func (s *server) Get(ctx context.Context, in *proto.GetRequest) (*proto.ServerResponse, error) {
	value, err := db.Get(in.GetKey())
	return generateResponse(value, err)
}
func (s *server) Delete(ctx context.Context, in *proto.DeleteRequest) (*proto.ServerResponse, error) {
	value, err := db.Delete(in.GetKey())
	return generateResponse(value, err)
}
func generateResponse(value string, err error) (*proto.ServerResponse, error) {
	if err != nil {
		return &proto.ServerResponse{Success: false, Value: value, Error: err.Error()}, nil
	}
	return &proto.ServerResponse{Success: true, Value: value, Error: ""}, nil
}

 

啟動服務

為了測試方便用docker-compose定義了我們的微服務,對docker-compose不太熟悉的朋友可以簡單的看下我之前寫的《利用Docker Compose快速搭建本地測試環境》這篇文章。該服務的docker-compose.yaml內容如下:

version: "3.7"

services: 

  server:
    build: .
    ports:
      - "4040:4040"
    depends_on: 
      - redis
  
  redis:
    container_name: redis_container
    image: redis  

可以看出我們通過暴露4040端口提供我們的服務,服務依賴於redis,所以redis服務會在我們服務之前以容器的方式被拉起來。微服務的啟動命令可以從Dockerfile中獲取:

FROM golang:latest 
RUN mkdir /app 
ADD . /app/ 
WORKDIR /app 
EXPOSE 4040
CMD ["go", "run", "main.go", "redis"]

拉起服務:  

docker-compose up
Starting redis_container ... done
Starting microservice-golang_server_1 ... done
Attaching to redis_container, microservice-golang_server_1
redis_container | 1:C 22 Dec 2019 13:11:10.761 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
redis_container | 1:C 22 Dec 2019 13:11:10.761 # Redis version=5.0.7, bits=64, commit=00000000, modified=0, pid=1, just started
redis_container | 1:C 22 Dec 2019 13:11:10.761 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf
redis_container | 1:M 22 Dec 2019 13:11:10.763 * Running mode=standalone, port=6379.
redis_container | 1:M 22 Dec 2019 13:11:10.763 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
redis_container | 1:M 22 Dec 2019 13:11:10.763 # Server initialized
redis_container | 1:M 22 Dec 2019 13:11:10.763 # WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix this issue run the command 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' as root, and add it to your /etc/rc.local in order to retain the setting after a reboot. Redis must be restarted after THP is disabled.
redis_container | 1:M 22 Dec 2019 13:11:10.764 * DB loaded from disk: 0.000 seconds
redis_container | 1:M 22 Dec 2019 13:11:10.764 * Ready to accept connections
server_1  | Prepare to serve

通過docker ps看到啟動了兩個容器,一個是redis,一個是我們的主程序:

測試

測試的客戶端用的gRPC的圖形化工具BloomRPC,安裝方法比較簡單:brew cask install bloomrpc

然后導入我們的gRPC定義文件server.proto就能點擊測試:

 

總結

本文從工程實踐的角度帶讀者實現了一個通過gRPC通信的增刪查Redis的微服務,希望對讀者有所啟發。

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM