go-zero

news/2024/11/27 2:10:44/

目录

  • 引入
    • 开发派系
      • 标准库/自研派系——不要让框架束缚开发
      • web框架派系——gin+grpc
      • 大一统框架
  • go-zero
  • go-zero快速实现一个微服务
    • user service
    • order api server
    • 启动
  • goctl
    • 安装
    • 生成的api网关目录
    • 生成的pb目录
    • api语法
      • syntax
      • import语法块
      • info
      • type
      • service
      • 注释
    • 命令大全

引入

在这里插入图片描述
该图片来自微软开源的一个容器商城项目:eShopOnContainers,其中红框部分就是各个微服务模块。

每一个微服务都是一个独立的生态,比较直观的一点是各自拥有独立的数据库。

微服务化后,带来了诸多好处,比如弹性,敏捷,灵活扩展,易于部署,可重用代码等。

但也带来了复杂性,让整个架构变得不易于维护,所以诞生出来很多组件用于辅助,这些组件同样成为了微服务架构中的一员:

  1. 服务网关:确保服务提供者对客户端的透明,这一层可以进行反向路由,安全认证,灰度发布,日志监控等前置动作。
    在这里插入图片描述
  2. 服务发现:注册并维护远程服务及服务提供者的地址,供服务消费者发现和调用,如:etcd,consul等
  3. 服务框架:实现了rpc框架,包含服务接口描述和实现,向注册中心发布服务等功能,比如grpc等
  4. 服务监控:对服务消费者与提供者之间的的调用情况进行监控和数据展示比如:普罗米修斯(prometheus)
  5. 服务追踪:记录每个请求的为服务器调用完整链路,以便进行问题定位和故障分析,比如jeager,zipkin等
  6. 服务治理:服务治理就是通过一系列的手段来保证在各种意外情况下,服务调用仍然能够正常进行,这些手段包括熔断,隔离,限流,降级,负载均衡等,比如:Sentinel等.
  7. 基础设施:用以提供服务底层的基础数据服务,比如分布式消息队列,日志存储,数据库,缓存,文件服务器,搜索集群。比如:kafka,mysql,pgsql,mongodb,redis,minio,elasticSearch等。
  8. 分布式配置中心:统一配置,比如nacos,consul,zk,apollo等
  9. 分布式事务:dtm,seata等
  10. 容器以及容器编排:docker,k8s等
  11. 定时任务

综上,容器时微服务架构的绝佳示例,现代云原生应用使用容器来构建微服务。

开发派系

标准库/自研派系——不要让框架束缚开发

  1. 对于go标准库的强大(稳定,高性能),让很多开发者不使用框架也可以写出高效的应用程序。
  2. 微服务的基础是通信,也就是rpc框架的选择,大部分会选择grpc或者基于grpc的基础进行自研rpc框架的开发
  3. 其他组件需要的时候,进行集成就可以了,而不是非得用某个框架定义的组件。
  4. 如果部署采用k8s,并且使用服务网格,比如Istio来处理,那么开发者只需要关心业务逻辑即可,不需要关心服务发现,熔断,流量控制,负载均衡。

web框架派系——gin+grpc

  1. 由于标准库到web框架开发仍然需要一定量的开发工作,所以选择成熟的gin框架,出现了grpc+gin核心,其他组件集成进来的微服务框架。
  2. gin在这里可以作为grpc网关使用,写一些限流中间件,认证中间件。通过在api view中调用内部的微服务,对外提供服务。
  3. 同样可以使用k8s+istio.

大一统框架

  1. 使用框架能减轻工作量,达到快速开发的目的。代价就是遵循框架的规则。
  2. go的微服务框架比较多,如:go-zero,go-micro,go-kit…
  3. go-zero是一个不错的选择,其社区活跃,文档齐全。

go-zero

在这里插入图片描述

go-zero 是一个集成了各种工程实践的包含 web 和 rpc 框架,有如下主要特点:

  1. 强大的工具支持,尽可能少的代码编写
  2. 极简的接口
  3. 完全兼容 net/http
  4. 支持中间件,方便扩展
  5. 高性能
  6. 面向故障编程,弹性设计
  7. 内建服务发现、负载均衡
  8. 内建限流、熔断、降载,且自动触发,自动恢复
  9. API 参数自动校验
  10. 超时级联控制
  11. 自动缓存控制
  12. 链路跟踪、统计报警等
  13. 高并发支撑,稳定保障了疫情期间每天的流量洪峰

在这里插入图片描述

go-zero快速实现一个微服务

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

user service

  1. 创建user目录

  2. 编写proto文件:

    syntax = "proto3";package user;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. 使用goctl生成go-zero模板和pb文件:goctl rpc protoc user.proto --go_out=./types --go-grpc_out=./types --zrpc_out=.

  4. 实现查询用户的功能:

    func (l *GetUserLogic) GetUser(in *user.IdRequest) (*user.UserResponse, error) {return &user.UserResponse{Id:     in.Id,Name:   "generalzy",Gender: "武装直升机",}, nil
    }
    

    在这里插入图片描述

  5. go build编译

order api server

  1. 创建order目录

  2. 编写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)
    }
    
  3. 使用goctl生成api:goctl api go -api order.api -dir .

  4. 配置user config:

    type Config struct {rest.RestConfUserRpc zrpc.RpcClientConf
    }
    

    在这里插入图片描述

  5. 配置yaml:

    Name: order
    Host: 0.0.0.0
    Port: 8888
    UserRpc:Etcd:Hosts:- 127.0.0.1:2379Key: user.rpc
    
  6. 完善服务依赖(将user放入到order的上下文)

    type ServiceContext struct {Config  config.ConfigUserRpc user.User
    }func NewServiceContext(c config.Config) *ServiceContext {return &ServiceContext{Config:  c,UserRpc: user.NewUser(zrpc.MustNewClient(c.UserRpc)),}
    }
    

    在这里插入图片描述

  7. 编写order业务逻辑

func (l *GetOrderLogic) GetOrder(req *types.OrderReq) (resp *types.OrderReply, err error) {u, err := l.svcCtx.UserRpc.GetUser(l.ctx, &user.IdRequest{Id: "1",})if err != nil {return nil, err}if u.Name != "generalzy" {return nil, errors.New("用户不存在")}return &types.OrderReply{Id:   req.Id,Name: "test order",}, nil
}

在这里插入图片描述

  1. go build编译

启动

  1. 启动etcd:etcd.exe
    在这里插入图片描述
  2. 启动user:user.exe -f ./etc/user.yaml
  3. 启动order:order.exe -f ./etc/order.yaml
  4. 访问url:http://localhost:8888/api/order/get/1返回:{"id":"1","name":"test order"}

goctl

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

  1. api服务生成
  2. rpc服务生成
  3. model代码生成
  4. 模板管理

安装

go install github.com/zeromicro/go-zero/tools/goctl@latest

生成的api网关目录

.
├── etc
│   └── greet-api.yaml              // 配置文件
├── go.mod                          // mod文件
├── greet.api                       // api描述文件
├── greet.go                        // main函数入口
└── internal                        ├── config  │   └── config.go               // 配置声明type├── handler                     // 路由及handler转发│   ├── greethandler.go│   └── routes.go├── logic                       // 业务逻辑│   └── greetlogic.go├── middleware                  // 中间件文件│   └── greetmiddleware.go├── svc                         // logic所依赖的资源池│   └── servicecontext.go└── types                       // request、response的struct,根据api自动生成,不建议编辑└── types.go

生成的pb目录

.
├── etc
│   └── greet.yaml
├── go.mod
├── go.sum
├── greet // [1]
│   ├── greet.pb.go
│   └── greet_grpc.pb.go
├── greet.go
├── greet.proto
├── internal
│   ├── config
│   │   └── config.go
│   ├── logic
│   │   └── greetlogic.go
│   ├── server
│   │   └── streamgreeterserver.go
│   └── svc
│       └── servicecontext.go
└── streamgreeter└── streamgreeter.go

api语法

  • syntax语法声明
  • import语法块
  • info语法块
  • type语法块
  • service语法块
  • 隐藏通道

syntax

一个api语法文件只能有0或者1个syntax语法声明,如果没有syntax,则默认为v1版本

// api语法版本
syntax = "v1"

import语法块

import语法块可以导入拆分的api文件, 不同的api文件按照一定规则声明,可以降低阅读难度和维护难度。

import "foo.api"
import "foo/bar.api"import("bar.api""foo/bar/foo.api"
)

info

info语法块是一个包含了多个键值对的语法体,其作用相当于一个api服务的描述

info(foo: "foo value"bar: "bar value"desc: "long long long long long long text"
)

type

在api服务中,需要用到一个结构体(类)来作为请求体,响应体的载体,因此需要声明一些结构体来完成这件事情, type语法块由golang的type演变而来,保留着一些golang type的特性,沿用golang特性有:

  1. 保留了golang内置数据类型bool,int,int8,int16,int32,int64,uint,uint8,uint16,uint32,uint64,uintptr ,float32,float64,complex64,complex128,string,byte,rune,
  2. 兼容golang struct风格声明
  3. 保留golang关键字
  4. 不支持time.Time数据类型,用int64表示,因为api支持客户端代码生成,并非所有客户端语言都有time.Time对应的类型
  5. 结构体名称、字段名称、不能为golang关键字
type Foo{Id int `path:"id"`Foo int `json:"foo"`
}type Bar{Bar int `form:"bar"`
}type(FooBar{FooBar int `json:"fooBar"`}
)

tag定义和golang中json tag语法一样,除了json tag外,go-zero还提供了另外一些tag来实现对字段的描述, 详情见下表。(tag修饰符需要在tag value后以英文逗号,隔开)

  • tag表

    绑定参数时,以下四个tag只能选择其中一个

    tag key描述提供方有效范围 示例
    jsonjson序列化taggolangrequest、responsejson:"fooo"
    path路由path,如/foo/:idgo-zerorequestpath:"id"
    form标志请求体是一个form(POST方法时)或者一个query(GET方法时/search?name=keyword)go-zerorequestform:"name"
    headerHTTP header,如 Name: valuego-zerorequestheader:"name"
  • tag修饰符

    常见参数校验描述

    tag key 描述 提供方 有效范围 示例
    optional定义当前字段为可选参数go-zerorequestjson:"name,optional"
    options定义当前字段的枚举值,多个以竖线|隔开go-zerorequestjson:"gender,options=male"
    default定义当前字段默认值go-zerorequestjson:"gender,default=male"
    range定义当前字段数值范围go-zerorequestjson:"age,range=[0:120]"

service

service语法块用于定义api服务,包含服务名称,服务metadata,中间件声明,路由,handler等。

语法:

  1. serviceSpec:包含了一个可选语法块atServer和serviceApi语法块,其遵循序列模式(编写service必须要按照顺序,否则会解析出错)

  2. atServer: 可选语法块,定义key-value结构的server metadata,‘@server’ 表示这一个server语法块的开始,其可以用于描述serviceApi或者route语法块,其用于描述不同语法块时有一些特殊关键key 需要值得注意,见 atServer关键key描述说明。

  3. serviceApi:包含了1到多个serviceRoute语法块

  4. serviceRoute:按照序列模式包含了atDoc,handler和route

  5. atDoc:可选语法块,一个路由的key-value描述,其在解析后会传递到spec.Spec结构体,如果不关心传递到spec.Spec, 推荐用单行注释替代。

  6. handler:是对路由的handler层描述,可以通过atServer指定handler key来指定handler名称, 也可以直接用atHandler语法块来定义handler名称

  7. atHandler:‘@handler’ 固定token,后接一个遵循正则[a-zA-Z][a-zA-Z-]*)的值,用于声明一个handler名称

  8. route:路由,有httpMethod、path、可选request、可选response组成,httpMethod是必须是小写。

  9. body:api请求体语法定义,必须要由()包裹的可选的ID值

  10. replyBody:api响应体语法定义,必须由()包裹的struct、array(向前兼容处理,后续可能会废弃,强烈推荐以struct包裹,不要直接用array作为响应体)

  11. kvLit: 同info key-value

  12. serviceName: 可以有多个’-'join的ID值

  13. path:api请求路径,必须以’/‘或者’/:‘开头,切不能以’/‘结尾,中间可包含ID或者多个以’-'join的ID字符串

atServer关键key:

修饰service时

key描述示例
jwt声明当前service下所有路由需要jwt鉴权,且会自动生成包含jwt逻辑的代码jwt: Auth
group声明当前service或者路由文件分组group: login
middleware声明当前service需要开启中间件middleware: AuthMiddleware
prefix添加路由分组prefix: api

修饰route时

key描述示例
handler声明一个handler-
@server(jwt: Authgroup: foomiddleware: AuthMiddlewareprefix: api
)
service foo-api{@doc "foo"@handler foopost /foo/:id (Foo) returns (Bar)
}service foo-api{@handler pingget /ping@doc "foo"@handler barpost /bar/:id (Foo)
}

注释

// doc
// comment

命令大全


http://www.ppmy.cn/news/61883.html

相关文章

开放原子训练营(第三季)inBuilder低代码开发实验室---报销单录入系统

作为一名低代码初学者,我使用inBuilder系统设计了一款报销单录入系统,实现了报销单录入与显示报销单列表的功能(如图1与图2所示),并获得了很多开发心得。从inBuilder系统的优点、缺点以及开发过程三方面出发&#xff0…

Three.js--》模型材质与纹理的使用

目录 初识材质与纹理 修改模型材质颜色 模型添加纹理 纹理常用属性使用 纹理显示算法 设置粗糙度 纹理加载进度情况 设置环境贴图 初识材质与纹理 three.js中的材质就是几何体表面的材料。所有材质均继承自Material。ThreeJS的材质分为:基础材质、深度材质…

深入理解 Linux 内核(二)

系列文章目录 Linux 内核设计与实现 深入理解 Linux 内核(一) 深入理解 Linux 内核(二) Linux 设备驱动程序 Linux设备驱动开发详解 文章目录 系列文章目录六、定时测量1、时钟和定时器电路2、Linux 计时体系结构(1&am…

Python每日一练:最长递增的区间长度(一行代码花样解法)

文章目录 前言一、题目二、一行超人三、分析一下思路 总结 前言 很显然,Python的受众远远大于C,其实笔者本人对Python的理解也是远强于C的,C纯粹是为了假装笔者是个职业选手才随便玩玩的,借着十多年前学的C的功底,强行…

树脂塞孔有哪些优缺点及应用?

树脂塞孔的概述 树脂塞孔就是利用导电或者非导电树脂,通过印刷,利用一切可能的方式,在机械通孔、机械盲埋孔等各种类型的孔内进行填充,实现塞孔的目的。 树脂塞孔的目的 1 树脂填充各种盲埋孔之后,利于层压的真空下…

Android 13 变更及适配攻略

准备工作 首先将我们项目中的 targetSdkVersion和compileSdkVersion 升至 33。 影响Android 13上所有应用 1.通知受限 对新安装的应用的影响: 如果用户在搭载 Android 13 或更高版本的设备上安装您的应用,应用的通知默认处于关闭状态。在您请求新的…

多通道振弦传感器无线采集仪通过短信和FTP文件修改参数

多通道振弦传感器无线采集仪通过短信和FTP文件修改参数 通过短信修改参数 向设备发送参数修改指令,设备在下次采发过程中若收到包含有合法指令的短信时会解析并执行短信内的指令,参数修改完成后会以短信形式回发应答信息。短信指令的格式如下&#xff1a…

各种ID生成策略对比

1. id⾃增的劣势 问题:当数据量庞⼤时,在数据库分库分表后,数据库⾃增id不能满⾜唯⼀id来标识数据;因为每个表都按⾃⼰节奏⾃增,会造成id冲突,⽆法满⾜需求。 所以分布式id就有了一定规则 - 全局唯一&…