Skip to main content

확장성 및 멀티 테넌시

여러 사용자에게 서비스를 제공하고, 동시 세션을 처리하고, 인프라 전체에서 수평으로 확장하도록 Copilot SDK 배포를 디자인합니다. 이 가이드에서는 세션 격리 패턴, 크기 조정 토폴로지 및 프로덕션 모범 사례를 설명합니다.

SDK 수준 옵션 및 패턴은 다중 테넌트 및 서버 배포을 참조하세요.

최적 대상: 플랫폼 개발자, SaaS 작성기, 소수의 동시 사용자를 제공하는 모든 배포.

핵심 개념

패턴을 선택하기 전에 세 가지 크기 조정 차원을 이해합니다.

다이어그램: 설명된 프로세스를 보여 주는 순서도입니다.

세션 격리 패턴

패턴 1: 사용자당 격리된 CLI

각 사용자는 자체 CLI 서버 인스턴스를 가져옵니다. 가장 강력한 격리 - 사용자의 세션, 메모리 및 프로세스가 완전히 분리됩니다.

다이어그램: 설명된 프로세스를 보여 주는 순서도입니다.

사용 시기:

  • 데이터 격리가 중요한 다중 테넌트 SaaS
  • 다른 인증 자격 증명을 가진 사용자
  • 규정 준수 요구 사항(SOC 2, HIPAA)
// CLI pool manager — one CLI per user
class CLIPool {
    private instances = new Map<string, { client: CopilotClient; port: number }>();
    private nextPort = 5000;

    async getClientForUser(userId: string, token?: string): Promise<CopilotClient> {
        if (this.instances.has(userId)) {
            return this.instances.get(userId)!.client;
        }

        const port = this.nextPort++;

        // Spawn a dedicated CLI for this user
        await spawnCLI(port, token);

        const client = new CopilotClient({
            cliUrl: `localhost:${port}`,
        });

        this.instances.set(userId, { client, port });
        return client;
    }

    async releaseUser(userId: string): Promise<void> {
        const instance = this.instances.get(userId);
        if (instance) {
            await instance.client.stop();
            this.instances.delete(userId);
        }
    }
}

패턴 2: 세션 격리를 사용하는 공유 CLI

여러 사용자가 하나의 CLI 서버를 공유하지만 고유한 세션 ID를 통해 격리된 세션이 있습니다. 리소스가 더 가벼우지만 격리가 약합니다.

다이어그램: 설명된 프로세스를 보여 주는 순서도입니다.

사용 시기:

  • 신뢰할 수 있는 사용자가 있는 내부 도구
  • 리소스가 제한된 환경
  • 낮은 격리 요구 사항
const sharedClient = new CopilotClient({
    cliUrl: "localhost:4321",
});

// Enforce session isolation through naming conventions
function getSessionId(userId: string, purpose: string): string {
    return `${userId}-${purpose}-${Date.now()}`;
}

// Access control: ensure users can only access their own sessions
async function resumeSessionWithAuth(
    sessionId: string,
    currentUserId: string
): Promise<Session> {
    const [sessionUserId] = sessionId.split("-");
    if (sessionUserId !== currentUserId) {
        throw new Error("Access denied: session belongs to another user");
    }
    return sharedClient.resumeSession(sessionId);
}

패턴 3: 공유 세션(공동 작업)

여러 사용자가 코필로트와 공유 채팅방과 같은 동일한 세션과 상호 작용합니다.

다이어그램: 설명된 프로세스를 보여 주는 순서도입니다.

사용 시기:

  • 팀 공동 작업 도구
  • 공유 코드 검토 세션
  • 프로그래밍 도우미 페어링

⚠️중요: SDK는 기본 제공 세션 잠금을 제공하지 않습니다. 동일한 세션에 대한 동시 쓰기를 방지하려면 액세스를 직렬화 해야 합니다 .

import Redis from "ioredis";

const redis = new Redis();

async function withSessionLock<T>(
    sessionId: string,
    fn: () => Promise<T>,
    timeoutSec = 300
): Promise<T> {
    const lockKey = `session-lock:${sessionId}`;
    const lockId = crypto.randomUUID();

    // Acquire lock
    const acquired = await redis.set(lockKey, lockId, "NX", "EX", timeoutSec);
    if (!acquired) {
        throw new Error("Session is in use by another user");
    }

    try {
        return await fn();
    } finally {
        // Release lock (only if we still own it)
        const currentLock = await redis.get(lockKey);
        if (currentLock === lockId) {
            await redis.del(lockKey);
        }
    }
}

// Usage: serialize access to shared session
app.post("/team-chat", authMiddleware, async (req, res) => {
    const result = await withSessionLock("team-project-review", async () => {
        const session = await client.resumeSession("team-project-review");
        return session.sendAndWait({ prompt: req.body.message });
    });

    res.json({ content: result?.data.content });
});

격리 패턴 비교

사용자별로 분리된 CLI공유 CLI 및 세션 격리공유 세션
Isolation
✅ 완료
⚠️ 논리
❌ 공유
리소스 사용량높음(사용자당 CLI)낮음(하나의 명령줄 인터페이스)낮음(하나의 CLI + 세션)
복잡성중간낮음높음(잠금)
인증 유연성
✅ 사용자별 토큰
⚠️ 서비스 토큰
⚠️ 서비스 토큰
최적입니다다중 사용자 SaaS내부 도구Collaboration

수평 크기 조정

부하 분산 장치 뒤에 여러 CLI 서버

다이어그램: 설명된 프로세스를 보여 주는 순서도입니다.

주요 요구 사항: 모든 CLI 서버가 세션을 다시 시작할 수 있도록 세션 상태는 공유 스토리지 에 있어야 합니다.

// Route sessions to CLI servers
class CLILoadBalancer {
    private servers: string[];
    private currentIndex = 0;

    constructor(servers: string[]) {
        this.servers = servers;
    }

    // Round-robin selection
    getNextServer(): string {
        const server = this.servers[this.currentIndex];
        this.currentIndex = (this.currentIndex + 1) % this.servers.length;
        return server;
    }

    // Sticky sessions: same user always hits same server
    getServerForUser(userId: string): string {
        const hash = this.hashCode(userId);
        return this.servers[hash % this.servers.length];
    }

    private hashCode(str: string): number {
        let hash = 0;
        for (let i = 0; i < str.length; i++) {
            hash = (hash << 5) - hash + str.charCodeAt(i);
            hash |= 0;
        }
        return Math.abs(hash);
    }
}

const lb = new CLILoadBalancer([
    "cli-1:4321",
    "cli-2:4321",
    "cli-3:4321",
]);

app.post("/chat", async (req, res) => {
    const server = lb.getServerForUser(req.user.id);
    const client = new CopilotClient({ cliUrl: server });

    const session = await client.createSession({
        sessionId: `user-${req.user.id}-chat`,
        model: "gpt-4.1",
    });

    const response = await session.sendAndWait({ prompt: req.body.message });
    res.json({ content: response?.data.content });
});

고정 세션 및 공유 스토리지

다이어그램: 설명된 프로세스를 보여 주는 순서도입니다.

스티키 세션은 더 간단합니다. 즉, 사용자가 특정 CLI 서버에 계속 연결되도록 합니다. 공유 스토리지는 필요하지 않지만 부하 분산은 고르지 않습니다.

공유 스토리지 를 사용하면 모든 CLI에서 모든 세션을 처리할 수 있습니다. 부하 분산은 더 우수하지만, ~/.copilot/session-state/에는 네트워크 스토리지가 필요합니다.

수직 크기 조정

단일 CLI 서버 튜닝

단일 CLI 서버는 여러 동시 세션을 처리할 수 있습니다. 주요 고려 사항:

다이어그램: 설명된 프로세스를 보여 주는 순서도입니다.

세션 수명 주기 관리는 수직적 크기 조정의 핵심입니다.

// Limit concurrent active sessions
class SessionManager {
    private activeSessions = new Map<string, Session>();
    private maxConcurrent: number;

    constructor(maxConcurrent = 50) {
        this.maxConcurrent = maxConcurrent;
    }

    async getSession(sessionId: string): Promise<Session> {
        // Return existing active session
        if (this.activeSessions.has(sessionId)) {
            return this.activeSessions.get(sessionId)!;
        }

        // Enforce concurrency limit
        if (this.activeSessions.size >= this.maxConcurrent) {
            await this.evictOldestSession();
        }

        // Create or resume
        const session = await client.createSession({
            sessionId,
            model: "gpt-4.1",
        });

        this.activeSessions.set(sessionId, session);
        return session;
    }

    private async evictOldestSession(): Promise<void> {
        const [oldestId] = this.activeSessions.keys();
        const session = this.activeSessions.get(oldestId)!;
        // Session state is persisted automatically — safe to disconnect
        await session.disconnect();
        this.activeSessions.delete(oldestId);
    }
}

임시 세션과 영구 세션 비교

다이어그램: 설명된 프로세스를 보여 주는 순서도입니다.

임시 세션

각 요청이 독립적인 상태 비스테이스 API 엔드포인트의 경우:

app.post("/api/analyze", async (req, res) => {
    const session = await client.createSession({
        model: "gpt-4.1",
    });

    try {
        const response = await session.sendAndWait({
            prompt: req.body.prompt,
        });
        res.json({ result: response?.data.content });
    } finally {
        await session.disconnect();  // Clean up immediately
    }
});

영구 세션

대화형 인터페이스 또는 장기 실행 워크플로의 경우:

// Create a resumable session
app.post("/api/chat/start", async (req, res) => {
    const sessionId = `user-${req.user.id}-${Date.now()}`;

    const session = await client.createSession({
        sessionId,
        model: "gpt-4.1",
        infiniteSessions: {
            enabled: true,
            backgroundCompactionThreshold: 0.80,
        },
    });

    res.json({ sessionId });
});

// Continue the conversation
app.post("/api/chat/message", async (req, res) => {
    const session = await client.resumeSession(req.body.sessionId);
    const response = await session.sendAndWait({ prompt: req.body.message });

    res.json({ content: response?.data.content });
});

// Clean up when done
app.post("/api/chat/end", async (req, res) => {
    await client.deleteSession(req.body.sessionId);
    res.json({ success: true });
});

컨테이너 배포

영구 스토리지가 있는 Kubernetes

apiVersion: apps/v1
kind: Deployment
metadata:
  name: copilot-cli
spec:
  replicas: 3
  selector:
    matchLabels:
      app: copilot-cli
  template:
    metadata:
      labels:
        app: copilot-cli
    spec:
      containers:
        - name: copilot-cli
          image: your-registry/copilot-cli:latest  # See backend-services.md for how to build and push this image
          args: ["--headless", "--host", "0.0.0.0", "--port", "4321"]
          env:
            - name: COPILOT_GITHUB_TOKEN
              valueFrom:
                secretKeyRef:
                  name: copilot-secrets
                  key: github-token
          ports:
            - containerPort: 4321
          volumeMounts:
            - name: session-state
              mountPath: /root/.copilot/session-state
      volumes:
        - name: session-state
          persistentVolumeClaim:
            claimName: copilot-sessions-pvc
---
apiVersion: v1
kind: Service
metadata:
  name: copilot-cli
spec:
  selector:
    app: copilot-cli
  ports:
    - port: 4321
      targetPort: 4321

다이어그램: 설명된 프로세스를 보여 주는 순서도입니다.

Azure 컨테이너 인스턴스

containers:
  - name: copilot-cli
    image: your-registry/copilot-cli:latest  # See backend-services.md for how to build and push this image
    command: ["copilot", "--headless", "--host", "0.0.0.0", "--port", "4321"]
    volumeMounts:
      - name: session-storage
        mountPath: /root/.copilot/session-state

volumes:
  - name: session-storage
    azureFile:
      shareName: copilot-sessions
      storageAccountName: myaccount

프로덕션 체크리스트

다이어그램: 설명된 프로세스를 보여 주는 순서도입니다.

관심사Recommendation
세션 정리주기적 정리를 실행하여 TTL보다 오래된 세션을 삭제합니다.
상태 검사주기적으로 CLI 서버 Ping; 응답하지 않는 경우 다시 시작
스토리지
~/.copilot/session-state/에 영구 볼륨 탑재
비밀플랫폼의 시크릿 관리 도구(Vault, K8s Secrets 등)를 사용하세요.
Monitoring활성 세션 수, 응답 대기 시간, 오류 비율 추적
Locking공유 세션 액세스에 Redis 또는 이와 유사한 항목 사용
종료CLI 서버를 중지하기 전에 활성 세션 드레이닝

Limitations

LimitationDetails
기본 제공 세션 잠금 없음동시 액세스를 위한 애플리케이션 수준 잠금 구현
기본 제공 부하 분산 없음외부 로드 밸런서 또는 서비스 메시 사용
세션 상태는 파일 기반입니다.다중 서버 설치를 위한 공유 파일 시스템 필요
30분 유휴 시간 제한작업이 없는 세션은 CLI에 의해 자동으로 정리됩니다.
CLI는 단일 프로세스입니다.스레드가 아닌 CLI 서버 인스턴스를 더 추가하여 크기 조정

다음 단계