gitee.com/woood2/luca@v1.0.4/docs/README.md (about)

     1  
     2  ### 概述
     3  LUCA Enterprise Framework(简称luca)是一款支持多入口、开箱即用的企业级Golang框架。
     4  在设计哲学上,luca更接近于 [整洁架构](https://book.douban.com/subject/30333919/) ,而非 [Spring](https://spring.io/) 这种包办一切的大管家。
     5  - 支持4种作业类型:Restful服务、微服务、定时任务、队列消费。
     6  - 配套设施整合:注册/配置中心、链路追踪、日志收集、指标监控、熔断器、API文档。
     7  - 程序设计实践:错误处理、分层、依赖注入、数据库、缓存、多环境、优雅关闭、灰度发布、单元测试。
     8  
     9  ![avatar](https://gitee.com/woood2/luca/raw/master/docs/overview.png)
    10  
    11  ### 初始化
    12  ```
    13  wget https://gitee.com/woood2/luca/raw/master/scripts/gen.sh
    14  chmod +x ./gen.sh
    15  ./gen.sh
    16  ```
    17  
    18  ### 目录结构
    19  遵循:[社区规范](https://github.com/golang-standards/project-layout/blob/master/README_zh.md)  
    20  
    21  ``` 
    22  ├── cmd
    23  │   ├── backend                     Restful服务
    24  │   │   ├── README.md
    25  │   │   ├── docs                    swagger文档
    26  │   │   │   ├── docs.go
    27  │   │   │   ├── swagger.json
    28  │   │   │   └── swagger.yaml
    29  │   │   ├── internal
    30  │   │   │   ├── assembly            装配器
    31  │   │   │   │   ├── route.go
    32  │   │   │   │   └── sdk.go
    33  │   │   │   ├── controller          C层
    34  │   │   │   │   └── app.go
    35  │   │   │   └── middleware          中间件
    36  │   │   │       ├── auth.go
    37  │   │   │       ├── metrics.go
    38  │   │   │       ├── oplog.go
    39  │   │   │       ├── perm.go
    40  │   │   │       └── trace.go
    41  │   │   └── main.go
    42  │   ├── consumer                    队列消费
    43  │   │   ├── internal
    44  │   │   │   ├── alarm               告警
    45  │   │   │   │   ├── alarm.go
    46  │   │   │   │   └── watcher.go
    47  │   │   │   ├── handler             C层
    48  │   │   │   │   ├── greet_one.go
    49  │   │   │   │   ├── greet_two.go
    50  │   │   │   │   └── groups.go
    51  │   │   │   ├── middleware          中间件
    52  │   │   │   │   ├── logging.go
    53  │   │   │   │   ├── metrics.go
    54  │   │   │   │   └── trace.go
    55  │   │   │   └── subscriber          订阅者
    56  │   │   │       ├── chain.go
    57  │   │   │       ├── msg_handler.go
    58  │   │   │       ├── retry_consumer.go
    59  │   │   │       └── subscriber.go
    60  │   │   └── main.go
    61  │   ├── cron                        定时任务
    62  │   │   ├── internal
    63  │   │   │   ├── handler             C层
    64  │   │   │   │   ├── greet.go
    65  │   │   │   │   ├── hello.go
    66  │   │   │   │   └── set.go
    67  │   │   │   ├── job                 作业
    68  │   │   │   │   ├── chain.go
    69  │   │   │   │   ├── job.go
    70  │   │   │   │   └── list.go
    71  │   │   │   └── middleware          中间件
    72  │   │   │       ├── logging.go
    73  │   │   │       └── trace.go
    74  │   │   └── main.go
    75  │   └── micro                       微服务
    76  │       ├── internal
    77  │       │   ├── endpoint            C层
    78  │       │   │   ├── check_perm.go
    79  │       │   │   ├── check_token.go
    80  │       │   │   └── validate.go
    81  │       │   ├── grpc                通信层
    82  │       │   │   ├── check_perm.go
    83  │       │   │   ├── check_token.go
    84  │       │   │   ├── grpc_health_v1
    85  │       │   │   │   ├── health.pb.go
    86  │       │   │   │   ├── health.proto
    87  │       │   │   │   ├── health_grpc.pb.go
    88  │       │   │   │   ├── health_impl.go
    89  │       │   │   │   └── protoc.sh
    90  │       │   │   ├── pb
    91  │       │   │   │   ├── protoc.sh
    92  │       │   │   │   ├── server.pb.go
    93  │       │   │   │   ├── server.proto
    94  │       │   │   │   └── server_grpc.pb.go
    95  │       │   │   └── set.go
    96  │       │   ├── middleware          中间件
    97  │       │   │   ├── auth
    98  │       │   │   │   ├── context.go
    99  │       │   │   │   ├── middleware.go
   100  │       │   │   │   ├── option.go
   101  │       │   │   │   └── token.go
   102  │       │   │   ├── chain.go
   103  │       │   │   ├── logging
   104  │       │   │   │   └── middleware.go
   105  │       │   │   └── metrics
   106  │       │   │       └── middleware.go
   107  │       │   ├── output              输出
   108  │       │   │   └── format.go
   109  │       │   └── param               参数
   110  │       │       ├── check_perm.go
   111  │       │       └── check_token.go
   112  │       ├── main.go
   113  │       └── pkg                     SDK
   114  │           ├── check_perm.go
   115  │           ├── check_token.go
   116  │           ├── err.go
   117  │           └── sdk.go
   118  ├── configs                         配置文件
   119  │   ├── application-example.yml
   120  │   └── application.yml
   121  ├── deployments                     部署
   122  │   ├── docker
   123  │   │   ├── docker-compose-example.yml
   124  │   │   ├── docker-compose.yml
   125  │   │   ├── prometheus-example.yml
   126  │   │   └── prometheus.yml
   127  │   ├── nav-example.html
   128  │   └── nav.html
   129  ├── docs                            文档
   130  ├── go.mod
   131  ├── go.sum
   132  ├── internal
   133  │   ├── cache                       缓存
   134  │   │   ├── cache.go
   135  │   │   ├── dict.go         
   136  │   │   ├── key.go
   137  │   │   ├── local.go
   138  │   │   ├── local_test.go
   139  │   │   ├── miss.go
   140  │   │   ├── nop.go
   141  │   │   ├── protector.go
   142  │   │   ├── redis.go
   143  │   │   ├── redis_test.go
   144  │   │   └── serialization.go
   145  │   ├── conf                        配置
   146  │   │   └── attr.go
   147  │   ├── db                          数据库
   148  │   │   ├── gorm.go
   149  │   │   ├── mongo.go
   150  │   │   └── zapgorm2
   151  │   │       └── zapgorm2.go
   152  │   ├── discovery                   服务发现
   153  │   │   └── consul.go
   154  │   ├── errcode                     错误
   155  │   │   ├── business.go
   156  │   │   ├── micro.go
   157  │   │   ├── resp.go
   158  │   │   └── restful.go
   159  │   ├── layer                       分层
   160  │   │   ├── controller.go
   161  │   │   ├── repository.go
   162  │   │   └── service.go
   163  │   ├── log                         日志
   164  │   │   └── zap.go
   165  │   ├── mq                          消息
   166  │   │   ├── greet.go
   167  │   │   └── greet_test.go
   168  │   ├── producer                    队列生产
   169  │   │   ├── sarama_producer.go
   170  │   │   └── scram_client.go
   171  │   ├── repository                  DAO层
   172  │   │   ├── app.go
   173  │   │   ├── app_test.go
   174  │   │   ├── student.go
   175  │   │   └── student_test.go
   176  │   ├── sdk                         SDK引用
   177  │   │   └── demo.go
   178  │   ├── service                     service层
   179  │   │   ├── acl.go
   180  │   │   ├── app.go
   181  │   │   └── app_test.go
   182  │   ├── status                      状态
   183  │   │   ├── ginpprof.go
   184  │   │   ├── hystrix.go
   185  │   │   └── prometheus.go
   186  │   ├── trace                       链路追踪
   187  │   │   └── zipkin.go
   188  │   └── util                        工具
   189  │       ├── file.go
   190  │       ├── jsontime.go
   191  │       ├── md5.go
   192  │       └── test.go
   193  ├── scripts                         脚本
   194  │   ├── init.sql
   195  │   ├── init.sh
   196  └── test
   197      └── grpc_client                 微服务本地测试
   198          └── main.go
   199  ```
   200      
   201  ### 多入口
   202  [cmd/](https://gitee.com/woood2/luca/tree/master/cmd) 默认拥有4个子目录,对应4个入口、4种作业类型。
   203  ```
   204  ├── cmd
   205  │   ├── backend                     Restful服务
   206  │   │   ├── README.md
   207  │   │   ├── docs                    
   208  │   │   ├── internal
   209  │   │   └── main.go
   210  │   ├── consumer                    队列消费
   211  │   │   ├── internal
   212  │   │   └── main.go
   213  │   ├── cron                        定时任务
   214  │   │   ├── internal
   215  │   │   └── main.go
   216  │   └── micro                       微服务
   217  │       ├── internal
   218  │       ├── main.go
   219  │       └── pkg                     
   220  ```
   221  
   222  入口专用的代码存放于 [cmd/](https://gitee.com/woood2/luca/tree/master/cmd) 的子目录中,跨入口公用的代码存放于 [internal/](https://gitee.com/woood2/luca/tree/master/internal) 下,例如:
   223  - backend Controller层代码:[cmd/backend/internal/controller/](https://gitee.com/woood2/luca/tree/master/cmd/backend/internal/controller)
   224  - Service层代码:[internal/service/](https://gitee.com/woood2/luca/tree/master/internal/service)
   225  - Repository层代码:[internal/repository/](https://gitee.com/woood2/luca/tree/master/internal/repository)
   226  
   227  同一种作业类型,可以创建多个入口。例如:项目中允许存在`backend`与`frontend`两个Restful服务。
   228  
   229  示例1:添加`frontend`入口
   230  1. 复制目录:`cp -a cmd/backend cmd/frontend`
   231  2. 在 `cmd/frontend` 路径下批量替换:`backend=>frontend`、`Backend=>Frontend`
   232  3. 修改配置:[internal/conf/attr.go](https://gitee.com/woood2/luca/tree/master/internal/conf/attr.go) 、[configs/application-example.yml](https://gitee.com/woood2/luca/tree/master/configs/application-example.yml) 
   233  
   234  示例2:删除`frontend`入口
   235  1. 删除目录:`rm -rf cmd/frontend`
   236  2. 修改配置:[internal/conf/attr.go](https://gitee.com/woood2/luca/tree/master/internal/conf/attr.go) 、[configs/application-example.yml](https://gitee.com/woood2/luca/tree/master/configs/application-example.yml)
   237  
   238  ### 运行
   239  步骤1:安装Go环境以及所依赖的服务,详见 [deployments/README.md](https://gitee.com/woood2/luca/tree/master/deployments/README.md) 。
   240    
   241  步骤2:执行init脚本,键入本机IP,生成 `configs/application.yml`。
   242  ```
   243  cd scripts
   244  ./init.sh
   245  ``` 
   246  
   247  步骤3:按需修改 `configs/application.yml`。
   248  
   249  步骤4:执行 `go run cmd/{xyz}/main.go`。
   250      
   251  ### 配置
   252  文件路径
   253  - 本地开发:`configs/application.yml`
   254  - 远程部署:`程序运行目录/application.yml`
   255  
   256  文件结构
   257  - stub:用于设置本机host以及配置类型。
   258  - detail:可供多个go程序实例复用的详细配置,根据stub设置决定其存放位置。
   259  
   260  stub详解
   261  
   262  |  一级   | 二级  | 说明  | 示例  |
   263  |  ----  | ----  | ----  | ----  |
   264  | host  |  | 本机IP地址 | 192.168.1.100 |
   265  | configType  |  | file:本地文件 consul:配置中心 | consul |
   266  | dataKey  |  | consul kv键名 | config/luca/attr |
   267  | consul  |  |  |  |
   268  |   | host | consul主机 | 192.168.1.100 |    
   269  |   | port | consul端口 | 8500 |    
   270      
   271  本地文件示例
   272  ```
   273  application.yml
   274  
   275  # === stub part ===
   276  host: {ip}
   277  configType: file
   278  dataKey: 
   279  consul:
   280    host: 
   281    port: 
   282  # === detail part ===
   283  project: luca
   284  mysql:
   285    user: root
   286    pwd: '123456'
   287    host: {ip}
   288    port: 3306
   289    db: luca
   290  ```
   291  
   292  配置中心示例
   293  ```
   294  application.yml
   295  
   296  # === stub part ===
   297  host: {ip}
   298  configType: consul
   299  dataKey: config/luca/attr
   300  consul:
   301    host: {ip}
   302    port: 8500
   303  
   304  访问consul后台,配置KV字典如下:
   305  < Key/Values < config < luca 
   306  attr 
   307  
   308  Value 
   309      # === detail part ===
   310      project: luca
   311      mysql:
   312        user: root
   313        pwd: '123456'
   314        host: {ip}
   315        port: 3306
   316        db: luca
   317  ```
   318      
   319  detail详解
   320  
   321  |  一级   | 二级  | 说明  | 示例  |
   322  |  ----  | ----  | ----  | ----  |
   323  | project  |  | 项目名 | luca |
   324  | env  |  | 环境:dev/demo/test/pre/pro | dev |
   325  | consoleLog  |  | true:控制台日志<br/>false:文件日志 | true |
   326  | pprof  |  |  | |
   327  |   | user | 用户名 | qjs |
   328  |   | pwd | 密码 | 731 |
   329  | mysql  |  |  | |
   330  |   | user | 用户名 | root |
   331  |   | pwd | 密码 | 123456 |
   332  |   | host | 主机 | 192.168.1.100 |
   333  |   | port | 端口 | 3306 |
   334  |   | db | 数据库 | luca |
   335  |   | maxOpenConns | 最大连接数 | 30 |
   336  |   | maxIdleConns | 最大空闲连接数 | 10 |
   337  | mongo  |  |  | |
   338  |   | user | 用户名 | woood2 |
   339  |   | pwd | 密码 | 123456 |
   340  |   | host | 主机 | 192.168.1.100 |
   341  |   | port | 端口 | 27017 |
   342  |   | db | 数据库 | luca |
   343  |   | maxPoolSize | 最大连接数 | 30 |
   344  |   | minPoolSize | 最小连接数 | 10 |
   345  | redis  |  |  | |
   346  |   | addr | 地址 | 192.168.1.100:6379 |
   347  |   | pwd | 密码 |  |
   348  |   | poolSize | 最大连接数 | 30 |
   349  |   | minIdleConns | 最小空闲连接数 | 10 |
   350  | zipkin  |  |  | |
   351  |   | reporterAddr | 上报地址(允许为空)| 192.168.1.100:6379 |
   352  | kafka  |  |  | |
   353  |   | version | 版本 | 2.5.0 |
   354  |   | brokers | broker地址(允许多个) | 192.168.1.100:9092 |
   355  |   | enableSASL | 是否开启SASL | true |
   356  |   | user | 用户名 | qjs |
   357  |   | password | 密码 | 731 |
   358  |   | algorithm | 算法 | sha256 |
   359  | backend  |  |  | |
   360  |   | addr | Restful服务地址 | :8080 |
   361  |   | register | 是否注册到consul | true |
   362  |   | pprofAddr | pprof地址 | :6059 |
   363  |   | metricsAddr | metrics地址 | :8082 |
   364  |   | hystrixPort | hystrix端口 | 8282 |
   365  |   | allowOrigins | 允许来源(允许多个) | * |
   366  | micro  |  |  | |
   367  |   | port | 端口 | 8081 |
   368  |   | register | 是否注册到consul | true |
   369  |   | pprofAddr | pprof地址 | :6060 |
   370  |   | metricsAddr | metrics地址 | :6061 |
   371  |   | hystrixPort | hystrix端口 | 8283 |
   372  | consumer  |  |  | |
   373  |   | pprofAddr | pprof地址 | :6064 |
   374  |   | metricsAddr | metrics地址 | :6063 |
   375  |   | hystrixPort | hystrix端口 | 8084 |
   376  | cron  |  |  | |
   377  |   | pprofAddr | pprof地址 | :6065 |
   378  |   | hystrixPort | hystrix端口 | 8085 |
   379  
   380  ### 错误处理
   381  luca倡导在项目中基于 [github.com/pkg/errors](https://github.com/pkg/errors) 传递 error,而非使用 panic-recover。
   382  
   383  统一的错误字典
   384  - Restful服务通用错误:[internal/errcode/restful.go](https://gitee.com/woood2/luca/tree/master/internal/errcode/restful.go)
   385  - 微服务通用错误:[internal/errcode/micro.go](https://gitee.com/woood2/luca/tree/master/internal/errcode/micro.go)
   386  - 业务逻辑错误:[internal/errcode/business.go](https://gitee.com/woood2/luca/tree/master/internal/errcode/business.go)
   387  
   388  为了对调用者友好,微服务SDK冗余了一份错误字典
   389  - 微服务通用错误:[cmd/micro/pkg/err_micro.go](https://gitee.com/woood2/luca/tree/master/cmd/micro/pkg/err_micro.go)
   390  - 业务逻辑错误:[cmd/micro/pkg/err_business.go](https://gitee.com/woood2/luca/tree/master/cmd/micro/pkg/err_business.go)
   391  
   392  更新方式
   393  ```
   394  cd cmd/micro/pkg
   395  ./update_err.sh
   396  ```
   397  
   398  Resp结构体:[internal/errcode/resp.go](https://gitee.com/woood2/luca/tree/master/internal/errcode/resp.go)
   399  ```
   400  package errcode
   401  //4 restful & micro service
   402  type Resp struct {
   403  	ErrCode string      `json:"errCode"`
   404  	ErrMsg  string      `json:"errMsg"`
   405  	Data    interface{} `json:"data"`
   406  	TraceID string      `json:"traceID"` //only 4 restful
   407  	Stack   string      `json:"stack"`   //only 4 restful, non-pro env
   408  }
   409  ```
   410  
   411  一次`Restful请求`的错误处理
   412  - 当程序走入错误分支或者发生内部错误,一个`error`对象被逐层传递到最上层的`controller`中。
   413  - 持有这个`error`对象的`controller`前往`错误字典`查找对应的`错误代码`,并封装成`Resp`对象作为http返回值。
   414  - 每个`错误代码`对应一条程序分支,通常由用户的错误操作引发,例如"用户名或密码错误",无需记录日志,`http code`为200。
   415  - 找不到`错误代码`的`error`统一归为`errcode.ServerErr`并且记录一条error等级的日志,`http code`为500。
   416  - 顺利走完程序主分支的成功请求,`Resp.ErrCode`与`Resp.ErrMsg`均为空值,`Resp.Data`携带返回值正文,`http code`为200。
   417  
   418  一次`微服务调用`的错误处理
   419  - 当程序走入错误分支或者发生内部错误,一个`error`对象被逐层传递到最上层的`endpoint`中。
   420  - 持有这个`error`对象的`endpoint`前往`错误字典`查找对应的`错误代码`,并封装成`Resp`对象作为返回值。
   421  - 每个`错误代码`对应一条程序分支,通常由client的非法调用引发,例如"非法的鉴权凭证",无需记录日志,无需对接`hystrix`。
   422  - 找不到`错误代码`的`error`需要记录一条error等级的日志,并且对接`hystrix`。
   423  - 顺利走完程序主分支的成功调用,`Resp.ErrCode`与`Resp.ErrMsg`均为空值,`Resp.Data`携带返回值正文。
   424  
   425  Crash-free
   426  - 尽管luca不主张使用`panic-recover`,但无法保证第三方库没有`panic`,必须在`goroutine`级别进行`recover`,保障整个进程的运行安全。
   427  - 捕获`panic`后,任何作业类型均会记录一条error等级的日志。
   428  - Restful请求中发生`panic`,`http code`为500。
   429  - 微服务调用中发生`panic`,需要对接`hystrix`,error日志由调用端(SDK)负责记录。
   430      
   431  ### Restful服务
   432  luca基于 [gin](https://github.com/gin-gonic/gin) 提供Restful服务。
   433  
   434  示例
   435  - 认证:[cmd/backend/internal/middleware/auth.go](https://gitee.com/woood2/luca/tree/master/cmd/backend/internal/middleware/auth.go)
   436  - 授权:[cmd/backend/internal/middleware/perm.go](https://gitee.com/woood2/luca/tree/master/cmd/backend/internal/middleware/perm.go)
   437  - validator:[cmd/backend/internal/controller/app.go](https://gitee.com/woood2/luca/tree/master/cmd/backend/internal/controller/app.go)
   438  - CRUD:[cmd/backend/internal/controller/app.go](https://gitee.com/woood2/luca/tree/master/cmd/backend/internal/controller/app.go)
   439  
   440  基于 [gin-contrib/cors](https://github.com/gin-contrib/cors) 支持CORS。
   441      
   442  允许多个来源:
   443  ```
   444  backend:  
   445    allowOrigins:
   446      - "http://google.com"
   447      - "http://facebook.com"    
   448  ```
   449  允许任意来源:
   450  ```
   451  backend:  
   452    allowOrigins:
   453      - "*"       
   454  ```
   455  
   456  基于 [swaggo/swag](https://github.com/swaggo/swag/blob/master/README_zh-CN.md) 支持API文档。  
   457  示例
   458  - 全局注释:[cmd/backend/main.go](https://gitee.com/woood2/luca/tree/master/cmd/backend/main.go) 
   459  - API注释:[cmd/backend/internal/controller/app.go](https://gitee.com/woood2/luca/tree/master/cmd/backend/internal/controller/app.go)
   460  - 更新命令:`cd cmd/backend && swag init`
   461  
   462  ### 微服务
   463  luca 基于 [go-kit](https://github.com/go-kit/kit) 提供micro service。 
   464   
   465  详细选型
   466  - 通信:[gRPC](https://doc.oschina.net/grpc) 
   467  - 注册/配置中心:[consul](https://developer.hashicorp.com/consul/docs/architecture) 
   468  - 熔断器:[hystrix](https://pkg.go.dev/github.com/afex/hystrix-go/hystrix) 
   469  - validator:[go-playground/validator](https://github.com/go-playground/validator) 
   470  
   471  API示例
   472  - [cmd/micro/internal/grpc/check_perm.go](https://gitee.com/woood2/luca/tree/master/cmd/micro/internal/grpc/check_perm.go)
   473  - [cmd/micro/internal/grpc/check_token.go](https://gitee.com/woood2/luca/tree/master/cmd/micro/internal/grpc/check_token.go)
   474  
   475  SDK示例
   476  - [cmd/micro/pkg/check_perm.go](https://gitee.com/woood2/luca/tree/master/cmd/micro/pkg/check_perm.go)
   477  - [cmd/micro/pkg/check_token.go](https://gitee.com/woood2/luca/tree/master/cmd/micro/pkg/check_token.go)
   478  
   479  本地测试
   480  - [test/grpc_client/main.go](https://gitee.com/woood2/luca/tree/master/test/grpc_client/main.go) 
   481  
   482  ### 定时任务
   483  luca基于 [robfig-cron](https://github.com/robfig/cron) 提供定时任务。  
   484  
   485  基于redis实现`Secondary Nodes`模式的高可用,详见 [main.go](https://gitee.com/woood2/luca/tree/master/cmd/cron/main.go) 中的`campaign()`与`renew()`。
   486  
   487  job示例
   488  - [cmd/cron/internal/handler/greet.go](https://gitee.com/woood2/luca/tree/master/cmd/cron/internal/handler/greet.go)
   489  - [cmd/cron/internal/handler/hello.go](https://gitee.com/woood2/luca/tree/master/cmd/cron/internal/handler/hello.go)
   490  
   491  ### 消息队列
   492  luca 基于 [Shopify/sarama](https://github.com/Shopify/sarama) 支持 Kafka。 
   493  
   494  application.yml
   495  ```
   496  kafka:
   497    version: 2.5.0
   498    brokers:
   499      - {ip}:9092
   500    enableSASL: true
   501    user: qjs
   502    password: '731'
   503    algorithm: sha256
   504  ```
   505  
   506  示例
   507  - topic:[internal/mq/greet.go](https://gitee.com/woood2/luca/tree/master/internal/mq/greet.go)
   508  - 生产:[internal/mq/greet_test.go](https://gitee.com/woood2/luca/tree/master/internal/mq/greet_test.go)
   509  - 消费:[cmd/consumer/internal/handler/greet_one.go](https://gitee.com/woood2/luca/tree/master/cmd/consumer/internal/handler/greet_one.go)
   510  
   511  ### 分层
   512  推荐方案
   513  ![avatar](https://gitee.com/woood2/luca/raw/master/docs/layer.png)
   514  
   515  controller层包括:
   516  - Restful服务中的 [Controller](https://gitee.com/woood2/luca/tree/master/cmd/backend/internal/controller)
   517  - 微服务中的 [Endpoint](https://gitee.com/woood2/luca/tree/master/cmd/micro/internal/endpoint)
   518  - 定时任务中的 [Handler](https://gitee.com/woood2/luca/tree/master/cmd/cron/internal/handler)
   519  - 队列消费中的 [Handler](https://gitee.com/woood2/luca/tree/master/cmd/consumer/internal/handler)
   520  
   521  [service](https://gitee.com/woood2/luca/tree/master/internal/service) 层涵盖:
   522  - Service: CRUD场景常见的服务层
   523  - Domain: [《领域驱动设计》](https://book.douban.com/subject/5344973/) 描绘的领域层
   524  
   525  [repository](https://gitee.com/woood2/luca/tree/master/internal/repository) 层负责操作ORM层,luca选择 [GORM](https://gorm.io/zh_CN/docs/index.html)  作为ORM框架。
   526  
   527  [sdk](https://gitee.com/woood2/luca/tree/master/internal/sdk) 或 [kafka producer](https://gitee.com/woood2/luca/tree/master/internal/producer/sarama_producer.go) 可视作远程service。
   528  
   529  ### 依赖注入
   530  在luca中,依赖注入随处可见:
   531  
   532  |  被依赖的对象   | 接收注入的对象  |
   533  |  ----  | ----  |
   534  | logger  | 任何需要记录日志的代码 |
   535  | db(mysql、redis、mongo等)  | repository |
   536  | consul client  | sdk |
   537  | kafka producer  | controller、service |
   538  | sdk  | controller、service |
   539  | service  | controller |
   540  | repository  | service |
   541  
   542  在Spring的世界中,使用`@Autowired`即可自动装配。但是在luca中,我们需要在以下位置手动装配:
   543  - [cmd/backend/internal/assembly/route.go](https://gitee.com/woood2/luca/tree/master/cmd/backend/internal/assembly/route.go)
   544  - [cmd/micro/internal/grpc/set.go](https://gitee.com/woood2/luca/tree/master/cmd/micro/internal/grpc/set.go)
   545  - [cmd/cron/internal/handler/set.go](https://gitee.com/woood2/luca/tree/master/cmd/cron/internal/handler/set.go)
   546  - [cmd/consumer/internal/handler/groups.go](https://gitee.com/woood2/luca/tree/master/cmd/consumer/internal/handler/groups.go)
   547  
   548  ### Mysql
   549  luca选择 [GORM](https://gorm.io/zh_CN/docs/index.html) 作为ORM框架。
   550  
   551  application.yml
   552  ```
   553  mysql:
   554    user: root
   555    pwd: '123456'
   556    host: {ip}
   557    port: 3306
   558    db: luca
   559    maxOpenConns: 30
   560    maxIdleConns: 10
   561  ```
   562  
   563  示例
   564  - CRUD:[internal/repository/app.go ](https://gitee.com/woood2/luca/tree/master/internal/repository/app.go)  
   565  - 事务:[AppServiceImpl.Twins](https://gitee.com/woood2/luca/tree/master/internal/service/app.go) 
   566  
   567  ### MongoDB
   568  luca 基于 [mongo-go-driver](https://github.com/mongodb/mongo-go-driver) 操作MongoDB。
   569   
   570  application.yml
   571  ```
   572  mongo:
   573    user: woood2
   574    pwd: '123456'
   575    host: {ip}
   576    port: 27017
   577    db: luca
   578    maxPoolSize: 30
   579    minPoolSize: 10
   580  ```
   581  
   582  示例
   583  - [internal/repository/student.go](https://gitee.com/woood2/luca/tree/master/internal/repository/student.go)
   584  
   585  ### 缓存
   586  luca提供了统一的 [Cache](https://gitee.com/woood2/luca/tree/master/internal/cache/cache.go) 接口以及3种默认实现:
   587  - [LocalCache](https://gitee.com/woood2/luca/tree/master/internal/cache/local.go):基于本地内存的cache实现,性能水平100w/sec。
   588  - [RedisCache](https://gitee.com/woood2/luca/tree/master/internal/cache/redis.go) :基于redis的cache实现,性能水平1w/sec。
   589  - [NopCache](https://gitee.com/woood2/luca/tree/master/internal/cache/nop.go):基于「无」的cache实现。
   590  
   591  其中,[RedisCache](https://gitee.com/woood2/luca/tree/master/internal/cache/redis.go) 基于 [go-redis](https://github.com/go-redis/redis) 操作Redis,对应配置:
   592  ```
   593  redis:
   594    addr: {ip}:6379
   595    pwd: ''
   596    poolSize: 30
   597    minIdleConns: 10
   598  ```
   599  
   600  默认采用json序列化,允许修改 [serialization.go](https://gitee.com/woood2/luca/tree/master/internal/cache/serialization.go) 替换成其它序列化算法。
   601  
   602  示例
   603  - Local: [local_test.go](https://gitee.com/woood2/luca/tree/master/internal/cache/local_test.go)
   604  - Redis: [redis_test.go](https://gitee.com/woood2/luca/tree/master/internal/cache/redis_test.go)
   605  - 防雪崩:[AppServiceImpl.GetByKeyFromCacheSafely](https://gitee.com/woood2/luca/tree/master/internal/service/app.go)
   606  
   607  ### logger
   608  日志维度
   609  
   610  |  日志维度   | 说明  |  日志库   | 输出  | 接入 [zipkin](https://zipkin.io/)  | 接入 [EFK](https://blog.csdn.net/easylife206/article/details/112057417)  |
   611  |  ----  | ----  |  ----  | ----  |  ----  | ----  |
   612  |  服务日志   | 服务运行周期中的启动、关闭和状态日志 |  标准库 [log](https://pkg.go.dev/log)   | stdout/stderr  |  否   | 否  |
   613  |  请求日志   | 请求/作业周期内产生的日志  |  [uber-go/zap](https://github.com/uber-go/zap)  | stdout/stderr或者./zap.log文件  |  是   | 是  |
   614  
   615  application.yml(zap配置)
   616  
   617  |  名称   | 说明  |
   618  |  ----  | ----  |
   619  | env  | pro: 日志等级Info<br/>其它: 日志等级Debug |
   620  | consoleLog  | true: 控制台日志<br/>false: 文件日志(./zap.log) |
   621  
   622  内置日志点(zap logger)
   623  
   624  |  围绕   | 类型  | 说明  | 等级  |
   625  |  ----  | ----  | ----  | ----  |
   626  | 请求/作业 |  |  |  |
   627  |  | access日志 | 覆盖所有作业类型 | info |
   628  |  | error日志  | 覆盖所有作业类型 | error |
   629  |  | oplog日志  | 用于Restful服务 | info |
   630  | GORM |  |  |  |
   631  |   | sql日志   |  | debug |
   632  |   | slow日志  |  | warn |
   633  |   | error日志 |  | error |
   634  | SDK |  |  |  |
   635  |  | call日志  |  | debug |
   636  |  | error日志 |  | error |
   637  
   638  ### 链路追踪
   639  luca 选择 [zipkin](https://zipkin.io/) 作为链路追踪的实现引擎。
   640  
   641  跟踪范围
   642  - Restful请求
   643  - 微服务调用
   644  - 定时任务作业
   645  - 队列消费作业
   646  - 其它,如单元测试
   647  
   648  从 gin.Context 提取 TraceID:
   649  ```
   650  func (ctr AnyController) Demo(c *gin.Context) {
   651      traceID := trace.GinID(c)
   652      ...
   653  }
   654  ```
   655  
   656  从 context.Context 提取 TraceID:
   657  ```
   658  func(ctx context.Context){
   659      traceID := trace.ID(ctx)
   660      ...
   661  }
   662  ```
   663  
   664  向 GORM logger 传递 TraceID:
   665  ```
   666  func (repo *AppRepoImpl) Create(ctx context.Context, app *App) (int, error) {
   667      result := repo.DB.WithContext(ctx).Create(app)
   668      ...
   669  }
   670  ```
   671  
   672  向 Restful 请求返回 TraceID:
   673  ```
   674  package errcode
   675  
   676  type Resp struct {
   677      ErrCode string      `json:"errCode"`
   678      ErrMsg  string      `json:"errMsg"`
   679      Data    interface{} `json:"data"`
   680      TraceID string      `json:"traceID"` 
   681      Stack   string      `json:"stack"`   
   682  }
   683  ```
   684  
   685  application.yml
   686  
   687  |  一级   | 二级  | 说明  | 示例  |
   688  |  ----  | ----  | ----  | ----  |
   689  | zipkin |  |  |  |
   690  |  | reporterAddr | 上报地址(允许为空) | http://192.168.0.100:9411/api/v2/spans |
   691  
   692  zipkin server
   693  - 安装:[deployments/README.md](https://gitee.com/woood2/luca/tree/master/deployments/README.md)
   694  - 访问:`deployments/nav.html`
   695  - 为性能考虑,生产环境建议关闭zipkin server,只需要将Zipkin.ReporterAddr设置为空。
   696  
   697  ### 日志收集
   698  luca 选择 [EFK](https://blog.csdn.net/easylife206/article/details/112057417) 日志收集方案:
   699  - 通过 [fluentd](https://docs.fluentd.org) 从 ./zap.log 文件中读取日志。
   700  - 将收集来的日志数据存入 [elastic search](https://www.elastic.co/cn/what-is/elasticsearch) 。
   701  - 通过 [Kibana](https://www.elastic.co/cn/kibana/) 界面查询日志。
   702  
   703  EFK 安装、使用
   704  - 详见 [deployments/EFK.md](https://gitee.com/woood2/luca/tree/master/deployments/EFK.md)
   705  
   706  ### pprof
   707  支持 [pprof](https://pkg.go.dev/net/http/pprof) 的Go进程:
   708  - Restful服务
   709  - 微服务
   710  - 定时任务
   711  - 队列消费
   712  
   713  application.yml
   714  ```
   715  pprof:
   716    user: qjs
   717    pwd: '731'
   718  
   719  backend:  
   720    pprofAddr: ":6059"
   721    
   722  micro:
   723    pprofAddr: ":6060"
   724    
   725  consumer:
   726    pprofAddr: ":6064"
   727  
   728  cron:
   729    pprofAddr: ":6065"
   730  ```
   731  
   732  访问
   733  - 详见 `deployments/nav.html`
   734  
   735  ### metrics
   736  luca 为3种作业类型接入 [prometheus](https://prometheus.io/) 指标统计:
   737  - Restful请求
   738  - 微服务调用
   739  - 队列消费作业
   740  
   741  application.yml
   742  ```
   743  backend:  
   744    metricsAddr: ":8082"
   745    
   746  micro:
   747    metricsAddr: ":6061"
   748    
   749  consumer:  
   750    metricsAddr: ":6063"  
   751  ```
   752  
   753  安装 prometheus
   754  - 详见 [deployments/README.md](https://gitee.com/woood2/luca/tree/master/deployments/README.md)
   755  
   756  访问 prometheus
   757  - 详见 `deployments/nav.html`
   758  
   759  ### 多环境
   760  推荐方案
   761  
   762  |  环境   | env  | 部署位置 | 部署套数 | 用途  |git分支 | zap等级 | swagger |
   763  |  ----  | ----  | ----  | ----  | ---- | ---- | ---- | ---- |
   764  | 本机 | dev  | 本机  | 1/每人 | 开发 | 个人、feature、fixbug | Debug | 开启 | 
   765  | dev | dev | 远程 | 1 | 联调 | dev | Debug | 开启 |
   766  | demo | demo | 远程 | 1 | 对客演示 | demo | Debug | 开启 |  
   767  | test | test | 远程 | \>=1 | 测试 | test | Debug | 开启 |   
   768  | pre | pre | 远程 | 1 | 发版演练 | pre | Debug | 开启 |  
   769  | pro | pro | 远程 | \>=1 | 生产 | master | Info | 关闭 |  
   770  
   771  本机 & dev
   772  - 允许本机环境与dev环境共用同一套资源,如数据库、消息队列等。
   773  - 允许本机程序单向依赖dev环境的微服务,只需在本机配置dev环境的consul地址,并且将Backend.Register、Micro.Register设置为false。
   774  
   775  demo
   776  - 假如demo环境的使用频率较低,建议按需构建。
   777  - 考虑到demo环境的不确定性,暂不纳入 `git 分支策略`。
   778  
   779  git 分支策略
   780  ![avatar](https://gitee.com/woood2/luca/raw/master/docs/git-branch.png)
   781  
   782  git 分支命名
   783  
   784  |  分支   | 命名规则  | 示例 |
   785  |  ----  | ----  | ----  |
   786  | 主分支 | master  | -  |
   787  | 开发 | dev  | -  |
   788  | 演示 | demo  | -  |
   789  | 测试 | test  | -  |
   790  | 预生产 | pre  | -  |
   791  | feature | {name}-feature  | first-feature、second-feature  |
   792  | fixbug | {name}-fixbug  | stackoverflow-fixbug  |
   793  | 个人 | 姓名全拼、缩写  | qiujiashu、qjs  |
   794   
   795  ### 优雅关闭
   796  支持优雅关闭的Go进程
   797  - Restful服务
   798  - 微服务
   799  - 定时任务
   800  - 队列消费
   801  
   802  工作原理
   803  1. 接收来自kill命令的信号量。
   804  2. 停止接收新的作业。
   805  3. 等待正在进行中的作业完成或者超时(默认:5秒)。
   806  4. 关闭进程。
   807  
   808  ### 灰度发布 
   809  luca支持微服务及Restful服务的灰度发布,以实现程序的不停服更新。
   810  
   811  前提
   812  - 不论是Restful服务还是微服务,运行的实例数量必须是两个及以上,单机模式不支持灰度发布。
   813  - Restful服务需要前置一个nginx反向代理,并且借助consul-template监视实例列表的变化。详见:[Load Balancing with NGINX and Consul Template](https://developer.hashicorp.com/consul/tutorials/load-balancing/load-balancing-nginx)
   814  
   815  工作原理
   816  - 发布程序的新版本时,分批重启集群中的实例。
   817  - 实例重启前通知consul注销自己,将流量导向其它运行中的实例。
   818  - 等待实例重启完成,再次注册到consul上迎回流量。
   819  - 发布过程中,始终有实例运行,提供连续服务。
   820  
   821  ### 单元测试
   822  luca鼓励开发者采用主流的`table driven`模式进行单元测试。
   823  
   824  单元测试的优先目标是计算逻辑,而不是IO。对于一般的CRUD,单元测试意义不大,API测试是更适合的选择。
   825  
   826  luca支持在CI/CD中跳过指定的单元测试:
   827  ```
   828  CLI
   829      CI=true go test -v -cover ./...
   830  
   831  internal/util/test.go
   832      package util
   833  
   834      import (
   835          "os"
   836          "testing"
   837      )
   838  
   839      func CI() bool {
   840          return os.Getenv("CI") != ""
   841      }
   842  
   843      func SkipCI(t *testing.T) {
   844          if CI() {
   845              t.Skip("Skipping testing in CI environment")
   846          }
   847      }
   848  
   849  xxx_test.go
   850      func TestMain(m *testing.M) {
   851          if !util.CI() {
   852              attr := conf.Load("application.yml", "configs/application.yml")
   853              ..
   854          }
   855          m.Run()
   856      }
   857  
   858      func TestXXX(t *testing.T) {
   859          util.SkipCI(t)
   860          ..
   861      }