Appearance
SDK 扩展规模有三种模式:每用户独立 CLI(最强隔离)、共享 CLI + 独立 Session ID(平衡方案)、团队共享 Session(低成本)。水平扩展需要把 Session 状态存到外部存储(Redis/数据库),确保任意节点都能接管同一个 Session。
GitHub Copilot SDK 扩展规模:多用户 Session 隔离与水平扩展方案
三种隔离模式
模式一:每用户独立 CLI 进程(最强隔离)
每个用户启动独立的 CLI 进程和 SDK 实例:
typescript
// 为每个用户维护独立的 CLI 进程
const userCLIs = new Map<string, { session: CopilotSession, pid: number }>()
async function getSessionForUser(userId: string) {
if (userCLIs.has(userId)) {
return userCLIs.get(userId)!.session
}
const session = await createSession({
sessionId: userId,
// 每个用户独立的 CLI 实例(SDK 自动启动)
})
userCLIs.set(userId, { session, pid: session.cliPid })
return session
}优点:完全隔离,一个用户崩溃不影响其他人。
缺点:每个用户消耗一个 CLI 进程,100 个用户 = 100 个进程,内存开销大。
模式二:共享 CLI + Session ID 隔离(推荐)
多个用户共享同一个 CLI 服务,通过 sessionId 区分:
typescript
// 全局单例 CLI 服务
const CLI_URL = 'http://localhost:3001'
async function getSessionForUser(userId: string, projectId?: string) {
// sessionId 包含 userId 确保隔离
const sessionId = projectId
? `user-${userId}-proj-${projectId}`
: `user-${userId}`
return createSession({
cliUrl: CLI_URL,
sessionId
})
}优点:共享 CLI 进程,资源利用率高;Session ID 确保对话历史独立。
缺点:CLI 进程崩溃影响所有用户;需要确保 sessionId 唯一性。
模式三:团队共享 Session
同一个项目团队共用同一个 Session,保持共同上下文:
typescript
// 按团队/项目分配 Session
const teamSessions = new Map<string, CopilotSession>()
async function getTeamSession(teamId: string) {
if (!teamSessions.has(teamId)) {
const session = await createSession({
sessionId: `team-${teamId}`,
cliUrl: CLI_URL
})
teamSessions.set(teamId, session)
}
return teamSessions.get(teamId)!
}适用:小团队结对编程、Pair AI 编程。
注意:所有成员看到同一段对话历史,隐私要求低的场景才适用。
水平扩展
多台服务器时,需要把 Session 状态存到外部存储:
typescript
import Redis from 'ioredis'
const redis = new Redis(process.env.REDIS_URL!)
// 把 Session 路由信息存到 Redis
async function assignSession(userId: string): Promise<string> {
const existingNode = await redis.get(`session:${userId}:node`)
if (existingNode) {
return existingNode // 路由到已有节点
}
// 选择负载最低的节点
const nodes = ['node-1:3001', 'node-2:3001', 'node-3:3001']
const selectedNode = await selectLeastLoadedNode(nodes)
await redis.setex(`session:${userId}:node`, 3600, selectedNode)
return selectedNode
}
async function createUserSession(userId: string) {
const nodeUrl = await assignSession(userId)
return createSession({
cliUrl: `http://${nodeUrl}`,
sessionId: `user-${userId}`
})
}Session 状态持久化
跨进程重启保持对话历史:
typescript
const session = await createSession({
sessionId: `user-${userId}`,
persist: true, // 启用持久化
storage: {
// 自定义存储后端(默认是本地文件)
async save(sessionId: string, state: SessionState) {
await db.sessions.upsert({ id: sessionId, state: JSON.stringify(state) })
},
async load(sessionId: string) {
const row = await db.sessions.findById(sessionId)
return row ? JSON.parse(row.state) : null
}
}
})生产环境检查清单
| 项目 | 说明 |
|---|---|
| Session ID 唯一性 | 用 userId + timestamp 或 UUID,避免碰撞 |
| CLI 进程监控 | 用 PM2 或 systemd 管理 CLI 进程,崩溃自动重启 |
| 连接池 | 为 CLI 服务配置最大并发连接数限制 |
| Session 超时清理 | 定期清理超过 N 小时没有活动的 Session |
| 限流 | 每个用户的 Prompt 频率限制,避免滥用 |
| 日志追踪 | sessionId 作为 trace ID 贯穿日志,便于排查 |
常见问题
Q: 多个节点的 CLI 服务如何同步 Session 状态?
A: Session 状态应该绑定到固定节点(粘性会话),或者使用共享存储方案。不建议在多节点间同步 Session 内存状态——代价高且复杂。优先使用"一个 Session 绑定一个节点"的策略。
Q: 每个 CLI 服务实例最多支持多少并发 Session?
A: 经验值是单个 CLI 实例处理 20-50 个并发 Session 比较稳定,超过后建议扩容 CLI 实例。具体限制取决于 Copilot 后端的并发策略和机器资源。
Q: Session 持久化会不会有隐私风险?
A: Session 状态包含对话历史,需要按照数据保护要求处理:加密存储、设置保留期限(如 30 天自动删除)、用户可以主动清除自己的历史。