성공한 서비스는 성장하는 순간부터 위험해진다
지난 장에서 우리는 사용자가 서비스를 처음 만나고, 이해하고, 가치를 체감하고, 다시 돌아오는 여정을 설계했다. 그런데 여기서 잔인한 진실 하나가 등장한다. 사용자가 사랑하기 시작한 서비스는 바로 그 순간부터 위험해진다.
처음에는 하루에 열 명이 쓰던 기능이 어느 날 천 명에게 동시에 열릴 수 있다. 마케팅 캠페인이 터지고, 유명 인플루언서가 언급하고, 기업 고객이 전사 도입을 결정하고, 새벽 두 시에 배치 작업이 몰리고, 결제일 아침에 모든 사용자가 대시보드로 달려온다. 이때 서비스가 느려지거나 멈추면 사용자는 이렇게 생각하지 않는다.
"아, 아키텍처가 아직 수평 확장에 최적화되지 않았구나."
사용자는 훨씬 단순하게 판단한다.
"못 믿겠네."
기술 아키텍처는 사용자가 평소에는 보지 못하는 무대 뒤 구조물이다. 하지만 서비스가 성장하거나 실패하거나 공격받거나 예측을 벗어나는 순간, 그 구조물은 고객 경험의 전면으로 튀어나온다. 성공한 서비스는 트래픽이 몰릴 때 무너지지 않는다. 더 정확히 말하면, 무너질 부분을 미리 나누어 두고, 실패하더라도 조용히 감지하고 격리하고 회복한다.
이 장의 목표는 멋진 기술 유행어를 나열하는 것이 아니다. 최고의 IT 서비스를 만들기 위해 필요한 기술 구조의 사고방식을 세우는 것이다. 어떤 서비스는 처음부터 거대한 마이크로서비스로 시작했다가 복잡성에 깔려 죽고, 어떤 서비스는 단순한 구조로 시작했지만 성장의 압력을 견디지 못해 고객 앞에서 무너진다. 우리가 원하는 길은 그 중간에 있다. 지금은 단순하되, 내일의 성장을 배신하지 않는 구조다.

아키텍처는 기술 그림이 아니라 서비스 약속의 뼈대다
좋은 아키텍처는 서버, 데이터베이스, API, 큐, 캐시를 예쁘게 그린 그림이 아니다. 그것은 서비스가 고객에게 한 약속을 기술적으로 지키는 방식이다.
예를 들어 채용 SaaS가 "지원자 관리를 한곳에서 빠르게 끝낸다"고 약속했다면, 지원자 목록 조회는 빠르고 안정적이어야 한다. 병원의 예약 서비스가 "진료 예약을 놓치지 않게 한다"고 약속했다면, 알림 발송과 예약 상태 동기화는 핵심 경로다. 금융 서비스가 "내 돈의 상태를 실시간으로 보여준다"고 말한다면, 데이터 정합성과 보안은 부가 기능이 아니라 제품 그 자체다.
따라서 아키텍처 설계의 첫 질문은 "어떤 기술 스택을 쓸까?"가 아니다.
"우리 서비스에서 절대 깨지면 안 되는 고객 약속은 무엇인가?"
이 질문에 답해야 확장성, 가용성, 보안, 관측 가능성, 비용 효율성의 우선순위가 정해진다. 모든 것을 최고 수준으로 만들 수는 없다. 모든 기능에 같은 수준의 복구 시간, 같은 수준의 이중화, 같은 수준의 성능 목표를 적용하면 비용과 복잡성이 폭발한다. 반대로 모든 것을 대충 만들면 서비스의 가장 중요한 순간에 고객 신뢰를 잃는다.
기술 아키텍처는 결국 선택의 기술이다. 어떤 흐름은 반드시 즉시 처리해야 하고, 어떤 흐름은 몇 초 늦어도 된다. 어떤 데이터는 절대 잃으면 안 되고, 어떤 로그는 샘플링해도 된다. 어떤 기능은 장애가 나면 전체 서비스를 멈춰야 하지만, 어떤 기능은 잠시 숨겨도 된다. 이 구분을 하지 못한 시스템은 성장할수록 비싸지고 느려지고 위험해진다.
Microsoft의 클라우드 아키텍처 신뢰성 원칙도 비슷한 관점을 강조한다. 신뢰성은 막연한 "안정적이면 좋겠다"가 아니라, 비즈니스 요구사항, 사용자 흐름, 복구 목표, 관측 가능성, 비용 제약을 함께 문서화하고 설계에 반영해야 하는 활동이다1. 아키텍처는 엔지니어의 취향이 아니라 고객 약속의 번역문이어야 한다.
단순하게 시작하되, 미래의 목을 조르지 말라
초기 서비스에서 가장 흔한 실수는 두 가지다. 하나는 너무 빨리 복잡해지는 것, 다른 하나는 너무 오래 한 덩어리로 버티는 것이다.
첫 번째 팀은 아직 고객도 많지 않은데 Kubernetes, 이벤트 스트리밍, 서비스 메시, 복잡한 마이크로서비스, 다중 리전 배포를 한꺼번에 도입한다. 결과는 화려하지만 느리다. 기능 하나를 바꾸려면 배포 파이프라인과 네트워크 정책과 인증 흐름을 모두 만져야 한다. 고객 문제를 배워야 할 시간에 인프라를 돌보느라 지친다.
두 번째 팀은 "일단 만들자"는 말로 모든 것을 하나의 코드베이스, 하나의 데이터베이스, 하나의 서버, 하나의 관리자 계정에 밀어 넣는다. 처음에는 빠르다. 그런데 고객이 늘어나자 로그인, 결제, 검색, 리포트, 알림, 관리자 기능이 서로 얽혀 작은 변경도 전체 장애로 이어진다. 어느 날 개발자는 말한다.
"이제는 어디를 고치면 어디가 터질지 모르겠습니다."
좋은 초기 아키텍처는 거대한 시스템이 아니다. 좋은 초기 아키텍처는 잘 나눌 수 있는 단순한 시스템이다. 처음부터 모든 서비스를 독립 배포할 필요는 없다. 하지만 나중에 나눌 수 있도록 경계를 잡아야 한다. 이를 흔히 "모듈러 모놀리스"라고 부른다. 겉으로는 하나의 애플리케이션이지만 내부는 도메인별로 분리되어 있고, 각 모듈은 명확한 인터페이스를 통해 대화한다.
초기 아키텍처에서 반드시 지켜야 할 원칙은 다음 네 가지다.
모듈화: 사용자, 결제, 주문, 알림, 리포트처럼 책임이 다른 영역을 코드와 데이터 흐름에서 구분한다.
느슨한 결합: 한 영역의 변경이 다른 영역을 연쇄적으로 깨뜨리지 않도록 직접 의존을 줄인다.
명확한 인터페이스: 내부 함수 호출이든 API든 이벤트든, 어떤 입력을 받고 어떤 결과를 돌려주는지 계약을 분명히 한다.
상태 분리: 서버 인스턴스 자체에 중요한 사용자 상태를 묶어두지 않고, 데이터베이스·캐시·스토리지 같은 적절한 저장 계층에 둔다.
특히 SaaS와 클라우드 환경에서는 이 원칙이 더 중요해진다. SaaS 아키텍처 연구에서도 확장성과 유지보수성을 높이기 위해 기능 단위의 구조화, 모듈성, API 중심 설계, 유지보수 가능한 참조 구조가 중요하다고 설명한다2. SaaS는 한 번 만들고 끝나는 제품이 아니라, 여러 고객 조직이 동시에 사용하고 계속 변경되는 살아 있는 서비스다. 고객사가 늘어날수록 테넌트, 권한, 데이터 격리, 사용량 제한, 과금, 감사 로그 같은 문제가 함께 커진다.
여기서 테넌트란 SaaS를 사용하는 고객 조직 또는 고객 단위를 말한다. 멀티테넌시는 하나의 서비스가 여러 고객 조직을 함께 수용하는 구조다. 예를 들어 하나의 프로젝트 관리 SaaS에 A회사, B회사, C회사가 각각 로그인해 자기 회사 데이터만 보는 식이다. 멀티테넌시를 가볍게 보면 나중에 데이터 권한, 성능 격리, 고객별 설정, 요금제 차등, 보안 감사가 모두 지옥이 된다.
초기부터 거대한 멀티테넌트 플랫폼을 만들 필요는 없다. 하지만 최소한 "고객 조직 ID가 모든 핵심 데이터와 요청 흐름에서 자연스럽게 따라다니는가?"는 확인해야 한다. 이것 하나만 놓쳐도 나중에 엔터프라이즈 고객을 받을 때 데이터 구조 전체를 갈아엎어야 한다.
확장성의 핵심은 더 큰 서버가 아니라 병목의 분산이다
초기 트래픽이 늘면 많은 팀이 가장 먼저 서버 사양을 올린다. CPU를 늘리고, 메모리를 늘리고, 더 비싼 인스턴스로 바꾼다. 이것을 수직 확장, 즉 스케일 업이라고 한다. 나쁜 선택은 아니다. 초기에 가장 단순하고 빠른 해결책일 때가 많다.
문제는 수직 확장에는 천장이 있다는 점이다. 아무리 큰 서버도 무한히 커질 수 없고, 커질수록 비용 효율은 나빠진다. 더 큰 문제는 단일 장애 지점이다. 모든 요청이 하나의 거대한 서버에 몰려 있으면 그 서버가 흔들리는 순간 전체 서비스가 흔들린다.
성장하는 서비스는 수평 확장, 즉 스케일 아웃을 고려해야 한다. 수평 확장은 서버 하나를 크게 키우는 대신 여러 서버가 일을 나누어 처리하게 하는 방식이다. 이때 중요한 전제는 애플리케이션 인스턴스가 가능하면 상태를 갖지 않는 것이다. 로그인 세션, 임시 파일, 장바구니 상태 같은 것을 특정 서버의 메모리에만 저장하면 로드 밸런서가 요청을 다른 서버로 보냈을 때 문제가 생긴다.
로드 밸런서는 여러 서버 앞에서 교통정리를 하는 장치다. 사용자의 요청을 여러 인스턴스에 나누어 보내고, 죽은 인스턴스에는 요청을 보내지 않는다. 하지만 로드 밸런서만 있다고 확장성이 생기지는 않는다. 읽기 부하가 문제인지, 쓰기 부하가 문제인지, 이미지 전송이 문제인지, 검색 연산이 문제인지, 외부 API 호출이 문제인지 알아야 한다.
확장성의 비밀은 "전체를 키우는 것"이 아니라 "병목을 분리하는 것"이다.
| 병목 유형 | 흔한 증상 | 대표 해법 |
|---|---|---|
| 읽기 부하 | 목록·대시보드 조회가 느려진다 | 캐싱, 읽기 전용 복제본, CDN |
| 쓰기 부하 | 주문·결제·저장 요청이 밀린다 | 큐, 배치 처리, 샤딩, 쓰기 모델 최적화 |
| 연산 부하 | 이미지 처리·추천·AI 분석이 느리다 | 비동기 워커, GPU/전용 노드, 작업 큐 |
| 네트워크 부하 | 정적 파일·이미지·동영상 전송이 느리다 | CDN, 압축, 지역별 엣지 캐시 |
| 데이터베이스 잠금 | 특정 테이블에서 지연과 오류가 반복된다 | 인덱스 최적화, 트랜잭션 축소, 파티셔닝 |
| 외부 의존성 | 결제사·메일·문자 API 장애가 전체 장애로 번진다 | 타임아웃, 재시도, 서킷 브레이커, 대체 경로 |
캐시는 자주 쓰는 데이터를 더 빠른 곳에 잠시 저장하는 방식이다. CDN은 이미지, 스크립트, 동영상 같은 정적 콘텐츠를 사용자와 가까운 서버에서 전달하는 네트워크다. 글로벌 사용자를 상대한다면 CDN은 성능 기능이 아니라 사용자 경험 기능이다.
큐는 즉시 처리하지 않아도 되는 일을 줄 세우는 장치다. 사용자가 회원가입을 했을 때 환영 이메일, 추천 데이터 생성, CRM 동기화까지 모두 한 요청 안에서 처리하면 응답은 느려진다. 대신 핵심 데이터 저장만 즉시 끝내고 나머지는 큐에 넣어 백그라운드 워커가 처리하게 만들면 사용자는 빠르게 다음 단계로 이동한다.
데이터베이스 확장도 신중해야 한다. 읽기 부하가 많으면 리플리카, 즉 복제 데이터베이스를 두어 조회 요청을 분산할 수 있다. 데이터가 너무 커지면 샤딩을 고려할 수 있다. 샤딩은 데이터를 고객 ID나 지역 같은 기준으로 여러 데이터베이스에 나누어 저장하는 방식이다. 강력하지만 복잡하다. 샤딩을 너무 늦게 해도 고통스럽지만, 너무 빨리 해도 개발 속도를 크게 떨어뜨린다.
아키텍처 설계자는 늘 이렇게 물어야 한다.
"지금 병목은 어디인가? 앞으로 병목이 될 가능성이 높은 곳은 어디인가? 이 병목을 전체 시스템을 흔들지 않고 따로 키울 수 있는가?"
데이터는 가장 조용하지만 가장 무서운 병목이다
사용자는 화면이 느리면 "서버가 느리다"고 말한다. 하지만 실제 원인의 상당수는 데이터에 있다. 잘못된 인덱스, 비대한 쿼리, 너무 긴 트랜잭션, 한 테이블에 몰린 쓰기, 비효율적인 조인, 무분별한 로그 저장, 권한 체크를 위한 반복 조회가 서비스를 서서히 무겁게 만든다.
데이터 아키텍처에서 중요한 것은 저장소를 하나 고르는 일이 아니다. 데이터의 성격을 나누는 일이다. 모든 데이터가 같은 속도, 같은 정합성, 같은 보존 기간, 같은 접근 패턴을 필요로 하지 않는다.
결제 기록은 정확해야 한다. 몇 초 빨리 보여주는 것보다 한 원도 틀리지 않는 것이 중요하다. 반면 인기 게시글 순위는 몇 초 늦어도 된다. 실시간 알림 카운트는 가끔 1개 차이가 나도 치명적이지 않지만, 의료 예약 상태나 계좌 잔액은 그렇지 않다.
이 구분을 하지 않으면 서비스는 두 가지 극단 중 하나로 간다. 하나는 모든 데이터를 강한 정합성으로 처리하다가 느려지는 길이다. 다른 하나는 모든 데이터를 느슨하게 처리하다가 신뢰를 잃는 길이다.
데이터 설계에서 실무적으로 꼭 확인해야 할 질문은 이렇다.
이 데이터는 잃어도 되는가, 절대 잃으면 안 되는가?
이 데이터는 즉시 정확해야 하는가, 잠시 후 맞아도 되는가?
이 데이터는 주로 읽히는가, 주로 쓰이는가?
이 데이터는 고객별로 격리되어야 하는가, 전체 통계로 합쳐도 되는가?
이 데이터는 몇 년 동안 보관해야 하는가, 며칠 후 버려도 되는가?
이 질문은 성능뿐 아니라 비용과 보안에도 영향을 준다. 모든 로그를 영원히 고성능 저장소에 보관하면 비용이 폭발한다. 반대로 감사 로그를 너무 빨리 지우면 보안 사고나 분쟁이 발생했을 때 증거가 사라진다. 데이터는 서비스의 기억이다. 기억을 어떻게 저장하고, 언제 압축하고, 무엇을 잊을지 결정하는 것도 아키텍처다.
신뢰성은 장애가 없다는 약속이 아니라 회복한다는 능력이다
초보 팀은 장애를 부끄러워한다. 성숙한 팀은 장애를 예상한다. 최고의 팀은 장애가 고객 경험 전체로 번지지 않게 설계한다.
분산 시스템에서는 일부 구성요소가 실패하는 것이 정상이다. 네트워크는 끊기고, 서버는 죽고, 배포는 실패하고, 외부 API는 지연되고, 데이터베이스는 잠기고, 인간은 실수한다. 그래서 신뢰성 설계의 출발점은 "장애가 나지 않게 하자"가 아니라 "장애가 나면 어떻게 감지하고, 어디까지 격리하고, 얼마나 빨리 복구할 것인가"다.
고가용성을 위해 가장 먼저 생각할 것은 이중화다. 중요한 구성요소가 하나뿐이면 그 하나가 곧 서비스의 운명이다. 애플리케이션 서버는 여러 대로 두고, 데이터베이스는 복제와 백업을 갖추고, 캐시는 장애 시 우회 경로를 준비하고, 파일 저장소는 내구성을 확인해야 한다. 하지만 이중화만으로는 충분하지 않다. 같은 버그가 모든 인스턴스에 동시에 배포되면 서버가 열 대여도 함께 망가진다.
그래서 장애 격리가 필요하다. 장애 격리는 문제가 생긴 영역의 폭발 반경을 줄이는 일이다. 추천 서비스가 실패했다고 로그인까지 실패해서는 안 된다. 이메일 발송이 지연된다고 결제 완료 화면이 멈춰서는 안 된다. 검색 인덱스가 늦게 갱신된다고 주문 데이터가 틀어져서는 안 된다.
실패에 강한 시스템은 여러 방어 장치를 가진다.
타임아웃: 외부 서비스나 내부 API 응답을 무한히 기다리지 않고 일정 시간 후 중단한다.
재시도: 일시적 네트워크 오류처럼 다시 시도하면 해결될 수 있는 실패를 처리한다.
서킷 브레이커: 실패가 계속되는 대상에 요청을 계속 보내지 않고 잠시 차단해 전체 시스템을 보호한다.
폴백: 핵심 기능이 실패했을 때 대체 응답이나 축소된 기능을 제공한다.
벌크헤드: 선박의 격벽처럼 자원 풀을 나누어 한 영역의 과부하가 전체를 침몰시키지 않게 한다.
복구 목표도 숫자로 정해야 한다. RPO는 Recovery Point Objective의 약자로, 장애 발생 시 어느 시점의 데이터까지 복구할 수 있어야 하는지를 뜻한다. 쉽게 말해 "최대 얼마만큼의 데이터를 잃어도 되는가"다. RTO는 Recovery Time Objective의 약자로, 서비스를 어느 시간 안에 복구해야 하는지를 뜻한다. 쉽게 말해 "얼마나 오래 멈춰도 되는가"다.
백업은 복구가 검증되기 전까지 백업이 아니다. 많은 팀이 백업 파일은 가지고 있지만 실제로 복구해본 적은 없다. 그러다 장애가 난 뒤에야 백업이 깨졌거나, 복구 절차가 너무 오래 걸리거나, 권한이 없거나, 문서가 낡았다는 사실을 발견한다. 신뢰성은 문서에 있는 계획이 아니라, 연습을 통과한 능력이다.
배포는 기능 출시가 아니라 통제된 위험 관리다
서비스가 성장할수록 장애의 상당수는 새로운 배포에서 발생한다. 아이러니하게도 팀이 열심히 일할수록 서비스는 더 자주 위험해진다. 기능을 빨리 내는 능력과 안정적으로 운영하는 능력은 서로 싸우는 것처럼 보인다. 그러나 좋은 아키텍처와 배포 전략은 이 둘을 화해시킨다.
무중단 배포의 핵심은 새 버전을 올리는 동안 기존 사용자의 경험을 깨뜨리지 않는 것이다. 이를 위해 블루/그린 배포, 카나리 배포, 롤링 배포 같은 전략을 사용할 수 있다. 블루/그린 배포는 기존 환경과 새 환경을 나란히 두고 트래픽을 전환하는 방식이다. 카나리 배포는 일부 사용자에게만 새 버전을 먼저 노출해 문제가 없는지 확인한 뒤 점진적으로 확대하는 방식이다. 롤링 배포는 여러 인스턴스를 순차적으로 교체하는 방식이다.
이보다 더 강력한 도구는 기능 플래그다. 기능 플래그는 코드는 배포하되 기능 노출은 설정으로 켜고 끄는 방식이다. 새 결제 화면을 전체 사용자에게 바로 공개하지 않고 내부 직원, 베타 고객, 5% 사용자, 30% 사용자 순서로 열 수 있다. 문제가 생기면 코드를 되돌리지 않고 플래그를 끄면 된다.
데이터베이스 변경은 특히 조심해야 한다. 애플리케이션 코드는 롤백할 수 있어도 데이터 구조 변경은 쉽게 되돌릴 수 없다. 안전한 마이그레이션은 대개 두 단계 이상으로 나눈다. 먼저 새 컬럼이나 테이블을 추가하고, 기존 코드와 새 코드가 함께 동작하게 만든 뒤, 데이터가 충분히 채워지고 검증되면 오래된 구조를 제거한다. 서두른 스키마 변경은 한 번의 배포를 전체 서비스 사고로 바꾼다.
배포를 잘하는 팀은 "성공했는가?"만 보지 않는다. 배포 직후 오류율, 지연 시간, 트래픽, 주요 전환율, 결제 성공률, 고객 문의 증가, 특정 테넌트 장애 여부를 함께 본다. 배포는 버튼을 누르는 행위가 아니라, 위험을 감지하고 되돌릴 수 있는 운영 절차다.
관측 가능성은 운영팀의 도구가 아니라 제품 신뢰도의 감각기관이다
서비스가 아프면 어디가 아픈지 알아야 한다. 그런데 많은 팀은 사용자가 고객센터에 문의하기 전까지 서비스가 아픈지 모른다. 이것은 매우 위험한 상태다. 고객이 먼저 장애를 발견하는 서비스는 이미 신뢰를 잃고 있다.
관측 가능성은 시스템 바깥으로 드러나는 신호를 통해 내부 상태를 이해하는 능력이다. 대표적인 신호는 로그, 메트릭, 트레이스다. 로그는 사건의 기록이다. "누가, 언제, 어떤 요청을 했고, 어떤 오류가 났는가"를 남긴다. 메트릭은 숫자의 흐름이다. CPU 사용률, 요청 수, 오류율, 응답 시간, 큐 길이처럼 시간에 따라 변하는 값을 본다. 트레이스는 하나의 요청이 여러 서비스를 지나가는 경로를 추적한다. 마이크로서비스나 복잡한 API 구조에서는 트레이스가 없으면 병목을 찾기 어렵다.
관측 가능성의 목표는 데이터를 많이 모으는 것이 아니다. 질문에 답할 수 있게 만드는 것이다.
"방금 배포 이후 오류가 늘었는가?"
"특정 고객사만 느린가, 전체 사용자가 느린가?"
"로그인은 정상인데 결제만 실패하는가?"
"응답 지연의 원인은 애플리케이션인가, 데이터베이스인가, 외부 API인가?"
"SLO를 위반하기 전에 알 수 있는 전조가 있는가?"
SLO는 Service Level Objective의 약자로, 서비스가 달성해야 하는 목표 수준이다. 예를 들어 "주요 API 요청의 99%는 300ms 이내에 응답한다" 또는 "월간 결제 성공 API 가용성은 99.9% 이상이다"처럼 정의한다. SLI는 Service Level Indicator로, 그 목표를 측정하는 지표다. SLA는 Service Level Agreement로, 고객과 계약상 약속한 수준이다. SLO는 내부 운영 목표이고, SLA는 외부 약속에 가깝다.
SRE, 즉 사이트 신뢰성 엔지니어링은 이런 사고방식을 체계화한 접근이다. SRE는 실패를 비정상으로 숨기는 대신, SLI와 SLO를 합의하고, 오류 예산을 관리하며, 반복적인 수작업을 자동화하는 방식으로 신뢰성과 변화 속도의 균형을 잡는다3. 오류 예산은 허용 가능한 실패의 범위다. 예를 들어 한 달 가용성 목표가 99.9%라면, 남은 0.1% 안에서 어느 정도의 장애나 실험을 감당할 수 있는지 판단한다. 오류 예산을 초과하면 새 기능 출시보다 안정화가 우선이다.
좋은 대시보드는 화려하지 않아도 된다. 오히려 너무 많은 그래프는 사람을 마비시킨다. 핵심은 고객 경험과 연결된 신호를 보는 것이다. 업타임, 지연 시간, 오류율, 처리량, 리소스 사용률은 기본이다. 여기에 로그인 성공률, 결제 성공률, 검색 결과 없음 비율, 온보딩 완료율, 알림 발송 지연, 고객사별 장애 현황처럼 제품 지표를 연결해야 한다.
관측 가능성은 이제 선택적 운영 기능이 아니라 미션 크리티컬한 비즈니스 기능으로 이동하고 있다. 2026년 관측 가능성 트렌드 조사에서도 조직들이 관측 가능성을 성숙한 핵심 기능으로 발전시키는 동시에, 비용 정당화와 비즈니스 영향 보고를 더 강하게 요구받고 있음을 보여준다4. 즉, 이제는 "모니터링 툴을 샀다"가 아니라 "이 데이터가 장애를 줄이고, 고객 경험을 지키고, 비용을 통제하는가?"를 증명해야 한다.
빠른데 비싼 시스템도 실패이고, 싼데 불안정한 시스템도 실패다
엔지니어는 빠른 시스템을 좋아한다. 경영진은 저렴한 시스템을 좋아한다. 고객은 안정적인 시스템을 좋아한다. 모바일 사용자는 배터리를 덜 쓰는 시스템을 좋아한다. 보안팀은 안전한 시스템을 좋아한다. 문제는 이 모든 요구가 동시에 온다는 점이다.
최고의 아키텍처는 하나의 지표만 극단적으로 최적화하지 않는다. 성능, 비용, 전력, 신뢰성, 개발 속도, 보안, 운영 난이도 사이의 균형을 잡는다. 컴퓨터 아키텍처 연구 영역에서도 성능과 확장성뿐 아니라 데이터센터와 모바일 플랫폼을 포괄하는 전체적 접근이 중요하게 다뤄지고5, 하드웨어와 소프트웨어 구현의 도전 과제로 성능, 전력, 비용, 신뢰성이 함께 언급된다6. 서비스 아키텍처도 마찬가지다. 빠르기만 한 시스템은 오래가지 못하고, 싸기만 한 시스템은 신뢰를 잃기 쉽다.
모든 요청을 최고 사양 서버에서 처리하면 빠를 수 있다. 하지만 고객 한 명을 처리하는 비용이 매출보다 높다면 비즈니스는 망한다. 반대로 비용을 아끼려고 최소 사양 서버만 쓰면 평소에는 괜찮다가 이벤트나 월말 정산 때 무너진다. 결국 봐야 할 지표는 단순 CPU 사용률이 아니다. 사용자 요청 한 건당 비용, 고객사별 인프라 비용, 기능별 처리 비용, p95·p99 지연 시간, 장애 시 손실 비용, 관측 데이터 저장 비용까지 함께 봐야 한다.
p95 지연 시간은 요청 100개 중 95번째로 느린 요청의 응답 시간을 뜻한다. 평균 응답 시간이 100ms라 해도 일부 사용자가 5초씩 기다린다면 경험은 나쁘다. p99는 더 극단적인 꼬리 지연을 보여준다. 실제 서비스에서는 평균보다 꼬리가 중요하다. VIP 고객, 대형 고객사, 결제 직전 사용자, 모바일 네트워크가 불안정한 사용자에게 느린 경험이 집중될 수 있기 때문이다.
비용 효율적인 아키텍처는 무조건 적게 쓰는 구조가 아니다. 필요한 곳에는 충분히 쓰고, 필요 없는 곳에서는 자동으로 줄이는 구조다. 오토스케일링은 트래픽이나 리소스 사용량에 따라 인스턴스를 늘리고 줄인다. 서버리스는 특정 작업이 실행될 때만 비용을 내는 방식으로 유용할 수 있다. 다만 오토스케일링도 마법은 아니다. 애플리케이션이 상태를 서버에 묶어두거나, 데이터베이스가 이미 병목이거나, 시작 시간이 너무 느리면 기대만큼 효과가 없다.
비용도 관측해야 한다. 어느 서비스가 비용을 많이 쓰는지, 어느 고객사가 과도한 리소스를 사용하는지, 어떤 로그가 저장 비용을 폭발시키는지, 야간 배치가 필요한 만큼만 확장되는지 봐야 한다. 비용을 보지 않는 아키텍처는 결국 성장할수록 돈을 태우는 기계가 된다.
보이지 않는 의존성이 서비스를 무너뜨린다
IT 서비스는 혼자 존재하지 않는다. 결제 게이트웨이, 이메일 발송 서비스, 문자 메시지, 지도 API, 인증 제공자, 클라우드 스토리지, 검색 엔진, CRM, 회계 시스템, 데이터 웨어하우스, AI 모델 API와 연결된다. 이 외부 의존성은 빠른 출시를 가능하게 하지만, 동시에 서비스 신뢰성의 일부가 된다.
가장 위험한 의존성은 문서화되지 않은 의존성이다. 개발자 한 명만 알고 있는 배치, 특정 클라우드 리전에만 있는 리소스, 실패하면 대체 경로가 없는 외부 API, 장애 알림이 없는 웹훅, 만료일을 아무도 모르는 인증서가 그렇다.
의존성을 설계할 때는 세 가지를 확인해야 한다. 첫째, 이 의존성이 실패하면 고객에게 어떤 일이 생기는가. 둘째, 실패를 얼마나 빨리 알 수 있는가. 셋째, 실패했을 때 대체 경로가 있는가.
예를 들어 이메일 발송 서비스가 장애라면 비밀번호 재설정, 회원가입 인증, 결제 영수증, 보안 알림이 모두 영향을 받을 수 있다. 이메일이 단순 마케팅 채널처럼 보이지만 실제로는 인증과 신뢰의 핵심 경로일 수 있다. 이 경우 발송 실패를 큐에 보관하고 재시도하며, 중요한 알림은 문자나 앱 푸시로 대체하는 전략을 마련해야 한다.
외부 API 호출에는 반드시 타임아웃을 둬야 한다. 상대 서비스가 응답하지 않는데 우리 서버가 계속 기다리면 스레드나 커넥션 풀이 고갈되어 우리 서비스까지 멈춘다. 이것이 연쇄 장애다. 한 서비스의 작은 지연이 전체 장애로 번지는 순간, 사용자는 어떤 회사의 책임인지 구분하지 않는다. 그냥 우리 서비스를 믿지 않게 된다.
기술 부채는 없애는 것이 아니라 관리하는 것이다
기술 부채라는 말은 자주 오해된다. 많은 사람이 기술 부채를 "나쁜 코드"와 같은 뜻으로 쓴다. 하지만 더 정확히 말하면 기술 부채는 미래의 비용을 감수하고 현재의 속도를 얻는 선택이다. 창업 초기, 실험 단계, 시장 검증 단계에서는 어느 정도의 부채가 필요하다. 모든 것을 완벽하게 설계하다가 고객을 만나기도 전에 시간이 끝날 수 있다.
문제는 부채 자체가 아니라 상환 계획 없는 부채다. 신용카드로 필요한 장비를 사는 것은 전략일 수 있지만, 청구서를 보지 않는 것은 파산의 시작이다. 기술 부채도 마찬가지다. 빠른 출시를 위해 감수한 임시 구조, 하드코딩, 수동 운영, 단일 장애 지점, 부족한 테스트, 미흡한 권한 모델은 반드시 기록되어야 한다.
기술 부채 목록에는 적어도 다음 정보가 있어야 한다.
어떤 결정을 왜 임시로 했는가
이 부채가 어떤 위험을 만들 수 있는가
어느 지표나 사건이 발생하면 갚아야 하는가
갚는 데 필요한 대략적 비용은 얼마인가
책임자는 누구인가
예를 들어 "현재 리포트 생성은 웹 서버에서 동기 처리한다. 고객사 50개 또는 리포트 생성 시간이 p95 기준 5초를 넘으면 비동기 큐와 워커로 분리한다"라고 기록할 수 있다. 이렇게 쓰면 부채는 막연한 불안이 아니라 관리 가능한 선택이 된다.
부채를 갚아야 하는 신호는 분명하다. 배포가 무서워지고, 장애 복구가 오래 걸리고, 고객사 하나가 전체 성능에 영향을 주고, 보안 요구사항을 맞추기 어렵고, 새 기능 개발 속도가 계속 느려지고, 온보딩한 개발자가 구조를 이해하지 못하고, 운영팀이 매일 같은 수작업을 반복한다면 이제 이자를 내고 있는 것이다.
이때 필요한 것은 전면 재작성이라는 유혹을 조심하는 것이다. 전체를 새로 만들자는 말은 달콤하지만 위험하다. 대부분의 서비스는 멈출 수 없고, 기존 고객은 계속 사용해야 하며, 새 시스템은 기존 시스템의 복잡한 예외를 다시 배워야 한다. 더 현실적인 방법은 병목이 큰 영역부터 점진적으로 분리하는 것이다. 오래된 시스템 옆에 새 모듈을 붙이고, 트래픽을 조금씩 이동시키고, 검증된 뒤 낡은 부분을 제거한다. 아키텍처 전환은 수술이지 폭파가 아니다.
성장 단계별 아키텍처 설계도
이제 실제로 어떻게 시작하면 좋을까. 모든 서비스에 맞는 정답은 없지만, 성장 단계별로 적절한 구조는 있다.
초기 검증 단계에서는 단순성이 가장 중요하다. 하나의 애플리케이션, 하나의 주요 데이터베이스, 관리형 클라우드 서비스, 기본 모니터링으로 시작해도 된다. 대신 코드 내부의 도메인 경계, 테넌트 ID, 권한 모델, API 계약, 배포 자동화, 기본 로그 구조는 챙겨야 한다. 이 시기의 목표는 완벽한 확장이 아니라 빠른 학습이다.
초기 성장 단계에서는 병목을 분리하기 시작한다. 정적 파일은 CDN으로 보내고, 자주 읽는 데이터는 캐싱하고, 이메일·알림·리포트 생성 같은 작업은 큐로 분리한다. 읽기 부하가 커지면 리플리카를 붙이고, 배포는 카나리나 기능 플래그를 활용한다. SLO를 정의하고 대시보드를 고객 여정 중심으로 정리한다.
본격 확장 단계에서는 독립 배포 가능한 서비스나 플랫폼화가 필요해진다. 결제, 인증, 알림, 검색, 권한, 파일 처리, 데이터 파이프라인처럼 변화 속도와 부하 특성이 다른 영역을 분리한다. 테넌트별 사용량 제한, 고객별 성능 격리, 감사 로그, 데이터 보존 정책, 비용 배부, 장애 대응 훈련을 운영 체계에 포함한다.
엔터프라이즈 단계에서는 아키텍처가 조직 구조와 연결된다. 서비스별 책임 팀, 온콜 체계, 변경 승인 기준, 보안 검토, 재해 복구 훈련, 비용 거버넌스, 데이터 거버넌스, 내부 플랫폼 팀이 필요해진다. 이때 기술 아키텍처는 더 이상 개발팀만의 일이 아니다. 영업이 약속한 SLA, 법무가 검토한 규정, 고객지원의 대응 시간, 재무의 비용 목표, 경영진의 성장 전략이 모두 구조 안으로 들어온다.
최고의 서비스는 조용히 회복한다
사용자는 아키텍처를 칭찬하지 않는다. "오늘 로드 밸런싱이 참 좋네요"라고 말하는 고객은 없다. 하지만 사용자는 아키텍처를 느낀다. 화면이 즉시 뜰 때, 결제가 한 번에 끝날 때, 장애가 나도 데이터가 사라지지 않을 때, 새 기능이 자연스럽게 열릴 때, 문제가 생기기 전에 안내가 올 때, 고객은 말없이 신뢰를 쌓는다.
최고의 기술 아키텍처는 영웅을 필요로 하지 않는다. 새벽마다 한 명의 천재 개발자가 서버에 접속해 불을 끄는 구조는 멋진 이야기가 아니라 위험한 조직 신호다. 좋은 시스템은 실패를 예상하고, 실패를 작게 만들고, 실패를 빨리 발견하고, 실패에서 배운다.
이 장의 핵심을 한 문장으로 정리하면 이렇다.
성공한 서비스는 장애가 없어서 신뢰받는 것이 아니라, 장애가 나도 고객의 세계가 무너지지 않게 설계되어 있기 때문에 신뢰받는다.
이제 당신의 서비스 아키텍처를 다시 보자. 가장 중요한 고객 여정은 무엇인가. 그 여정의 병목은 어디인가. 어떤 구성요소가 실패하면 전체가 멈추는가. 어떤 데이터는 절대 잃으면 안 되는가. 배포 후 문제가 생기면 몇 분 안에 알 수 있는가. 롤백은 실제로 가능한가. 비용은 성장과 함께 예측 가능한가. 기술 부채는 기록되어 있는가.
이 질문들에 정직하게 답하는 순간, 아키텍처는 복잡한 기술 도표가 아니라 최고의 IT 서비스를 지키는 방어선이 된다. 그리고 다음 장에서 다룰 보안과 컴플라이언스는 이 방어선의 바깥 장식이 아니라, 처음부터 함께 세워야 할 기둥이라는 사실을 더 분명히 보게 될 것이다.
참고
1Microsoft Azure Well-Architected Framework Reliability design principles
2Scalable Software as a Service Architecture
3Capgemini Site reliability engineering 101
4Elastic Observability trends for 2026
이 노트는 보도·비평·교육·연구 목적으로 작성되었습니다. 저작권 문의가 있으시면 에서 알려주세요.