feat: enhance API and session management with Nacos and Redis integration

- Add Nacos registry for service registration and deregistration.
- Implement Redis registry for session management with heartbeat and session claiming.
- Improve completion service with session handling and request validation.
- Enhance WebSocket handling for completion requests with JSON-RPC support.
- Add tests for new registry implementations and completion manager functionalities.
- Refactor existing code for better readability and maintainability.
This commit is contained in:
2026-02-15 17:46:34 +08:00
parent 57afb90bc0
commit 3284ce07c7
22 changed files with 1863 additions and 87 deletions

View File

@@ -0,0 +1,94 @@
# 为什么要做 Redis 会话外置 + 粘性路由
## 背景
当前 LSP 网关的核心能力是:
- 把编辑器请求转成 LSPJSON-RPC over stdio
- 为每个 `language + sessionId` 维护一个长生命周期会话(对应语言服务器进程与文档状态)
单实例时,这套方案天然稳定。
一旦进入微服务部署(多副本 + 负载均衡),如果没有额外机制,会出现严重一致性问题。
## 不做会发生什么
### 1. 会话状态丢失
同一个用户会话的请求可能先到实例 A、再到实例 B。
但 B 没有 A 的内存态didOpen/didChange 版本、LSP 上下文),会导致:
- 补全质量波动
- 诊断/跳转不一致
- 重复初始化语言服务器
### 2. 成本放大
会话不稳定会触发频繁建进程,带来:
- 更高 CPU/内存
- 更高请求尾延迟P95/P99
- 更多瞬时失败
### 3. 故障不可控
无统一会话归属时,问题难定位(到底是哪台实例持有上下文、何时丢失)。
## 为什么要 Redis 会话外置
Redis 不是替代 LSP 进程而是做“会话目录Session Directory
- 记录某个 `language + sessionId` 当前归属哪个实例
- 记录实例心跳与可回源地址
- 给会话绑定 TTL支持自动过期与回收
它带来的价值:
- 多副本下会话归属可见、可控
- 实例重启/扩容/缩容时路由行为可预测
- 可以做统一治理(观测、告警、自动修复)
## 为什么要粘性路由
LSP 天然是“有状态协议”:同一会话必须持续命中同一实例才能复用上下文。
粘性路由的目标就是保证这一点。
网关当前策略:
1. 请求到达后先在 Redis `claim` 会话归属
2. 如果归属自己:本地处理
3. 如果归属其他实例:返回 `409 + routeTo`HTTP 头 `X-LSP-Route-To`
4. 上游(前端或 Java 网关)据此重试到目标实例
这比纯随机 LB 更符合 LSP 工作方式。
## 设计取舍
### 收益
- 会话一致性显著提升
- 进程复用率提高,资源更稳
- 故障域清晰,便于排障
### 代价
- 引入 Redis 依赖(网络与可用性要保障)
- 路由逻辑更复杂冲突重试、TTL 管理)
- 需要对上游调用方约束:必须稳定传 `sessionId`
## 什么时候可以不做
可以暂不启用 Redis/粘性路由的场景:
- 仅单实例部署
- 开发/演示环境
- 对补全一致性不敏感
但只要进入生产多副本,建议启用。
## 适配 Java 微服务体系的意义
将 LSP 网关作为独立微服务后:
- Java 业务服务无需关心各语言 LSP 细节
- 可以统一接入鉴权、限流、链路追踪
- LSP 能力扩展Go/JS/TS/Java/Python不会反复侵入业务服务
这就是把它做成独立 LSP 服务的核心原因:**把状态复杂性收敛在一个可治理的边界里**。
## 当前实现对应点
- Redis 默认配置:`10.0.0.10:6379`, `DB=1`, 无密码
- 会话注册与认领:`internal/cluster/redis_registry.go`
- 会话管理与归属检查:`internal/completion/manager.go`
- 路由冲突返回:`internal/api/handler.go`, `internal/api/ws_handler.go`
- 启动配置入口:`cmd/server/main.go`