/micro-demo

A microservice demo in golang.

Primary LanguageGoMIT LicenseMIT

Golang 微服务项目模板

这个模板主要使用 echo 提供 restful api, 目标是实现微服务体系中的一个业务服务,它 可以随意扩展。

一些基础设施的代码在 x

这里主要是业务代码

关于项目结构

关于项目结构,在 golang 的世界中争议颇大,有很多流派。

MVC/MVVM 流

本人不喜欢按层管理结构,确切的说是在微服务中再对代码横向按层分隔,本来微服务的一 个服务中业务内容就不多,因为已经被纵向分隔过了。这时尽量把相关的业务代码集中才更 容易维护。

在单体项目中,按层分隔代码是没有问题的。

"Standard"流

这个主要是使用 golang-standards/project-layout 的建议。

去他的 Issues 区看看吧,很多人有和我一样的观点,你发布一个 layout 没问题,但是自 己把它叫做 Standard 就太无耻了,带偏了很多初入 golang 的新人。

我在任何时候都不建议这个结构

平铺流

把所有文件都放在根目录下,适合小项目,这也是 golang 社区最初的建议。

我的 restdemo 就是这种结构的演示。

在单体小项目的情况下,推荐这个结构,可以让你把精力都集中在业务代码上。

其他

在 reddit 和 maillist 等地方其实经常讨论项目目录结构,我也在 3 年中尝试过四五种 不同的结构,它们各有优缺点,很难有一个尽善尽美的。

下面我会说一下本项目的文件结构考虑。

本案例项目结构

结构不是万能的,这个结构在以下条件下才更有优势:

  • 微服务中的业务模块,单个服务中管理的实体不多。
  • 倾向于使用 rest api 对外服务
  • 倾向于使用事件驱动的设计模式,让服务间通讯最优先选择 pub/sub 模式的异步通讯
  • 服务间同步通讯可以用 rest api,也可以用 grpc,但不作为主要通讯方式。这条很重要 ,如果主要选择 rpc 去通讯,可以去用一些成熟的微服务框架。
  • 使用了 vscode 或 goland ,最好启用了 gopls
  • 使用了 go module
  • 参与的程序员要认可使用 go 的模式去写 golang 代码。如果主要语言是别的,golang 项目只是参与以下,可能来回切换会很不习惯。

实体模型

我倾向于把实体模型放在根目录,但是如果根目录不是本来的项目名称,或者强迫症嫌根目 录有别的文件,那单独用这个项目名称做一个文件夹,里边放实体模型的定义。在这个项目 中是 demo 文件夹。

实体附带的一些方法当然也可以放在一起,如果有 client 或者 sdk 之类的东西,其 定义以及 New 的方法最好也放在这个文件夹。

这个文件夹是要被别的服务引用的,被引用的一般只有 模型 和 Client 。

业务代码

把模型外的业务代码全部放在 server 文件夹中。代码量不大可以每个实体就用一个 go 文件。代码量如果大,可以像这个例子一样,把同一个实体相关的代码,按照层分在不同的 文件中。但是它们在目录中还是会被排列到一起的,很方便查看业务代码。

这个例子中只写了 park 的 service 和对普通用户/管理员的 rest handler 。如果要添加 服务间调用的 rpc,可以继续再来一个 park_rpc.go 就好。如果有处理队列消息的订阅者 ,可以放在 park_worker.go 中,诸如此类。

总之最高宗旨就是把业务代码集中在一起,让协作的人和将来的自己更好阅读代码。

main 函数

我们服务端一般只有一个可执行程序,按照管理把它放在 cmd 中,如果将来有别的服务端 程序要启动,也预留了地方,在 cmd 中再来个文件夹就好了。

认证

  • endpoint 可以分为四组
    • 默认 通过 gateway 暴露,公开
    • user 通过 gateway 暴露,需要用户登录认证
    • admin 通过 gateway 暴露,需要管理员登录认证
    • sys 只能内部服务间访问,内部公开
  • 认证的接口必定能在 context 中取到相关字段
    • jwt 方案解析 token 写入 context
    • oauth 方案配合 session 读出常用的权限写入 context 即可

部署

部署方面,中小项目可以按照下边的极简方案来,需要学习的东西最少。大项目上各种微服 务工具都是支持的。

  • 服务发现和负载均衡使用 docker swarm 即可,内部直接用服务名访问别的服务。
  • API gateway 可以选用 nginx 或者 caddy
  • 使用事件驱动**,能异步的交互全部用异步,采用 nsq 等 pub/sub 模型的消息队列实 现。

Dockerfile

  • 使用两段构建,先 build ,再把二级制文件复制到生产镜像
  • 生产镜像使用了我略微修改的 debian
    • 增加证书,用以在镜像内访问别的 https 资源,否则会报 x509
    • 指定了**时区