golang构建生产级可扩展Web服务的插件库ardanlabs/service的使用
Golang构建生产级可扩展Web服务的插件库ardanlabs/service的使用
简介
ardanlabs/service是一个用于构建生产级可扩展Web服务的Go语言插件库和starter kit。它采用领域驱动、数据导向的架构设计,可以运行在Kubernetes环境中。
这个项目的目标是提供一个经过验证的起点,减少新项目投入生产所需的重复性任务。它使用最少的依赖,实现符合Go语言习惯的代码,并遵循Go的最佳实践。
主要特性
- 为生产级Web服务提供完整的架构和实现
- 领域驱动设计(DDD)和数据导向架构
- Kubernetes支持
- 最小化依赖
- 符合Go语言习惯的实现
- 生产环境最佳实践
安装
要克隆项目,创建一个文件夹并使用git clone命令:
$ cd $HOME
$ mkdir code
$ cd code
$ git clone https://github.com/ardanlabs/service.git
$ cd service
创建自己的版本
如果你想创建项目的自定义版本,可以使用gonew命令:
$ go install golang.org/x/tools/cmd/gonew@latest
$ cd $HOME
$ mkdir code
$ cd code
$ gonew github.com/ardanlabs/service github.com/mydomain/myproject
$ cd myproject
$ go mod vendor
运行项目
使用以下命令运行项目:
# 安装工具
$ make dev-gotooling
$ make dev-brew
$ make dev-docker
# 运行测试
$ make test
# 运行项目
$ make dev-up
$ make dev-update-apply
$ make token
$ export TOKEN=<COPY TOKEN>
$ make users
# 运行负载测试
$ make load
# 运行监控工具
$ make grafana
$ make statsviz
# 关闭项目
$ make dev-down
示例代码
以下是一个使用ardanlabs/service构建Web服务的简单示例:
package main
import (
"context"
"fmt"
"net/http"
"os"
"os/signal"
"syscall"
"time"
"github.com/ardanlabs/service/app/services/sales-api/handlers"
"github.com/ardanlabs/service/business/web/v1/debug"
"github.com/ardanlabs/service/foundation/web"
)
func main() {
// 创建日志器
log := debug.New()
// 创建应用
app := web.NewApp(log)
// 注册路由
app.Handle(http.MethodGet, "/", handlers.Home)
app.Handle(http.MethodGet, "/health", handlers.Health)
// 启动服务器
api := http.Server{
Addr: "localhost:3000",
Handler: app,
ReadTimeout: 5 * time.Second,
WriteTimeout: 10 * time.Second,
IdleTimeout: 120 * time.Second,
}
// 启动服务器
go func() {
log.Info(context.Background(), "startup", "status", "api router started", "host", api.Addr)
if err := api.ListenAndServe(); err != nil && err != http.ErrServerClosed {
log.Error(context.Background(), "shutdown", "msg", err)
}
}()
// 等待中断信号
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
<-quit
// 优雅关闭
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if err := api.Shutdown(ctx); err != nil {
log.Error(ctx, "shutdown", "msg", err)
}
fmt.Println("Server stopped")
}
项目优势
- 减少复杂性:项目通过合理的架构设计帮助管理和减少系统复杂性
- 生产就绪:包含监控、日志、配置管理等生产环境所需功能
- 可扩展性:支持Kubernetes,可以轻松扩展
- 最佳实践:遵循Go语言和Web开发的最佳实践
- 领域驱动:采用领域驱动设计,代码结构清晰
学习资源
该项目背后有一个完整的培训课程,教你如何利用领域驱动和数据导向的架构在Go中构建生产级软件。课程从设计哲学和指南开始,逐步添加功能,并学习如何部署和管理Kubernetes环境。
更多关于golang构建生产级可扩展Web服务的插件库ardanlabs/service的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
更多关于golang构建生产级可扩展Web服务的插件库ardanlabs/service的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
使用ardanlabs/service构建生产级可扩展Web服务
ardanlabs/service是Go语言中一个优秀的Web服务框架,它提供了一套完整的工具和最佳实践来构建生产级、可扩展的Web服务。下面我将详细介绍如何使用这个库。
核心特性
- 内置优雅关闭支持
- 健康检查端点
- 标准化日志记录
- 配置管理
- 中间件支持
- 监控和指标集成
基本使用示例
package main
import (
"context"
"net/http"
"github.com/ardanlabs/service/app/services/sales-api/handlers"
"github.com/ardanlabs/service/business/web/v1/debug"
"github.com/ardanlabs/service/foundation/logger"
"github.com/ardanlabs/service/foundation/web"
)
func main() {
// 初始化日志
log := logger.New("SALES-API")
// 创建Web应用
app := web.NewApp(
log,
web.WithShutdown(func(ctx context.Context) {
// 自定义关闭逻辑
log.Info(ctx, "shutdown complete")
}),
)
// 注册路由
app.Handle(http.MethodGet, "/v1/health", handlers.Health)
// 注册调试路由
debug.Mux(app)
// 启动服务
if err := web.Run(context.Background(), app, web.Config{
Host: "0.0.0.0",
Port: 3000,
ReadTimeout: 5 * time.Second,
WriteTimeout: 10 * time.Second,
IdleTimeout: 120 * time.Second,
}); err != nil {
log.Error(context.Background(), "startup", "msg", err)
os.Exit(1)
}
}
配置管理
ardanlabs/service推荐使用环境变量进行配置:
type Config struct {
Web struct {
APIHost string `default:"0.0.0.0:3000"`
DebugHost string `default:"0.0.0.0:4000"`
ReadTimeout time.Duration `default:"5s"`
WriteTimeout time.Duration `default:"10s"`
IdleTimeout time.Duration `default:"120s"`
ShutdownTimeout time.Duration `default:"20s"`
}
DB struct {
User string `default:"postgres"`
Password string `default:"postgres" mask:"true"`
Host string `default:"localhost"`
Name string `default:"postgres"`
MaxIdleConns int `default:"2"`
MaxOpenConns int `default:"0"`
DisableTLS bool `default:"true"`
}
}
func main() {
var cfg Config
if err := config.Load(&cfg); err != nil {
log.Error(context.Background(), "config", "msg", err)
os.Exit(1)
}
// 使用配置...
}
数据库集成
// 初始化数据库连接
db, err := database.Open(database.Config{
User: cfg.DB.User,
Password: cfg.DB.Password,
Host: cfg.DB.Host,
Name: cfg.DB.Name,
MaxIdleConns: cfg.DB.MaxIdleConns,
MaxOpenConns: cfg.DB.MaxOpenConns,
DisableTLS: cfg.DB.DisableTLS,
})
if err != nil {
log.Error(ctx, "startup", "msg", err)
os.Exit(1)
}
defer db.Close()
// 将数据库连接注入到handler中
userHandler := handlers.NewUser(log, db)
app.Handle(http.MethodGet, "/v1/users/:id", userHandler.GetByID)
中间件使用
// 添加全局中间件
app.Use(
middleware.Logger(log),
middleware.Errors(log),
middleware.Metrics(),
middleware.Panics(log),
)
// 路由特定中间件
app.Handle(http.MethodGet, "/v1/users", userHandler.Query, middleware.Authenticate())
监控和指标
// 初始化指标
metrics := expvar.New()
// 注册指标端点
app.Handle(http.MethodGet, "/debug/vars", web.WrapHandler(expvar.Handler()))
// 在业务代码中记录指标
func (h *UserHandler) GetByID(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
h.metrics.Add("users", 1)
// 业务逻辑...
}
测试支持
func TestUserHandlers(t *testing.T) {
// 创建测试应用
app := web.NewApp(
logger.NewTestLogger(),
web.WithShutdown(func(ctx context.Context) {}),
)
// 注册测试路由
app.Handle(http.MethodGet, "/v1/users/:id", testHandler)
// 创建测试服务器
srv := httptest.NewServer(app)
defer srv.Close()
// 执行测试请求
resp, err := http.Get(fmt.Sprintf("%s/v1/users/123", srv.URL))
if err != nil {
t.Fatalf("should not be error: %v", err)
}
defer resp.Body.Close()
// 验证响应
if resp.StatusCode != http.StatusOK {
t.Errorf("should be 200: %v", resp.StatusCode)
}
}
最佳实践
- 使用context传递请求范围的值
- 所有错误都通过中间件统一处理
- 业务逻辑与传输层分离
- 使用结构体标签进行配置验证
- 为所有外部依赖设置超时
- 实现健康检查端点
ardanlabs/service框架提供了一套完整的工具来构建生产级服务,遵循这些模式和最佳实践可以创建出健壮、可维护和可扩展的Web服务。