Go 后端学习项目:一个最小分布式即时通讯系统。后端是重点,前端只用于演示。
- 后端:Go、Gin、Gorm、WebSocket、Redis、MySQL、Kafka
- 前端:Vue 3、Pinia、Element Plus
- 环境:Docker Compose 管理 MySQL、Redis、Kafka
- 用户注册登录,JWT 鉴权
- 好友、群组 RESTful 管理接口
- 私聊、群聊、历史消息
- WebSocket 长连接、心跳保活、断线 5 秒重连
- 消息先落 MySQL,再通过 Kafka 投递
- 本地 TTL + Redis 群成员缓存,
singleflight合并并发回源 - Redis ZSet 增量补发离线消息,支持 ACK、已读同步
- 客户端序列号与 MySQL 唯一索引保证重复发送幂等
cmd/server 后端启动入口
internal/api Gin REST API
internal/ws WebSocket Hub、Client、协议
internal/service 业务逻辑
internal/model Gorm 模型
internal/cache Redis 缓存
internal/bus Kafka 消息事件
frontend Vue 演示前端
docker compose -p ping-im up -d复制配置:
copy .env.example .envPowerShell 启动后端:
$env:PORT="8080"; $env:NODE_ID="node-1"; go run ./cmd/server启动前端:
cd frontend
npm install
npm run dev浏览器打开 Vite 地址,后端地址默认填 http://localhost:8080。
开两个终端分别启动:
$env:PORT="8080"; $env:NODE_ID="node-1"; go run ./cmd/server$env:PORT="8081"; $env:NODE_ID="node-2"; go run ./cmd/server浏览器 1 登录用户 A,后端地址填 http://localhost:8080。
浏览器 2 登录用户 B,后端地址填 http://localhost:8081。
用户 A 给用户 B 发私聊消息,可验证 Redis + Kafka 支撑跨节点推送。断开 B 后发送消息,B 重连后会收到离线消息。
Hub.run() 是一个主 goroutine,通过 register、unregister、deliver channel 串行管理连接和投递。
每个连接有两个 goroutine:readPump 只读客户端事件,writePump 只写 client.send channel 中的消息,避免并发写 WebSocket。
已读事件通过 channel 每 200ms 或累计 100 条批量更新;离线消息按 ID 每批拉取 100 条。
POST /api/registerPOST /api/loginGET /api/usersGET /api/friendsPOST /api/friendsDELETE /api/friends/:idGET /api/groupsPOST /api/groupsGET /api/groups/:id/membersPOST /api/groups/:id/membersGET /api/messages?type=private&target_id=2GET /ws?token=xxx
客户端发送:
{ "type": "chat", "client_seq": 1001, "chat_type": "private", "target_id": 2, "content": "hello" }{ "type": "ack", "message_id": 1 }{ "type": "read", "message_id": 1 }{ "type": "offline_pull", "after_id": 100 }服务端推送:message、receipt、offline_messages、heartbeat。
go test ./...
cd frontend
npm run build