引言
在之前《选课风云》专栏,我分享了如何用Go-zero构建高可用选课系统。这一次,我们团队将挑战更复杂的场景——简易版抖音电商系统。项目不仅实现了购物、支付、优惠券等核心功能,还集成了AI查询、全链路追踪、秒级监控告警等高级特性。本文将深入解析技术选型、架构设计、核心实现与踩坑经验,为微服务开发提供实战参考。
项目地址
项目地址: github.com/jijizhazha1… 欢迎对Go微服务架构、云原生技术感兴趣的伙伴欢迎 Star⭐️ / Fork📂,相互交流,卷起来!!
技术栈全景
核心框架与组件
-
开发语言: Go
-
微服务框架: Go-zero(内置RPC、API网关、ORM等工具链)
-
存储层:
- MySQL(核心业务数据)
- Redis(缓存、分布式锁)
- Elasticsearch(日志检索)
-
中间件:
- RabbitMQ(异步通信,处理订单超时、库存回滚)
- DTM(分布式事务)
- Consul(服务发现)
-
可观测性:
- EFK(日志系统)
- Prometheus + Grafana(监控告警)
- Jaeger(链路追踪)
-
部署与CI/CD:
- Docker Compose(本地开发)
- Kubernetes + ArgoCD(生产级编排与持续部署)
架构设计:分层解耦,弹性扩展
1. 分层架构
- API Gateway层: 统一鉴权、限流、路由转发,集成Gzip压缩优化网络传输。
- 服务层: 拆分为用户、商品、订单、支付等10+微服务,独立开发部署。
- 基础设施层: 通过Consul实现服务发现,RabbitMQ解耦服务间通信。
- 存储层: 多级缓存(Redis热点数据)+ 分库分表(MySQL订单表按用户ID Hash)。
- 可观测层: 全链路日志追踪(Jaeger)、秒级监控(Prometheus)、可视化看板(Grafana)。
核心实现:高并发场景优化
1. 令牌续约与安全
-
方案: JWT双Token(Access Token + Refresh Token)实现无感刷新。
-
优化点:
- Token绑定客户端IP,防止盗用。
- 通过记录Token版本号,登出时强制旧Token失效。
func WrapperAuthMiddleware(rpcConf zrpc.RpcClientConf, whitePaths, optionPaths []string) func(next http.HandlerFunc) http.HandlerFunc {
return func(next http.HandlerFunc) http.HandlerFunc {
var (
once sync.Once
authRpc authsclient.Auths
)
return func(w http.ResponseWriter, r *http.Request) {
// 白名单路径直接放行
if _, ok := whitePathSet[r.URL.Path]; ok {
next(w, r)
return
}
// 获取认证令牌
token := r.Header.Get(biz.TokenKey)
refreshToken := r.Header.Get(biz.RefreshTokenKey)
// 处理可选令牌路径
if _, ok := optionPathSet[r.URL.Path]; ok && token == "" {
next(w, r)
return
}
// 非可选路径必须携带令牌
if token == "" {
sendAuthError(w, r, code.AuthBlank, code.AuthBlankMsg)
return
}
// 延迟初始化认证客户端
once.Do(func() {
authRpc = authsclient.NewAuths(zrpc.MustNewClient(rpcConf))
})
clientIP := r.Context().Value(biz.ClientIPKey).(string)
if clientIP == "" {
sendAuthError(w, r, code.IllegalProxyAddress, code.IllegalProxyAddressMsg)
return
}
// 执行认证流程
authRes, err := authRpc.Authentication(r.Context(), &auths.AuthReq{Token: token, ClientIp: clientIP})
if err != nil {
logx.Errorw("back err", logx.Field("err", err),
logx.Field("client_ip", clientIP),
logx.Field("token", maskToken(token)), logx.Field("path", r.URL.Path))
sendServerError(w, r)
return
}
// 处理认证结果
switch authRes.StatusCode {
case code.Success:
setUserContext(r, authRes.UserId)
next(w, r)
case code.AuthExpired:
handleTokenExpiration(w, r, authRpc, refreshToken, clientIP)
default:
sendAuthError(w, r, int(authRes.StatusCode), authRes.StatusMsg)
}
}
}
}
2. 防超卖:Lua脚本 + Redis原子操作
- 痛点: 秒杀场景下库存扣减需保证原子性。
- 方案: 通过Redis预扣库存,异步同步至数据库。
-- 幂等性检查
if redis.call("EXISTS", KEYS[1]) == 1 then
return 1
end
-- 预检查库存
for i=2, #KEYS do
local stock = tonumber(redis.call('GET',KEYS[i]) or 0)
local deduct = tonumber(ARGV[i]) -- ARGV索引从1开始
if stock < deduct then
--删除锁
redis.call("DEL", KEYS[1])
return 2
end
end
-- 扣减库存
for i=2, #KEYS do
redis.call('DECRBY', KEYS[i], tonumber(ARGV[i]))
end
-- 设置处理标记(30分钟过期)
redis.call("SET", KEYS[1], ARGV[1], "EX", 1800)
return 0
3. 订单超时:RabbitMQ延迟队列
- 传统方案: 数据库轮询(性能差、精度低)。
- 优化: 基于RabbitMQ插件
x-delayed-message
实现秒级延迟任务。
项目亮点:AI驱动与全链路治理
1. 大模型商品查询
-
流程: 用户自然语言 → 大模型解析AST → 条件过滤 → 返回结果。
-
安全防护:
- 上下文隔离防止Prompt注入。
- AST语法树校验非法操作。
2. 全链路追踪
- 价值: 一次下单请求穿透6个服务?通过Jaeger快速定位性能瓶颈。
- 实现: Go-zero集成OpenTelemetry,自动注入TraceID。
3. 监控告警体系
- 核心指标: QPS、延迟、错误率、节点资源占用。
测试与压测
关键场景验证
- 用户服务: 单节点支撑2000+ QPS(4C8G VM)。
- 秒杀场景: edis库存预扣减耗时<50ms。
- 支付超时: 5分钟测试订单自动关闭成功率100%。
总结与反思
项目成果
- 完整电商核心链路(商品→购物车→订单→支付)。
- 支撑万级QPS,平均延迟<100ms。
- 输出20+技术文档,沉淀微服务最佳实践。
待优化点
- 缓存雪崩: Redis集群化 + 本地缓存二级降级。
- 日志规范: 统一Log Schema,接入Sentry告警。
- 数据库扩展: 分库分表(目前按用户ID Hash)。
写在最后
从选课系统到电商平台,微服务架构的复杂性呈指数级上升。技术选型的合理性、团队协作的规范性成为项目成败的关键。如果你对Go-zero或电商系统设计感兴趣,欢迎Star项目源码,也欢迎在评论区探讨技术细节!
技术永不眠,我们下期见! 🚀