教程集 www.jiaochengji.com
教程集 >  Golang编程  >  golang教程  >  正文 arcgis datastore服务不可用_Golang 微服务教程(三)

arcgis datastore服务不可用_Golang 微服务教程(三)

发布时间:2021-05-29   编辑:jiaochengji.com
教程集为您提供arcgis datastore服务不可用,Golang 微服务教程(三)等资源,欢迎您收藏本站,我们将为您提供最新的arcgis datastore服务不可用,Golang 微服务教程(三)资源

Golang 微服务教程(三)

发表于 2018-05-22 | 阅读次数: | 字数统计: 5,102

原文链接:ewanvalentine.io,翻译已获作者 Ewan Valentine 授权。

本文完整代码:GitHub

在上节中,我们使用 go-micro 重新实现了微服务并进行了 Docker 化,但是每个微服务都要单独维护自己的 Makefile 未免过于繁琐。本节将学习 docker-compose 来统一管理和部署微服务,引入第三个微服务 user-service 并进行存储数据。

MongoDB 与 Postgres

微服务的数据存储

到目前为止,consignment-cli 要托运的货物数据直接存储在 consignment-service 管理的内存中,当服务重启时这些数据将会丢失。为了便于管理和搜索货物信息,需将其存储到数据库中。

可以为每个独立运行的微服务提供独立的数据库,不过因为管理繁琐少有人这么做。如何为不同的微服务选择合适的数据库,可参考:How to choose a database for your microservices

选择关系型数据库与 NoSQL

如果对存储数据的可靠性、一致性要求不那么高,那 NoSQL 将是很好的选择,因为它能存储的数据格式十分灵活,比如常常将数据存为 JSON 进行处理,在本节中选用性能和生态俱佳的MongoDB

如果要存储的数据本身就比较完整,数据之间关系也有较强关联性的话,可以选用关系型数据库。事先捋一下要存储数据的结构,根据业务看一下是读更多还是写更多?高频查询的复不复杂?… 鉴于本文的较小的数据量与操作,作者选用了 Postgres,读者可自行更换为 MySQL 等。

更多参考:如何选择NoSQL数据库、梳理关系型数据库和NoSQL的使用情景

docker-compose

引入原因

上节把微服务 Docker 化后,使其运行在轻量级、只包含服务必需依赖的容器中。到目前为止,要想启动微服务的容器,均在其 Makefile 中 docker run 的同时设置其环境变量,服务多了以后管理起来十分麻烦。

基本使用

docker-compose 工具能直接用一个 docker-compose.yaml 来编排管理多个容器,同时设置各容器的 metadata 和 run-time 环境(环境变量),文件的 service 配置项来像先前 docker run 命令一样来启动容器。举个例子:

docker 命令管理容器

$ docker run -p 50052:50051  -e MICRO_SERVER_ADDRESS=:50051  -e MICRO_REGISTRY=mdns  vessel-service

等效于 docker-compose 来管理

version: '3.1'vessel-service: build: ./vessel-service ports: - 50052:50051 environment: MICRO_ADRESS: ":50051" MICRO_REGISTRY: "mdns"

想加减和配置微服务,直接修改 docker-compose.yaml,是十分方便的。

更多参考:使用 docker-compose 编排容器

编排当前项目的容器

针对当前项目,使用 docker-compose 管理 3 个容器,在项目根目录下新建文件:

# docker-compose.yaml# 同样遵循严格的缩进version: '3.1'# services 定义容器列表services: consignment-cli: build: ./consignment-cli environment: MICRO_REGISTRY: "mdns" consignment-service: build: ./consignment-service ports: - 50051:50051 environment: MICRO_ADRESS: ":50051" MICRO_REGISTRY: "mdns" DB_HOST: "datastore:27017" vessel-service: build: ./vessel-service ports: - 50052:50051 environment: MICRO_ADRESS: ":50051" MICRO_REGISTRY: "mdns"

首先,我们指定了要使用的 docker-compose 的版本是 3.1,然后使用 services 来列出了三个待管理的容器。

每个微服务都定义了自己容器的名字, build 指定目录下的 Dockerfile 将会用来编译镜像,也可以直接使用 image 选项直接指向已编译好的镜像(后边会用到);其他选项则指定了容器的端口映射规则、环境变量等。

可使用 docker-compose build 来编译生成三个对应的镜像;使用 docker-compose run 来运行指定的容器, docker-compose up -d 可在后台运行;使用 docker stop $(docker ps -aq ) 来停止所有正在运行的容器。

运行效果

使用 docker-compose 的运行效果如下:

Protobuf 与数据库操作

复用及其局限性

到目前为止,我们的两个 protobuf 协议文件,定义了微服务客户端与服务端数据请求、响应的数据结构。由于 protobuf 的规范性,也可将其生成的 struct 作为数据库表 Model 进行数据操作。这种复用有其局限性,比如 protobuf 中数据类型必须与数据库表字段严格一致,二者是高耦合的。很多人并不赞将 protobuf 数据结构作为数据库中的表结构:Do you use Protobufs in place of structs ?

中间层逻辑转换

一般来说,在表结构变化后与 protobuf 不一致,需要在二者之间做一层逻辑转换,处理差异字段:

func (service *Service)(ctx context.Context, req *proto.User, res *proto.Response) error {entity := &models.User{Name: req.Name.Email: req.Email,Password: req.Password,}err := service.repo.Create(entity)// 无中间转换层// err := service.repo.Create(req)...}

这样隔离数据库实体 models 和 proto.* 结构体,似乎很方便。但当 .proto 中定义 message 各种嵌套时,models 也要对应嵌套,比较麻烦。

上边隔不隔离由读者自行决定,就我个人而言,中间用 models 做转换是不太有必要的,protobuf 已足够规范,直接使用即可。

consignment-service 重构

回头看第一个微服务 consignment-service,会发现服务端实现、接口实现等都往 main.go 里边塞,功能跑通了,现在要拆分代码,使项目结构更加清晰,更易维护。

MVC 代码结构

对于熟悉 MVC 开发模式的同学来说,可能会把代码按功能拆分到不同目录中,比如:

main.gomodels/ user.gohandlers/ auth.go  user.goservices/ auth.go

微服务代码结构

不过这种组织方式并不是 Golang 的 style,因为微服务是切割出来独立的,要做到简洁明了。对于大型 Golang 项目,应该如下组织:

main.gousers/ services/ auth.go handlers/ auth.go user.go users/ user.gocontainers/ services/ manage.go models/ container.go

这种组织方式叫领域(domain)驱动,而不是 MVC 的功能驱动。

consignment-service 的重构

由于微服务的简洁性,我们会把该服务相关的代码全放到一个文件夹下,同时为每个文件起一个合适的名字。

在 consignmet-service/ 下创建三个文件:handler.go、datastore.go 和 repository.go

consignmet-service/  ├── Dockerfile ├── Makefile ├── datastore.go# 创建与 MongoDB 的主会话 ├── handler.go# 实现微服务的服务端,处理业务逻辑 ├── main.go# 注册并启动服务 ├── proto └── repository.go# 实现数据库的基本 CURD 操作

负责连接 MongoDB 的 datastore.go

package mainimport "gopkg.in/mgo.v2"// 创建与 MongoDB 交互的主回话func CreateSession(host string) (*mgo.Session, error) {s, err := mgo.Dial(host)if err != nil {return nil, err}s.SetMode(mgo.Monotonic, true)return s, nil}

连接 MongoDB 的代码够精简,传参是数据库地址,返回数据库会话以及可能发生的错误,在微服务启动的时候就会去连接数据库。

负责与 MongoDB 交互的 repository.go

现在让我们来将 main.go 与数据库交互的代码拆解出来,可以参考注释加以理解:

package mainimport (...)const (DB_NAME = "shippy"CON_COLLECTION = "consignments")type Repository interface {Create(*pb.Consignment) errorGetAll() ([]*pb.Consignment, error)Close()}type ConsignmentRepository struct {session *mgo.Session}// 接口实现func (repo *ConsignmentRepository) Create(c *pb.Consignment) error {return repo.collection().Insert(c)}// 获取全部数据func (repo *ConsignmentRepository) GetAll() ([]*pb.Consignment, error) {var cons []*pb.Consignment// Find() 一般用来执行查询,如果想执行 select * 则直接传入 nil 即可// 通过 .All() 将查询结果绑定到 cons 变量上// 对应的 .One() 则只取第一行记录err := repo.collection().Find(nil).All(&cons)return cons, err}// 关闭连接func (repo *ConsignmentRepository) Close() {// Close() 会在每次查询结束的时候关闭会话// Mgo 会在启动的时候生成一个 "主" 会话// 你可以使用 Copy() 直接从主会话复制出新会话来执行,即每个查询都会有自己的数据库会话// 同时每个会话都有自己连接到数据库的 socket 及错误处理,这么做既安全又高效// 如果只使用一个连接到数据库的主 socket 来执行查询,那很多请求处理都会阻塞// Mgo 因此能在不使用锁的情况下完美处理并发请求// 不过弊端就是,每次查询结束之后,必须确保数据库会话要手动 Close// 否则将建立过多无用的连接,白白浪费数据库资源repo.session.Close()}// 返回所有货物信息func (repo *ConsignmentRepository) collection() *mgo.Collection {return repo.session.DB(DB_NAME).C(CON_COLLECTION)}

拆分后的 main.go

package mainimport (...)const (DEFAULT_HOST = "localhost:27017")func main() {// 获取容器设置的数据库地址环境变量的值dbHost := os.Getenv("DB_HOST")if dbHost == ""{ dbHost = DEFAULT_HOST}session, err := CreateSession(dbHost)// 创建于 MongoDB 的主会话,需在退出 main() 时候手动释放连接defer session.Close()if err != nil {log.Fatalf("create session error: %v
到此这篇关于“arcgis datastore服务不可用_Golang 微服务教程(三)”的文章就介绍到这了,更多文章或继续浏览下面的相关文章,希望大家以后多多支持JQ教程网!

您可能感兴趣的文章:
arcgis datastore服务不可用_Golang 微服务教程(三)
golang微服务框架对比_golang微服务框架gozero系列4:gozero文件服务
golang 字符串分割_Golang 微服务教程(四)
golang微服务框架对比_Golang 微服务教程(一)
golang微服务框架对比_Golang 微服务教程(二)
golang微服务框架对比_Golang 中的微服务 - 第一部分
php服务器用什么系统
PHP 微服务集群搭建 - Hyperf
php的web容器有哪些
云原生环境下微服务管理系统开发

[关闭]
~ ~