테넌트와 테넌시란 무엇일까요?

하나의 계정으로 여러 회사의 업무 공간을 오갈 수 있는 서비스를 생각해 보겠습니다. 로그인은 한 번 했는데, 회사를 바꾸면 보이는 문서도 사용할 수 있는 기능도 달라집니다. 같은 계정으로 접속했으니 같은 사용자라는 것은 알겠습니다. 그런데 그것만으로는 지금 어느 회사의 일을 하고 있는지 알 수 없습니다.
같은 사람이 같은 서비스에 접속했는데, 회사를 바꾸면 데이터와 권한은 어떻게 달라져야 할까요?
이 글에서 다루는 내용
테넌시(tenancy)를 여러 회사가 함께 쓰는 SaaS의 예시로 풀어보겠습니다. SaaS는 소프트웨어를 서비스로 제공해 고객이 접속해서 이용하는 방식입니다. 아래에 나오는 회사와 인물, 시스템 구성은 개념을 설명하기 위한 가상의 예시입니다.
먼저 서비스에서 말하는 고객과 사용자를 구분하고, 그 고객들에게 소프트웨어를 제공하는 방식을 살펴봅니다. 특정 클라우드나 프레임워크를 몰라도 읽을 수 있는 기초 설명입니다.
- 테넌트는 누구일까요?
- 한 사람이 여러 회사에 속한다면
- 싱글테넌시: 고객마다 전용 환경을 둡니다
- 멀티테넌시: 함께 쓰면서 경계를 지킵니다
- DB를 나누는 방법은 별도로 고릅니다
- 로그인했다고 모든 데이터를 볼 수는 없습니다
- 무엇을 기준으로 선택할까요?
1. 테넌트는 누구일까요?
테넌트(tenant)는 서비스를 사용하는 고객이나 사용자 집단을 가리킵니다. 원래는 세입자라는 뜻입니다. 건물에 여러 세입자가 들어오듯, 하나의 서비스에 여러 고객이 들어온다고 생각하면 이름이 조금 익숙해집니다.
기업용 SaaS라면 고객사 하나를 테넌트 하나로 생각하는 것부터 시작할 수 있습니다. A사가 문서 협업 서비스를 도입하고 그 안에서 여러 사용자가 함께 문서를 작성합니다. 로그인하는 사람은 여러 명이지만 이들이 일하는 고객 환경은 A사 하나입니다. B사가 같은 서비스를 도입하면 별도의 테넌트가 생깁니다. Microsoft의 멀티테넌트 아키텍처 개요도 테넌트와 개별 사용자를 구분합니다.
테넌시(tenancy)는 이렇게 구분한 고객들에게 소프트웨어와 자원을 제공하는 방식을 말합니다. A사와 B사에 프로그램을 각각 따로 실행해 줄 수도 있고, 함께 쓰는 프로그램이 두 회사의 요청을 모두 처리하게 할 수도 있습니다. 무엇을 함께 쓰고 무엇을 따로 둘지 정하는 것입니다. 여기서 자원은 프로그램을 실행하는 데 쓰는 CPU와 메모리, 데이터를 보관하는 저장 공간 등을 가리킵니다.
테넌트는 서비스를 사용하는 고객 단위이고, 테넌시는 그 고객들이 서비스를 사용하는 구조입니다. 고객을 구분하는 일과 그 고객들에게 실행 환경을 배정하는 일은 서로 연결되어 있지만 같은 결정은 아닙니다.
테넌트의 범위가 반드시 회사 하나여야 하는 것은 아닙니다. 한 회사가 독립된 업무 공간을 여러 개 만들 수 있는 서비스라면 업무 공간마다 테넌트를 둘 수도 있습니다. 이 글에서는 A사와 B사를 각각 하나의 테넌트로 두겠습니다.
2. 한 사람이 여러 회사에 속한다면
민수라는 사람이 A사와 B사의 업무를 함께 맡는 상황을 가정해 보겠습니다. A사에서는 관리자이고 B사에서는 공유받은 문서를 읽을 수만 있습니다.
| 로그인 사용자 | 선택한 회사 | 그 회사에서의 역할 |
|---|---|---|
| 민수 | A사 | 관리자 |
| 민수 | B사 | 읽기 전용 사용자 |
민수는 한 사람이지만 회사마다 할 수 있는 일이 다릅니다. 민수의 계정에 소속 회사 하나와 역할 하나만 기록하면 이 관계를 담기 어렵습니다. A사에서 관리자라는 이유로 B사에서도 관리자가 되어서는 안 되기 때문입니다.
이때 사용자와 테넌트 사이에 소속 관계(membership)를 둘 수 있습니다. 사용자는 로그인하는 계정을 나타내고, 소속 관계는 그 계정이 어느 테넌트에 어떤 자격으로 참여하는지를 나타냅니다.
화면에서 회사를 바꾸는 동작도 이 관계를 따라갑니다. 서비스는 로그인한 계정과 함께 현재 어느 테넌트의 일을 하는지를 알아야 합니다. 요청을 처리할 때 기준으로 삼는 이 테넌트 정보를 테넌트 컨텍스트(tenant context)라고 부릅니다. 민수가 A사를 선택하고 문서 목록을 요청했다면, 서버는 A사의 문서 중 민수에게 허용된 것을 찾아야 합니다. B사로 전환한 뒤에는 B사를 기준으로 같은 판단을 해야 합니다. Microsoft의 사용자와 테넌트 구분 안내에서도 한 사용자가 여러 테넌트에 참여할 수 있음을 설명합니다.
다만 회사 전환 메뉴가 있다고 해서 서버까지 공유한다는 뜻은 아닙니다. 계정과 소속을 표현하는 방법을 정했으니, 이제 각 회사의 요청을 어떤 환경에서 처리할지 살펴보겠습니다.
3. 싱글테넌시: 고객마다 전용 환경을 둡니다
싱글테넌시(single-tenancy)는 하나의 애플리케이션 실행 환경이나 특정 자원을 하나의 테넌트가 전용으로 사용하는 방식입니다. A사를 위한 환경은 A사의 요청만 처리하고, B사를 위한 환경은 B사의 요청만 처리합니다. Red Hat의 설명도 한 사용자 집단에 전용으로 제공되는 소프트웨어 인스턴스 또는 시스템으로 정의합니다.
이 글에서 애플리케이션은 문서 조회·수정 같은 기능을 처리하는 서버 프로그램을 뜻합니다. 인스턴스(instance)는 그 프로그램을 실제로 실행한 개별 단위입니다.
같은 코드로 만든 프로그램을 A사용과 B사용으로 각각 실행할 수 있습니다. 코드가 같아도 실행되는 두 인스턴스는 서로 구분됩니다. 따라서 같은 소프트웨어를 사용한다는 사실만으로 실행 환경까지 공유한다고 볼 수는 없습니다.
예를 들어 A사와 B사에 애플리케이션과 데이터베이스(DB)를 각각 제공할 수 있습니다. 애플리케이션이 문서 조회 요청을 처리한다면, DB는 그 문서의 제목과 내용 같은 데이터를 저장하고 찾아주는 역할을 합니다.
여기서 싱글은 로그인할 수 있는 사람이 한 명이라는 뜻이 아닙니다. A사 구성원 수백 명이 동시에 접속해도 그 환경이 A사만을 위한 것이라면 싱글테넌시입니다.
고객별 환경을 나누면 특정 고객에게 필요한 용량을 따로 늘리거나 변경 시점을 조정하기 쉬워집니다. A사에서 무거운 작업을 실행하더라도 전용으로 나눈 자원에서는 B사와 직접 경쟁하지 않습니다. 다만 네트워크나 공통 서비스처럼 여전히 공유하는 부분까지 영향이 사라지는 것은 아닙니다.
대신 새로운 고객이 들어올 때마다 그 고객을 위한 환경을 준비해야 합니다. C사가 가입했다면 C사 전용 실행 환경과 DB를 마련하고 필요한 설정을 적용하는 것입니다. 이렇게 서비스 이용에 필요한 자원을 할당하고 사용할 수 있도록 준비하는 작업을 프로비저닝(provisioning)이라고 합니다. 이 구조에서는 고객 수가 늘수록 프로비저닝하고 관리할 전용 환경도 늘어납니다.
이미 준비된 환경에 프로그램을 설치하거나 새 버전을 적용하는 작업은 배포(deployment)입니다. 문서 검색 기능을 고쳤다면 A사 전용 환경과 B사 전용 환경에 각각 새 버전을 배포해야 합니다. 프로비저닝과 배포를 하나의 자동화 절차로 묶을 수는 있지만, 환경을 준비하는 일과 그 환경에서 실행할 프로그램을 반영하는 일은 구분됩니다.
배포 이후에는 고객별 적용 버전 관리도 필요합니다. A사는 새 버전 적용에 성공했지만 B사는 실패해 이전 버전에 남아 있을 수 있습니다. 어느 고객 환경에 어떤 버전이 실행 중인지 추적하고, 실패한 배포를 다시 진행할지 이전 버전으로 되돌릴지 판단해야 합니다. 자동화하더라도 고객별 적용 상태를 확인할 필요는 남습니다. AWS의 Silo isolation은 전용 환경의 프로비저닝과 분산된 환경의 운영에서 생기는 부담을 다룹니다.
또 전용 앱을 둔다고 해서 물리 서버 한 대를 통째로 빌려야 하는 것은 아닙니다. 하나의 물리 장비 안에 서로 구분된 실행 환경을 만들 수도 있습니다. 어느 수준까지 전용으로 제공하는지를 확인해야 합니다. 환경을 나눴더라도 잘못된 접근 권한이나 공통 코드의 취약점은 별도로 점검해야 합니다.
4. 멀티테넌시: 함께 쓰면서 경계를 지킵니다
멀티테넌시(multi-tenancy)는 여러 테넌트가 애플리케이션이나 자원을 공유하면서, 각 테넌트의 데이터와 접근 범위를 구분해 사용하는 방식입니다. A사와 B사의 요청을 같은 애플리케이션에서 처리하는 구조가 한 예입니다.
같은 프로그램이 요청을 받더라도, A사의 요청에는 A사에서 허용된 데이터를, B사의 요청에는 B사에서 허용된 데이터를 돌려줘야 합니다. 사용자가 다른 회사의 데이터를 마음대로 조회하거나 수정할 수 없도록 제한하는 것입니다.
데이터 격리(data isolation)는 한 테넌트의 사용자가 다른 테넌트의 데이터에 허가 없이 접근하지 못하도록 경계를 지키는 것을 뜻합니다.
고객마다 저장소를 따로 둘 수도 있고, 같은 저장소 안에서 각 데이터의 소속 테넌트를 구분하고 접근을 제한할 수도 있습니다. 후자처럼 공통 환경 안에서 구분 규칙과 접근 제어로 경계를 지키는 방식을 논리적 격리라고 합니다. 데이터를 함께 저장한다는 것과 서로의 데이터를 볼 수 있다는 것은 다른 이야기입니다.
위 그림은 DB까지 공유하는 예시입니다. AWS의 Pool isolation도 자원을 공동으로 사용하면서 테넌트별 접근을 제한하는 모델을 설명합니다. 테넌트 식별자는 데이터가 어느 고객에게 속하는지 구분하는 값입니다. A사의 데이터에는 A, B사의 데이터에는 B처럼 표시한다고 생각하면 됩니다. 다만 값을 붙이는 것만으로 접근이 제한되지는 않습니다. 데이터를 읽고 쓰는 과정에서 그 구분을 실제로 확인해야 합니다.
공유의 이점은 고객마다 같은 실행 환경을 따로 준비하는 비용을 줄일 수 있다는 것입니다. 새로운 회사가 가입할 때 전용 앱과 DB를 새로 마련하는 대신, 기존 공유 환경에 테넌트를 등록하고 초기 설정이나 저장 공간을 준비하는 방식으로 프로비저닝할 수 있습니다. 물론 공유 환경의 용량이 부족해지면 증설이 필요합니다.
문서 검색 기능을 고쳤을 때는 공유 앱에 새 버전을 배포합니다. 그 앱을 사용하는 회사들이 같은 변경을 적용받으므로, 고객마다 별도로 운영하는 앱의 버전을 맞춰야 하는 부담이 줄어듭니다.
같은 코드를 쓰면서 고객별 설정을 다르게 둘 수도 있습니다. A사는 문서를 외부에 공유할 수 있게 하고 B사는 회사 안에서만 공유하도록 구성할 수 있습니다. 이 경우 문서 공유를 처리하는 코드는 공유하되, 허용 범위는 테넌트별 설정에서 읽습니다.
규모가 커지면 공유 앱을 여러 대로 늘릴 수 있습니다. 서버가 열 대여도 그 서버들이 여러 테넌트의 요청을 처리한다면 공유 방식은 유지됩니다. 멀티테넌시에서 세는 것은 서버 수가 아니라 그 환경을 함께 사용하는 테넌트 수입니다. 여러 실행 환경에 순차적으로 배포하거나 일부 고객부터 기능을 제공할 수도 있으므로, 모든 고객에게 항상 한 번에 같은 변경이 적용되는 것은 아닙니다.
5. DB를 나누는 방법은 별도로 고릅니다
앱을 공유하기로 했더라도 DB까지 같은 방식으로 공유할 필요는 없습니다. 같은 앱이 A사의 요청을 처리할 때는 A사 DB에, B사의 요청을 처리할 때는 B사 DB에 연결하도록 만들 수도 있습니다.
관계형 DB는 데이터를 행과 열로 이루어진 테이블에 저장합니다. 문서 테이블이라면 한 행이 문서 하나를 나타내고, 문서 번호·제목·내용 등이 각각 열이 됩니다. 이 테이블을 고객마다 따로 둘지, 함께 쓸지도 선택할 수 있습니다.
스키마(schema)는 데이터의 구조를 뜻하기도 하지만, 여기서는 PostgreSQL의 스키마처럼 DB 안에서 테이블 등을 묶어 구분하는 단위를 뜻합니다.
폴더를 나누듯 A용 묶음과 B용 묶음을 두고, 각 묶음 안에 문서 테이블을 둘 수 있다고 생각하면 됩니다. 이때 이름을 나누는 것만으로 접근까지 차단되는 것은 아니므로 권한도 설정해야 합니다. DB 제품마다 스키마의 의미와 지원 방식은 다릅니다.
| 데이터 구성 | 구분 방법 | 관리할 때의 부담 |
|---|---|---|
| DB 분리 | 고객마다 별도 DB | DB별 생성·변경·백업 관리 |
| 스키마 분리 | 한 DB 안에 고객별 테이블 묶음 | 스키마별 변경·권한 관리 |
| 테이블 공유 | 같은 테이블에서 테넌트 ID로 구분 | 모든 접근에서 테넌트 범위 유지 |
테이블을 공유하는 방식을 조금 더 살펴보겠습니다. 여러 회사의 문서를 같은 테이블에 저장하면서, 각 행에 테넌트 ID를 함께 기록하는 것입니다.
| 테넌트 ID | 문서 번호 | 제목 |
|---|---|---|
| A | 1001 | 프로젝트 계획 |
| A | 1002 | 회의 기록 |
| B | 1001 | 제품 소개 |
이 예시의 문서 번호는 회사 안에서만 유일합니다. 1001만으로 조회하면 어느 회사의 문서인지 정할 수 없습니다. A사의 문서 1001을 조회한다면 테넌트와 문서 번호를 함께 사용해야 합니다. 문서 ID 자체를 서비스 전체에서 유일하게 만들 수도 있지만, 그 경우에도 요청한 테넌트의 문서인지 확인하는 일은 필요합니다.
DB를 나누면 운영도 달라집니다. 공유 DB에서 A사의 데이터만 복구하려면 B사의 현재 데이터를 건드리지 않도록 복구 절차를 설계해야 합니다. DB가 고객마다 있다면 복구 단위는 명확해지지만 관리할 DB 수는 늘어납니다. Microsoft의 데이터 저장 설계 안내는 격리 방식과 함께 백업·복구·이관을 고려하도록 설명합니다.
따라서 “우리 서비스는 멀티테넌시입니다”라는 말만으로 DB 구조를 알 수는 없습니다. “애플리케이션은 공유하고 DB는 고객마다 분리합니다”처럼 어느 계층을 공유하는지까지 말하면 구조가 분명해집니다. AWS는 전용 자원과 공유 자원을 함께 쓰는 구성을 브리지 모델로 설명합니다.
고객과 데이터가 늘어나면 하나의 DB로 용량과 처리 부하를 감당하기 어려워질 수 있습니다. 이때 데이터를 여러 저장소로 나누어 분산하는 방법이 샤딩(sharding)입니다. 나뉜 각 저장 단위를 샤드(shard)라고 부릅니다.
테넌트 ID를 기준으로 A·B사의 데이터는 DB 1에, C·D사의 데이터는 DB 2에 배치할 수 있습니다. 각 DB 안에서는 여러 테넌트가 함께 데이터를 저장하므로, 여전히 테넌트별 접근을 제한해야 합니다. 샤딩으로 저장 위치를 나누는 것만으로 접근 권한까지 보장되지는 않습니다. Microsoft의 샤딩 안내에서도 여러 테넌트가 하나의 샤드를 공유하는 구성을 설명합니다.
6. 로그인했다고 모든 데이터를 볼 수는 없습니다
데이터를 어느 곳에 저장할지 정했다면, 누가 그 데이터에 접근할 수 있는지도 정해야 합니다. 인증(authentication)은 요청한 사용자가 누구인지 확인하는 일이고, 인가(authorization)는 그 사용자가 요청한 행동을 해도 되는지 판단하는 일입니다.
민수가 A사에서 문서를 수정하는 요청을 보냈다고 가정해 보겠습니다.
- 로그인한 계정이 민수인지 확인합니다. 인증에 해당합니다.
- 민수에게 A사에 접근할 자격이 있는지 확인하고, 처리하는 데이터도 A사의 범위로 제한합니다.
- 민수가 A사에서 해당 문서를 수정할 수 있는지 확인합니다. 회사 안에서의 인가 문제입니다.
테넌트에 접근할 자격을 판단하는 일도 인가에 포함됩니다. 다만 A사에 들어올 수 있는 것과 A사의 모든 문서를 수정할 수 있는 것은 다르므로, 구현할 때 각각의 조건을 놓치지 않아야 합니다. AWS의 Identity and isolation도 인증과 일반적인 권한 확인만으로 테넌트 격리가 충족되지는 않는다고 설명합니다.
브라우저가 요청에 tenantId: "A"를 붙였다고 그대로 믿을 수는 없습니다. 사용자는 요청 값을 바꿀 수 있습니다. 서버는 검증된 로그인 정보와 소속·권한 정보를 바탕으로 그 테넌트에 접근해도 되는지 판단해야 합니다. 회사 선택 메뉴는 사용자의 의도를 전달하는 화면이고, 접근을 허용하는 판단은 서버에서 이루어집니다.
이 구분은 DB 밖에서도 필요합니다. 문서 협업 서비스의 다른 기능에서도 같은 문제가 생길 수 있습니다.
- 문서 내용을 빠르게 다시 보여주려고 임시 저장하는 캐시(cache)를 둔다면, 그 저장 값에서도 A사
1001과 B사1001을 구분할 수 있어야 합니다. - 첨부 파일을 내려줄 때는 파일 경로를 아는지만 볼 것이 아니라 해당 회사와 파일에 접근할 권한을 확인해야 합니다.
- 문서 내보내기처럼 오래 걸리는 일을 요청 직후 끝내지 않고 별도의 작업으로 처리한다면, 나중에 그 작업을 실행하는 쪽에도 대상 테넌트 정보가 전달되어야 합니다.
한 사용자가 여러 회사에 속해 있어도 각 회사의 데이터가 합쳐져야 하는 것은 아닙니다. 회사 간 통합 조회가 필요한 제품이라면 그 범위와 권한을 별도로 정해야 합니다.
7. 무엇을 기준으로 선택할까요?
데이터 접근을 잘 분리해도 자원을 공유하면 성능에 영향을 줄 수 있습니다. A사가 대량의 문서를 한꺼번에 내보내면서 공유 DB와 작업 처리 자원을 오래 사용한다고 가정해 보겠습니다. B사는 A사의 데이터를 전혀 볼 수 없지만, 자신의 문서 목록이 느려지는 일은 겪을 수 있습니다.
이처럼 한 테넌트의 자원 사용이 다른 테넌트의 성능을 떨어뜨리는 현상을 시끄러운 이웃 문제(noisy neighbor)라고 부릅니다. 고객별 요청량이나 작업 동시 실행 수를 제한하고, 무거운 작업에 별도 자원을 배정하는 등의 대응을 검토할 수 있습니다. Microsoft의 Noisy Neighbor 안내는 자원 사용 관찰, 제한, 격리 등의 대응을 다룹니다.
여러 회사의 사용량이 비슷한 시기에 몰리는 경우도 생각해야 합니다. 업무 시작 시간에 문서 조회와 검색이 겹친다면 고객별 최대 사용량뿐 아니라 동시에 발생하는 전체 부하를 봐야 합니다. 공유해서 아낄 수 있는 자원과, 집중되는 작업을 감당하기 위해 확보할 자원을 함께 계산하는 것입니다.
비슷한 기능과 운영 조건을 요구하는 고객이 많다면 공유 환경이 비용과 운영 측면에서 유리할 수 있습니다. 반대로 특정 고객에게 전용 용량이나 별도의 복구 단위가 필요하다면 그 고객의 자원을 분리하는 방식을 검토할 수 있습니다. Microsoft의 테넌시 모델 안내는 공유 환경과 전용 환경을 조합하는 선택도 설명합니다.
제게는 로그인한 사람과 현재 선택한 회사를 따로 생각하는 것이 테넌시를 이해하기 쉬운 출발점입니다. 같은 민수라도 A사의 업무를 할 때와 B사의 업무를 할 때 적용할 데이터와 권한이 달라집니다.
그 회사들을 각각 전용 환경에 둘지, 같은 환경에서 처리할지는 그다음에 이어지는 설계입니다. 먼저 우리 서비스가 무엇을 하나의 고객 환경으로 보는지 정해야 어디를 나누고 어디를 함께 쓸지도 구체적으로 이야기할 수 있습니다.
References
- Microsoft: Architect multitenant solutions on Azure
- Red Hat: 멀티테넌시란?
- Microsoft: Architectural approaches for identity in multitenant solutions
- AWS: Silo isolation
- AWS: Pool isolation
- AWS: The bridge model
- AWS: Identity and isolation
- Microsoft: Architectural approaches for storage and data in multitenant solutions
- Microsoft: Noisy Neighbor antipattern
- Microsoft: Tenancy models for a multitenant solution
- PostgreSQL: Schemas
- Microsoft: Sharding pattern
