背景

在之前的文章《漫谈微服务》我已经简单的介绍过微服务,微服务特性是轻量级跨平台和跨语言的服务,也列举了比较了集中微服务通信的手段的利弊,本文将通过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的微服务,希望对读者有所启发。

  


Golang微服务实践的更多相关文章

  1. 【GoLang】GoLang 微服务、开源库等参考资料

    参考资料: GoLang书籍: https://github.com/dariubs/GoBooksGo名库: https://github.com/Unknwon/go-rock-libraries ...

  2. 干货 | 国内互联网公司是如何做微服务实践的?(附PPT下载)

    微服务的概念最早由Martin Fowler与James Lewis于2014年共同提出,并随着Netflix最佳实践的发布而为业界所知.如今,在国内有了大量的微服务实践案例,5月18日,网易云联合云 ...

  3. golang 微服务以及相关web框架

    golang 中国gocn golang Applicable to all database connection pools xorm是一个简单而强大的Go语言ORM库,通过它可以使数据库操作非常 ...

  4. 【GoLang】golang 微服务框架 go-kit

    golang-Microservice Go kit - A toolkit for microservices kubernetes go-kit_百度搜索 Peter Bourgon谈使用Go和& ...

  5. 2019年微服务实践第一课,网易&谐云&蘑菇街&奥思技术大咖深度分享

    微服务的概念最早由Martin Fowler与James Lewis于2014年共同提出,核心思想是围绕业务能力组织服务,各个微服务可被独立部署,服务间是松耦合的关系,以及数据和治理的去中心化管理.微 ...

  6. QCon技术干货:个推基于Docker和Kubernetes的微服务实践

    2016年伊始,Docker无比兴盛,如今Kubernetes万人瞩目.在这个无比需要创新与速度的时代,由容器.微服务.DevOps构成的云原生席卷整个IT界.在近期举办的QCon全球软件开发大会上, ...

  7. .NET CORE微服务实践

    .NET CORE微服务实践 https://www.cnblogs.com/zengqinglei/p/9570343.html .NET CORE 实践部署架构图 实践源码:https://git ...

  8. SFDC 微服务实践之路 2016.12.10 杭州(整理)--转

    原文地址:http://mp.weixin.qq.com/s/8cC4Ewt6yPjnxdYxuNZlFQ 微服务是什么? 微服务是一种细粒度(Fine-Grain)的SOA 或许在座的高朋了解过其概 ...

  9. 微服务实践(七):从单体式架构迁移到微服务架构 - DockOne.io

    原文:微服务实践(七):从单体式架构迁移到微服务架构 - DockOne.io [编者的话]这是用微服务开发应用系列博客的第七篇也是最后一篇.第一篇中介绍了微服务架构模式,并且讨论了微服架构的优缺点: ...

随机推荐

  1. golang学习笔记---string && strconv

    1.字符串的组成?Golang的字符串都是由单个字节连接起来的,每个字节都是UTF8编码标识的Unicode文本.(不需要在考虑中文不兼容问题) 2.如何遍历字符串?先看一个例子: package m ...

  2. mysql解决Fatal error encountered during command execution. 500内部错误

    Asp.net 连接mysql 会出现Fatal error encountered during command execution.的错误 解决办法如下: 连接字符串添加  Allow User ...

  3. SQL参数化出现执行慢问题

    问题: 应用程序通过参数化访问数据库时出现执行效率慢,直接通过语句查时秒出结果,通过参数化查询时用时是前者的几十上百倍. 排查:1.使用了错误的执行计划; 解决:清除缓存的执行计划(未能解决上面问题) ...

  4. Winform 后台生成饼状图并保存为图片

    .cs代码如下 string ldt_picPath = System.Windows.Forms.Application.StartupPath + @"Pic\" + Item ...

  5. 开发技术--Numpy模块

    开发|Numpy模块 Numpy模块是数据分析基础包,所以还是很重要的,耐心去体会Numpy这个工具可以做什么,我将从源码与 地产呢个实现方式说起,祝大家阅读愉快! Numpy模块提供了两个重要对象: ...

  6. 解决PL/SQL使用无法导出dmp

    解决PL/SQL使用无法导出dmp 1.配置plsql Export Executable:D:\app\product\11.2.0\dbhome_1\BIN\exp.exe 2.配置环境变量ORA ...

  7. 无线安全审计工具FruityWifi初体验

    FruityWIfi是一款有名的无线安全审计的开源工具,其灵感来自于wifipineapple,目前该工具已经更新到2.4.它能够让用户通过web界面来控制和管理模块,十分方便.FriutyWifi最 ...

  8. Cocos Creator (JavaScript手机类型判断)

    手机类型判断 var BrowserInfo = { userAgent: navigator.userAgent.toLowerCase() isAndroid: Boolean(navigator ...

  9. idea svn 文件还原到指定版本

    使用svn经常会遇见,由于自己或者其他同事的提交(或者误操作),把原本正确代码或文件覆盖掉了,现在就得需要恢复到之前指定的某个版本. 先打开指定的文件,然后右上角点击时间的按钮: 这比会出现以前的许多 ...

  10. jmeter+jenkins配置过程

    目录 前置条件 脚本规划 讲解非GUI方式运行脚本 在jenkins里面新建项目 在Jmeter的jtl结果文件转换成html页面 邮件.配置 前置条件 1.jmeter安装好并已配置好环境变量,可正 ...