멀티테넌시 운영

멀티테넌시 운영 (Multi-tenancy operations)

여러 사용자를 서로 다른 고객사에 제공하는 서비스라면, 각 테넌트의 데이터가 절대 섞이면 안 돼요. Weaviate의 **멀티테넌시(Multi-tenancy)**는 이를 데이터 격리로 해결합니다. 각 테넌트는 별도의 샤드(shard)에 저장되어, 어떤 테넌트의 데이터는 다른 테넌트에게 보이지 않아요. 데이터가 많은 사용자마다 나뉘어 있으면 프라이버시는 물론 DB 운영 효율도 좋아집니다.

출처: 공식문서 - Multi-tenancy operations

용어 변경 안내v1.26에서 HOT 상태는 ACTIVE로, COLD 상태는 INACTIVE로 이름이 바뀌었습니다.

멀티테넌시 켜기

멀티테넌시는 기본 비활성입니다. 컬렉션 정의의 multiTenancyConfig로 켭니다.

from weaviate.classes.config import Configure

multi_collection = client.collections.create(
    name="MultiTenancyCollection",
    # 새 컬렉션에서 멀티테넌시 활성화
    multi_tenancy_config=Configure.multi_tenancy(enabled=True)
)

자동 테넌트 생성

기본적으로 존재하지 않는 테넌트에 객체를 넣으려 하면 Weaviate는 오류를 반환합니다. 대신 새 테넌트를 자동으로 만들게 하려면 컬렉션 정의에서 autoTenantCreationtrue로 설정하세요. 자동 테넌트 생성은 배치 임포트에선 v1.25.0부터, 단일 객체 삽입에선 v1.25.2부터 지원됩니다.

from weaviate.classes.config import Configure

multi_collection = client.collections.create(
    name="CollectionWithAutoMTEnabled",
    # 자동 테넌트 생성 활성화
    multi_tenancy_config=Configure.multi_tenancy(
        enabled=True,
        auto_tenant_creation=True
    )
)

자동 테넌트 생성은 큰 규모의 객체를 임포트할 때 유용합니다. 다만 데이터에 사소한 불일치나 오타가 있을 수 있다면 조심해야 해요. 예를 들어 TenantOne, tenantOne, TenntOne은 서로 다른 세 테넌트가 됩니다.

기존 컬렉션은 클라이언트로 자동 테넌트 생성 설정만 갱신할 수 있습니다. 자동 테넌트는 배치 삽입에서만 동작합니다.

from weaviate.classes.config import Reconfigure

collection = client.collections.use(collection_name)

collection.config.update(
    multi_tenancy_config=Reconfigure.multi_tenancy(auto_tenant_creation=True)
)

테넌트 추가

컬렉션과 새 테넌트를 지정해 테넌트를 추가합니다. 선택적으로 테넌트 활동 상태를 ACTIVE(사용 가능, 기본), INACTIVE(사용 불가, 디스크 상), OFFLOADED(사용 불가, 클라우드로 오프로드)로 지정할 수 있어요.

허용되는 테넌트 이름 — 영숫자(a-z, A-Z, 0-9), 밑줄(_), 하이픈(-)만 사용 가능하며 길이는 4~64자입니다. 테넌트 상태는 Weaviate 1.21부터 지원됩니다.

from weaviate.classes.tenants import Tenant

# 컬렉션에 테넌트 두 개 추가
multi_collection.tenants.create(
    tenants=[
        Tenant(name="tenantA"),
        Tenant(name="tenantB"),
    ]
)

테넌트 목록 · 조회

컬렉션의 테넌트를 나열하거나, 이름으로 특정 테넌트를 가져올 수 있습니다. 존재하지 않는 테넌트 이름은 응답에서 무시됩니다.

multi_collection = client.collections.use("MultiTenancyCollection")

tenants = multi_collection.tenants.get()  # 테넌트 목록
print(tenants)
multi_collection = client.collections.use("MultiTenancyCollection")

tenant_names = ["tenantA", "tenantB", "nonExistentTenant"]  # `nonExistentTenant`은 없으므로 무시됨
tenants_response = multi_collection.tenants.get_by_names(tenant_names)

for k, v in tenants_response.items():
    print(k, v)
multi_collection = client.collections.use("MultiTenancyCollection")

tenant_obj = multi_collection.tenants.get_by_name(tenant_name)
print(tenant_obj.name)

테넌트 삭제

테넌트를 삭제하려면 컬렉션과 테넌트들을 지정합니다. 이름이 컬렉션에 없으면 무시됩니다. 테넌트 삭제는 곧 데이터 삭제입니다 — 연결된 모든 객체가 지워져요.

multi_collection = client.collections.use("MultiTenancyCollection")

# 테넌트 리스트 제거 - tenantX는 무시됩니다
multi_collection.tenants.remove(["tenantB", "tenantX"])

테넌트 상태 변경

테넌트 상태를 ACTIVE, INACTIVE, OFFLOADED 사이에서 변경할 수 있습니다.

from weaviate.classes.tenants import Tenant, TenantActivityStatus

multi_collection = client.collections.use("MultiTenancyCollection")

multi_collection.tenants.update(tenants=[
    Tenant(
        name="tenantA",
        activity_status=TenantActivityStatus.ACTIVE  # INACTIVE, OFFLOADED
    )
])

테넌트 상태 관리의 자세한 예시는 테넌트 상태 관리에서, hot·warm·cold 스토리지 계층 전략은 리소스 관리 가이드에서 확인하세요.

테넌트별 객체 작업

멀티테넌시 컬렉션은 CRUD 작업마다 테넌트 이름(예: tenantA)을 요구합니다. with_tenant()로 특정 테넌트의 컬렉션 핸들을 얻어 그 안에서 객체를 다룹니다.

multi_collection = client.collections.use("MultiTenancyCollection")

# 필요한 테넌트에 해당하는 컬렉션 가져오기
multi_tenantA = multi_collection.with_tenant("tenantA")

# tenantA에 객체 삽입
object_id = multi_tenantA.data.insert(
    properties={
        "question": "This vector DB is OSS & supports automatic property type inference on import"
    }
)

검색도 같은 방식으로 테넌트를 지정해 수행합니다.

multi_collection = client.collections.use("MultiTenancyCollection")

# 필요한 테넌트에 해당하는 컬렉션 가져오기
multi_tenantA = multi_collection.with_tenant("tenantA")

# tenantA를 쿼리
result = multi_tenantA.query.fetch_objects(
    limit=2,
)
print(result.objects[0].properties)

교차 참조와 쿼리 성능

교차 참조를 포함한 쿼리는 포함하지 않은 쿼리보다 느릴 수 있어요. 특히 객체가 많거나 쿼리가 복잡한 규모에서 그렇습니다. 확장 가능한 AI 데이터베이스인 Weaviate는 필터를 포함한 벡터·키워드·하이브리드 검색을 잘 수행하므로, 가능하면 데이터 스키마를 재설계해 교차 참조를 피하는 걸 권장합니다. 예를 들어 "Author"와 "Book" 컬렉션을 분리하고 교차 참조로 연결하는 대신, 저자 정보를 Book 객체에 직접 포함하고 검색·필터로 찾는 방식이 더 낫습니다.

멀티테넌시 컬렉션 객체에서 교차 참조는 다음 중 하나를 가리킬 수 있습니다.

  • 멀티테넌시가 아닌 컬렉션의 객체, 또는
  • 같은 테넌트에 속한 객체

멀티테넌시 컬렉션은 교차 참조를 만들거나 갱신·삭제할 때도 테넌트 이름을 요구합니다.

from weaviate.classes.config import ReferenceProperty

multi_collection = client.collections.use("MultiTenancyCollection")

# 멀티테넌시 클래스에 교차 참조 속성 추가
multi_collection.config.add_reference(
    ReferenceProperty(
        name="hasCategory",
        target_collection="JeopardyCategory"
    )
)

# 필요한 테넌트에 해당하는 컬렉션 가져오기
multi_tenantA = multi_collection.with_tenant(tenant="tenantA")

# MultiTenancyCollection 객체에서 JeopardyCategory 객체로 참조 추가
multi_tenantA.data.reference_add(
    from_uuid=object_id,  # MultiTenancyCollection 객체 id (Jeopardy 질문)
    from_property="hasCategory",
    to=category_id  # JeopardyCategory id
)

백업 주의 — 멀티테넌시 컬렉션의 백업에는 active 테넌트만 포함되고 inactive·offloaded 테넌트는 포함되지 않습니다. 모든 데이터가 포함되게 하려면 백업 전에 테넌트를 활성화하세요.

더 알아보기 (Learn more)