5.4 KiB
HY Voice Room
HY Voice Room 是一个语音房后端 monorepo。当前重点不是做通用 IM 平台,而是把语音房的实时业务闭环跑起来:HTTP 命令入口、房间 Room Cell、WebSocket 消息投递、MySQL 状态恢复、Redis 房间路由。
Architecture
核心边界:
gateway-service是客户端 HTTP JSON 入口,负责鉴权、协议转换和调用room-service。它不持有房间状态,也不终止 WebSocket。room-service是房间业务状态 owner,负责 Room Cell、麦位、房间 presence、本地礼物榜、送礼落房间、snapshot、command log、outbox、Redis lease 路由。im-service是连接和消息 owner,负责 WebSocket、房间频道订阅、公屏、房间系统消息、单聊、ACK、最近房间历史。wallet-service当前提供送礼扣费 stub,room-service的SendGift同步调用它。user-service和activity-service当前是独立进程骨架,后续分别承接用户主数据和活动消费。
外部协议和内部协议:
- 客户端命令面:
gateway-service暴露 HTTP JSON。 - 客户端实时面:
im-service暴露 WebSocket JSON。 - 服务内部调用:gRPC + protobuf,契约在
api/proto。 - 房间外事件:protobuf outbox,当前先落 MySQL。
Ports
本地和 Docker 编排统一使用 13xxx 端口:
| Component | Port | Purpose |
|---|---|---|
gateway-service |
13000 |
HTTP JSON |
room-service |
13001 |
gRPC |
im-service |
13002 |
HTTP/WebSocket |
im-service |
13003 |
gRPC |
wallet-service |
13004 |
gRPC |
user-service |
13005 |
gRPC |
activity-service |
13006 |
gRPC |
| MySQL | 13306 -> 3306 |
local Docker only |
| Redis | 13379 -> 6379 |
local Docker only |
Run Locally
Use Docker for local and test environments:
make compose-up
make compose-up starts the stack in detached mode and prints host-local, host-LAN, and Docker-network addresses for every service port.
Follow logs:
make compose-logs
Print addresses again without restarting services:
make compose-addresses
Stop services:
make compose-down
The compose stack starts MySQL and Redis. MySQL schema is initialized from:
services/room-service/deploy/mysql/initdb/001_room_service.sql
For direct host execution, each service reads its own services/<service>/configs/config.yaml.
Development Commands
make proto
make test
make build
make compose-up
make compose-addresses
make compose-logs
make compose-down
make proto requires protoc, protoc-gen-go, and protoc-gen-go-grpc.
Storage Model
room-service uses MySQL as the durable source:
rooms: room metadata.room_snapshots: latest room state snapshot.room_command_log: replayable command log for recovery.room_outbox: async event records.
room-service uses Redis for current room ownership:
room:route:{room_id}
The Redis value stores room_id, node_id, lease_token, and expires_at_ms. Lease acquisition is atomic through Lua in internal/router/redis_directory.go.
Room Recovery
A room is not permanently bound to one process. A node is only the current executor while its Redis lease is valid.
Recovery path:
- A request reaches a node that can own the room.
- The node acquires or renews
room:route:{room_id}. - If the local Room Cell does not exist, it loads the latest MySQL snapshot.
- It replays command log records after the snapshot version.
- It installs a local Room Cell and continues processing.
This is single-active recovery, not hot standby. Short retry/reconnect windows are expected during node failure.
Cloud Deployment
Local Docker uses:
services/room-service/configs/config.docker.yaml
Tencent Cloud deployment should follow:
services/room-service/configs/config.tencent.example.yaml
Set the real Tencent Cloud MySQL DSN, Redis address, Redis password, and internal service DNS names. Keep mysql_auto_migrate: false online; schema changes should run through a controlled migration process.
Deployment lifecycle requirements are documented in:
docs/health-checks.md
docs/graceful-shutdown.md
API Entry Points
Gateway HTTP routes:
POST /rooms/createPOST /rooms/joinPOST /rooms/leavePOST /rooms/mic/upPOST /rooms/mic/downPOST /rooms/mic/changePOST /rooms/user/mutePOST /rooms/user/kickPOST /rooms/gift/send
IM WebSocket path:
ws://127.0.0.1:13002/ws
The first WS frame must be auth; later frames include subscribe_room, unsubscribe_room, room_chat_send, peer_send, ack, and pull_history.
Project Layout
api/proto/ protobuf contracts
pkg/ small shared packages
services/gateway-service/ HTTP entry service
services/room-service/ Room Cell and durable room state
services/im-service/ WebSocket and message delivery
services/wallet-service/ wallet stub
services/user-service/ user stub
services/activity-service/ activity stub
Current Limits
wallet-service,user-service, andactivity-serviceare still stubs.room-serviceoutbox is durable, but external activity consumption is not implemented yet.im-servicekeeps message/session state in memory; scaling it across nodes still needs shared online routing or a delivery bus.- JWT secrets in local config are development values only.