다음을 통해 공유


Azure Cosmos DB for PostgreSQL에서 다중 테넌트 SaaS 앱 모델링

적용 대상: Azure Cosmos DB for PostgreSQL(PostgreSQL에 대한 Citus 데이터베이스 확장 기반)

테넌트 ID를 분할 키로

테넌트 ID는 워크로드의 루트 또는 데이터 모델의 계층 구조 맨 위에 있는 열입니다. 예를 들어 이 SaaS 전자상거래 스키마에서 스토어 ID는 다음과 같습니다.

store_id 열이 강조 표시된 테이블의 다이어그램

이 데이터 모델은 Shopify와 같은 비즈니스에 일반적입니다. 각 스토어가 자체 데이터와 상호 작용하는 여러 온라인 스토어의 사이트를 호스트합니다.

  • 이 데이터 모델에는 스토어, 제품, 주문, 품목 및 국가와 같은 많은 테이블이 있습니다.
  • 스토어 테이블은 계층 구조의 맨 위에 있습니다. 제품, 주문 및 라인 항목은 모두 스토어와 연결되므로 계층 구조가 더 낮습니다.
  • 국가 테이블은 개별 스토어와 관련이 없으며 스토어 전체에 걸쳐 있습니다.

이 예에서 계층의 맨 위에 있는 store_id는 테넌트의 식별자입니다. 올바른 분할 키입니다. store_id를 분할 키로 선택하면 단일 작업자의 단일 스토어에 대한 모든 테이블에 데이터를 배치할 수 있습니다.

스토어별로 테이블을 공동 배치하면 다음과 같은 이점이 있습니다.

  • 외래 키, JOIN과 같은 SQL 적용 범위를 제공합니다. 단일 테넌트에 대한 트랜잭션은 각 테넌트가 있는 단일 작업자 노드에서 지역화됩니다.
  • 한 자릿수 밀리초 성능을 얻을 수 있습니다. 단일 테넌트에 대한 쿼리는 병렬화되는 대신 단일 노드로 라우팅되어 네트워크 홉을 최적화하고 컴퓨팅/메모리 크기를 조정하는 데 도움이 됩니다.
  • 규모가 조정됩니다. 테넌트 수가 증가함에 따라 노드를 추가하고 테넌트 균형을 새 노드로 다시 조정하거나 대규모 테넌트가 자체 노드로 격리할 수도 있습니다. 테넌트 격리를 통해 전용 리소스를 제공할 수 있습니다.

동일한 노드에 공동 배치된 테이블의 다이어그램

다중 테넌트 앱을 위한 최적의 데이터 모델

이 예에서는 스토어 ID별로 스토어별 테이블을 배포하고 countries를 참조 테이블로 만들어야 합니다.

store_id가 보다 보편적으로 강조 표시된 테이블의 다이어그램

테넌트별 테이블에는 테넌트 ID가 있고 배포됩니다. 이 예에서는 스토어, 제품 및 line_items가 배포됩니다. 나머지 테이블은 참조 테이블입니다. 이 예에서 국가 테이블은 참조 테이블입니다.

-- Distribute large tables by the tenant ID

SELECT create_distributed_table('stores', 'store_id');
SELECT create_distributed_table('products', 'store_id', colocate_with => 'stores');
-- etc for the rest of the tenant tables...

-- Then, make "countries" a reference table, with a synchronized copy of the
-- table maintained on every worker node

SELECT create_reference_table('countries');

큰 테이블에는 모두 테넌트 ID가 있어야 합니다.

  • 기존 다중 테넌트 앱을 Azure Cosmos DB for PostgreSQL로 마이그레이션하는 경우 조금 비정규화하고 테넌트 ID 열이 없는 경우 큰 테이블에 추가한 다음 열의 누락된 값을 다시 채워야 할 수 있습니다.
  • Azure Cosmos DB for PostgreSQL의 새 앱의 경우 테넌트 ID가 모든 테넌트별 테이블에 있는지 확인합니다.

분산 테이블의 기본, 고유 및 외래 키 제약 조건에 테넌트 ID를 복합 키 형식으로 포함해야 합니다. 예를 들어, 테이블에 있는 기본 키가 id면 이를 복합 키 (tenant_id,id)로 바꿉니다. 참조 테이블의 키를 변경할 필요가 없습니다.

최상의 성능을 위한 쿼리 고려 사항

테넌트 ID를 필터링하는 분산 쿼리는 다중 테넌트 앱에서 가장 효율적으로 실행됩니다. 쿼리의 범위가 항상 단일 테넌트로 지정되어 있는지 확인합니다.

SELECT *
  FROM orders
 WHERE order_id = 123
   AND store_id = 42;  -- ← tenant ID filter

원래 필터 조건이 원하는 행을 명확하게 식별하는 경우에도 테넌트 ID 필터를 추가해야 합니다. 테넌트 ID 필터는 중복되는 것처럼 보이지만 단일 작업자 노드로 쿼리를 라우팅하는 방법을 Azure Cosmos DB for PostgreSQL에 알려줍니다.

마찬가지로 두 개의 분산 테이블을 조인할 때 두 테이블의 범위가 단일 테넌트로 지정되었는지 확인합니다. 조인 조건에 테넌트 ID가 포함되도록 하여 범위를 지정할 수 있습니다.

SELECT sum(l.quantity)
  FROM line_items l
 INNER JOIN products p
    ON l.product_id = p.product_id
   AND l.store_id = p.store_id   -- ← tenant ID in join
 WHERE p.name='Awesome Wool Pants'
   AND l.store_id='8c69aa0d-3f13-4440-86ca-443566c1fc75';
       -- ↑ tenant ID filter

쿼리에 테넌트 ID를 쉽게 포함할 수 있도록 하는 몇 가지 자주 사용되는 애플리케이션 프레임워크용 도우미 라이브러리가 있습니다. 지침은 다음과 같습니다.

다음 단계

이제 확장 가능한 앱에 대한 데이터 모델링 탐색을 완료했습니다. 다음 단계는 선택한 프로그래밍 언어로 데이터베이스를 연결하고 쿼리하는 것입니다.