3.14 멀티테넌시와 SaaS 아키텍처
개요와 동기
멀티테넌시는 소프트웨어의 한 인스턴스를 운영하여 많은 별개의 고객을 동시에 제공하면서, 각 고객의 데이터와 설정을 논리적으로 분리해 두고 같은 코드와 흔히 같은 인프라를 공유하는 실천입니다. 각 고객이 테넌트입니다. 이 하나의 아이디어가 서비스형 소프트웨어(SaaS), 곧 설치할 사본이 아니라 실행 중인 애플리케이션에 대한 접근을 파는 모델의 경제적 엔진입니다. 천 개의 테넌트가 같은 배포를 공유하면 한 번 패치하고, 하나의 시스템을 확장하며, 다음 고객의 한계 비용은 0에 가까워집니다. 잘 만든 멀티테넌트 제품이 두 사람의 스타트업과 10만 좌석의 기업을 같은 코드베이스로 섬길 수 있는 이유이며, 고르는 테넌시 모델이 여러 해 동안 마진, 보안 태세, 운영 부하를 형성하는 이유입니다.
큰 팀에서는 이해관계가 비용보다 깊습니다. 멀티테넌시는 아키텍처의 중심에 단단한 요구 사항을 둡니다. 테넌트 A는 어떤 버그, 경쟁 상태, 잘못된 설정 아래서도 결코 테넌트 B의 데이터를 봐서는 안 됩니다. 단 한 번의 테넌트 간 유출이 회사를 끝낼 수 있습니다. 동시에 공유의 요점이 효율이므로 모든 설계 결정은 강한 격리(더 안전하고 더 비쌈)와 조밀한 공유(더 싸고 더 위험함) 사이의 스펙트럼 위에 있습니다. 이를 맞게 하는 것이 우아하게 확장되는 제품과 인프라로 파산시키거나 헤드라인에 오르게 하는 제품의 차이입니다. 이 장은 클라우드 아키텍처(3.11장) 위에 서고, 데이터 아키텍처(3.4장)와 클라우드 보안(4.3장)에 크게 기대며, 확장성과 복원력(3.5장), 비용 귀속(9.4장)과 연결됩니다.
기업과 정부는 기준을 더 높입니다. 기업 구매자는 계약상의 데이터 보장을 협상하고, 자기 등급에 전용 격리를 요구하며, 다운타임 없이 환경 사이로 이전해 줄 것을 기대합니다. 정부는 데이터 거주법, 분류에 따른 분리, 각 기관이 자체 감사 경계를 가진 자체 테넌트여야 한다는 빈번한 요건을 더합니다. 여기서의 테넌시 결정은 구현 세부가 아닙니다. 데이터를 맡기는 모든 고객에게 하는 약속입니다.
핵심 원칙
- 격리는 스위치가 아니라 스펙트럼입니다. 사일로, 풀, 브리지 모델은 효율을 분리와 맞바꿉니다. 모든 것에 한 번이 아니라 등급별, 자원별로 고르십시오.
- 테넌트 컨텍스트는 신성합니다. 모든 요청, 질의, 로그 줄, 백그라운드 작업이 테넌트 식별자를 지녀야 하며, 모든 데이터 접근이 그것으로 범위가 정해져야 합니다.
- 테넌트 간 유출이 가장 중요한 실패입니다. 단일 필터 하나가 빠져도 다른 테넌트의 데이터를 노출할 수 없도록 설계하십시오. WHERE 절 하나가 아니라 심층 방어입니다.
- 시끄러운 이웃은 아키텍처 문제입니다. 할당량과 공정성이 없으면 무거운 테넌트 하나가 모두를 저하시킵니다. 일어나기 전에 계획하십시오.
- 테넌트별 설정은 확장되지만 테넌트별 코드는 그렇지 않습니다. 포크가 아니라 데이터와 플래그로 제품을 구부리십시오.
- 테넌트 수명 주기는 제품 기능입니다. 온보딩, 프로비저닝, 오프보딩, 데이터 내보내기가 일급이고, 자동화되고, 감사 가능해야 합니다.
- 귀속할 수 없는 것은 관리할 수 없습니다. 관측 가능성과 비용을 테넌트별로 나누지 않으면 신뢰성과 마진 양쪽에서 눈 감고 비행하는 것입니다.
권장 사항
격리 대 효율의 스펙트럼을 따라 등급별로 테넌시 모델을 고른다
세 모델이 스펙트럼의 닻입니다. 사일로(전용) 모델에서는 각 테넌트가 자체의 격리된 스택을 얻습니다. 별도의 컴퓨트, 별도의 데이터베이스, 때로 별도의 계정이나 네트워크입니다. 격리가 가장 강하고 버그의 영향 범위가 한 테넌트이지만, 고객당 유휴 용량에 값을 치르고 많은 사본을 운영합니다. 풀(공유) 모델에서는 모든 테넌트가 같은 컴퓨트와 데이터베이스를 공유하며 논리와 테넌트 식별자로만 분리됩니다. 효율이 가장 높고 테넌트의 한계 비용이 0에 가깝지만, 격리가 이제 전적으로 코드가 올바른 것에 달려 있습니다. 브리지(하이브리드) 모델은 둘을 섞습니다. 테넌트별 데이터베이스를 가진 공유 컴퓨트, 또는 작은 테넌트를 위한 공유 풀과 크거나 규제되는 테넌트를 위한 전용 사일로입니다.
제품 전체에 하나의 모델을 고르지 마십시오. 맞는 답은 대개 가격 등급에 대응하는 브리지입니다. 작은 테넌트의 롱테일은 경제성이 맞는 효율적인 공유 풀에 두십시오. 격리와 계약상의 보장에 값을 치를 기업 고객에게는 전용 또는 단일 테넌트 배포를 프리미엄 등급으로 제공하십시오. “어떤 테넌트가 무엇을 공유하는가”는 보안, 영업, 재무 팀이 모두 의존하는 주장이므로, 그 대응을 아키텍처 결정 기록(3.11장)으로 적어 두십시오.
데이터를 의도적으로 분할하고 테넌트 범위 지정을 잊을 수 없게 만든다
데이터는 멀티테넌시가 살거나 죽는 곳이므로, 분할 선택을 핵심 데이터 아키텍처 결정(3.4장)으로 다루십시오. 세 전략이 테넌시 모델과 평행합니다. 테넌트별 별도 데이터베이스는 가장 강한 격리, 쉬운 테넌트별 백업과 복원, 단순한 데이터 내보내기를 주지만 운영할 데이터베이스가 많고 스키마 이전을 뿌려야 하는 대가를 치릅니다. 공유 데이터베이스 안의 테넌트별 별도 스키마는 중간 길입니다. 서버 하나, 논리적 분리, 이전할 객체는 여전히 많습니다. 테넌트 컬럼으로 키가 지정된 공유 테이블은 모든 행이 tenant_id를 지니며, 가장 조밀하고 싸고 가장 위험합니다. 테넌트 필터가 빠진 질의 하나가 고객 간에 데이터를 유출하기 때문입니다.
테이블을 공유한다면 개발자가 필터를 기억하는 데 의존하지 마십시오. 우회할 수 없는 계층에서 테넌트 범위 지정을 시행하십시오. 세션의 테넌트에 근거해 모든 질의에 필수 조건을 붙이는 데이터베이스 행 수준 보안, 테넌트 절을 자동으로 주입하는 ORM이나 데이터 접근 계층, 또는 둘 다입니다. 여기서는 벨트와 멜빵이 맞습니다. 테넌트가 커지면 테넌트별 샤딩이 자연스러워집니다. 테넌트 그룹을 다른 데이터베이스 샤드에 두어 어떤 단일 인스턴스도 모두를 지니지 않게 하며, 이는 한 샤드 실패의 영향 범위에 상한을 두고 모델을 바꾸지 않고 큰 테넌트를 자체 샤드로 옮길 수 있게 합니다.
테넌트 컨텍스트를 어디서나 전파하고 테넌트 간 유출을 심층 방어한다
테넌트 식별자는 모든 작업 단위와 함께 가야 합니다. 엣지에서 보통 인증된 세션이나 서브도메인으로부터 수립하고, 검증하고, 요청 컨텍스트, 모든 다운스트림 서비스 호출, 모든 데이터베이스 세션, 모든 큐 작업, 모든 로그 줄과 지표를 통해 엮어 넣으십시오. 위험한 간극은 비동기 쪽입니다. 테넌트 컨텍스트를 다시 수립하지 않고 작업을 처리하는 백그라운드 워커, 테넌트 없이 키가 지정된 캐시, 호출자의 테넌트 식별자를 신뢰하는 웹훅 핸들러입니다. 각각이 한 테넌트의 데이터를 다른 테넌트에게 제공하는 경로입니다.
테넌트 간 격리를 심층 방어를 갖춘 보안 속성으로 다루고 세부는 4.3장에 넘기십시오. 최소 권한 원칙을 적용해 침해된 구성 요소조차 자신이 대신 행동하는 테넌트에만 닿게 하십시오. 인가 결정에 클라이언트가 통제하는 입력으로부터 테넌트 식별자를 절대 받지 말고, 인증된 신원에서 도출하십시오. 키 충돌이 경계를 넘을 수 없도록 캐시, 객체 스토리지 접두사, 검색 색인을 테넌트별로 네임스페이스화하십시오. 그다음 경계를 일부러 테스트하십시오. 테넌트 A의 자격 증명이 테넌트 B의 레코드를 읽을 수 없음을 단언하는 자동화된 테스트와 테넌트에서 탈출하려는 주기적 레드팀 연습입니다. 테스트 스위트가 찾은 유출은 버그이고, 고객이 찾은 유출은 위기입니다.
할당량, 속도 제한, 공정성으로 시끄러운 이웃을 가둔다
테넌트가 자원을 공유하면 한 테넌트의 급증이 모두의 장애가 됩니다. 이 시끄러운 이웃 문제는 엣지 케이스가 아니라 부하 아래 공유 풀의 기본 동작입니다. 처음부터 그에 맞서 설계하십시오. 중요한 자원(초당 요청, 동시 작업, 스토리지, 질의 비용)에 테넌트별 할당량을 설정하고 엣지와 비싼 내부 경계에서 속도 제한으로 시행하십시오. 한 테넌트가 나머지를 굶기게 두는 선착순 큐보다 각 테넌트에게 몫을 주는 공정 스케줄링을 선호하십시오.
시행을 테넌시 모델에 맞추십시오. 공유 풀에서는 할당량과 공정성이 주된 방어이므로 거기에 투자하십시오. 부하가 공정 공유가 흡수할 수 있는 것을 진정으로 넘는 테넌트에게는, 답이 흔히 풀에서 브리지나 사일로 배포로 올려 주는 것이며, 이는 실패가 아니라 팔 수 있는 기능입니다. 이를 확장성과 복원력 작업(3.5장)에 연결하십시오. 부하 차단, 서킷 브레이커, 백프레셔가 모두 테넌트를 인식해야 한 테넌트의 초과 부하를 떨어내는 것이 시스템 전체를 저하시키는 대신 다른 이들을 보호합니다.
코드 포크가 아니라 데이터로 테넌트를 설정한다
모든 고객은 조금씩 다른 것을 원할 것입니다. 로고, 워크플로 규칙, 통합, 없는 필드. 그렇다고 말하는 확장 가능한 방법은 테넌트별 설정입니다. 데이터이고, 런타임에 평가되고, 하나의 코드베이스가 공유하는 기능 플래그, 설정, 권한, 확장점입니다. SaaS 사업을 망치는 길은 테넌트별 맞춤 코드입니다. 큰 고객을 위한 브랜치나 포크나 코드 경로의 특수 케이스입니다. 그런 것이 열 개가 되면 더는 제품이 아니라 트렌치코트를 입은 열 개의 제품이 있고, 모든 변경을 열 번 테스트해야 합니다.
단단한 선을 그으십시오. 지원할 변이의 축을 일급 설정으로 모델링하고, 그 축 밖의 요청은 제품 로드맵이거나 단호한 거절로 다루십시오. 고객에게 진짜 맞춤화가 필요하면, 여러분의 것을 분기하지 않고 그들의 로직을 실행하는 확장점(웹훅, API, 플러그인, 맞춤 필드)을 주십시오. 진정으로 맞춤형인 배포는 격리가 요점이고 더 높은 가격이 운영 비용을 덮는 단일 테넌트 프리미엄 등급에 남겨 두십시오.
테넌트 수명 주기를 자동화하고, 관측 가능하게 하고, 비용을 귀속시킨다
테넌트 온보딩은 셀프서비스의 자동화된 흐름이어야 합니다. 테넌트의 데이터 파티션을 프로비저닝하고, 기본값을 시드하고, 권한을 설정하고, 운영 팀에 올리는 티켓이 아니라 몇 초 안에 준비되어야 합니다. 오프보딩도 똑같이 중요하고 방치하기 더 쉽습니다. 테넌트가 떠날 때 데이터를 쓸 수 있는 형식으로 내보낸 뒤 입증 가능하게 삭제할 수 있어야 합니다. 계약과 프라이버시법이 둘 다 요구할 것이기 때문입니다. 데이터 내보내기와 삭제를 첫날부터 설계하십시오. 공유 테이블 스키마에 사후 보강하는 것은 고통스럽습니다.
모든 것을 테넌트별로 계측하십시오. 로그, 추적, 지표에 테넌트 식별자를 태깅해 “이 장애가 모든 테넌트입니까 하나입니까?”와 “어느 테넌트가 이 비용을 이끌고 있습니까?”에 몇 초 안에 답할 수 있게 하십시오. 인프라 비용을 테넌트에 귀속시켜 고객당 진짜 마진을 알고 현재 가격에서 사용량이 그들을 수익성 없게 만드는 테넌트를 찾아내십시오(9.4장). 테넌트를 인식하는 관측 가능성과 비용 귀속이 멀티테넌시를 블랙박스에서 실제로 운영하고 가격을 매길 수 있는 시스템으로 바꿉니다.
장단점
| 테넌시 모델 | 장점 | 단점 |
|---|---|---|
| 사일로 (테넌트별 전용 스택) | 가장 강한 격리. 가장 작은 영향 범위. 쉬운 테넌트별 컴플라이언스와 내보내기. 단순한 시끄러운 이웃 이야기 | 가장 높은 비용. 테넌트당 유휴 용량. 운영하고 패치할 많은 사본 |
| 풀 (완전 공유) | 가장 낮은 한계 비용. 가장 조밀한 패킹. 확장하고 업그레이드할 시스템 하나 | 격리가 전적으로 코드 정확성에 의존. 최악의 시끄러운 이웃 위험. 가장 어려운 테넌트별 내보내기와 삭제 |
| 브리지 (하이브리드, 등급별) | 작은 테넌트에 효율적. 큰 테넌트에 전용 격리. 가격에 대응 | 만들고 운영할 모델이 더 많음. 등급 간 승급 경로를 유지해야 함 |
| 공유 DB, 공유 스키마 (테넌트 컬럼) | 가장 싼 스토리지. 이전 한 번. 가장 단순한 운영 | 필터 하나 누락이 데이터를 유출. 최후 방어선으로 행 수준 보안 필요 |
| 공유 DB, 테넌트별 스키마 | 논리적 격리. 서버 하나. 괜찮은 내보내기 | 많은 스키마 객체. 이전이 뿌려짐. 서버당 확장 한계 |
| 테넌트별 데이터베이스 | 강한 데이터 격리. 테넌트별 백업과 내보내기 | 많은 데이터베이스. 이전 뿌리기. 더 높은 비용 |
핵심 긴장은 격리 대 효율이며, 모든 행에 흐릅니다. 더 조밀한 공유는 마진을 곱절로 하는 동시에 위험도 곱절로 합니다. 더 강한 격리는 실제 테넌트당 비용으로 안전과 단순함을 삽니다. 해법은 한 극을 고르는 것이 아니라 각 테넌트를 스펙트럼 위에, 대개 등급별로 의도적으로 배치하는 것입니다. 경제성이 요구하고 위험이 한정된 곳에서는 작은 테넌트를 조밀하게 패킹하고, 값을 치를 큰 테넌트와 규제되는 테넌트는 영향 범위가 작아야 하는 곳에서 격리하십시오. 그다음 조밀한 쪽은 시행되는 테넌트 범위 지정으로 안전하게, 격리된 쪽은 자동화로 싸게 만들어 어느 극도 순진한 버전만큼 아프지 않게 하십시오.
팀과 논의할 질문
내일 테넌트 범위 필터 하나가 빠지면, 고객이 다른 고객의 데이터를 보겠습니까? 이것이 방어 가능한 멀티테넌트 제품과 일어나기를 기다리는 사고를 가르는 질문입니다. 정직한 시험은 실제 읽기 경로를 따라가며 무엇이 테넌트 경계를 시행하는지 묻는 것입니다. 개발자가 쓴 WHERE 절 하나입니까, 아니면 데이터베이스 행 수준 보안이나 무슨 일이 있어도 범위를 주입하는 데이터 접근 계층 같은 최후 방어선이 있습니까? 실제 질의 경로, 백그라운드 작업, 캐시를 가져오십시오. 유출은 거의 항상 아무도 범위를 정하지 않은 비동기 구석에 숨어 있기 때문입니다. 테넌트 A의 세션으로 테넌트 B의 레코드를 요청해 거부를 단언하는 테스트 결과도 가져와야 합니다. 경계가 사람의 경계심에만 달려 있다면 잠재적 침해가 있는 것이고, 해법(심층 방어)이 백로그 맨 위로 올라가야 합니다.
각 고객 등급이 실제로 어떤 테넌시와 데이터 분할 모델을 쓰며, 우리가 판 것과 맞습니까? 많은 팀이 기본으로 단일 모델로 표류하다가 가격과 아키텍처가 서로 어긋남을 발견합니다. 기업 고객에게 공유 풀이 제공하지 않는 격리를 약속했거나, 작은 고객이 마진을 망치는 비싼 전용 스택에 있습니다. 각 등급을 실제 모델(사일로, 풀, 브리지, 테넌트별 데이터베이스, 스키마, 공유 테이블)에 대응시키고, 영업 팀이 하는 계약상의 데이터 보장 옆에 놓으십시오. 어긋나는 곳에는 컴플라이언스 위험이나 비용 문제가 있으며, 둘 다 고객이나 감사자가 찾기 전에 드러낼 가치가 있습니다. 가져올 증거는 등급과 모델의 대응, 테넌트별 비용, 기업 계약의 실제 문구입니다.
큰 테넌트의 부하가 급증하면 누가 영향을 받으며, 우리 계획은 무엇입니까? 공유 풀에서 답은 흔히 “모두”이며, 팀은 인시던트가 분명히 할 때까지 이를 모르는 경우가 많습니다. 가장 큰 테넌트가 대량 가져오기를 실행하거나 트래픽 급증을 맞을 때 무슨 일이 일어나는지 따라가 보십시오. 테넌트별 할당량과 공정 스케줄링이 가두는지, 부하 차단이 이웃을 보호하는지, 아니면 시스템 전체가 함께 저하되는지. 부하 데이터와 마지막 시끄러운 이웃 인시던트의 이야기를 가져오십시오. 여러분을 아프게 하는 테넌트는 대개 이름을 댈 수 있는 테넌트이기 때문입니다. 답은 속도 제한 투자와 등급 전략을 모두 형성해야 합니다. 공정 공유를 넘어서는 테넌트의 가장 깔끔한 해법은 청구할 수 있는 브리지나 전용 배포로 올려 주는 것이기 때문입니다.
내일 테넌트가 오프보딩한다면, 깨끗한 내보내기를 건네고 모든 흔적을 삭제했음을 입증할 수 있습니까, 아니면 허둥대겠습니까? 오프보딩은 계약 종료 조항이나 프라이버시법 요청이 강제할 때까지 팀이 방치하는 테넌트 수명 주기의 부분이며, 그때는 공유 스키마가 추출과 삭제를 고통스럽게 만듭니다. 큰 팀에서는 위험이 누적됩니다. 테넌트의 데이터가 기본 데이터베이스, 캐시, 객체 스토리지, 검색 색인, 백업, 분석 파이프라인에 흩어져 있고, 각각을 쓸 수 있는 형식으로 내보낸 뒤 입증 가능하게 비워야 하기 때문입니다. 상충하는 고려는 실제입니다. 싼 스토리지를 주는 조밀한 공유 테이블이 정확히 테넌트별 추출과 삭제를 가장 어렵게 하는 것이므로, 스토리지 계층에서 산 효율을 출구에서 되갚을 수 있습니다. 실제 테넌트에 대한 오프보딩의 실시간 시연, 테넌트 데이터를 보유한 모든 저장소의 목록, 삭제가 실제로 일어났음을 보일 증거를 가져오십시오. 기업과 정부 테넌트에게 내보내기는 인증되어야 하고 삭제는 공공 기록법과 프라이버시법을 충족하도록 입증 가능해야 하므로, 없는 삭제 경로를 고객이 떠날 때 추가할 기능이 아니라 지금 닫을 컴플라이언스 결함으로 다루십시오.
개별 고객을 위한 일회성 특수 케이스가 이미 코드 경로에 몇 개나 있으며, 넘지 않을 선은 어디입니까? 테넌트별 코드 포크는 SaaS 사업이 하나의 제품이기를 멈추고 한 이름을 쓰는 여러 제품이 되는 조용한 방식입니다. 모든 변경을 모든 특수 케이스에 대해 테스트해야 하고 고객이 늘수록 속도가 쇠퇴합니다. 긴장은 진짜 필요가 있는 큰 고객을 거절하기 어렵고 코드 경로의 분기가 설정 표면을 만드는 것보다 빨라 느껴져서, 특수 케이스가 합리적인 예외 하나씩 쌓인다는 점입니다. 정직한 목록을 가져오십시오. 코드베이스에서 고객 이름과 등급별 분기를 grep해 세고, 각각이 무관한 변경에 부과하는 추가 테스트와 리뷰 비용을 추정하십시오. 논의는 일급 설정(플래그, 권한, 확장점)으로 모델링하는 변이와, 더 높은 가격이 운영 비용을 덮는 단일 테넌트 프리미엄 등급에 남겨 두는 진정한 맞춤 작업 사이에 단호한 선을 그어야 합니다. 깊은 맞춤화를 요구하는 기업 구매자에게 지속 가능한 답은 여러분의 로직을 분기하지 않고 그들의 로직을 실행하는 확장점이며, 그래야 거버넌스와 감사가 장치군 전반에서 다룰 만하게 유지됩니다.
테넌트별로 인시던트가 누구에게 얼마의 비용을 치르게 하는지, 어느 고객이 현재 가격에서 수익성이 없는지 말할 수 있습니까? 로그, 추적, 지표, 인프라 비용에 테넌트 차원이 없는 순간 멀티테넌시는 블랙박스가 됩니다. 장애가 한 테넌트인지 장치군 전체인지, 계약 가격에서 사용량이 손실이 되는 테넌트가 누구인지 답할 수 없기 때문입니다. 큰 팀에서 이 귀속이 플랫폼을 운영하는 것과 추측하는 것을 가르며, 신뢰성 대응과 가격 책정을 모두 직접 형성합니다. 고려 사항은 계측 비용과 카디널리티 쪽으로 당깁니다. 모든 것을 테넌트별로 태깅하는 것은 공짜가 아니고, 카디널리티가 높은 지표는 관측 가능성 예산에 부담을 주므로, 테넌트별로 무엇을 나누고 무엇을 샘플링할지 의도적으로 고릅니다. 현재 테넌트 태깅 커버리지, 클라우드 지출을 단일 테넌트에 귀속시키는 실제 질의, 가장 수익성 낮은 고객을 지명하게 해 줄 마진 표를 가져오십시오. 기업과 정부 환경에서 테넌트별 비용과 감사 범위가 있는 관측 가능성은 비용 청구, 용량 계획, 각 기관이나 사업부가 받을 자격이 있는 감사 경계에도 공급되므로, 테넌트 차원은 운영상의 필요만큼 거버넌스 요건입니다.
분야별 관점
스타트업. 첫날부터 단일 공유 풀을 출시하고 희소한 엔지니어링 주의를 사후 보강할 수 없는 한 가지, 곧 시행되는 테넌트 범위 지정에 쓰십시오. 행 수준 보안이 있는 관리형 Postgres, 모든 테이블의 tenant_id, 엣지에서 해석되는 테넌트 컨텍스트가 운영 팀 없이 안전한 밀도를 사 줍니다. 사일로 등급이나 테넌트별 인프라를 추측으로 만들지 마십시오. 돈을 내는 기업 가망 고객이 격리를 비용만큼 가치 있게 만들 때만 브리지 등급을 추가하십시오.
소기업. 플랫폼 전문가도 빠듯한 예산도 없으니, 격리 장치를 직접 만들기보다 클라우드와 프레임워크가 이미 주는 것에 기대십시오. 행 수준 보안이 있는 관리형 데이터베이스, 테넌트 범위를 대신 정해 주는 서비스형 플랫폼, 테넌트 신원을 싣는 인증 제공자가 대개 직접 만든 등가물보다 싸고 안전합니다. 멀티테넌시를 모든 계층에서 사느냐 만드느냐 결정으로 다루고, 맞춤 작업은 여러분만 쓸 수 있는 테넌트 경계 테스트에 남겨 두십시오.
대기업. 문제는 많은 팀에 걸친 포트폴리오 거버넌스입니다. 등급별 브리지 아키텍처, 각 등급을 테넌시와 데이터 분할 모델에 대응시키는 아키텍처 결정 기록, 재무가 모든 계정의 진짜 마진을 알도록 하는 테넌트별 비용 귀속입니다. 어느 팀도 다시 발명하지 않도록 테넌트 컨텍스트 전파와 범위 지정 최후 방어선을 표준화하고, 격리와 수명 주기 자동화를 명시적으로 예산에 넣고, 테넌트가 커지거나 컴플라이언스 필요가 바뀔 때 다운타임 없이 등급 사이로 이전할 수 있는 지원되고 가격이 매겨진 경로를 유지하십시오.
정부. 조달, 데이터 거주, 공적 책임성이 모델을 이끕니다. 코드형 정책으로 각 기관의 데이터를 국내 리전에 고정하고, 민감하거나 분류 등급이 높은 워크로드는 자체 감사 경계를 가진 별도 계정에 사일로화하고, 한 기관의 감사자가 다른 기관의 활동을 결코 보지 않도록 각 기관에 자체 신원 통합, 보존 규칙, 감사 추적을 주십시오. 오프보딩은 공공 기록법과 프라이버시법을 충족하도록 인증된 내보내기와 입증 가능한 삭제를 만들어야 하며, 서명하는 테넌시 보장은 아키텍처가 실제로 지킬 수 있는 것이어야 합니다.
사례
스타트업. 열다섯 명 규모의 스타트업이 첫날부터 제품을 단일 공유 풀로 만드는데, 옳은 선택입니다. 모든 테넌트가 모든 테이블에 tenant_id가 있는 하나의 관리형 Postgres 데이터베이스를 공유하고, 행 수준 보안이 데이터베이스에서 테넌트 조건을 시행해 잊은 필터가 유출할 수 없으며, 애플리케이션은 엣지에서 서브도메인으로 테넌트를 해석해 모든 요청과 백그라운드 작업에 엮어 넣습니다. 온보딩은 셀프서비스입니다. 새 가입이 테넌트 행을 프로비저닝하고 기본값을 시드하며 몇 초 안에 가동됩니다. 운영할 시스템이 하나이므로 엔지니어 두 명이 플랫폼 전체를 운영합니다. 첫 진짜 기업 가망 고객이 전용 데이터베이스와 계약상의 격리 보장을 요구하자 브리지 등급을 추가합니다. 같은 코드베이스지만 이 테넌트는 자체 샤드의 자체 데이터베이스를 얻고, 비용을 덮는 가격에 판매됩니다.
대기업. 대형 금융 기관을 섬기는 SaaS 벤더가 등급별 브리지 아키텍처를 운영합니다. 수천 개의 중소 고객이 테넌트별로 샤딩된 리전 공유 풀에 살고, 할당량과 공정 스케줄링이 시끄러운 이웃을 억제합니다. 최상위 은행 고객은 전용 데이터베이스, 테넌트별 암호화 키, 마스터 계약서에 쓰인 계약상의 데이터 거주 및 격리 보장이 있는 격리된 클라우드 계정의 단일 테넌트 배포를 얻습니다. 플랫폼 능력이 테넌트가 커지거나 컴플라이언스 필요가 바뀔 때 다운타임 없이 테넌트를 등급 사이로 이전합니다. 모든 테넌트의 비용이 태깅으로 귀속되어 재무가 모든 계정의 진짜 마진을 알고, 테넌트 태그가 붙은 관측 가능성은 호출 대기 엔지니어가 경보가 한 테넌트인지 장치군 전체인지 몇 초 안에 알게 합니다.
정부. 한 국가 플랫폼 제공자가 많은 정부 기관을 별도 테넌트로 호스팅하며 격리를 선호가 아닌 법적 요건으로 다룹니다. 데이터 거주법이 각 기관의 데이터를 국내 리전에 고정하고, 허용되지 않은 리전의 자원을 막는 코드형 정책(3.11장)이 이를 시행합니다. 분류가 모델을 이끕니다. 민감한 자료를 다루는 기관은 자체 감사 경계가 있는 별도 계정의 완전히 사일로화된 배포를 얻고, 분류 등급이 낮은 워크로드는 다스려지는 풀을 공유합니다. 각 기관은 자체 신원 통합, 자체 보존 및 내보내기 규칙, 자기 경계로 범위가 정해진 감사 추적을 가진 자체 테넌트이므로 한 기관의 감사자가 다른 기관의 활동을 결코 보지 않습니다. 기록이 공공 기록법과 프라이버시법의 대상이므로 오프보딩은 인증된 데이터 내보내기와 입증 가능한 삭제를 만듭니다.
비즈니스 사례: 동기, ROI, TCO
멀티테넌시의 핵심 비즈니스 사례는 마진입니다. 고객마다 새 사본을 배포하는 단일 테넌트 모델은 인프라와 운영 비용이 고객 수에 대략 선형으로 늘고, 엔지니어가 하루를 많은 사본을 패치하며 보낸다는 뜻입니다. 공유 멀티테넌트 모델은 그 연결을 끊습니다. 한 번 패치하고, 하나의 시스템을 확장하고, 다음 테넌트의 한계 비용이 0에 가까워질 만큼 고객을 조밀하게 패킹합니다. 그것이 SaaS 사업이 비용보다 훨씬 빠르게 매출을 키울 수 있게 하는 것이며, 투자자와 이사회가 깨끗한 멀티테넌트 아키텍처를 확장 가능한 회사의 대용 지표로 다루는 이유입니다.
수익은 세 곳에서 나타납니다. 운영 지렛대(한 팀이 장치군 전체를 운영), 더 빠른 전달(수정이 모든 테넌트에 한꺼번에 출시되어 고객을 추가해도 속도가 쇠퇴하지 않음), 가격 선택 가능성(롱테일을 위한 공유 요금제와 기업을 위한 프리미엄 격리 요금제, 둘 다 하나의 코드베이스에서). 이를 정직하게 재원을 대야 하는 비용에 견주십시오. 시행되는 테넌트 격리, 할당량, 수명 주기 자동화, 테넌트별 관측 가능성을 만드는 엔지니어링과 경계를 온전하게 유지하는 규율입니다. 잘못했을 때의 비용은 비대칭적이고 심각합니다. 단 한 번의 테넌트 간 데이터 침해가 공유로 아낀 인프라를 압도하는 규제 벌금, 대규모 이탈, 평판 손상을 촉발할 수 있기 때문입니다. 리더십에게는 위쪽의 마진과 확장성, 아래쪽의 존재적 위험으로 논거를 구성하십시오. 서비스 수준 협약과 계약상의 데이터 보장을 실제로 제공할 수 있는 테넌시 모델에 닻을 내리십시오. 아키텍처가 지킬 수 없는 약속은 판매가 아니라 부채이기 때문입니다.
안티패턴과 함정
- 관례에 의한 테넌트 범위 지정. 데이터베이스 수준이나 데이터 접근 계층의 최후 방어선 없이, 모든 질의에서 개발자가 테넌트 필터를 기억하는 데 의존하는 것. 한 번의 누락이 침해입니다.
- 클라이언트가 제공한 테넌트 식별자 신뢰. 인증된 신원에서 도출하는 대신 요청 입력에서 테넌트를 받아 인가하여, 호출자가 다른 사람의 데이터를 요청하게 하는 것.
- 범위가 정해지지 않은 백그라운드 작업. 누군가 동기 요청 경로만 범위를 정해서 테넌트 컨텍스트를 잃는 작업, 캐시, 웹훅, 내보내기.
- 테넌트별 코드 포크. 한 이름 아래 갈라진 많은 제품을 유지하게 되고 모든 변경이 열 배 비용이 들 때까지 큰 고객을 코드 경로에 특수 케이스로 넣는 것.
- 시끄러운 이웃 방어 없음. 테넌트별 할당량이나 공정성 없이 공유 풀을 운영하여, 처음 급증하는 테넌트가 모두를 내리는 것.
- 사후 생각으로서의 오프보딩. 데이터 내보내기와 입증 가능한 삭제 없이 만들었다가, 공유 스키마가 추출을 고통스럽게 만들어 고객의 종료 조항이나 프라이버시법 요청에 실패하는 것.
- 테넌트별로 눈 감고 비행. 테넌트 차원이 없는 로그, 지표, 비용으로, 누구의 인시던트인지 어느 테넌트가 수익성 없는지 말할 수 없는 것.
성숙도 모델
- 1단계, 시작: 멀티테넌시가 즉흥적이고 반응적입니다. 테넌트 분리가 최후 방어선 없는 손으로 쓴 필터에 의존하고, 모델은 만능이며, 할당량이 없고, 온보딩은 수동이며, 로그와 비용에 테넌트 차원이 없습니다. 팀은 시끄러운 이웃과 아슬아슬하게 피한 유출을 인시던트에서 배웁니다.
- 2단계, 발전: 기본 실천이 나타나지만 팀마다 일관되지 않습니다. 테넌시 모델이 선택되고 테넌트 컨텍스트가 주 요청 경로를 통해 전파되며, 데이터베이스 수준이나 데이터 접근 최후 방어선이 핵심 테이블의 범위 지정을 시행하고, 기본적인 테넌트별 할당량이 있습니다. 온보딩은 부분적으로 자동화되고 로그에 테넌트 식별자가 있지만, 백그라운드 경로, 내보내기, 비용 귀속은 서비스마다 다르고 어디에도 적혀 있지 않습니다.
- 3단계, 표준화: 테넌시 접근이 문서화되어 조직 전체에서 시행됩니다. 등급별 테넌시가 가격에 대응해 작은 테넌트는 공유 풀, 기업과 규제 테넌트는 격리된 배포를 쓰고, 테넌트 범위 지정은 심층적으로 시행되고 일부러 테스트되며, 할당량과 공정 스케줄링이 시끄러운 이웃을 가두고, 내보내기와 입증 가능한 삭제를 포함한 테넌트 수명 주기가 자동화되고, 관측 가능성과 비용이 테넌트별로 나뉩니다. 모든 팀이 각자의 것이 아니라 같은 테넌시 표준을 따릅니다.
- 4단계, 관리: 테넌시 자산이 기준선에 대해 측정되고 통제됩니다. 테넌트별 격리, 공정성, 지연, 비용이 합의된 목표를 가진 지표로 추적됩니다. 테넌트 간 테스트 커버리지, 할당량 위반과 시끄러운 이웃 인시던트 비율, 온보딩과 오프보딩 시간, 테넌트별 마진이 기준선에 대해 보고되고, 테넌트를 등급 사이로 승급시키거나 수익성 없는 것의 가격을 재조정하는 결정은 일화가 아니라 그 증거로 내려집니다. 거주와 분류 적합성이 지속적으로 모니터링되고, 표준에서의 표류는 문서화된 대응을 촉발합니다.
- 5단계, 오케스트레이션: 테넌시가 조직 전체에서 지속적으로 개선되고 통합됩니다. 테넌트 간 경계가 일상적인 레드팀 연습으로 시험되고, 테넌트는 커지거나 컴플라이언스 필요가 바뀔 때 다운타임 없이 등급 사이를 이동하며, 테넌트별 마진이 가격과 용량 계획에 공급되고, 거주와 분류 규칙은 리뷰가 아니라 정책으로 시행됩니다. 모델은 고객 구성과 규제 환경이 이동함에 따라 적응하고, 교훈은 제품, 보안, 재무에 하나의 순환으로 공급됩니다.
논의를 위한 아이디어
- 고객 등급 각각은 오늘 격리 대 효율 스펙트럼의 어디에 있으며, 판매한 보장이나 필요한 마진에 비추어 잘못된 모델에 있는 등급이 있습니까?
- 감사자에게 테넌트 A가 테넌트 B의 데이터에 접근할 수 없음을 입증해야 한다면, 지금 어떤 증거를 제시할 수 있으며, 그중 얼마가 단언이 아닌 자동화입니까?
- 비동기 경로(작업, 캐시, 웹훅, 내보내기, 검색 색인) 중 어느 것이 테넌트 컨텍스트를 다시 수립하고, 어느 것이 그저 상속하거나 호출자를 신뢰합니까?
- 테넌트가 공정 공유를 넘어서면, 브리지나 전용 배포로 가는 지원되고 가격이 매겨진 승급 경로가 있습니까, 아니면 답이 기본적으로 인시던트가 됩니까?
- 가장 수익성 낮은 고객을 지명할 수 있을 만큼 인프라 비용을 개별 테넌트에 귀속시킬 수 있으며, 그것이 가격 책정을 바꾸겠습니까?
- 정부나 규제 테넌트에 대해 데이터 거주와 분류에 따른 격리를 정책으로 시행하고, 인증된 내보내기와 입증 가능한 삭제로 오프보딩할 수 있습니까?
핵심 요점
- 하나의 인스턴스가 많은 테넌트를 섬기는 멀티테넌시는 SaaS의 경제적 엔진입니다. 마진을 이끌고, 테넌트 간 격리를 아키텍처의 중심에 놓습니다.
- 격리 대 효율을 스펙트럼으로 다루고 등급을 나누십시오. 작은 테넌트는 효율적인 공유 풀에 패킹하고, 크고 규제되는 테넌트는 값을 치를 브리지나 사일로 배포에서 격리하십시오.
- 테넌트 범위 지정을 손으로 쓴 필터에 얹지 마십시오. 행 수준 보안이나 데이터 접근 계층으로 심층 시행하고, 경계를 일부러 테스트하십시오.
- 테넌트 컨텍스트를 모든 요청, 작업, 캐시, 로그를 통해 전파하고, 유출이 숨은 비동기 경로를 방어하십시오.
- 테넌트별 할당량, 속도 제한, 공정 스케줄링으로 시끄러운 이웃을 가두고, 풀을 넘어선 테넌트를 저하시키게 두지 말고 승급시키십시오.
- 테넌트별 코드가 아니라 테넌트별 설정으로 제품을 구부리고, 테넌트 수명 주기와 테넌트별 관측 가능성 및 비용 귀속을 일급으로 만드십시오.
참고 문헌과 더 읽을거리
- Tom Kwok, Thao Nguyen, and Linh Lam, A Software as a Service with Multi-tenancy Support for an Electronic Contract Management Application (IEEE International Conference on Services Computing)
- Frederick Chong and Gianpaolo Carraro, Architecture Strategies for Catching the Long Tail (Microsoft)
- Amazon Web Services, SaaS Lens, AWS Well-Architected Framework and SaaS Tenant Isolation Strategies
- Microsoft, Multitenant SaaS architecture and patterns (Azure Architecture Centre)
- Google Cloud, Architecture for Multi-tenant SaaS Applications
- Cor-Paul Bezemer and Andy Zaidman, Multi-Tenant SaaS Applications: Maintenance Dream or Nightmare? (Proceedings of the Joint ERCIM Workshop on Software Evolution)
- The Open Web Application Security Project, OWASP Application Security Verification Standard (access-control and multi-tenancy requirements)
- Martin Kleppmann, Designing Data-Intensive Applications (partitioning, sharding, and data isolation)