如何快速构建微服务项目(Phanes )

Phanes 快速构建微服务项目

目录

项目介绍

Phanes 的初衷为快速构建微服务项目而生,基于go-micro, 提供了一个 CMD 命令行工具用于生成脚手架,后续还会有生成代码功能,类似 PHP Laravel 框架的命令行生成工具。帮助快速构建一个微服务项目。 项目本身提供了大部分微服务必须的组件,让你只需要关注业务开发。

项目基本功能

  • 支持自动服务注册和服务发现
  • 支持负载均衡,服务熔断等
  • 支持Open-Telemetry可检测日志/链路追踪/指标监控
  • 支持事件总线
  • 支持各类型数据库
  • 支持灵活的Http Middleware和gRpc middleware
  • 支持配置中心配置热加载

快速体验

安装 cmd 工具


go install github.com/phanes-o/phanes@v0.1.0

使用 cmd 工具创建项目脚手架


phanes new helloworld

执行tree helloworld 你将看到如下结构


helloworld

├── Dockerfile

├── README.md

├── bll // 业务罗基础

│ ├── init.go

│ └── user.go

├── client // 客户端抽象层

│ ├── broker // 代理客户端

│ │ ├── init.go

│ │ ├── nats.go

│ │ └── rabbit.go

│ ├── grpc // grpc 客户端

│ │ └── init.go

│ ├── httpc // http 客户端

│ │ └── init.go

│ ├── init.go

│ └── websocket // websocket 客户端

│ └── init.go

├── collector // 系统监控

│ ├── init.go

│ ├── logger // 日志

│ │ ├── file_output.go

│ │ ├── init.go

│ │ ├── log.go

│ │ ├── otlp.go

│ │ ├── redis_output.go

│ │ └── zap.go

│ ├── metrics // 指标监控

│ │ ├── init.go

│ │ └── prometheus.go

│ └── trace // 链路追踪

│ └── init.go

├── config // 系统配置

│ ├── conf.go

│ ├── init.go

│ └── redis.go

├── docker-compose.yaml // 基础服务

├── errors // 错误处理

│ ├── error.go

│ └── error_type.go

├── event // 事件总线

│ ├── data.go

│ └── event.go

├── go.mod

├── go.sum

├── lib // 库

│ ├── example_server // 自定义服务

│ │ └── init.go

│ ├── trace // 链路追踪封装实现

│ │ └── trace.go

│ └── traefik // traefik 自动注册

│ ├── etcd.go

│ ├── traefik.go

│ └── traefik_test.go

├── main.go

├── makefile

├── model // 模型

│ ├── entity // 实体映射

│ │ └── user.go

│ ├── mapping // 映射处理

│ │ └── mapping.go

│ ├── model.go

│ └── user.go

├── script // 脚本文件

│ ├── config.json

│ ├── down.sql

│ ├── index.sql

│ └── up.sql

├── server // 服务

│ ├── example_server // 自定义示例服务

│ │ └── init.go

│ ├── grpc // grpc 服务

│ │ ├── init.go

│ │ ├── middleware // grpc 中间件

│ │ │ ├── log.go

│ │ │ └── trace.go

│ │ └── v1 // v1版本接口

│ │ └── user.go

│ ├── init.go

│ └── web // http 服务

│ ├── init.go

│ ├── middleware // http 中间件

│ │ └── log.go

│ └── v1 // v1 版本接口

│ ├── init.go

│ └── user.go

├── store // 数据存储抽象

│ ├── init.go

│ ├── mysql // mysql 实现

│ │ └── init.go

│ ├── postgres // postgres 实现

│ │ ├── init.go

│ │ └── user.go

│ ├── redis // redis 实现

│ │ └── init.go

│ └── user.go

└── utils // 通用工具集

└── utils.go

metric 目前暂未实现, 后续添加, 目前也只支持 etcd 作为注册中心和配置中心

修改配置文件


{

"name": "phanes",

"env": "develop",

"version": "0.1.0",

"http_listen": ":7771",

"collect": {

"log": {

"file_name": "admin",

"redis_key": "log_list"

},

"trace": {

"addr": ""

},

"metric": {

"addr": ""

}

},

"db": [

{

"type": "postgres",

"addr": "host=127.0.0.1 user=root password=root dbname=phanes port=5432 sslmode=disable TimeZone=Asia/Shanghai",

"user": "root",

"pwd": "root"

},

{

"type": "redis",

"addr": "127.0.0.1:6379",

"user": "",

"pwd": ""

}

],

"proxy": {

"domain": "http://127.0.0.1",

"prefix": "/phanes"

},

"broker": {

"type": "rabbitmq",

"addr": "amqp://coco:kk123123123@127.0.0.1:5672/",

"user": "",

"pwd": ""

},

"traefik": {

"enabled": false,

"domain": "test.com",

"prefix": "/phanes"

}

}

启动项目基础服务

项目依赖:Mysql或者 PostgresNats或者RabbitMQRedisEtcdJaeger(测试时非必需),Otel-Collector(测试时非必需)

可使用脚手架下提供的 docker-compose.yaml 启动以上依赖服务, 启动命令: docker-compose up -d, 基于已安装docker的前提下

项目使用Etcd作为注册中心和配置中心,目前只支持Etcd 作为注册中心和配置中心,后续会添加consul支持

写入配置文件到配置中心

在项目根目录执行 make config 将修改好的配置文件写入配置中心 etcd , 基于已安装 etcdctl

项目介绍

1. CMD 工具

提供方便的项目生成工具,目前支持以下命令:

  • phanes new project_name

其他更方便使用的工具命令正在开发中…

2. 项目基础脚手架

基础脚手架提供了微服务的基础代码架构,在执行 phanes new project_name你就将得到一个全新的微服务基础架构代码

3. proto

提供一个仓库供多个微服务项目引入

Example:

用户管理

用户请求流程可以是 gRpc,也可以是 Http代码逻辑流程如下:

gRpc→bll→store(Mysql)

http→bll→store(Mysql)

  1. bll(业务逻辑) 层代码, /bll/user.go

package bll

import (

"context"

"github.com/phanes-o/proto/base"

"github.com/phanes-o/proto/dto"

log "go-micro.dev/v4/logger"

"phanes/errors"

"phanes/event"

"phanes/model/entity"

"phanes/store"

"phanes/store/postgres"

)

var  User = &user{}

type  user  struct {

// bll 层需要使用存储层提供数据存储

user store.IUser

}

// 事件监听

func (a *user) onEvent(ed* event.Data) {

}

// 初始化 user

func (a* user) init() func() {

a.user = postgres.NewUser()

return  func() {}

}

// 创建用户

func (a* user) Create(ctx context.Context, in* dto.CreateUserRequest) (err error) {

u := &entity.User{

Username: in.Username,

Password: in.Password,

}

_, err = a.user.Create(u)

if err != nil {

log.Error(err)

return errors.Wrap(err, "user create failed")

}

return  nil

}

// 删除用户

func (a *user) Delete(ctx context.Context, p* base.Int64) error {

return a.user.Delete(p.Value)

}
  1. store(存储抽象层) 接口代码 /store/user.go

package store

import (

"phanes/model/entity"

)

// User 存储层抽象

type  IUser  interface {

Create(u* entity.User) (id int64, err error)

Find(id int64) (user* entity.User, err error)

Update(id int64, updates map[string]interface{}) (err error)

Delete(id int64) (err error)

List(opts map[string]interface{}) (users []*entity.User, err error)

}
  1. mysql(存储接口实现)代码 /store/mysql/user.go

package mysql

import (

"phanes/model/entity"

)

type  user  struct{}

func  NewUser() *user {

return &user{}

}

func (a* user) Create(u* entity.User) (id int64, err error) {

err = db.Model(&entity.User{}).Create(u).Error

return u.ID, err

}

func (a* user) Find(id int64) (user* entity.User, err error) {

u := new(entity.User)

err = db.Model(&entity.User{}).Find(u, id).Error

return

}

func (a* user) Update(id int64, updates map[string]interface{}) (err error) {

return db.Model(&entity.User{}).Where("id = ?", id).Updates(updates).Error

}

func (a* user) Delete(id int64) (err error) {

return db.Delete(&entity.User{}, id).Error

}

func (a* user) List(opts map[string]interface{}) (users []*entity.User, err error) {

// todo: implement

return  nil, nil

}
  1. gRpc Api 接口层代码 /server/grpc/v1/user.go

package v1

import (

"context"

"github.com/phanes-o/proto/base"

"github.com/phanes-o/proto/dto"

"phanes/bll"

)

type  User  struct{}

func (u *User) Create(ctx context.Context, request* dto.CreateUserRequest, empty* base.Empty) error {

return bll.User.Create(ctx, request)

}

func (u* User) Delete(ctx context.Context, p* base.Int64, empty* base.Empty) error {

return bll.User.Delete(ctx, p)

}
  1. HttpApi 接口层代码, /server/web/v1/user.go

package v1

import (

"github.com/gin-gonic/gin"

"github.com/phanes-o/proto/base"

"github.com/phanes-o/proto/dto"

"phanes/bll"

"phanes/errors"

)

var  User = &user{}

type  user  struct{}

func (a* user) Init(r* gin.RouterGroup) {

u := r.Group("user")

{

u.POST("register", a.register)

u.DELETE("/:value", a.delete)

}

}

func (a* user) register(c* gin.Context) {

var  u = &dto.CreateUserRequest{}

if  err := c.ShouldBindJSON(&u); err != nil {

c.Error(err)

return

}

// 此处处理参数确实错误并返回,错误由拦截器拦截处理,并根据错误码返回对应的 Http StatusCode

if u.Username == "" {

c.Error(errors.BadRequest.New("username is required"))

return

}

if u.Password == "" {

c.Error(errors.BadRequest.New("password is required"))

return

}

if  err := bll.User.Create(c.Request.Context(), u); err != nil {

c.Error(err)

return

}

c.JSON(200, gin.H{

"code": 0,

"msg": "success",

})

}

func (a* user) delete(c* gin.Context) {

d := &base.Int64{}

if  err := c.ShouldBindJSON(&d); err != nil {

c.Error(err)

return

}

if  err := bll.User.Delete(c.Request.Context(), d); err != nil {

c.Error(err)

return

}

c.JSON(200, gin.H{

"code": 0,

"msg": "success",

})

}

以上均为示例代码,所以部分未实现,只做展示使用。

错误处理

错误处理封装在 /errors


errors.BadRequest.New("password is required")

日志/链路追踪/指标监控

目前实现了 日志/链路追踪,并添加了对应的中间件和拦截器,指标监控目前还未完成

根据以上代码示例可以发现,我们只需要专注三个层面的开发: 接口->业务逻辑->数据存储。可能也会涉及事件,MQ的使用,后续会有专门的文字来介绍

有好想法和建议可以给我们提 issues, 项目日志如下:
脚手架项目: github.com/phanes-o/phanes-layout
命令行工具项目:github.com/phanes-o/phanes

本作品采用《CC 协议》,转载必须注明作者和本文链接
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!