> Discover all available pages from the documentation index: https://mastra.zisheng.pro/ko/llms.txt # Google Cloud Spanner 스토리지 Google Cloud Spanner 스토리지 구현은 Mastra를 위한 수평적 고용량의 강력하고 일관된 스토리지 백엔드를 제공합니다. Cloud Spanner의 GoogleSQL 언어를 대상으로 합니다. ## 설치 **npm**: ```bash npm install @mastra/spanner@latest ``` **pnpm**: ```bash pnpm add @mastra/spanner@latest ``` **Yarn**: ```bash yarn add @mastra/spanner@latest ``` **Bun**: ```bash bun add @mastra/spanner@latest ``` ## 용법 ```typescript import { SpannerStore } from '@mastra/spanner' const storage = new SpannerStore({ id: 'spanner-storage', projectId: process.env.SPANNER_PROJECT_ID!, instanceId: process.env.SPANNER_INSTANCE_ID!, databaseId: process.env.SPANNER_DATABASE_ID!, }) ``` 인스턴스와 데이터베이스가 이미 존재해야 합니다. 어댑터는 처음 사용할 때 필요한 테이블을 생성하므로 Spanner 클라이언트에 제공된 사용자 인증 정보에는 스키마 변경을 실행할 권한이 있어야 합니다. 또는 배포 단계에서 권한이 더 높은 사용자 인증 정보로 `storage.init()`을 한 번 실행하세요. ## 매개변수 **id** (`string`): 이 저장소 인스턴스의 고유 식별자입니다. **projectId** (`string`): Google Cloud 프로젝트 ID입니다. database를 제공하지 않는 경우 필수입니다. **instanceId** (`string`): Cloud Spanner 인스턴스 ID입니다. database를 제공하지 않는 경우 필수입니다. **databaseId** (`string`): Cloud Spanner 데이터베이스 ID입니다. database를 제공하지 않는 경우 필수입니다. **database** (`@google-cloud/spanner Database`): 미리 구성된 Spanner Database 핸들입니다. 다른 위치에서 Spanner 클라이언트를 관리하는 경우(예: 서비스 간 인증 또는 연결 옵션 공유) 사용합니다. **spannerOptions** (`object`): @google-cloud/spanner 클라이언트 생성자에 전달되는 옵션입니다. 자격 증명이나 사용자 지정 엔드포인트를 설정하거나 로컬 에뮬레이터를 지정할 때 사용합니다. **disableInit** (`boolean`): true이면 처음 사용할 때 테이블을 자동으로 생성하지 않습니다. 별도의 배포 단계에서 storage.init()을 명시적으로 호출해야 합니다. (Default: `false`) **skipDefaultIndexes** (`boolean`): true이면 초기화 중 기본 인덱스 생성을 건너뜁니다. (Default: `false`) **indexes** (`CreateIndexOptions[]`): 생성할 사용자 지정 보조 인덱스입니다. 각 인덱스에는 해당 인덱스가 속한 테이블을 지정해야 합니다. 인덱스는 테이블 이름을 기준으로 적절한 도메인에 라우팅됩니다. **initMode** (`'sync' | 'validate'`): 스키마 초기화 동작을 제어합니다. 'sync'는 init() 중 누락된 테이블, 열, 인덱스를 생성합니다(기존 동작). 'validate'는 DDL을 실행하지 않고 필요한 모든 테이블, 열, 기본/사용자 지정 인덱스가 이미 존재하는지 확인하며, 누락된 항목이 있으면 형식이 지정된 사용자 오류를 발생시킵니다. 외부 프로세스(Terraform, Liquibase, 릴리스 파이프라인 등)가 스키마를 관리하고 Mastra는 검증만 수행해야 할 때 유용합니다. (Default: `'sync'`) ## 생성자 예 `SpannerStore`는 여러 방법으로 인스턴스화할 수 있습니다. ```typescript import { Spanner } from '@google-cloud/spanner' import { SpannerStore } from '@mastra/spanner' // Using projectId / instanceId / databaseId const store1 = new SpannerStore({ id: 'spanner-storage-1', projectId: 'my-gcp-project', instanceId: 'my-instance', databaseId: 'mastra', }) // Reusing an existing Spanner Database handle const spanner = new Spanner({ projectId: 'my-gcp-project' }) const database = spanner.instance('my-instance').database('mastra') const store2 = new SpannerStore({ id: 'spanner-storage-2', database, }) // Using the local Spanner emulator (set the SPANNER_EMULATOR_HOST env var) process.env.SPANNER_EMULATOR_HOST = 'localhost:9010' const store3 = new SpannerStore({ id: 'spanner-storage-emulator', projectId: 'test-project', instanceId: 'test-instance', databaseId: 'test-db', spannerOptions: { servicePath: 'localhost', port: 9010, sslCreds: undefined }, }) ``` ## 추가 참고사항 ### 스키마 관리 스토리지 어댑터는 모두 GoogleSQL 언어를 사용하여 다음 테이블을 생성합니다. - `mastra_workflow_snapshot`: Workflow 상태 및 실행 데이터 - `mastra_threads`: 대화 스레드 - `mastra_messages`: 개별 메시지 - `mastra_resources`: 리소스 작업 Memory - `mastra_scorers`: 평가 점수 - `mastra_background_tasks`: 백그라운드 Tool 실행 상태 - `mastra_agents`: 간소화된 Agent 레코드(ID, 상태, 활성 버전) - `mastra_agent_versions`: 버전이 지정된 Agent 구성 스냅샷 - `mastra_mcp_clients` / `mastra_mcp_client_versions`: MCP 클라이언트 구성 및 버전 기록 - `mastra_mcp_servers` / `mastra_mcp_server_versions`: MCP 서버 구성 및 버전 기록 - `mastra_skills` / `mastra_skill_versions`: Skill 레코드 및 버전이 지정된 Skill 스냅샷(지침, 참조, 스크립트, 에셋, 콘텐츠 트리) - `mastra_skill_blobs`: SHA-256 해시를 키로 사용하며 Skill 버전 콘텐츠에 사용되는 콘텐츠 주소 지정 가능 Blob 저장소 - `mastra_prompt_blocks` / `mastra_prompt_block_versions`: Prompt 블록 레코드 및 버전이 지정된 콘텐츠 스냅샷(템플릿 콘텐츠, 규칙, 요청 컨텍스트 스키마) - `mastra_scorer_definitions` / `mastra_scorer_definition_versions`: 채점기 정의 레코드 및 버전이 지정된 구성 스냅샷(판정 지침, Model, 점수 범위, 사전 설정 구성, 기본 샘플링) - `mastra_schedules` / `mastra_schedule_triggers`: Mastra에 내장된 `WorkflowScheduler`가 사용하는 cron 기반 Workflow 일정 및 트리거 기록 - `mastra_workspaces` / `mastra_workspace_versions`: Workspace 레코드 및 버전이 지정된 구성 스냅샷(파일 시스템, Sandbox, 마운트, 검색, Skill, Tool) - `mastra_datasets` / `mastra_dataset_items` / `mastra_dataset_versions`: 평가 데이터 세트, SCD-2 버전 관리 항목 및 버전 스냅샷 - `mastra_experiments` / `mastra_experiment_results`: 실험 실행 및 항목별 결과 - `mastra_favorites`: 비정규화된 Agent 및 Skill에 대한 사용자별 즐겨찾기이며, 상위 레코드에서 `favoriteCount`가 유지됨 - `mastra_channel_installations` / `mastra_channel_config`: 다중 플랫폼 채널 설치 및 플랫폼별 구성 - `mastra_ai_spans`: Observability를 위한 AI Trace 범위(Studio Trace UI를 구동하는 데 사용되는 Trace별 및 범위별 레코드) 테이블은 텍스트와 JSON 페이로드에 `STRING(MAX)`를 사용하고, 그 밖에 `INT64`, `FLOAT64`, `BOOL`, `TIMESTAMP`를 사용하여 생성됩니다. 다음 Spanner 관련 테이블에는 어댑터가 JSON 페이로드에서 채우는 `STORED` 생성 열이 포함되어 있어, 일반적인 필터에서 `JSON_VALUE` 스캔 대신 일반 보조 인덱스를 사용할 수 있습니다. - `mastra_workflow_snapshot.snapshotStatus`: `snapshot`에서 `$.status`를 추출합니다. `listWorkflowRuns({ status })`를 지원합니다. - `mastra_schedules.target_workflow_id`: `target`에서 `$.workflowId`를 추출합니다. `listSchedules({ workflowId })`를 지원합니다. 두 열 모두 `init()` 중 `ALTER TABLE ... ADD COLUMN IF NOT EXISTS`를 통해 추가되며, 스키마를 외부에서 관리하는 `initMode: 'validate'`에서는 건너뜁니다. 열이 없으면 어댑터는 런타임에 `JSON_VALUE` 필터로 대체합니다. 어댑터는 스키마를 생성하거나 사용하지 않습니다. 격리를 위해 전용 데이터베이스를 사용합니다. ### 초기화 저장소를 `Mastra` 클래스에 전달하면 저장소 작업 전에 `init()`이 자동으로 호출됩니다. ```typescript import { Mastra } from '@mastra/core' import { SpannerStore } from '@mastra/spanner' const storage = new SpannerStore({ id: 'spanner-storage', projectId: process.env.SPANNER_PROJECT_ID!, instanceId: process.env.SPANNER_INSTANCE_ID!, databaseId: process.env.SPANNER_DATABASE_ID!, }) const mastra = new Mastra({ storage, // init() is called automatically }) ``` 스토리지를 직접 사용하는 경우 첫 번째 작업 전에 `init()`을 한 번 호출하세요. Spanner는 동시 스키마 변경을 허용하지 않으므로 `SpannerStore.init()`은 각 도메인의 설정을 순차적으로 실행합니다. ```typescript const storage = new SpannerStore({ id: 'spanner-storage', projectId: process.env.SPANNER_PROJECT_ID!, instanceId: process.env.SPANNER_INSTANCE_ID!, databaseId: process.env.SPANNER_DATABASE_ID!, }) await storage.init() const memory = await storage.getStore('memory') const thread = await memory?.getThreadById({ threadId: '...' }) ``` > **경고:** `init()`을 호출하지 않고 `disableInit`이 true이면 필요한 테이블이 존재하지 않아 저장소 작업이 실패합니다. ### GoogleSQL 세부사항 몇 가지 동작이 다른 관계형 어댑터와 다릅니다. - Upsert는 `INSERT OR UPDATE`를 사용합니다. Spanner는 upsert에 `RETURNING` 절을 제공하지 않으므로 쓰기 후 상태가 필요한 호출자는 이를 다시 읽어야 합니다. - `TRUNCATE`는 존재하지 않습니다. `dangerouslyClearAll()`은 `DELETE WHERE TRUE`를 실행합니다. - 식별자는 백틱으로 묶습니다. - DDL은 비동기 장기 실행 작업인 `database.updateSchema(...)`를 통해 적용됩니다. - `NULLS FIRST/LAST`는 지원되지 않습니다. NULL 처리가 포함된 정렬은 `IS NULL` 정렬 키를 통해 에뮬레이션됩니다. - JSON 포함 연산은 기본적으로 지원되지 않습니다. `listTraces`의 `metadata` 및 `scope` 필터는 키별 `JSON_VALUE(...) = @v` 동등성 검사로 컴파일되고, `tags` 필터는 `JSON_QUERY_ARRAY(...)`에 대한 `EXISTS`로 컴파일됩니다. 이는 단일 인덱스 스캔에서 중첩 구조를 일치시킬 수 있는 Postgres의 `@>` 포함 연산자와 다릅니다. 대부분의 일회성 조회는 계속 작동하지만 깊이 중첩된 구조 일치는 표현할 수 없습니다. ### 직접 데이터베이스 액세스 `SpannerStore`기본 Spanner 클라이언트 객체를 노출합니다. ```typescript store.database // @google-cloud/spanner Database store.instance // @google-cloud/spanner Instance (when created internally) store.spanner // @google-cloud/spanner Spanner client (when created internally) ``` 이는 맞춤형 트랜잭션이나 스키마 검사와 같은 고급 시나리오를 위한 것입니다. 데이터베이스를 직접 재사용하는 경우 어댑터의 유효성 검사 및 JSON 변환 논리를 우회합니다. ### 에뮬레이터를 사용한 로컬 개발 Docker를 사용하여 Cloud Spanner 에뮬레이터를 로컬에서 실행합니다. ```bash docker run -p 9010:9010 -p 9020:9020 gcr.io/cloud-spanner-emulator/emulator ``` `SPANNER_EMULATOR_HOST=localhost:9010`을 설정하고 앱을 실행하기 전에 인스턴스와 데이터베이스를 생성하세요. ```bash gcloud spanner instances create test-instance --config=emulator-config --nodes=1 gcloud spanner databases create test-db --instance=test-instance ``` 그런 다음 Node.js 프로세스에 동일한 환경 변수를 설정하여 연결하세요. `@google-cloud/spanner` 클라이언트가 에뮬레이터를 자동으로 감지합니다.