↓ 본문으로 건너뛰기

SaaS Architecture Single-Tenant

싱글 테넌트 vs 멀티 테넌트 SaaS: 언제 무엇을 쓸까

싱글 테넌트(멀티 인스턴스)와 멀티 테넌트 SaaS는 무엇이 다를까요. 격리, 비용, 운영 비교, 그 사이의 선택지, 언제 무엇을 쓸지, 공유 데이터베이스에서 테넌트를 분리하는 방법, 그리고 고객별 인스턴스 운영을 버틸 만하게 만드는 도구들을 정리했습니다.

싱글 테넌트 vs 멀티 테넌트 SaaS: 언제 무엇을 쓸까

싱글 테넌트 SaaS는 고객마다 애플리케이션과 데이터베이스를 한 벌씩 따로 줍니다. 멀티 테넌트 SaaS는 모든 고객을 하나의 공유 애플리케이션과 데이터베이스에 올리고 테넌트 ID로 구분합니다. 이 확인은 모든 쿼리에서 해야 하죠. 싱글 테넌트는 격리, 고객별 제어, 쉬운 컴플라이언스 대응을 얻는 대신 수많은 복사본을 운영하는 비용을 치릅니다. 멀티 테넌트는 저렴하고 운영도 훨씬 단순하지만, 고객끼리 섞이지 않게 하는 일이 코드의 몫이 됩니다. 대부분의 제품은 멀티 테넌트로 시작해서, 꼭 필요한 일부 고객에게만 전용 인스턴스를 제공합니다.

B2B SaaS를 하다 보면 언젠가는 반드시 테넌시 문제에 부딪힙니다. 보통은 큰 잠재 고객이 “우리 데이터를 다른 회사와 분리해서 둘 수 있나요?“라고 묻는 날이죠. 저도 이 논의를 여러 번 가까이서 지켜봤습니다. 답은 기본적으로 둘 중 하나입니다. 고객마다 전용 인스턴스를 주거나(싱글 테넌트, 멀티 인스턴스), 모두를 하나의 공유 인스턴스에서 운영하거나(멀티 테넌트, 싱글 인스턴스). 어느 쪽이 정답인 건 아닙니다. 그저 망가지는 방식이 다를 뿐입니다.

인프라 설계
#

싱글 테넌트, 멀티 인스턴스
#

싱글 테넌트, 멀티 인스턴스: 이 설정에서는 여러 인프라 인스턴스가 여러 테넌트에 서비스를 제공합니다.

이 방식의 매력은 결국 격리입니다. 장점 대부분이 여기서 나옵니다. 고객 데이터가 각자 독립된 환경에 있으니 보안 리뷰와 컴플라이언스 이야기가 훨씬 수월해집니다. 배포 사고나 무거운 워크로드가 터져도 전체가 아니라 고객 한 곳만 영향을 받습니다. 인스턴스별로 독립적으로 확장하고 튜닝하고 커스터마이징할 수 있고, 리소스가 전용이라 옆 테넌트가 뭘 하든 내 성능이 흔들리지 않습니다. 유지보수도 고객 단위로 잡을 수 있어서 다운타임이 작고 국소적입니다. 가격 설계만 잘하면 인프라 비용을 테넌트별 실제 사용량에 맞출 수도 있습니다.

대가는 모든 걸 N벌씩 운영하게 된다는 점입니다. 리소스 오버헤드가 쌓이고, 인스턴스 간 설정이 조금씩 어긋나고, 전체 플릿의 버전과 데이터를 맞추는 일 자체가 하나의 프로젝트가 됩니다. 확장, 격리, 비용 관리 문제는 사라지는 게 아니라 늘어납니다.

멀티 테넌트, 싱글 인스턴스
#

멀티 테넌트, 싱글 인스턴스: 단일 소프트웨어 애플리케이션이 여러 테넌트에 서비스를 제공합니다.

이게 기본값인 데는 이유가 있습니다. 배포도 하나, 백업할 데이터베이스도 하나, 프로덕션 버전도 하나. 리소스 효율이 좋고 운영이 단순하며, 업데이트와 보안 패치가 모든 고객에게 동시에 적용됩니다.

어려운 부분은 공유의 이면입니다. 한 테넌트가 무겁게 쓰면 모두의 성능이 끌려 내려가고, 고객별 커스터마이징에는 한계가 있습니다. 그리고 데이터 격리가 인프라가 아니라 애플리케이션 코드의 책임이 되기 때문에, 버그 하나가 테넌트 간 데이터 유출로 이어질 수 있습니다. 확장성 병목은 모든 고객에게 동시에 오고, “이 고객만"이라는 영향 범위가 없어지는 만큼 유지보수에도 더 신경을 써야 합니다.

SaaS 솔루션에 대한 자세한 정보 - 멀티 인스턴스 vs. 멀티 테넌트 아키텍처

멀티 테넌트 vs 멀티 인스턴스
#

같은 선택을 ‘멀티 테넌트 vs 멀티 인스턴스’라고 부르는 경우도 많은데, 같은 것을 반대편에서 본 것뿐입니다. ‘테넌트’는 고객 이야기로, 소프트웨어 한 벌을 몇 고객이 함께 쓰느냐입니다. ‘인스턴스’는 배포 이야기로, 소프트웨어를 몇 벌 돌리느냐입니다. 싱글 테넌트 제품은 고객마다 한 벌씩 돌리는 멀티 인스턴스 배포이고, 멀티 테넌트 제품은 보통 모두가 함께 쓰는 싱글 인스턴스입니다. 그러니 누군가 멀티 인스턴스를 원한다고 하면, 싱글 테넌트를 원한다는 뜻입니다.

실제로는 두 칸짜리 선택이라기보다 스펙트럼에 가깝고, 진짜 결정은 대부분 데이터베이스에서 내려집니다. 가장 많이 공유하는 쪽은 모든 고객의 행을 같은 테이블에 넣고 tenant_id 컬럼을 둔 다음, 모든 쿼리에서 그걸로 거르는 방식입니다. 운영 비용은 가장 싸고, 실수하기도 가장 쉽습니다. 한 단계 나아가면 공유 데이터베이스 안에 고객마다 스키마를 따로 두는 방식입니다. 분리가 깔끔해지고 고객 단위 백업도 가능하지만, 마이그레이션을 스키마 수만큼 돌려야 합니다. 더 나아가면 애플리케이션은 공유하고 데이터베이스만 고객마다 따로 두는 방식이 있습니다. 고객마다 스택 전체를 돌리지 않고도 데이터를 확실히 분리할 수 있어서 많이 쓰이는 절충안이죠. 반대쪽 끝이 완전한 싱글 테넌트로, 애플리케이션과 데이터베이스 모두 전용입니다. AWS의 SaaS 가이드에서는 양쪽 끝을 사일로(silo)와 풀(pool), 둘을 섞은 것을 브리지(bridge)라고 부르는데, 고객사 보안팀에 구성을 설명할 때 쓰기 좋은 말입니다.

싱글 테넌트 vs 멀티 테넌트 한눈에 비교
#

싱글 테넌트(멀티 인스턴스)멀티 테넌트(싱글 인스턴스)
데이터 격리고객마다 별도 인프라코드나 데이터베이스 정책으로 보장
고객당 비용높음: 고객마다 스택 한 벌낮음: 모두가 하나를 공유
운영배포, 업그레이드, 대시보드가 고객 수만큼전부 하나씩
시끄러운 이웃없음무거운 테넌트 하나가 모두를 느리게 할 수 있음
커스터마이징고객별로 가능, 버전을 달리할 수도 있음대부분 설정과 피처 플래그 수준
릴리스고객별로 차례차례모두에게 한 번에
배포 사고의 영향고객 하나모든 고객
보안 리뷰와 데이터 위치답하기 쉬움설명이 더 필요함

언제 무엇을 쓸까
#

특별한 이유가 없다면 멀티 테넌트로 가세요. 적은 금액을 내는 고객이 많을 때, 사용자가 직접 가입할 때, 그리고 환경 서른 개를 떠안으면 팀이 버티지 못할 만큼 작을 때 멀티 테넌트가 맞는 기본값입니다.

싱글 테넌트가 그 수고만큼의 값을 하는 건 몇 가지 경우입니다. 의료, 금융, 공공 분야 고객은 데이터를 물리적으로 분리하거나 특정 국가에 두라고 요구하는 경우가 많은데, 보안 리뷰에서 거기에 정직하게 답하는 가장 간단한 방법이 전용 인스턴스입니다. 엔터프라이즈 계약을 맺은 대형 고객 몇 곳이라면 전용 스택 비용을 감당할 수 있고, 애초에 그걸 기대하는 경우도 많습니다. 그리고 고객마다 릴리스 일정을 따로 가져가거나, 버전을 고정하거나, 깊게 커스터마이징해야 한다면, 인스턴스를 나누는 건 오버헤드가 아니라 파는 제품의 일부가 됩니다.

결국 대부분의 팀은 둘 다 하게 됩니다. 거의 모든 고객에게는 멀티 테넌트 제품을, 필요하고 비용도 낼 일부 고객에게는 엔터프라이즈 요금제로 전용 인스턴스를요. 멀티 테넌트 버전에서 처음부터 모든 곳에 테넌트 ID를 달아 두면, 나중에 고객 하나를 전용 데이터베이스로 옮기는 일은 재작성이 아니라 마이그레이션으로 끝납니다.

멀티 테넌트 격리를 쉽게 깨지지 않게 하기
#

멀티 테넌트에서 가장 무서운 버그는 테넌트 필터를 빠뜨린 쿼리입니다. 실패하지도 않습니다. 다른 고객의 데이터를 조용히 돌려줄 뿐이고, 코드 리뷰가 이걸 전부 잡아내지도 못합니다. Postgres를 쓴다면 행 수준 보안(RLS)으로 이 확인을 데이터베이스로 옮길 수 있습니다. 필터를 빠뜨린 쿼리라도 현재 고객의 행만 보이게 되죠.

ALTER TABLE invoices ENABLE ROW LEVEL SECURITY;

CREATE POLICY tenant_isolation ON invoices
    USING (tenant_id = current_setting('app.tenant_id')::uuid);

그다음 각 요청이 트랜잭션 안에서 SET LOCAL app.tenant_id = '…'로 테넌트를 지정합니다. 이렇게 하면 커넥션 풀의 연결이 앞 고객의 ID를 다음 요청으로 넘기지 않고, 지정을 깜빡한 요청은 행 대신 오류를 받습니다. 주의할 점은 두 가지입니다. 앱은 테이블 소유자가 아닌 역할로 접속해야 합니다. 소유자는 FORCE ROW LEVEL SECURITY를 추가하지 않는 한 이 정책을 건너뛰거든요. 그리고 슈퍼유저로는 절대 접속하지 마세요. 슈퍼유저는 무조건 건너뜁니다.

싱글 테넌트, 어디서부터 시작할까
#

싱글 테넌트로 간다면, 이게 “관리 가능한 일"이 될지 “슬로모션 재난"이 될지는 도구가 결정합니다. 서른 개의 환경을 손으로 돌볼 수는 없으니까요.

핵심은 컨테이너와 Infrastructure as Code입니다. Docker로 모든 테넌트에 동일한 형태로 앱을 패키징하고, Kubernetes로 그 많은 인스턴스의 배포와 확장을 처리합니다. Terraform, Pulumi, AWS CloudFormation으로 테넌트 스택 전체를 코드로 정의해 두면, 31번째 고객 셋업이 주말을 갈아 넣는 일이 아니라 풀 리퀘스트 하나가 됩니다. VM 세계에 더 가깝다면 Ansible, Chef, Puppet 같은 구성 관리 도구가 같은 역할을 해줍니다. CI/CD 파이프라인(Jenkins, GitLab CI/CD)은 평소보다 훨씬 중요해집니다. 모든 릴리스를 일일이 붙어 있지 않고도 전체 인스턴스에 배포해야 하거든요.

그다음부터는 제품의 형태에 달렸습니다. 일부 워크로드는 서버리스(AWS Lambda, Azure Functions)로 서버 계층 자체를 없앨 수 있습니다. Amazon RDS나 Azure SQL Database 같은 관리형 데이터베이스는 테넌트마다 DB를 손으로 관리하는 고행에서 구해줍니다. 모니터링(Prometheus, Grafana, New Relic)은 플릿이 생기는 순간부터 선택이 아닙니다. 어느 인스턴스가 아픈지는 고객이 말해주기 전에 알아야 하니까요. 인증은 Auth0나 Okta 같은 IAM 서비스에 맡기면 테넌트마다 새로 만들 필요가 없습니다. 어떤 언어를 쓰든 이런 배관 작업을 덜어주는 SaaS 지향 프레임워크나 라이브러리가 있을 것이고, 호스팅은 AWS, Azure, Google Cloud Platform 같은 대형 클라우드 어디든 무리 없이 받아줍니다.

첫날부터 이 목록을 전부 살 필요는 없습니다. 컨테이너와 IaC로 시작해서, 테넌트가 쌓이는 만큼 모니터링과 IAM을 더하고, 나머지는 실제로 아픈 순서대로 고르면 됩니다.

짧게 정리하면
#

싱글 테넌트, 즉 멀티 인스턴스는 고객마다 애플리케이션과 데이터베이스를 따로 두는 방식입니다. 강한 격리와 고객별 제어를 얻는 대신 운영할 플릿이 생깁니다. 멀티 테넌트는 하나를 모두가 함께 쓰는 방식으로, 저렴하고 단순하지만 격리는 코드로 보장합니다. 대부분의 제품은 멀티 테넌트로 시작해서, 모든 곳에 테넌트 ID를 두고 데이터베이스가 그걸 강제하게 한 뒤, 필요하고 비용도 낼 일부 고객에게만 전용 인스턴스를 주는 게 좋습니다. 싱글 테넌트로 운영한다면 관리 가능한 상태를 지켜주는 건 컨테이너와 Infrastructure as Code입니다.