发布于

Go语言微服务开发:构建可扩展的分布式系统

作者

Go语言微服务开发:构建可扩展的分布式系统

Go语言凭借其简洁的语法、高效的性能和内置的并发支持,成为构建微服务的理想选择。本文将详细介绍使用Go开发微服务的完整流程。

微服务架构基础

项目结构和依赖

// go.mod
module microservice-demo

go 1.21

require (
    github.com/gin-gonic/gin v1.9.1
    github.com/go-kit/kit v0.13.0
    github.com/golang/protobuf v1.5.3
    github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0
    github.com/prometheus/client_golang v1.16.0
    github.com/spf13/viper v1.16.0
    go.mongodb.org/mongo-driver v1.12.1
    go.uber.org/zap v1.24.0
    google.golang.org/grpc v1.57.0
    google.golang.org/protobuf v1.31.0
)

微服务项目结构

microservice-demo/
├── api/
│   ├── proto/
│   │   └── user.proto
│   └── swagger/
├── cmd/
│   ├── user-service/
│   │   └── main.go
│   ├── order-service/
│   │   └── main.go
│   └── api-gateway/
│       └── main.go
├── internal/
│   ├── user/
│   │   ├── domain/
│   │   ├── repository/
│   │   ├── service/
│   │   └── transport/
│   └── order/
│       ├── domain/
│       ├── repository/
│       ├── service/
│       └── transport/
├── pkg/
│   ├── auth/
│   ├── database/
│   ├── logger/
│   └── tracing/
├── deployments/
│   ├── docker/
│   └── kubernetes/
├── scripts/
├── go.mod
└── go.sum

服务定义和接口设计

// api/proto/user.proto
syntax = "proto3";

package user;
option go_package = "microservice-demo/api/proto/user";

import "google/api/annotations.proto";

service UserService {
  rpc CreateUser(CreateUserRequest) returns (CreateUserResponse) {
    option (google.api.http) = {
      post: "/v1/users"
      body: "*"
    };
  }
  
  rpc GetUser(GetUserRequest) returns (GetUserResponse) {
    option (google.api.http) = {
      get: "/v1/users/{id}"
    };
  }
  
  rpc UpdateUser(UpdateUserRequest) returns (UpdateUserResponse) {
    option (google.api.http) = {
      put: "/v1/users/{id}"
      body: "*"
    };
  }
  
  rpc DeleteUser(DeleteUserRequest) returns (DeleteUserResponse) {
    option (google.api.http) = {
      delete: "/v1/users/{id}"
    };
  }
  
  rpc ListUsers(ListUsersRequest) returns (ListUsersResponse) {
    option (google.api.http) = {
      get: "/v1/users"
    };
  }
}

message User {
  string id = 1;
  string username = 2;
  string email = 3;
  string full_name = 4;
  string created_at = 5;
  string updated_at = 6;
}

message CreateUserRequest {
  string username = 1;
  string email = 2;
  string password = 3;
  string full_name = 4;
}

message CreateUserResponse {
  User user = 1;
}

message GetUserRequest {
  string id = 1;
}

message GetUserResponse {
  User user = 1;
}

message UpdateUserRequest {
  string id = 1;
  string email = 2;
  string full_name = 3;
}

message UpdateUserResponse {
  User user = 1;
}

message DeleteUserRequest {
  string id = 1;
}

message DeleteUserResponse {
  bool success = 1;
}

message ListUsersRequest {
  int32 page = 1;
  int32 page_size = 2;
}

message ListUsersResponse {
  repeated User users = 1;
  int32 total = 2;
}

领域模型和业务逻辑

// internal/user/domain/user.go
package domain

import (
    "time"
    "errors"
    "regexp"
    
    "golang.org/x/crypto/bcrypt"
)

var (
    ErrInvalidUsername = errors.New("invalid username")
    ErrInvalidEmail    = errors.New("invalid email")
    ErrInvalidPassword = errors.New("invalid password")
)

// User 领域模型
type User struct {
    ID        string    `json:"id" bson:"_id,omitempty"`
    Username  string    `json:"username" bson:"username"`
    Email     string    `json:"email" bson:"email"`
    Password  string    `json:"-" bson:"password"`
    FullName  string    `json:"full_name" bson:"full_name"`
    CreatedAt time.Time `json:"created_at" bson:"created_at"`
    UpdatedAt time.Time `json:"updated_at" bson:"updated_at"`
}

// NewUser 创建新用户
func NewUser(username, email, password, fullName string) (*User, error) {
    // 验证用户名
    if !isValidUsername(username) {
        return nil, ErrInvalidUsername
    }
    
    // 验证邮箱
    if !isValidEmail(email) {
        return nil, ErrInvalidEmail
    }
    
    // 验证密码
    if !isValidPassword(password) {
        return nil, ErrInvalidPassword
    }
    
    // 加密密码
    hashedPassword, err := hashPassword(password)
    if err != nil {
        return nil, err
    }
    
    now := time.Now()
    
    return &User{
        Username:  username,
        Email:     email,
        Password:  hashedPassword,
        FullName:  fullName,
        CreatedAt: now,
        UpdatedAt: now,
    }, nil
}

// UpdateProfile 更新用户资料
func (u *User) UpdateProfile(email, fullName string) error {
    if email != "" && email != u.Email {
        if !isValidEmail(email) {
            return ErrInvalidEmail
        }
        u.Email = email
    }
    
    if fullName != "" {
        u.FullName = fullName
    }
    
    u.UpdatedAt = time.Now()
    return nil
}

// VerifyPassword 验证密码
func (u *User) VerifyPassword(password string) bool {
    err := bcrypt.CompareHashAndPassword([]byte(u.Password), []byte(password))
    return err == nil
}

// 辅助函数
func isValidUsername(username string) bool {
    if len(username) < 3 || len(username) > 30 {
        return false
    }
    
    pattern := `^[a-zA-Z0-9_]+$`
    matched, _ := regexp.MatchString(pattern, username)
    return matched
}

func isValidEmail(email string) bool {
    pattern := `^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$`
    matched, _ := regexp.MatchString(pattern, email)
    return matched
}

func isValidPassword(password string) bool {
    return len(password) >= 8
}

func hashPassword(password string) (string, error) {
    hashedBytes, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
    if err != nil {
        return "", err
    }
    return string(hashedBytes), nil
}

数据访问层

// internal/user/repository/mongodb_repository.go
package repository

import (
    "context"
    "time"
    
    "go.mongodb.org/mongo-driver/bson"
    "go.mongodb.org/mongo-driver/bson/primitive"
    "go.mongodb.org/mongo-driver/mongo"
    "go.mongodb.org/mongo-driver/mongo/options"
    
    "microservice-demo/internal/user/domain"
)

type UserRepository interface {
    Create(ctx context.Context, user *domain.User) error
    FindByID(ctx context.Context, id string) (*domain.User, error)
    FindByUsername(ctx context.Context, username string) (*domain.User, error)
    FindByEmail(ctx context.Context, email string) (*domain.User, error)
    Update(ctx context.Context, user *domain.User) error
    Delete(ctx context.Context, id string) error
    List(ctx context.Context, page, pageSize int) ([]*domain.User, int, error)
}

type mongoUserRepository struct {
    collection *mongo.Collection
}

func NewMongoUserRepository(db *mongo.Database) UserRepository {
    collection := db.Collection("users")
    
    // 创建索引
    indexModels := []mongo.IndexModel{
        {
            Keys:    bson.D{{Key: "username", Value: 1}},
            Options: options.Index().SetUnique(true),
        },
        {
            Keys:    bson.D{{Key: "email", Value: 1}},
            Options: options.Index().SetUnique(true),
        },
    }
    
    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    defer cancel()
    
    _, err := collection.Indexes().CreateMany(ctx, indexModels)
    if err != nil {
        panic(err)
    }
    
    return &mongoUserRepository{
        collection: collection,
    }
}

func (r *mongoUserRepository) Create(ctx context.Context, user *domain.User) error {
    if user.ID == "" {
        user.ID = primitive.NewObjectID().Hex()
    }
    
    _, err := r.collection.InsertOne(ctx, user)
    return err
}

func (r *mongoUserRepository) FindByID(ctx context.Context, id string) (*domain.User, error) {
    var user domain.User
    
    err := r.collection.FindOne(ctx, bson.M{"_id": id}).Decode(&user)
    if err != nil {
        if err == mongo.ErrNoDocuments {
            return nil, nil
        }
        return nil, err
    }
    
    return &user, nil
}

func (r *mongoUserRepository) FindByUsername(ctx context.Context, username string) (*domain.User, error) {
    var user domain.User
    
    err := r.collection.FindOne(ctx, bson.M{"username": username}).Decode(&user)
    if err != nil {
        if err == mongo.ErrNoDocuments {
            return nil, nil
        }
        return nil, err
    }
    
    return &user, nil
}

func (r *mongoUserRepository) FindByEmail(ctx context.Context, email string) (*domain.User, error) {
    var user domain.User
    
    err := r.collection.FindOne(ctx, bson.M{"email": email}).Decode(&user)
    if err != nil {
        if err == mongo.ErrNoDocuments {
            return nil, nil
        }
        return nil, err
    }
    
    return &user, nil
}

func (r *mongoUserRepository) Update(ctx context.Context, user *domain.User) error {
    user.UpdatedAt = time.Now()
    
    _, err := r.collection.ReplaceOne(ctx, bson.M{"_id": user.ID}, user)
    return err
}

func (r *mongoUserRepository) Delete(ctx context.Context, id string) error {
    _, err := r.collection.DeleteOne(ctx, bson.M{"_id": id})
    return err
}

func (r *mongoUserRepository) List(ctx context.Context, page, pageSize int) ([]*domain.User, int, error) {
    if page < 1 {
        page = 1
    }
    if pageSize < 1 {
        pageSize = 10
    }
    
    skip := (page - 1) * pageSize
    
    // 查询总数
    total, err := r.collection.CountDocuments(ctx, bson.M{})
    if err != nil {
        return nil, 0, err
    }
    
    // 查询用户列表
    findOptions := options.Find().
        SetSkip(int64(skip)).
        SetLimit(int64(pageSize)).
        SetSort(bson.D{{Key: "created_at", Value: -1}})
    
    cursor, err := r.collection.Find(ctx, bson.M{}, findOptions)
    if err != nil {
        return nil, 0, err
    }
    defer cursor.Close(ctx)
    
    var users []*domain.User
    if err := cursor.All(ctx, &users); err != nil {
        return nil, 0, err
    }
    
    return users, int(total), nil
}

服务层实现

// internal/user/service/service.go
package service

import (
    "context"
    "errors"
    
    "microservice-demo/internal/user/domain"
    "microservice-demo/internal/user/repository"
)

var (
    ErrUserNotFound      = errors.New("user not found")
    ErrUsernameExists    = errors.New("username already exists")
    ErrEmailExists       = errors.New("email already exists")
    ErrInvalidCredentials = errors.New("invalid credentials")
)

type UserService interface {
    CreateUser(ctx context.Context, username, email, password, fullName string) (*domain.User, error)
    GetUser(ctx context.Context, id string) (*domain.User, error)
    UpdateUser(ctx context.Context, id, email, fullName string) (*domain.User, error)
    DeleteUser(ctx context.Context, id string) error
    ListUsers(ctx context.Context, page, pageSize int) ([]*domain.User, int, error)
    AuthenticateUser(ctx context.Context, username, password string) (*domain.User, error)
}

type userService struct {
    repo repository.UserRepository
}

func NewUserService(repo repository.UserRepository) UserService {
    return &userService{
        repo: repo,
    }
}

func (s *userService) CreateUser(ctx context.Context, username, email, password, fullName string) (*domain.User, error) {
    // 检查用户名是否已存在
    existingUser, err := s.repo.FindByUsername(ctx, username)
    if err != nil {
        return nil, err
    }
    if existingUser != nil {
        return nil, ErrUsernameExists
    }
    
    // 检查邮箱是否已存在
    existingUser, err = s.repo.FindByEmail(ctx, email)
    if err != nil {
        return nil, err
    }
    if existingUser != nil {
        return nil, ErrEmailExists
    }
    
    // 创建新用户
    user, err := domain.NewUser(username, email, password, fullName)
    if err != nil {
        return nil, err
    }
    
    // 保存用户
    if err := s.repo.Create(ctx, user); err != nil {
        return nil, err
    }
    
    return user, nil
}

func (s *userService) GetUser(ctx context.Context, id string) (*domain.User, error) {
    user, err := s.repo.FindByID(ctx, id)
    if err != nil {
        return nil, err
    }
    if user == nil {
        return nil, ErrUserNotFound
    }
    
    return user, nil
}

func (s *userService) UpdateUser(ctx context.Context, id, email, fullName string) (*domain.User, error) {
    user, err := s.repo.FindByID(ctx, id)
    if err != nil {
        return nil, err
    }
    if user == nil {
        return nil, ErrUserNotFound
    }
    
    // 检查邮箱是否已被其他用户使用
    if email != "" && email != user.Email {
        existingUser, err := s.repo.FindByEmail(ctx, email)
        if err != nil {
            return nil, err
        }
        if existingUser != nil && existingUser.ID != id {
            return nil, ErrEmailExists
        }
    }
    
    // 更新用户资料
    if err := user.UpdateProfile(email, fullName); err != nil {
        return nil, err
    }
    
    // 保存更新
    if err := s.repo.Update(ctx, user); err != nil {
        return nil, err
    }
    
    return user, nil
}

func (s *userService) DeleteUser(ctx context.Context, id string) error {
    user, err := s.repo.FindByID(ctx, id)
    if err != nil {
        return err
    }
    if user == nil {
        return ErrUserNotFound
    }
    
    return s.repo.Delete(ctx, id)
}

func (s *userService) ListUsers(ctx context.Context, page, pageSize int) ([]*domain.User, int, error) {
    return s.repo.List(ctx, page, pageSize)
}

func (s *userService) AuthenticateUser(ctx context.Context, username, password string) (*domain.User, error) {
    user, err := s.repo.FindByUsername(ctx, username)
    if err != nil {
        return nil, err
    }
    if user == nil {
        return nil, ErrInvalidCredentials
    }
    
    if !user.VerifyPassword(password) {
        return nil, ErrInvalidCredentials
    }
    
    return user, nil
}

gRPC传输层实现

// internal/user/transport/grpc_server.go
package transport

import (
    "context"

    "google.golang.org/grpc/codes"
    "google.golang.org/grpc/status"

    pb "microservice-demo/api/proto/user"
    "microservice-demo/internal/user/service"
)

type grpcServer struct {
    pb.UnimplementedUserServiceServer
    userService service.UserService
}

func NewGRPCServer(userService service.UserService) pb.UserServiceServer {
    return &grpcServer{
        userService: userService,
    }
}

func (s *grpcServer) CreateUser(ctx context.Context, req *pb.CreateUserRequest) (*pb.CreateUserResponse, error) {
    user, err := s.userService.CreateUser(ctx, req.Username, req.Email, req.Password, req.FullName)
    if err != nil {
        return nil, status.Error(codes.Internal, err.Error())
    }

    return &pb.CreateUserResponse{
        User: &pb.User{
            Id:        user.ID,
            Username:  user.Username,
            Email:     user.Email,
            FullName:  user.FullName,
            CreatedAt: user.CreatedAt.Format("2006-01-02T15:04:05Z"),
            UpdatedAt: user.UpdatedAt.Format("2006-01-02T15:04:05Z"),
        },
    }, nil
}

func (s *grpcServer) GetUser(ctx context.Context, req *pb.GetUserRequest) (*pb.GetUserResponse, error) {
    user, err := s.userService.GetUser(ctx, req.Id)
    if err != nil {
        if err == service.ErrUserNotFound {
            return nil, status.Error(codes.NotFound, "user not found")
        }
        return nil, status.Error(codes.Internal, err.Error())
    }

    return &pb.GetUserResponse{
        User: &pb.User{
            Id:        user.ID,
            Username:  user.Username,
            Email:     user.Email,
            FullName:  user.FullName,
            CreatedAt: user.CreatedAt.Format("2006-01-02T15:04:05Z"),
            UpdatedAt: user.UpdatedAt.Format("2006-01-02T15:04:05Z"),
        },
    }, nil
}

func (s *grpcServer) UpdateUser(ctx context.Context, req *pb.UpdateUserRequest) (*pb.UpdateUserResponse, error) {
    user, err := s.userService.UpdateUser(ctx, req.Id, req.Email, req.FullName)
    if err != nil {
        if err == service.ErrUserNotFound {
            return nil, status.Error(codes.NotFound, "user not found")
        }
        return nil, status.Error(codes.Internal, err.Error())
    }

    return &pb.UpdateUserResponse{
        User: &pb.User{
            Id:        user.ID,
            Username:  user.Username,
            Email:     user.Email,
            FullName:  user.FullName,
            CreatedAt: user.CreatedAt.Format("2006-01-02T15:04:05Z"),
            UpdatedAt: user.UpdatedAt.Format("2006-01-02T15:04:05Z"),
        },
    }, nil
}

func (s *grpcServer) DeleteUser(ctx context.Context, req *pb.DeleteUserRequest) (*pb.DeleteUserResponse, error) {
    err := s.userService.DeleteUser(ctx, req.Id)
    if err != nil {
        if err == service.ErrUserNotFound {
            return nil, status.Error(codes.NotFound, "user not found")
        }
        return nil, status.Error(codes.Internal, err.Error())
    }

    return &pb.DeleteUserResponse{
        Success: true,
    }, nil
}

func (s *grpcServer) ListUsers(ctx context.Context, req *pb.ListUsersRequest) (*pb.ListUsersResponse, error) {
    users, total, err := s.userService.ListUsers(ctx, int(req.Page), int(req.PageSize))
    if err != nil {
        return nil, status.Error(codes.Internal, err.Error())
    }

    pbUsers := make([]*pb.User, len(users))
    for i, user := range users {
        pbUsers[i] = &pb.User{
            Id:        user.ID,
            Username:  user.Username,
            Email:     user.Email,
            FullName:  user.FullName,
            CreatedAt: user.CreatedAt.Format("2006-01-02T15:04:05Z"),
            UpdatedAt: user.UpdatedAt.Format("2006-01-02T15:04:05Z"),
        }
    }

    return &pb.ListUsersResponse{
        Users: pbUsers,
        Total: int32(total),
    }, nil
}

HTTP REST API实现

// internal/user/transport/http_server.go
package transport

import (
    "net/http"
    "strconv"

    "github.com/gin-gonic/gin"

    "microservice-demo/internal/user/service"
)

type HTTPServer struct {
    userService service.UserService
}

func NewHTTPServer(userService service.UserService) *HTTPServer {
    return &HTTPServer{
        userService: userService,
    }
}

func (h *HTTPServer) RegisterRoutes(router *gin.Engine) {
    v1 := router.Group("/api/v1")
    {
        users := v1.Group("/users")
        {
            users.POST("", h.CreateUser)
            users.GET("/:id", h.GetUser)
            users.PUT("/:id", h.UpdateUser)
            users.DELETE("/:id", h.DeleteUser)
            users.GET("", h.ListUsers)
        }
    }
}

type CreateUserRequest struct {
    Username string `json:"username" binding:"required"`
    Email    string `json:"email" binding:"required,email"`
    Password string `json:"password" binding:"required,min=8"`
    FullName string `json:"full_name"`
}

func (h *HTTPServer) CreateUser(c *gin.Context) {
    var req CreateUserRequest
    if err := c.ShouldBindJSON(&req); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
        return
    }

    user, err := h.userService.CreateUser(c.Request.Context(), req.Username, req.Email, req.Password, req.FullName)
    if err != nil {
        switch err {
        case service.ErrUsernameExists:
            c.JSON(http.StatusConflict, gin.H{"error": "username already exists"})
        case service.ErrEmailExists:
            c.JSON(http.StatusConflict, gin.H{"error": "email already exists"})
        default:
            c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
        }
        return
    }

    c.JSON(http.StatusCreated, gin.H{"user": user})
}

func (h *HTTPServer) GetUser(c *gin.Context) {
    id := c.Param("id")

    user, err := h.userService.GetUser(c.Request.Context(), id)
    if err != nil {
        if err == service.ErrUserNotFound {
            c.JSON(http.StatusNotFound, gin.H{"error": "user not found"})
        } else {
            c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
        }
        return
    }

    c.JSON(http.StatusOK, gin.H{"user": user})
}

type UpdateUserRequest struct {
    Email    string `json:"email"`
    FullName string `json:"full_name"`
}

func (h *HTTPServer) UpdateUser(c *gin.Context) {
    id := c.Param("id")

    var req UpdateUserRequest
    if err := c.ShouldBindJSON(&req); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
        return
    }

    user, err := h.userService.UpdateUser(c.Request.Context(), id, req.Email, req.FullName)
    if err != nil {
        switch err {
        case service.ErrUserNotFound:
            c.JSON(http.StatusNotFound, gin.H{"error": "user not found"})
        case service.ErrEmailExists:
            c.JSON(http.StatusConflict, gin.H{"error": "email already exists"})
        default:
            c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
        }
        return
    }

    c.JSON(http.StatusOK, gin.H{"user": user})
}

func (h *HTTPServer) DeleteUser(c *gin.Context) {
    id := c.Param("id")

    err := h.userService.DeleteUser(c.Request.Context(), id)
    if err != nil {
        if err == service.ErrUserNotFound {
            c.JSON(http.StatusNotFound, gin.H{"error": "user not found"})
        } else {
            c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
        }
        return
    }

    c.JSON(http.StatusOK, gin.H{"message": "user deleted successfully"})
}

func (h *HTTPServer) ListUsers(c *gin.Context) {
    page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
    pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "10"))

    users, total, err := h.userService.ListUsers(c.Request.Context(), page, pageSize)
    if err != nil {
        c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
        return
    }

    c.JSON(http.StatusOK, gin.H{
        "users": users,
        "total": total,
        "page":  page,
        "page_size": pageSize,
    })
}

服务启动和配置

// cmd/user-service/main.go
package main

import (
    "context"
    "fmt"
    "log"
    "net"
    "net/http"
    "os"
    "os/signal"
    "syscall"
    "time"

    "github.com/gin-gonic/gin"
    "go.mongodb.org/mongo-driver/mongo"
    "go.mongodb.org/mongo-driver/mongo/options"
    "google.golang.org/grpc"

    pb "microservice-demo/api/proto/user"
    "microservice-demo/internal/user/repository"
    "microservice-demo/internal/user/service"
    "microservice-demo/internal/user/transport"
    "microservice-demo/pkg/config"
    "microservice-demo/pkg/logger"
)

func main() {
    // 加载配置
    cfg := config.Load()

    // 初始化日志
    logger := logger.New(cfg.LogLevel)

    // 连接数据库
    client, err := mongo.Connect(context.Background(), options.Client().ApplyURI(cfg.MongoDB.URI))
    if err != nil {
        log.Fatal("Failed to connect to MongoDB:", err)
    }
    defer client.Disconnect(context.Background())

    db := client.Database(cfg.MongoDB.Database)

    // 初始化依赖
    userRepo := repository.NewMongoUserRepository(db)
    userService := service.NewUserService(userRepo)

    // 启动gRPC服务器
    go func() {
        lis, err := net.Listen("tcp", fmt.Sprintf(":%d", cfg.GRPC.Port))
        if err != nil {
            log.Fatal("Failed to listen for gRPC:", err)
        }

        grpcServer := grpc.NewServer()
        pb.RegisterUserServiceServer(grpcServer, transport.NewGRPCServer(userService))

        logger.Info("Starting gRPC server", "port", cfg.GRPC.Port)
        if err := grpcServer.Serve(lis); err != nil {
            log.Fatal("Failed to serve gRPC:", err)
        }
    }()

    // 启动HTTP服务器
    gin.SetMode(gin.ReleaseMode)
    router := gin.New()
    router.Use(gin.Logger(), gin.Recovery())

    httpServer := transport.NewHTTPServer(userService)
    httpServer.RegisterRoutes(router)

    srv := &http.Server{
        Addr:    fmt.Sprintf(":%d", cfg.HTTP.Port),
        Handler: router,
    }

    go func() {
        logger.Info("Starting HTTP server", "port", cfg.HTTP.Port)
        if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
            log.Fatal("Failed to start HTTP server:", err)
        }
    }()

    // 优雅关闭
    quit := make(chan os.Signal, 1)
    signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
    <-quit

    logger.Info("Shutting down servers...")

    ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
    defer cancel()

    if err := srv.Shutdown(ctx); err != nil {
        logger.Error("HTTP server forced to shutdown", "error", err)
    }

    logger.Info("Servers stopped")
}

Docker容器化

# deployments/docker/Dockerfile
FROM golang:1.21-alpine AS builder

WORKDIR /app

# 安装依赖
COPY go.mod go.sum ./
RUN go mod download

# 复制源代码
COPY . .

# 构建应用
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o user-service ./cmd/user-service

# 运行阶段
FROM alpine:latest

RUN apk --no-cache add ca-certificates
WORKDIR /root/

# 复制二进制文件
COPY --from=builder /app/user-service .

# 暴露端口
EXPOSE 8080 9090

# 运行应用
CMD ["./user-service"]

Kubernetes部署配置

# deployments/kubernetes/user-service.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: user-service
  labels:
    app: user-service
spec:
  replicas: 3
  selector:
    matchLabels:
      app: user-service
  template:
    metadata:
      labels:
        app: user-service
    spec:
      containers:
      - name: user-service
        image: user-service:latest
        ports:
        - containerPort: 8080
          name: http
        - containerPort: 9090
          name: grpc
        env:
        - name: MONGODB_URI
          valueFrom:
            secretKeyRef:
              name: user-service-secrets
              key: mongodb-uri
        - name: LOG_LEVEL
          value: "info"
        resources:
          requests:
            memory: "64Mi"
            cpu: "250m"
          limits:
            memory: "128Mi"
            cpu: "500m"
        livenessProbe:
          httpGet:
            path: /health
            port: 8080
          initialDelaySeconds: 30
          periodSeconds: 10
        readinessProbe:
          httpGet:
            path: /ready
            port: 8080
          initialDelaySeconds: 5
          periodSeconds: 5

---
apiVersion: v1
kind: Service
metadata:
  name: user-service
  labels:
    app: user-service
spec:
  selector:
    app: user-service
  ports:
  - name: http
    port: 80
    targetPort: 8080
  - name: grpc
    port: 9090
    targetPort: 9090
  type: ClusterIP

---
apiVersion: v1
kind: Secret
metadata:
  name: user-service-secrets
type: Opaque
data:
  mongodb-uri: bW9uZ29kYjovL3VzZXI6cGFzc3dvcmRAbW9uZ29kYjoyNzAxNy9kYXRhYmFzZQ==

总结

Go语言微服务开发的核心要点:

🎯 架构设计

  1. 领域驱动设计:清晰的领域模型和业务逻辑
  2. 微服务拆分:合理的服务边界和职责划分
  3. API设计:RESTful和gRPC接口设计
  4. 数据管理:分布式数据存储和一致性

✅ 技术栈

  • gRPC和Protocol Buffers
  • RESTful API和JSON
  • 容器化和Kubernetes
  • 服务发现和配置管理

🚀 最佳实践

  • 服务间通信模式
  • 错误处理和重试策略
  • 监控和可观测性
  • 安全性和认证授权

💡 性能优化

  • 并发处理和资源管理
  • 缓存策略和数据库优化
  • 负载均衡和自动扩缩容
  • 服务网格和流量控制

🔧 部署运维

  • Docker容器化
  • Kubernetes编排
  • CI/CD流水线
  • 监控和日志收集

掌握Go微服务开发,构建可扩展的分布式系统!


Go语言的简洁性和高性能特性使其成为构建微服务的理想选择,通过合理的架构设计和最佳实践,可以构建出高效、可靠的分布式系统。