Golang微服務實踐

背景

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

 

實驗環境

Mac OSjava

go version go1.12.4 darwin/amd64git

Docker version 18.09.2, build 6247962github

 

代碼倉庫

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

 

微服務實踐

gRPC代碼生成

選用gRPC的緣由是由於gRPC自己是一款開源且高性能的RPC框架,支持跨平臺,支持golang,java,c,C++ 等10多種編程語言。由於咱們要實現一個經過gRPC通訊的基於Redis 數據庫的增刪改微服務,因此咱們首先須要定義一個gRPC的通訊描述文件server.proto:redis

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的編譯器:docker

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文件。api

./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的微服務,但願對讀者有所啓發。

相關文章
相關標籤/搜索