Skip to content

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 天自动删除)、用户可以主动清除自己的历史。