在现代软件开发中,微服务架构已成为构建大型、复杂应用系统的首选方案。相比传统的单体架构,微服务具有以下显著优势:
- 技术多样性 - 不同服务可以使用最适合的技术栈
- 独立部署 - 服务可以独立开发、测试和部署
- 弹性扩展 - 根据负载需求灵活扩缩容
- 故障隔离 - 单个服务故障不会影响整个系统
- 团队自治 - 不同团队可以独立维护各自的服务
Go语言凭借其出色的并发性能、简洁的语法和丰富的生态系统,成为微服务开发的理想选择。
🏗️ 系统架构设计
整体架构图
scss
┌─────────────────────────────────────────────────────────────┐
│ API Gateway │
│ (Gin + 负载均衡) │
└─────────────────────┬───────────────────────────────────────┘
│
┌─────────────┴─────────────┐
│ │
┌───────▼────────┐ ┌────────▼────────┐
│ User Service │ │ Order Service │
│ (用户服务) │ │ (订单服务) │
│ │ │ │
│ ┌─────────────┐│ │ ┌─────────────┐ │
│ │ TORM ││ │ │ TORM │ │
│ │ MySQL ││ │ │ MySQL │ │
│ └─────────────┘│ │ └─────────────┘ │
└────────────────┘ └─────────────────┘
│ │
└─────────────┬─────────────┘
│
┌─────────────▼─────────────┐
│ Payment Service │
│ (支付服务) │
│ │
│ ┌─────────────────────────┐│
│ │ TORM + Redis ││
│ │ PostgreSQL ││
│ └─────────────────────────┘│
└───────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ 基础设施层 │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Consul │ │ Redis │ │ Prometh- │ │ Jaeger │ │
│ │服务发现 │ │ 缓存 │ │ eus │ │ 链路追踪 │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
└─────────────────────────────────────────────────────────────┘
技术栈选择
- Web框架: Gin (HTTP API)
- RPC框架: gRPC (服务间通信)
- ORM框架: TORM (数据库操作)
- 数据库: MySQL, PostgreSQL
- 缓存: Redis
- 服务发现: Consul
- 配置管理: Viper
- 监控: Prometheus + Grafana
- 链路追踪: Jaeger
- 容器化: Docker + Kubernetes
🚀 项目初始化
项目结构
bash
ecommerce-microservices/
├── api-gateway/ # API网关
├── services/
│ ├── user-service/ # 用户服务
│ ├── order-service/ # 订单服务
│ └── payment-service/ # 支付服务
├── shared/ # 共享库
│ ├── config/ # 配置管理
│ ├── middleware/ # 中间件
│ ├── utils/ # 工具函数
│ └── proto/ # Protobuf定义
├── docker/ # Docker配置
├── k8s/ # Kubernetes配置
├── monitoring/ # 监控配置
└── docs/ # 文档
共享配置和工具
首先创建共享的配置管理模块:
go
// shared/config/config.go
package config
import (
"fmt"
"github.com/spf13/viper"
)
type DatabaseConfig struct {
Driver string `mapstructure:"driver"`
Host string `mapstructure:"host"`
Port int `mapstructure:"port"`
Username string `mapstructure:"username"`
Password string `mapstructure:"password"`
Database string `mapstructure:"database"`
}
type RedisConfig struct {
Host string `mapstructure:"host"`
Port int `mapstructure:"port"`
Password string `mapstructure:"password"`
DB int `mapstructure:"db"`
}
type ConsulConfig struct {
Host string `mapstructure:"host"`
Port int `mapstructure:"port"`
}
type ServiceConfig struct {
Name string `mapstructure:"name"`
Port int `mapstructure:"port"`
Database DatabaseConfig `mapstructure:"database"`
Redis RedisConfig `mapstructure:"redis"`
Consul ConsulConfig `mapstructure:"consul"`
}
func LoadConfig(path string) (*ServiceConfig, error) {
viper.AddConfigPath(path)
viper.SetConfigName("config")
viper.SetConfigType("yaml")
viper.AutomaticEnv()
if err := viper.ReadInConfig(); err != nil {
return nil, fmt.Errorf("读取配置文件失败: %w", err)
}
var config ServiceConfig
if err := viper.Unmarshal(&config); err != nil {
return nil, fmt.Errorf("解析配置文件失败: %w", err)
}
return &config, nil
}
数据库连接管理
go
// shared/database/database.go
package database
import (
"fmt"
"github.com/zhoudm1743/torm/db"
"ecommerce/shared/config"
)
func InitDatabase(cfg config.DatabaseConfig, connectionName string) error {
conf := &db.Config{
Driver: cfg.Driver,
Host: cfg.Host,
Port: cfg.Port,
Username: cfg.Username,
Password: cfg.Password,
Database: cfg.Database,
}
return db.AddConnection(connectionName, conf)
}
func GetQuery(connectionName string) (*db.QueryBuilder, error) {
return db.Query(connectionName)
}
👤 用户服务实现
用户模型定义
go
// services/user-service/internal/models/user.go
package models
import (
"time"
"golang.org/x/crypto/bcrypt"
)
type User struct {
ID int `json:"id" torm:"id,primary_key,auto_increment"`
Username string `json:"username" torm:"username,unique,not_null"`
Email string `json:"email" torm:"email,unique,not_null"`
Password string `json:"-" torm:"password,not_null"`
Phone string `json:"phone" torm:"phone"`
Avatar string `json:"avatar" torm:"avatar"`
Status int `json:"status" torm:"status,default:1"`
CreatedAt time.Time `json:"created_at" torm:"created_at"`
UpdatedAt time.Time `json:"updated_at" torm:"updated_at"`
}
func (u *User) HashPassword() error {
hashedBytes, err := bcrypt.GenerateFromPassword([]byte(u.Password), bcrypt.DefaultCost)
if err != nil {
return err
}
u.Password = string(hashedBytes)
return nil
}
func (u *User) CheckPassword(password string) bool {
err := bcrypt.CompareHashAndPassword([]byte(u.Password), []byte(password))
return err == nil
}
type UserProfile struct {
UserID int `json:"user_id" torm:"user_id,primary_key"`
RealName string `json:"real_name" torm:"real_name"`
Gender int `json:"gender" torm:"gender"`
Birthday string `json:"birthday" torm:"birthday"`
Address string `json:"address" torm:"address"`
Bio string `json:"bio" torm:"bio"`
}
用户仓储层
TORM使用说明:
TORM提供了两种操作方式:
- 直接执行 - 使用
.Exec()
直接执行数据库操作(推荐) - 生成SQL - 使用
.ToSQL()
生成SQL语句后手动执行(调试和学习时使用)
go
// 直接执行(推荐的生产环境用法)
_, err := query.Table("users").Where("id", "=", id).Delete().Exec()
// 生成SQL(用于调试、日志记录或自定义执行)
sql, args, err := query.Table("users").Where("id", "=", id).Delete().ToSQL()
if err == nil {
fmt.Printf("Generated SQL: %s, Args: %v\n", sql, args) // 用于调试
_, err = query.Exec(sql, args...)
}
go
// services/user-service/internal/repository/user_repository.go
package repository
import (
"fmt"
"ecommerce/services/user-service/internal/models"
"ecommerce/shared/database"
)
type UserRepository interface {
Create(user *models.User) error
GetByID(id int) (*models.User, error)
GetByEmail(email string) (*models.User, error)
GetByUsername(username string) (*models.User, error)
Update(user *models.User) error
Delete(id int) error
List(offset, limit int) ([]models.User, error)
}
type userRepository struct {
connectionName string
}
func NewUserRepository(connectionName string) UserRepository {
return &userRepository{
connectionName: connectionName,
}
}
func (r *userRepository) Create(user *models.User) error {
query, err := database.GetQuery(r.connectionName)
if err != nil {
return fmt.Errorf("获取数据库连接失败: %w", err)
}
// 直接使用TORM执行插入操作
result, err := query.Table("users").Insert(map[string]interface{}{
"username": user.Username,
"email": user.Email,
"password": user.Password,
"phone": user.Phone,
"avatar": user.Avatar,
"status": user.Status,
"created_at": user.CreatedAt,
"updated_at": user.UpdatedAt,
}).Exec()
if err != nil {
return fmt.Errorf("执行插入失败: %w", err)
}
id, err := result.LastInsertId()
if err != nil {
return fmt.Errorf("获取插入ID失败: %w", err)
}
user.ID = int(id)
return nil
}
func (r *userRepository) GetByID(id int) (*models.User, error) {
query, err := database.GetQuery(r.connectionName)
if err != nil {
return nil, fmt.Errorf("获取数据库连接失败: %w", err)
}
rows, err := query.From("users").Where("id", "=", id).First()
if err != nil {
return nil, fmt.Errorf("查询用户失败: %w", err)
}
if len(rows) == 0 {
return nil, fmt.Errorf("用户不存在")
}
row := rows[0]
user := &models.User{
ID: int(row["id"].(int64)),
Username: row["username"].(string),
Email: row["email"].(string),
Password: row["password"].(string),
Phone: getStringFromInterface(row["phone"]),
Avatar: getStringFromInterface(row["avatar"]),
Status: int(row["status"].(int64)),
CreatedAt: row["created_at"].(time.Time),
UpdatedAt: row["updated_at"].(time.Time),
}
return user, nil
}
func (r *userRepository) GetByEmail(email string) (*models.User, error) {
query, err := database.GetQuery(r.connectionName)
if err != nil {
return nil, fmt.Errorf("获取数据库连接失败: %w", err)
}
rows, err := query.From("users").Where("email", "=", email).Find()
if err != nil {
return nil, fmt.Errorf("查询用户失败: %w", err)
}
if len(rows) == 0 {
return nil, fmt.Errorf("用户不存在")
}
return r.mapRowToUser(rows[0])
}
func (r *userRepository) GetByUsername(username string) (*models.User, error) {
query, err := database.GetQuery(r.connectionName)
if err != nil {
return nil, fmt.Errorf("获取数据库连接失败: %w", err)
}
rows, err := query.From("users").Where("username", "=", username).Find()
if err != nil {
return nil, fmt.Errorf("查询用户失败: %w", err)
}
if len(rows) == 0 {
return nil, fmt.Errorf("用户不存在")
}
return r.mapRowToUser(rows[0])
}
func (r *userRepository) Update(user *models.User) error {
query, err := database.GetQuery(r.connectionName)
if err != nil {
return fmt.Errorf("获取数据库连接失败: %w", err)
}
// 直接执行更新操作
_, err = query.Table("users").Where("id", "=", user.ID).Update(map[string]interface{}{
"username": user.Username,
"email": user.Email,
"phone": user.Phone,
"avatar": user.Avatar,
"status": user.Status,
"updated_at": user.UpdatedAt,
}).Exec()
if err != nil {
return fmt.Errorf("执行更新失败: %w", err)
}
return nil
}
func (r *userRepository) Delete(id int) error {
query, err := database.GetQuery(r.connectionName)
if err != nil {
return fmt.Errorf("获取数据库连接失败: %w", err)
}
// 直接执行删除操作
_, err = query.Table("users").Where("id", "=", id).Delete().Exec()
if err != nil {
return fmt.Errorf("执行删除失败: %w", err)
}
return nil
}
func (r *userRepository) List(offset, limit int) ([]models.User, error) {
query, err := database.GetQuery(r.connectionName)
if err != nil {
return nil, fmt.Errorf("获取数据库连接失败: %w", err)
}
rows, err := query.From("users").
OrderBy("id", "DESC").
Offset(offset).
Limit(limit).
Get()
if err != nil {
return nil, fmt.Errorf("查询用户列表失败: %w", err)
}
var users []models.User
for _, row := range rows {
user, err := r.mapRowToUser(row)
if err != nil {
continue // 跳过错误数据
}
users = append(users, *user)
}
return users, nil
}
// 辅助方法
func (r *userRepository) mapRowToUser(row map[string]interface{}) (*models.User, error) {
user := &models.User{
ID: int(row["id"].(int64)),
Username: row["username"].(string),
Email: row["email"].(string),
Password: row["password"].(string),
Phone: getStringFromInterface(row["phone"]),
Avatar: getStringFromInterface(row["avatar"]),
Status: int(row["status"].(int64)),
CreatedAt: row["created_at"].(time.Time),
UpdatedAt: row["updated_at"].(time.Time),
}
return user, nil
}
func getStringFromInterface(v interface{}) string {
if v == nil {
return ""
}
if str, ok := v.(string); ok {
return str
}
return ""
}
用户服务层
go
// services/user-service/internal/service/user_service.go
package service
import (
"fmt"
"time"
"ecommerce/services/user-service/internal/models"
"ecommerce/services/user-service/internal/repository"
)
type UserService interface {
Register(username, email, password string) (*models.User, error)
Login(email, password string) (*models.User, error)
GetProfile(userID int) (*models.User, error)
UpdateProfile(user *models.User) error
DeleteUser(userID int) error
ListUsers(page, pageSize int) ([]models.User, error)
}
type userService struct {
userRepo repository.UserRepository
}
func NewUserService(userRepo repository.UserRepository) UserService {
return &userService{
userRepo: userRepo,
}
}
func (s *userService) Register(username, email, password string) (*models.User, error) {
// 检查用户名是否已存在
if existingUser, _ := s.userRepo.GetByUsername(username); existingUser != nil {
return nil, fmt.Errorf("用户名已存在")
}
// 检查邮箱是否已存在
if existingUser, _ := s.userRepo.GetByEmail(email); existingUser != nil {
return nil, fmt.Errorf("邮箱已被注册")
}
// 创建新用户
user := &models.User{
Username: username,
Email: email,
Password: password,
Status: 1,
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}
// 加密密码
if err := user.HashPassword(); err != nil {
return nil, fmt.Errorf("密码加密失败: %w", err)
}
// 保存到数据库
if err := s.userRepo.Create(user); err != nil {
return nil, fmt.Errorf("创建用户失败: %w", err)
}
return user, nil
}
func (s *userService) Login(email, password string) (*models.User, error) {
user, err := s.userRepo.GetByEmail(email)
if err != nil {
return nil, fmt.Errorf("用户不存在")
}
if !user.CheckPassword(password) {
return nil, fmt.Errorf("密码错误")
}
if user.Status != 1 {
return nil, fmt.Errorf("用户账户已被禁用")
}
return user, nil
}
func (s *userService) GetProfile(userID int) (*models.User, error) {
return s.userRepo.GetByID(userID)
}
func (s *userService) UpdateProfile(user *models.User) error {
user.UpdatedAt = time.Now()
return s.userRepo.Update(user)
}
func (s *userService) DeleteUser(userID int) error {
return s.userRepo.Delete(userID)
}
func (s *userService) ListUsers(page, pageSize int) ([]models.User, error) {
offset := (page - 1) * pageSize
return s.userRepo.List(offset, pageSize)
}
用户控制器
go
// services/user-service/internal/handler/user_handler.go
package handler
import (
"net/http"
"strconv"
"github.com/gin-gonic/gin"
"ecommerce/services/user-service/internal/service"
"ecommerce/services/user-service/internal/models"
)
type UserHandler struct {
userService service.UserService
}
func NewUserHandler(userService service.UserService) *UserHandler {
return &UserHandler{
userService: userService,
}
}
type RegisterRequest struct {
Username string `json:"username" binding:"required,min=3,max=20"`
Email string `json:"email" binding:"required,email"`
Password string `json:"password" binding:"required,min=6"`
}
type LoginRequest struct {
Email string `json:"email" binding:"required,email"`
Password string `json:"password" binding:"required"`
}
type Response struct {
Code int `json:"code"`
Message string `json:"message"`
Data interface{} `json:"data,omitempty"`
}
func (h *UserHandler) Register(c *gin.Context) {
var req RegisterRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, Response{
Code: 400,
Message: "请求参数错误: " + err.Error(),
})
return
}
user, err := h.userService.Register(req.Username, req.Email, req.Password)
if err != nil {
c.JSON(http.StatusBadRequest, Response{
Code: 400,
Message: err.Error(),
})
return
}
// 清除密码字段
user.Password = ""
c.JSON(http.StatusCreated, Response{
Code: 201,
Message: "注册成功",
Data: user,
})
}
func (h *UserHandler) Login(c *gin.Context) {
var req LoginRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, Response{
Code: 400,
Message: "请求参数错误: " + err.Error(),
})
return
}
user, err := h.userService.Login(req.Email, req.Password)
if err != nil {
c.JSON(http.StatusUnauthorized, Response{
Code: 401,
Message: err.Error(),
})
return
}
// 清除密码字段
user.Password = ""
// 这里应该生成JWT token
// token := generateJWTToken(user)
c.JSON(http.StatusOK, Response{
Code: 200,
Message: "登录成功",
Data: gin.H{
"user": user,
// "token": token,
},
})
}
func (h *UserHandler) GetProfile(c *gin.Context) {
userIDStr := c.Param("id")
userID, err := strconv.Atoi(userIDStr)
if err != nil {
c.JSON(http.StatusBadRequest, Response{
Code: 400,
Message: "用户ID格式错误",
})
return
}
user, err := h.userService.GetProfile(userID)
if err != nil {
c.JSON(http.StatusNotFound, Response{
Code: 404,
Message: err.Error(),
})
return
}
// 清除密码字段
user.Password = ""
c.JSON(http.StatusOK, Response{
Code: 200,
Message: "获取成功",
Data: user,
})
}
func (h *UserHandler) UpdateProfile(c *gin.Context) {
userIDStr := c.Param("id")
userID, err := strconv.Atoi(userIDStr)
if err != nil {
c.JSON(http.StatusBadRequest, Response{
Code: 400,
Message: "用户ID格式错误",
})
return
}
var user models.User
if err := c.ShouldBindJSON(&user); err != nil {
c.JSON(http.StatusBadRequest, Response{
Code: 400,
Message: "请求参数错误: " + err.Error(),
})
return
}
user.ID = userID
if err := h.userService.UpdateProfile(&user); err != nil {
c.JSON(http.StatusBadRequest, Response{
Code: 400,
Message: err.Error(),
})
return
}
c.JSON(http.StatusOK, Response{
Code: 200,
Message: "更新成功",
})
}
func (h *UserHandler) ListUsers(c *gin.Context) {
pageStr := c.DefaultQuery("page", "1")
pageSizeStr := c.DefaultQuery("page_size", "10")
page, err := strconv.Atoi(pageStr)
if err != nil || page < 1 {
page = 1
}
pageSize, err := strconv.Atoi(pageSizeStr)
if err != nil || pageSize < 1 || pageSize > 100 {
pageSize = 10
}
users, err := h.userService.ListUsers(page, pageSize)
if err != nil {
c.JSON(http.StatusInternalServerError, Response{
Code: 500,
Message: err.Error(),
})
return
}
// 清除所有用户的密码字段
for i := range users {
users[i].Password = ""
}
c.JSON(http.StatusOK, Response{
Code: 200,
Message: "获取成功",
Data: gin.H{
"users": users,
"page": page,
"page_size": pageSize,
"total": len(users),
},
})
}
func (h *UserHandler) DeleteUser(c *gin.Context) {
userIDStr := c.Param("id")
userID, err := strconv.Atoi(userIDStr)
if err != nil {
c.JSON(http.StatusBadRequest, Response{
Code: 400,
Message: "用户ID格式错误",
})
return
}
if err := h.userService.DeleteUser(userID); err != nil {
c.JSON(http.StatusBadRequest, Response{
Code: 400,
Message: err.Error(),
})
return
}
c.JSON(http.StatusOK, Response{
Code: 200,
Message: "删除成功",
})
}
用户服务主程序
go
// services/user-service/cmd/main.go
package main
import (
"fmt"
"log"
"github.com/gin-gonic/gin"
"ecommerce/services/user-service/internal/handler"
"ecommerce/services/user-service/internal/repository"
"ecommerce/services/user-service/internal/service"
"ecommerce/shared/config"
"ecommerce/shared/database"
)
func main() {
// 加载配置
cfg, err := config.LoadConfig("./configs")
if err != nil {
log.Fatalf("加载配置失败: %v", err)
}
// 初始化数据库
if err := database.InitDatabase(cfg.Database, "user_service"); err != nil {
log.Fatalf("初始化数据库失败: %v", err)
}
// 初始化仓储层
userRepo := repository.NewUserRepository("user_service")
// 初始化服务层
userSvc := service.NewUserService(userRepo)
// 初始化处理器
userHandler := handler.NewUserHandler(userSvc)
// 设置路由
router := setupRoutes(userHandler)
// 启动服务
port := fmt.Sprintf(":%d", cfg.Port)
log.Printf("用户服务启动在端口 %s", port)
if err := router.Run(port); err != nil {
log.Fatalf("启动服务失败: %v", err)
}
}
func setupRoutes(userHandler *handler.UserHandler) *gin.Engine {
router := gin.Default()
// 健康检查
router.GET("/health", func(c *gin.Context) {
c.JSON(200, gin.H{"status": "ok"})
})
// API路由组
api := router.Group("/api/v1")
{
users := api.Group("/users")
{
users.POST("/register", userHandler.Register)
users.POST("/login", userHandler.Login)
users.GET("/:id", userHandler.GetProfile)
users.PUT("/:id", userHandler.UpdateProfile)
users.DELETE("/:id", userHandler.DeleteUser)
users.GET("", userHandler.ListUsers)
}
}
return router
}
🛒 订单服务实现
订单模型
go
// services/order-service/internal/models/order.go
package models
import (
"time"
)
type Order struct {
ID int `json:"id" torm:"id,primary_key,auto_increment"`
OrderNo string `json:"order_no" torm:"order_no,unique,not_null"`
UserID int `json:"user_id" torm:"user_id,not_null"`
TotalPrice float64 `json:"total_price" torm:"total_price,not_null"`
Status OrderStatus `json:"status" torm:"status,not_null"`
Items []OrderItem `json:"items" torm:"-"`
CreatedAt time.Time `json:"created_at" torm:"created_at"`
UpdatedAt time.Time `json:"updated_at" torm:"updated_at"`
}
type OrderItem struct {
ID int `json:"id" torm:"id,primary_key,auto_increment"`
OrderID int `json:"order_id" torm:"order_id,not_null"`
ProductID int `json:"product_id" torm:"product_id,not_null"`
Quantity int `json:"quantity" torm:"quantity,not_null"`
Price float64 `json:"price" torm:"price,not_null"`
Total float64 `json:"total" torm:"total,not_null"`
}
type OrderStatus int
const (
OrderStatusPending OrderStatus = iota + 1
OrderStatusPaid
OrderStatusShipped
OrderStatusDelivered
OrderStatusCancelled
)
func (s OrderStatus) String() string {
switch s {
case OrderStatusPending:
return "pending"
case OrderStatusPaid:
return "paid"
case OrderStatusShipped:
return "shipped"
case OrderStatusDelivered:
return "delivered"
case OrderStatusCancelled:
return "cancelled"
default:
return "unknown"
}
}
func GenerateOrderNo() string {
return fmt.Sprintf("ORD%d", time.Now().UnixNano())
}
订单服务
go
// services/order-service/internal/service/order_service.go
package service
import (
"context"
"fmt"
"time"
"ecommerce/services/order-service/internal/models"
"ecommerce/services/order-service/internal/repository"
)
type CreateOrderRequest struct {
UserID int `json:"user_id"`
Items []CreateOrderItemRequest `json:"items"`
}
type CreateOrderItemRequest struct {
ProductID int `json:"product_id"`
Quantity int `json:"quantity"`
Price float64 `json:"price"`
}
type OrderService interface {
CreateOrder(ctx context.Context, req *CreateOrderRequest) (*models.Order, error)
GetOrder(ctx context.Context, orderID int) (*models.Order, error)
GetUserOrders(ctx context.Context, userID int, page, pageSize int) ([]models.Order, error)
UpdateOrderStatus(ctx context.Context, orderID int, status models.OrderStatus) error
CancelOrder(ctx context.Context, orderID int) error
}
type orderService struct {
orderRepo repository.OrderRepository
itemRepo repository.OrderItemRepository
}
func NewOrderService(orderRepo repository.OrderRepository, itemRepo repository.OrderItemRepository) OrderService {
return &orderService{
orderRepo: orderRepo,
itemRepo: itemRepo,
}
}
func (s *orderService) CreateOrder(ctx context.Context, req *CreateOrderRequest) (*models.Order, error) {
// 计算订单总价
var totalPrice float64
var orderItems []models.OrderItem
for _, item := range req.Items {
total := item.Price * float64(item.Quantity)
orderItems = append(orderItems, models.OrderItem{
ProductID: item.ProductID,
Quantity: item.Quantity,
Price: item.Price,
Total: total,
})
totalPrice += total
}
// 创建订单
order := &models.Order{
OrderNo: models.GenerateOrderNo(),
UserID: req.UserID,
TotalPrice: totalPrice,
Status: models.OrderStatusPending,
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}
// 保存订单
if err := s.orderRepo.Create(order); err != nil {
return nil, fmt.Errorf("创建订单失败: %w", err)
}
// 保存订单项
for i := range orderItems {
orderItems[i].OrderID = order.ID
if err := s.itemRepo.Create(&orderItems[i]); err != nil {
return nil, fmt.Errorf("创建订单项失败: %w", err)
}
}
order.Items = orderItems
return order, nil
}
func (s *orderService) GetOrder(ctx context.Context, orderID int) (*models.Order, error) {
order, err := s.orderRepo.GetByID(orderID)
if err != nil {
return nil, err
}
items, err := s.itemRepo.GetByOrderID(orderID)
if err != nil {
return nil, err
}
order.Items = items
return order, nil
}
func (s *orderService) GetUserOrders(ctx context.Context, userID int, page, pageSize int) ([]models.Order, error) {
offset := (page - 1) * pageSize
orders, err := s.orderRepo.GetByUserID(userID, offset, pageSize)
if err != nil {
return nil, err
}
// 为每个订单加载订单项
for i := range orders {
items, err := s.itemRepo.GetByOrderID(orders[i].ID)
if err != nil {
continue // 跳过加载失败的订单项
}
orders[i].Items = items
}
return orders, nil
}
func (s *orderService) UpdateOrderStatus(ctx context.Context, orderID int, status models.OrderStatus) error {
return s.orderRepo.UpdateStatus(orderID, status)
}
func (s *orderService) CancelOrder(ctx context.Context, orderID int) error {
order, err := s.orderRepo.GetByID(orderID)
if err != nil {
return err
}
if order.Status != models.OrderStatusPending {
return fmt.Errorf("只能取消待支付的订单")
}
return s.orderRepo.UpdateStatus(orderID, models.OrderStatusCancelled)
}
💳 支付服务实现
支付模型
go
// services/payment-service/internal/models/payment.go
package models
import (
"time"
)
type Payment struct {
ID int `json:"id" torm:"id,primary_key,auto_increment"`
PaymentNo string `json:"payment_no" torm:"payment_no,unique,not_null"`
OrderID int `json:"order_id" torm:"order_id,not_null"`
UserID int `json:"user_id" torm:"user_id,not_null"`
Amount float64 `json:"amount" torm:"amount,not_null"`
PaymentMethod PaymentMethod `json:"payment_method" torm:"payment_method,not_null"`
Status PaymentStatus `json:"status" torm:"status,not_null"`
ThirdPartyID string `json:"third_party_id" torm:"third_party_id"`
CreatedAt time.Time `json:"created_at" torm:"created_at"`
UpdatedAt time.Time `json:"updated_at" torm:"updated_at"`
}
type PaymentMethod int
const (
PaymentMethodAlipay PaymentMethod = iota + 1
PaymentMethodWechat
PaymentMethodBank
PaymentMethodCredit
)
type PaymentStatus int
const (
PaymentStatusPending PaymentStatus = iota + 1
PaymentStatusProcessing
PaymentStatusSuccess
PaymentStatusFailed
PaymentStatusRefunded
)
func (s PaymentStatus) String() string {
switch s {
case PaymentStatusPending:
return "pending"
case PaymentStatusProcessing:
return "processing"
case PaymentStatusSuccess:
return "success"
case PaymentStatusFailed:
return "failed"
case PaymentStatusRefunded:
return "refunded"
default:
return "unknown"
}
}
func GeneratePaymentNo() string {
return fmt.Sprintf("PAY%d", time.Now().UnixNano())
}
支付服务
go
// services/payment-service/internal/service/payment_service.go
package service
import (
"context"
"fmt"
"time"
"ecommerce/services/payment-service/internal/models"
"ecommerce/services/payment-service/internal/repository"
)
type CreatePaymentRequest struct {
OrderID int `json:"order_id"`
UserID int `json:"user_id"`
Amount float64 `json:"amount"`
PaymentMethod models.PaymentMethod `json:"payment_method"`
}
type PaymentService interface {
CreatePayment(ctx context.Context, req *CreatePaymentRequest) (*models.Payment, error)
ProcessPayment(ctx context.Context, paymentID int) error
GetPayment(ctx context.Context, paymentID int) (*models.Payment, error)
GetPaymentByOrderID(ctx context.Context, orderID int) (*models.Payment, error)
RefundPayment(ctx context.Context, paymentID int) error
}
type paymentService struct {
paymentRepo repository.PaymentRepository
}
func NewPaymentService(paymentRepo repository.PaymentRepository) PaymentService {
return &paymentService{
paymentRepo: paymentRepo,
}
}
func (s *paymentService) CreatePayment(ctx context.Context, req *CreatePaymentRequest) (*models.Payment, error) {
payment := &models.Payment{
PaymentNo: models.GeneratePaymentNo(),
OrderID: req.OrderID,
UserID: req.UserID,
Amount: req.Amount,
PaymentMethod: req.PaymentMethod,
Status: models.PaymentStatusPending,
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}
if err := s.paymentRepo.Create(payment); err != nil {
return nil, fmt.Errorf("创建支付记录失败: %w", err)
}
return payment, nil
}
func (s *paymentService) ProcessPayment(ctx context.Context, paymentID int) error {
payment, err := s.paymentRepo.GetByID(paymentID)
if err != nil {
return err
}
if payment.Status != models.PaymentStatusPending {
return fmt.Errorf("支付状态不正确")
}
// 更新状态为处理中
if err := s.paymentRepo.UpdateStatus(paymentID, models.PaymentStatusProcessing); err != nil {
return err
}
// 模拟第三方支付处理
success := s.simulateThirdPartyPayment(payment)
if success {
payment.ThirdPartyID = fmt.Sprintf("THIRD_%d", time.Now().Unix())
if err := s.paymentRepo.UpdateThirdPartyID(paymentID, payment.ThirdPartyID); err != nil {
return err
}
return s.paymentRepo.UpdateStatus(paymentID, models.PaymentStatusSuccess)
} else {
return s.paymentRepo.UpdateStatus(paymentID, models.PaymentStatusFailed)
}
}
func (s *paymentService) GetPayment(ctx context.Context, paymentID int) (*models.Payment, error) {
return s.paymentRepo.GetByID(paymentID)
}
func (s *paymentService) GetPaymentByOrderID(ctx context.Context, orderID int) (*models.Payment, error) {
return s.paymentRepo.GetByOrderID(orderID)
}
func (s *paymentService) RefundPayment(ctx context.Context, paymentID int) error {
payment, err := s.paymentRepo.GetByID(paymentID)
if err != nil {
return err
}
if payment.Status != models.PaymentStatusSuccess {
return fmt.Errorf("只能退款成功的支付")
}
// 模拟退款处理
success := s.simulateRefundProcess(payment)
if success {
return s.paymentRepo.UpdateStatus(paymentID, models.PaymentStatusRefunded)
} else {
return fmt.Errorf("退款处理失败")
}
}
// 模拟第三方支付处理
func (s *paymentService) simulateThirdPartyPayment(payment *models.Payment) bool {
// 模拟90%的成功率
return time.Now().Unix()%10 != 0
}
// 模拟退款处理
func (s *paymentService) simulateRefundProcess(payment *models.Payment) bool {
// 模拟95%的成功率
return time.Now().Unix()%20 != 0
}
🌐 API网关实现
网关路由配置
go
// api-gateway/internal/router/router.go
package router
import (
"net/http"
"net/http/httputil"
"net/url"
"github.com/gin-gonic/gin"
"api-gateway/internal/middleware"
)
type ServiceConfig struct {
Name string
URL string
}
type Gateway struct {
services map[string]*ServiceConfig
}
func NewGateway() *Gateway {
return &Gateway{
services: make(map[string]*ServiceConfig),
}
}
func (g *Gateway) RegisterService(name, serviceURL string) {
g.services[name] = &ServiceConfig{
Name: name,
URL: serviceURL,
}
}
func (g *Gateway) SetupRoutes() *gin.Engine {
router := gin.Default()
// 添加中间件
router.Use(middleware.CORS())
router.Use(middleware.Logger())
router.Use(middleware.RateLimiter())
// 健康检查
router.GET("/health", func(c *gin.Context) {
c.JSON(200, gin.H{"status": "ok"})
})
// API路由
api := router.Group("/api/v1")
// 用户服务路由
userGroup := api.Group("/users")
userGroup.Use(g.createProxy("user-service"))
{
userGroup.Any("/*path", func(c *gin.Context) {})
}
// 订单服务路由
orderGroup := api.Group("/orders")
orderGroup.Use(middleware.AuthRequired()) // 需要认证
orderGroup.Use(g.createProxy("order-service"))
{
orderGroup.Any("/*path", func(c *gin.Context) {})
}
// 支付服务路由
paymentGroup := api.Group("/payments")
paymentGroup.Use(middleware.AuthRequired()) // 需要认证
paymentGroup.Use(g.createProxy("payment-service"))
{
paymentGroup.Any("/*path", func(c *gin.Context) {})
}
return router
}
func (g *Gateway) createProxy(serviceName string) gin.HandlerFunc {
return gin.HandlerFunc(func(c *gin.Context) {
service, exists := g.services[serviceName]
if !exists {
c.JSON(http.StatusNotFound, gin.H{"error": "Service not found"})
c.Abort()
return
}
// 创建反向代理
target, err := url.Parse(service.URL)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Invalid service URL"})
c.Abort()
return
}
proxy := httputil.NewSingleHostReverseProxy(target)
// 修改请求路径
c.Request.URL.Host = target.Host
c.Request.URL.Scheme = target.Scheme
c.Request.Header.Set("X-Forwarded-Host", c.Request.Header.Get("Host"))
c.Request.Host = target.Host
proxy.ServeHTTP(c.Writer, c.Request)
})
}
中间件实现
go
// api-gateway/internal/middleware/middleware.go
package middleware
import (
"net/http"
"time"
"github.com/gin-gonic/gin"
"golang.org/x/time/rate"
)
// CORS中间件
func CORS() gin.HandlerFunc {
return gin.HandlerFunc(func(c *gin.Context) {
c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With")
c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS, GET, PUT, DELETE")
if c.Request.Method == "OPTIONS" {
c.AbortWithStatus(204)
return
}
c.Next()
})
}
// 日志中间件
func Logger() gin.HandlerFunc {
return gin.LoggerWithFormatter(func(param gin.LogFormatterParams) string {
return fmt.Sprintf("%s - [%s] \"%s %s %s %d %s \"%s\" %s\"\n",
param.ClientIP,
param.TimeStamp.Format(time.RFC1123),
param.Method,
param.Path,
param.Request.Proto,
param.StatusCode,
param.Latency,
param.Request.UserAgent(),
param.ErrorMessage,
)
})
}
// 限流中间件
func RateLimiter() gin.HandlerFunc {
limiter := rate.NewLimiter(100, 200) // 每秒100个请求,突发200个
return func(c *gin.Context) {
if !limiter.Allow() {
c.JSON(http.StatusTooManyRequests, gin.H{
"error": "Too many requests",
})
c.Abort()
return
}
c.Next()
}
}
// 认证中间件
func AuthRequired() gin.HandlerFunc {
return func(c *gin.Context) {
token := c.GetHeader("Authorization")
if token == "" {
c.JSON(http.StatusUnauthorized, gin.H{
"error": "Authorization header required",
})
c.Abort()
return
}
// 这里应该验证JWT token
// if !validateJWTToken(token) {
// c.JSON(http.StatusUnauthorized, gin.H{
// "error": "Invalid token",
// })
// c.Abort()
// return
// }
c.Next()
}
}
🔧 服务发现与配置
Consul集成
go
// shared/consul/consul.go
package consul
import (
"fmt"
"github.com/hashicorp/consul/api"
)
type ServiceRegistry struct {
client *api.Client
}
func NewServiceRegistry(consulAddr string) (*ServiceRegistry, error) {
config := api.DefaultConfig()
config.Address = consulAddr
client, err := api.NewClient(config)
if err != nil {
return nil, fmt.Errorf("创建Consul客户端失败: %w", err)
}
return &ServiceRegistry{client: client}, nil
}
func (sr *ServiceRegistry) RegisterService(serviceName, serviceAddr string, port int) error {
registration := &api.AgentServiceRegistration{
ID: fmt.Sprintf("%s-%d", serviceName, port),
Name: serviceName,
Port: port,
Address: serviceAddr,
Check: &api.AgentServiceCheck{
HTTP: fmt.Sprintf("http://%s:%d/health", serviceAddr, port),
Timeout: "3s",
Interval: "10s",
DeregisterCriticalServiceAfter: "30s",
},
}
return sr.client.Agent().ServiceRegister(registration)
}
func (sr *ServiceRegistry) DiscoverService(serviceName string) ([]string, error) {
services, _, err := sr.client.Health().Service(serviceName, "", true, nil)
if err != nil {
return nil, fmt.Errorf("发现服务失败: %w", err)
}
var addresses []string
for _, service := range services {
addr := fmt.Sprintf("http://%s:%d", service.Service.Address, service.Service.Port)
addresses = append(addresses, addr)
}
return addresses, nil
}
func (sr *ServiceRegistry) DeregisterService(serviceID string) error {
return sr.client.Agent().ServiceDeregister(serviceID)
}
📊 监控和日志
Prometheus指标
go
// shared/metrics/metrics.go
package metrics
import (
"github.com/gin-gonic/gin"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
"strconv"
"time"
)
var (
RequestsTotal = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "http_requests_total",
Help: "Total number of HTTP requests",
},
[]string{"method", "path", "status"},
)
RequestDuration = prometheus.NewHistogramVec(
prometheus.HistogramOpts{
Name: "http_request_duration_seconds",
Help: "HTTP request duration in seconds",
},
[]string{"method", "path"},
)
DatabaseQueries = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "database_queries_total",
Help: "Total number of database queries",
},
[]string{"operation", "table"},
)
)
func init() {
prometheus.MustRegister(RequestsTotal)
prometheus.MustRegister(RequestDuration)
prometheus.MustRegister(DatabaseQueries)
}
func PrometheusMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
start := time.Now()
c.Next()
duration := time.Since(start).Seconds()
status := strconv.Itoa(c.Writer.Status())
RequestsTotal.WithLabelValues(c.Request.Method, c.FullPath(), status).Inc()
RequestDuration.WithLabelValues(c.Request.Method, c.FullPath()).Observe(duration)
}
}
func SetupMetrics(router *gin.Engine) {
router.GET("/metrics", gin.WrapH(promhttp.Handler()))
}
结构化日志
go
// shared/logger/logger.go
package logger
import (
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)
var Logger *zap.Logger
func InitLogger(level string) error {
var zapLevel zapcore.Level
switch level {
case "debug":
zapLevel = zapcore.DebugLevel
case "info":
zapLevel = zapcore.InfoLevel
case "warn":
zapLevel = zapcore.WarnLevel
case "error":
zapLevel = zapcore.ErrorLevel
default:
zapLevel = zapcore.InfoLevel
}
config := zap.Config{
Level: zap.NewAtomicLevelAt(zapLevel),
Development: false,
Sampling: &zap.SamplingConfig{
Initial: 100,
Thereafter: 100,
},
Encoding: "json",
EncoderConfig: zapcore.EncoderConfig{
TimeKey: "timestamp",
LevelKey: "level",
NameKey: "logger",
CallerKey: "caller",
MessageKey: "message",
StacktraceKey: "stacktrace",
LineEnding: zapcore.DefaultLineEnding,
EncodeLevel: zapcore.LowercaseLevelEncoder,
EncodeTime: zapcore.ISO8601TimeEncoder,
EncodeDuration: zapcore.SecondsDurationEncoder,
EncodeCaller: zapcore.ShortCallerEncoder,
},
OutputPaths: []string{"stdout"},
ErrorOutputPaths: []string{"stderr"},
}
var err error
Logger, err = config.Build()
if err != nil {
return err
}
return nil
}
func Info(message string, fields ...zap.Field) {
Logger.Info(message, fields...)
}
func Error(message string, fields ...zap.Field) {
Logger.Error(message, fields...)
}
func Debug(message string, fields ...zap.Field) {
Logger.Debug(message, fields...)
}
func Warn(message string, fields ...zap.Field) {
Logger.Warn(message, fields...)
}
🐳 容器化和部署
Docker配置
dockerfile
# services/user-service/Dockerfile
FROM golang:1.19-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 main ./cmd/main.go
FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=builder /app/main .
COPY --from=builder /app/configs ./configs
EXPOSE 8080
CMD ["./main"]
Docker Compose
yaml
# docker-compose.yml
version: '3.8'
services:
# 数据库
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: root123
MYSQL_DATABASE: ecommerce
ports:
- "3306:3306"
volumes:
- mysql_data:/var/lib/mysql
postgres:
image: postgres:13
environment:
POSTGRES_DB: payments
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
ports:
- "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
# 缓存和消息队列
redis:
image: redis:6-alpine
ports:
- "6379:6379"
# 服务发现
consul:
image: consul:1.11
ports:
- "8500:8500"
command: consul agent -dev -ui -client=0.0.0.0
# 微服务
user-service:
build: ./services/user-service
ports:
- "8081:8080"
depends_on:
- mysql
- consul
environment:
- DB_HOST=mysql
- CONSUL_HOST=consul
order-service:
build: ./services/order-service
ports:
- "8082:8080"
depends_on:
- mysql
- consul
environment:
- DB_HOST=mysql
- CONSUL_HOST=consul
payment-service:
build: ./services/payment-service
ports:
- "8083:8080"
depends_on:
- postgres
- redis
- consul
environment:
- DB_HOST=postgres
- REDIS_HOST=redis
- CONSUL_HOST=consul
# API网关
api-gateway:
build: ./api-gateway
ports:
- "8080:8080"
depends_on:
- user-service
- order-service
- payment-service
- consul
environment:
- CONSUL_HOST=consul
# 监控
prometheus:
image: prom/prometheus
ports:
- "9090:9090"
volumes:
- ./monitoring/prometheus.yml:/etc/prometheus/prometheus.yml
grafana:
image: grafana/grafana
ports:
- "3000:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin
volumes:
mysql_data:
postgres_data:
Kubernetes部署
yaml
# k8s/user-service-deployment.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: ecommerce/user-service:latest
ports:
- containerPort: 8080
env:
- name: DB_HOST
value: "mysql-service"
- name: CONSUL_HOST
value: "consul-service"
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "256Mi"
cpu: "200m"
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
---
apiVersion: v1
kind: Service
metadata:
name: user-service
spec:
selector:
app: user-service
ports:
- protocol: TCP
port: 80
targetPort: 8080
type: ClusterIP
🚀 启动和测试
启动命令
bash
# 启动所有服务
docker-compose up -d
# 查看服务状态
docker-compose ps
# 查看日志
docker-compose logs -f user-service
# 停止服务
docker-compose down
API测试
bash
# 用户注册
curl -X POST http://localhost:8080/api/v1/users/register \
-H "Content-Type: application/json" \
-d '{
"username": "john_doe",
"email": "john@example.com",
"password": "password123"
}'
# 用户登录
curl -X POST http://localhost:8080/api/v1/users/login \
-H "Content-Type: application/json" \
-d '{
"email": "john@example.com",
"password": "password123"
}'
# 创建订单
curl -X POST http://localhost:8080/api/v1/orders \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your-jwt-token" \
-d '{
"user_id": 1,
"items": [
{
"product_id": 1,
"quantity": 2,
"price": 99.99
}
]
}'
# 创建支付
curl -X POST http://localhost:8080/api/v1/payments \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your-jwt-token" \
-d '{
"order_id": 1,
"user_id": 1,
"amount": 199.98,
"payment_method": 1
}'
📈 性能优化
数据库连接池
go
// shared/database/pool.go
package database
import (
"time"
"github.com/zhoudm1743/torm/db"
)
func ConfigureConnectionPool(connectionName string) error {
// 获取底层数据库连接(这需要TORM支持)
// 这里假设TORM提供了获取底层sql.DB的方法
// sqlDB := db.GetSQLDB(connectionName)
// sqlDB.SetMaxOpenConns(100) // 最大连接数
// sqlDB.SetMaxIdleConns(10) // 最大空闲连接数
// sqlDB.SetConnMaxLifetime(time.Hour) // 连接最大生命周期
return nil
}
缓存策略
go
// shared/cache/redis.go
package cache
import (
"context"
"encoding/json"
"time"
"github.com/go-redis/redis/v8"
)
type RedisCache struct {
client *redis.Client
}
func NewRedisCache(addr, password string, db int) *RedisCache {
rdb := redis.NewClient(&redis.Options{
Addr: addr,
Password: password,
DB: db,
})
return &RedisCache{client: rdb}
}
func (r *RedisCache) Set(ctx context.Context, key string, value interface{}, expiration time.Duration) error {
data, err := json.Marshal(value)
if err != nil {
return err
}
return r.client.Set(ctx, key, data, expiration).Err()
}
func (r *RedisCache) Get(ctx context.Context, key string, dest interface{}) error {
val, err := r.client.Get(ctx, key).Result()
if err != nil {
return err
}
return json.Unmarshal([]byte(val), dest)
}
func (r *RedisCache) Delete(ctx context.Context, key string) error {
return r.client.Del(ctx, key).Err()
}
🔒 安全性考虑
JWT认证
go
// shared/auth/jwt.go
package auth
import (
"fmt"
"time"
"github.com/golang-jwt/jwt/v4"
)
type Claims struct {
UserID int `json:"user_id"`
Username string `json:"username"`
Email string `json:"email"`
jwt.RegisteredClaims
}
var jwtSecret = []byte("your-secret-key")
func GenerateToken(userID int, username, email string) (string, error) {
claims := Claims{
UserID: userID,
Username: username,
Email: email,
RegisteredClaims: jwt.RegisteredClaims{
ExpiresAt: jwt.NewNumericDate(time.Now().Add(24 * time.Hour)),
IssuedAt: jwt.NewNumericDate(time.Now()),
NotBefore: jwt.NewNumericDate(time.Now()),
},
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
return token.SignedString(jwtSecret)
}
func ValidateToken(tokenString string) (*Claims, error) {
token, err := jwt.ParseWithClaims(tokenString, &Claims{}, func(token *jwt.Token) (interface{}, error) {
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
}
return jwtSecret, nil
})
if err != nil {
return nil, err
}
if claims, ok := token.Claims.(*Claims); ok && token.Valid {
return claims, nil
}
return nil, fmt.Errorf("invalid token")
}
📊 总结
本文通过构建一个简单的电商微服务系统,深入展示了Go语言微服务架构的最佳实践:
🎯 核心优势
- 模块化设计 - 每个服务职责单一,便于维护和扩展
- 技术多样性 - 不同服务可采用最适合的技术栈
- 独立部署 - 服务间松耦合,支持独立发布
- 弹性扩展 - 可根据负载需求灵活伸缩
- 故障隔离 - 单点故障不影响整体系统
🛠️ 技术特色
- TORM集成 - 轻量级ORM,简化数据库操作
- 云原生支持 - Docker容器化,Kubernetes编排
- 完整监控 - Prometheus指标,Grafana可视化
- 服务治理 - Consul服务发现,API网关统一入口
- 安全保障 - JWT认证,HTTPS传输,数据加密
🚀 最佳实践
- 领域驱动设计 - 按业务领域划分服务边界
- 数据一致性 - 采用事件驱动架构保证最终一致性
- 错误处理 - 统一错误格式,完善降级策略
- 性能优化 - 连接池、缓存、异步处理
- 运维友好 - 结构化日志,健康检查,优雅关闭
通过本文的实践,您可以构建出生产级别的Go语言微服务系统,为企业数字化转型提供强有力的技术支撑。
微服务架构不是银弹,但在合适的场景下,它能帮助我们构建更加灵活、可靠和可扩展的系统。选择Go语言作为微服务开发语言,将让您的系统具备卓越的性能和优雅的代码结构。