GO语言工程实践记录 | 豆包MarsCode AI刷题

160 阅读3分钟

记录一下go工程实践

系统功能流程

用户下单流程

  1. 用户浏览商品,商品服务通过 Redis 提供快速的商品信息。
  2. 用户点击下单,订单服务生成订单并调用支付服务完成支付。
  3. 支付成功后,订单服务通过消息队列通知商品服务更新库存。
  4. 推荐服务根据订单数据更新用户的兴趣标签。

社交分享流程

  1. 用户在抖音商城下单后,可以一键生成短视频分享。
  2. 社交分享服务提供商品链接,其他用户通过链接访问商城并购买。

Hertz服务

Hertz是一个 Golang 微服务 HTTP 框架,在设计之初参考了其他开源框架 fasthttp 、 gin 、 echo 的优势, 并结合字节跳动内部的需求,使其具有高易用性、高性能、高扩展性等特点,目前在字节跳动内部已广泛使用。

启动Hertz服务

package main

import (
"context"

"github.com/cloudwego/hertz/pkg/app"
"github.com/cloudwego/hertz/pkg/app/server"
"github.com/cloudwego/hertz/pkg/protocol/consts"
)

func main() {
    h := server.Default()

    h.GET("/hello", func(c context.Context, ctx *app.RequestContext) {
       ctx.Data(consts.StatusOK, consts.MIMETextPlain, []byte("hello world"))
    })

    h.Spin()
}

成功启动了一个 Hertz 服务,并实现了简单的 /hello 路由。

安装 Gorm

运行以下命令安装 Gorm 和 MySQL 驱动:

go get -u gorm.io/driver/mysql

部署服务

目标

  • 将服务从本地环境部署到服务器或云平台。

部署步骤

  1. 打包服务

    • 构建可执行文件:

      bash
      
      go build -o hertz-app main.go
      
  2. 运行在 Linux

    • 将可执行文件和配置文件拷贝到服务器。

    • 在服务器上运行:

      bash
      
      ./hertz-app
      
  3. 使用容器化部署

    • 创建一个 Dockerfile

      dockerfile
      
      FROM golang:1.20
      WORKDIR /app
      COPY . .
      RUN go build -o hertz-app main.go
      CMD ["./hertz-app"]
      
    • 构建并运行:

      docker build -t hertz-app .
      docker run -p 8080:8080 hertz-app
      
      
      

AI生成文件结构

├── cmd/ # 程序入口 │ ├── main.go # 服务启动主文件 │ ├── migrate.go # 数据库迁移入口 ├── configs/ # 配置文件 │ └── config.yaml # 配置文件(如数据库、Redis、服务配置等) ├── internal/ # 核心业务代码 │ ├── routers/ # 路由管理 │ │ └── router.go # 注册所有路由 │ ├── handlers/ # 控制器层(请求处理) │ │ ├── user_handler.go # 用户模块处理逻辑 │ │ └── product_handler.go # 商品模块处理逻辑 │ ├── services/ # 服务层(业务逻辑) │ │ ├── user_service.go # 用户模块服务逻辑 │ │ └── product_service.go # 商品模块服务逻辑 │ ├── models/ # 数据层(数据库模型和访问逻辑) │ │ ├── user_model.go # 用户数据模型 │ │ └── product_model.go # 商品数据模型 │ ├── middlewares/ # 中间件 │ │ ├── logger_middleware.go # 日志中间件 │ │ └── auth_middleware.go # 认证中间件 │ └── utils/ # 工具类 │ ├── logger.go # 日志工具 │ └── response_util.go # 通用响应工具 ├── pkg/ # 可复用的第三方工具或组件 │ ├── db/ # 数据库连接管理 │ │ └── db.go # 初始化 MySQL 数据库 │ ├── cache/ # 缓存管理 │ │ └── redis.go # 初始化 Redis 缓存 │ ├── consul/ # 服务注册与发现 │ │ └── consul.go # Consul 相关逻辑 │ └── telemetry/ # 性能监控工具 │ └── trace.go # OpenTelemetry 集成 ├── test/ # 测试文件夹 │ ├── handlers_test.go # 处理函数测试 │ ├── services_test.go # 服务逻辑测试 │ └── integration/ # 集成测试 ├── Dockerfile # 容器化配置文件 ├── go.mod # Go 依赖管理文件 ├── go.sum # Go 依赖版本锁定文件 └── README.md # 项目说明文档

具体模块命名和功能划分

1. cmd/

  • main.go:程序主入口

2. configs/

  • config.yaml:存储全局配置。

3. internal/routers/

  • router.go:集中管理路由。

4. internal/handlers/

  • user_handler.go:处理用户相关的请求。

5. internal/services/

  • user_service.go:用户业务逻辑。

6. internal/models/

  • user_model.go:用户数据库模型和操作。

7. internal/middlewares/

  • logger_middleware.go:日志中间件。

具体实现

实现 AuthService

internal/auth/auth.go 中实现认证服务:


import (
	"context"
	"fmt"
	"sync"
)

// AuthServiceServer 实现 AuthService 的 gRPC 接口
type AuthServiceServer struct {
	tokenStore map[string]int32 // 模拟存储 token -> user_id 映射
	mu         sync.Mutex       // 用于并发访问 tokenStore
}

// NewAuthServiceServer 创建一个新的服务实例
func NewAuthServiceServer() *AuthServiceServer {
	return &AuthServiceServer{
		tokenStore: make(map[string]int32),
	}
}

// DeliverTokenByRPC 实现令牌生成逻辑
func (s *AuthServiceServer) DeliverTokenByRPC(ctx context.Context, req *DeliverTokenReq) (*DeliveryResp, error) {
	token := fmt.Sprintf("token-%d", req.UserId) // 简单生成 token
	s.mu.Lock()
	s.tokenStore[token] = req.UserId
	s.mu.Unlock()
	return &DeliveryResp{Token: token}, nil
}

// VerifyTokenByRPC 实现令牌验证逻辑
func (s *AuthServiceServer) VerifyTokenByRPC(ctx context.Context, req *VerifyTokenReq) (*VerifyResp, error) {
	s.mu.Lock()
	defer s.mu.Unlock()
	_, exists := s.tokenStore[req.Token]
	return &VerifyResp{Res: exists}, nil
}

编写 HTTP 接口

通过 HTTP 将认证服务暴露给前端,在 internal/handlers/auth_handler.go 中实现:


import (
	"context"
	"log"
	"net/http"
	"project-root/internal/auth"

	"github.com/cloudwego/hertz/pkg/app"
)

func DeliverTokenHandler(ctx context.Context, c *app.RequestContext) {
	userID := c.Query("user_id")
	if userID == "" {
		c.JSON(http.StatusBadRequest, map[string]string{"error": "user_id is required"})
		return
	}

	// 调用 gRPC 服务
	conn, err := grpc.Dial(":50051", grpc.WithInsecure())
	if err != nil {
		log.Fatalf("Failed to connect to gRPC server: %v", err)
	}
	defer conn.Close()

	client := auth.NewAuthServiceClient(conn)
	resp, err := client.DeliverTokenByRPC(ctx, &auth.DeliverTokenReq{UserId: 1}) // 示例 user_id
	if err != nil {
		c.JSON(http.StatusInternalServerError, map[string]string{"error": "Failed to deliver token"})
		return
	}

	c.JSON(http.StatusOK, map[string]string{"token": resp.Token})
}

To be continue