admin 管理员组

文章数量: 887021

golang:

项目官网

项目官网:
项目地址:

环境准备

go-zero-demo

go-zero-demo里面包含了文档中所有源码的一个大仓库,后续我们在编写演示demo时,我们均在此项目下创建子项目, 因此我们需要提前创建一个大仓库go-zero-demo,我这里把这个仓库放在home目录下。

$ mkdir go-zero-demo&&cd go-zero-demo
$ go mod init go-zero-demo
go: creating new go.mod: module go-zero-demo
$ ls
go.mod

开发流程

  • goctl环境准备
  • 数据库设计
  • 业务开发
  • 新建工程
  • 创建服务目录
  • 创建服务类型(api/rpc/rmq/job/script)
  • 编写api、proto文件
  • 代码生成
  • 生成数据库访问层代码model
  • 配置config,yaml变更
  • 资源依赖填充(ServiceContext)
  • 添加中间件
  • 业务代码填充
  • 错误处理

golang环境安装

目前已经安装好了

$ go version
go version go1.18.3 linux/amd64

Go Module设置

即Go Module是Golang管理依赖性的方式,像Java中的Maven,Android中的Gradle类似。

(1)查看GO111MODULE开启情况

$ go env GO111MODULE
on

开启GO111MODULE,如果已开启(即执行go env GO111MODULE结果为on)请跳过。

$ go env -w GO111MODULE="on"

(2)设置GOPROXY

$ go env -w GOPROXY=

(3)设置GOMODCACHE

查看GOMODCACHE

$ go env GOMODCACHE

如果目录不为空或者/dev/null,请跳过。

go env -w GOMODCACHE=$GOPATH/pkg/mod

protoc & protoc-gen-go安装

protoc是一款用C++编写的工具,其可以将proto文件翻译为指定语言的代码。在go-zero的微服务中,我们采用grpc进行服务间的通信,而grpc的编写就需要用到protoc和翻译成go语言rpc stub代码的插件protoc-gen-go。

$ protoc --version
libprotoc 3.20.2

安装 goctl 工具

goctl 读作 go control,不要读成 go C-T-L。goctl 的意思是不要被代码控制,而是要去控制它。其中的 go 不是指 golang。

cd go-zero-learningGOPROXY=/,direct go install github.com/zeromicro/go-zero/tools/goctl@latest

官网在此

goctl 是 go-zero 微服务框架下的代码生成工具。使用 goctl 可显著提升开发效率,让开发人员将时间重点放在业务开发上。

goctl 的命令可归纳为如下几类:

  • API 命令,快速生成一个 API 服务
  • rpc 命令,支持 proto 模板生成和 rpc 服务代码生成
  • model 命令,目前支持识别 mysql ddl 进行 model 层代码生成
  • plugin 命令,支持针对 API 自定义插件
  • 其他命令,目前是发布相关

goctl 的命令众多,本次涉及到的只是其中 API、rpc 和 model 相关的基础命令。

其他

在之前我们已经对Go环境、Go Module配置、Goctl、protoc & protoc-gen-go安装准备就绪,这些是开发人员在开发阶段必须要准备的环境,而接下来的环境你可以选择性的安装, 因为这些环境一般存在于服务器(安装工作运维会替你完成),但是为了后续演示流程能够完整走下去,我建议大家在本地也安装一下,因为我们的演示环境大部分会以本地为主。 以下仅给出了需要的准备工作,不以文档篇幅作详细介绍了。

  • etcd
  • redis
  • mysql

开发规范

命名规范

文件命名规范

  • 全部小写
  • 除unit test外避免下划线(_)
  • 文件名称不宜过长

变量命名规范参考

  • 首字母小写
  • 驼峰命名
  • 见名知义,避免拼音替代英文
  • 不建议包含下划线(_)
  • 不建议包含数字

函数、常量命名规范#

  • 驼峰式命名
  • 可exported的必须首字母大写
  • 不可exported的必须首字母小写
  • 避免全部大写与下划线(_)组合

编码规范

import

  • 单行import不建议用圆括号包裹
  • 按照官方包,NEW LINE,当前工程包,NEW LINE,第三方依赖包顺序引入
import ("context""string""greet/user/internal/config""google.golang.org/grpc"
)

函数返回

  • 对象避免非指针返回
  • 遵循有正常值返回则一定无error,有error则一定无正常值返回的原则

错误处理

  • 有error必须处理,如果不能处理就必须抛出。
  • 避免下划线(_)接收error

函数体编码

  • 建议一个block结束空一行,如if、for等
func main (){if x==1{// do something}fmt.println("xxx")
}
  • return前空一行
func getUser(id string)(string,error){....return "xx",nil
}

配置介绍

api配置

api配置控制着api服务中的各种功能,包含但不限于服务监听地址,端口,环境配置,日志配置等,下面我们从一个简单的配置来看一下api中常用配置分别有什么作用。

rpc配置

rpc配置控制着一个rpc服务的各种功能,包含但不限于监听地址,etcd配置,超时,熔断配置等,下面我们以一个常见的rpc服务配置来进行说明。

快速开始

单体服务

创建项目

$ mkdir go-zero-demo&&cd go-zero-demo
$ go mod init go-zero-demo
go: creating new go.mod: module go-zero-demo
$  goctl api new greet
Done.
$ go mod tidy
go: finding module for package github.com/zeromicro/go-zero/core/conf
go: finding module for package github.com/zeromicro/go-zero/core/logx
go: finding module for package github.com/zeromicro/go-zero/rest
go: finding module for package github.com/zeromicro/go-zero/rest/httpx
go: found github.com/zeromicro/go-zero/core/conf in github.com/zeromicro/go-zero v1.5.1
go: found github.com/zeromicro/go-zero/rest in github.com/zeromicro/go-zero v1.5.1
go: found github.com/zeromicro/go-zero/rest/httpx in github.com/zeromicro/go-zero v1.5.1
go: found github.com/zeromicro/go-zero/core/logx in github.com/zeromicro/go-zero v1.5.1

查看一下greet服务的目录结构

$ tree
.
├── go.mod
├── go.sum
└── greet├── etc│   └── greet-api.yaml├── greet.api├── greet.go└── internal├── config│   └── config.go├── handler│   ├── greethandler.go│   └── routes.go├── logic│   └── greetlogic.go├── svc│   └── servicecontext.go└── types└── types.go8 directories, 11 files

由以上目录结构可以观察到,greet服务虽小,但"五脏俱全"。接下来我们就可以在greetlogic.go中编写业务代码了。

编写逻辑

$ gedit  greet/internal/logic/greetlogic.go func (l *GreetLogic) Greet(req *types.Request) (*types.Response, error) {return &types.Response{Message: "Hello go-zero",}, nil
}

启动并访问服务

$ cd greet
$ go run greet.go -f etc/greet-api.yaml
Starting server at 0.0.0.0:8888...

默认侦听在 8888 端口(可以在配置文件里修改),可以通过 curl 请求:

$  curl -i http://localhost:8888/from/you
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Traceparent: 00-da4f919bb0a5400045020c0d414e0466-302de9c064b54d0e-00
Date: Wed, 12 Apr 2023 02:22:58 GMT
Content-Length: 4

微服务

本小节将以一个订单服务调用用户服务来简单演示一下,演示代码仅传递思路,其中有些环节不会一一列举。

场景提要

假设我们在开发一个商城项目,而开发者小明负责用户模块(user)和订单模块(order)的开发,我们姑且将这两个模块拆分成两个微服务①

目标

  • 订单服务(order)提供一个查询接口
  • 用户服务(user)提供一个方法供订单服务获取用户信息

分析

根据情景提要我们可以得知,订单是直接面向用户,通过http协议访问数据,而订单内部需要获取用户的一些基础数据,既然我们的服务是采用微服务的架构设计, 那么两个服务(user, order)就必须要进行数据交换,服务间的数据交换即服务间的通讯,到了这里,采用合理的通讯协议也是一个开发人员需要 考虑的事情,可以通过http,rpc等方式来进行通讯,这里我们选择rpc来实现服务间的通讯,相信这里我已经对"rpc服务存在有什么作用?"已经作了一个比较好的场景描述。 当然,一个服务开发前远不止这点设计分析,我们这里就不详细描述了。从上文得知,我们需要一个

  • user rpc
  • order api

两个服务来初步实现这个小demo。

实现

创建mall工程

$ mkdir go-zero-demo&&cd go-zero-demo
$ go mod init go-zero-demo
go: creating new go.mod: module go-zero-demo
$ ls
go.mod

创建user rpc服务

(1)创建目录

$ mkdir -p mall/user/rpc
$ tree
.
├── go.mod
└── mall└── user└── rpc3 directories, 1 file

(2)添加user.proto文件,增加getUser方法

syntax = "proto3";package user;// protoc-gen-go 版本大于1.4.0, proto文件需要加上go_package,否则无法生成
option go_package = "./user";message IdRequest {string id = 1;
}message UserResponse {// 用户idstring id = 1;// 用户名称string name = 2;// 用户性别string gender = 3;
}service User {rpc getUser(IdRequest) returns(UserResponse);
}

(3)生成代码 如未安装 protoc,protoc-gen-go,protoc-gen-grpc-go 你可以通过如下指令一键安装:

$ goctl env check -i -f

每一个 *.proto文件只允许有一个service error: only one service expected

$ cd mall/user/rpc
$ ls
user.proto
$ goctl rpc protoc user.proto --go_out=./types --go-grpc_out=./types --zrpc_out=.
Done.

(4)填充业务逻辑

$ gedit  internal/logic/getuserlogic.go

创建order api服务

  • 创建 order api目录
//回到 go-zero-demo/mall 目录
$ cd ../../
$ ls
user
$ mkdir -p order/api && cd order/api
  • 添加api文件
$  gedit order.api
type(OrderReq {Id string `path:"id"`}OrderReply {Id string `json:"id"`Name string `json:"name"`}
)
service order {@handler getOrderget /api/order/get/:id (OrderReq) returns (OrderReply)
}
  • 生成order服务
$ goctl api go -api order.api -dir .
Done.
  • 添加user rpc配置
$  gedit internal/config/config.go
package configimport ("github.com/zeromicro/go-zero/zrpc""github.com/zeromicro/go-zero/rest"
)type Config struct {rest.RestConfUserRpc zrpc.RpcClientConf
}
  • 添加yaml配置
$ gedit  etc/order.yaml 
Name: order
Host: 0.0.0.0
Port: 8888
UserRpc:Etcd:Hosts:- 127.0.0.1:2379Key: user.rpc
  • 完善服务依赖
gedit internal/svc/servicecontext.go
  • 添加order演示逻辑
    • 给 getorderlogic 添加业务逻辑
$ vim internal/logic/getorderlogic.go
package logicimport ("context""errors""go-zero-demo/mall/order/api/internal/svc""go-zero-demo/mall/order/api/internal/types""go-zero-demo/mall/user/rpc/types/user""github.com/zeromicro/go-zero/core/logx"
)type GetOrderLogic struct {logx.Loggerctx    context.ContextsvcCtx *svc.ServiceContext
}func NewGetOrderLogic(ctx context.Context, svcCtx *svc.ServiceContext) GetOrderLogic {return GetOrderLogic{Logger: logx.WithContext(ctx),ctx:    ctx,svcCtx: svcCtx,}
}func (l *GetOrderLogic) GetOrder(req *types.OrderReq) (*types.OrderReply, error) {user, err := l.svcCtx.UserRpc.GetUser(l.ctx, &user.IdRequest{Id: "1",})if err != nil {return nil, err}if user.Name != "test" {return nil, errors.New("用户不存在")}return &types.OrderReply{Id:   req.Id,Name: "test order",}, nil
}

本文标签: golang