15장, 공간 기반 아키텍처 스타일

2022.07.25

웹 기반 비지니스 애플리케이션은 대부분 일반적인 요청 흐름을 따라간다. 브라우저에서 요청을 보내면 웹 서버, 애플리케이션 서버, 데이터베이스 서버 순서로 도달한다. 이런 패턴은 유저가 많지 않으면 별 문제없지만 유저 수가 늘어나면 점점 병목 현상이 나타나기 시작한다. 처음에는 웹 서버 레이어에서 발생하다가 나중에는 애플리케이션, 데이터베이스 서버 레이어에서도 나타난다. 병목 현상의 가장 일반적인 해결 방법은 웹 서버 확장이다. 이 방법은 비교적 쉽고 저렴하며 효과적이지만, 유저 부하가 높을 때 웹 서버 레이어를 확장하면 병목점은 다시 애플리케이션 서버로, 데이터베이스 서버로 병목점이 이동한다.

동시 유저 부하가 많은 대용량 애플리케이션은 데이터베이스의 동시 처리 가능한 트랜잭션 수가 최종 제약조건이 되는 경우가 많다. 다양한 캐시 기술과 데이터베이스 확장 제품으로 문제를 해결할 수는 있지만, 부하가 엄청나게 밀려 들어오는 상황에서 여느 애플리케이션을 확장하는 작업은 결코 만만치 않다.


( 기존 웹 기반 토폴로지는 확장하기가 어렵다. )

공간 기반 아키텍처 스타일은 높은 확장성, 탄력성, 동시성 및 이와 관련된 문제를 해결하기 위해 설계된 아키텍처 스타일이다. 동시 유저 수가 매우 가변적이라서 예측조차 곤란한 애플리케이션에서도 유용하다. 극단적이고 가변적인 확장성 문제는 데이터베이스를 확장하거나, 확장성이 떨어지는 아키텍처에 맞게 캐시 기술을 적용하는 것보다 아키텍처적으로 해결하는 것이 더 낫다.

15.1 토폴로지

공간 기반 아키텍처라는 명칭은 튜플 공간(tuple space)에서 유래되었다. 튜플 공간은 공유 메모리를 통해 통신하는 다중 병렬 프로세서를 사용하는 기술이다. 시스템에서 동기 제약조건인 중앙 데이터베이스를 없애는 대신, 복제된 인메모리 데이터 그리드(in-memory data grid)를 활용하면 확장성, 탄력성, 성능을 높일 수 있다. 애플리케이션 데이터는 메모리에 둔 상태로 모든 활성 처리 장치들이 데이터를 복제한다.

공간 기반 아키텍처는 애플리케이션 코드가 구현된 처리 장치(processing unit), 처리 장치를 관리/조정하는 가상 미들웨어(virtualized middleware), 업데이트된 데이터를 데이터베이스에 비동기 전송하는 데이터 펌프(data pump), 데이터 펌프에서 데이터를 받아 업데이트를 수행하는 데이터 라이터(data writer), 처리 장치가 시작되자마자 데이터베이스의 데이터를 읽어 전달하는 데이터 리더(data reader) 컴포넌트로 구성된다.


15.1.1 처리 장치

처리 장치는 애플리케이션 로직(또는 로직의 일부분)을 갖고 있다. 보통 웹 기반 컴포넌트와 벡엔드 비지니스 로직이 포함되나 애플리케이션 종류마다 내용물은 달라진다. 작은 웹 기반 애플리케이션은 단일 처리 장치에 배포할 수 있지만, 대규모 애플리케이션은 기능별로 여러 처리 장치에 나누어 배포해야 한다.


15.1.2 가상 미들웨어

가상 미들웨어는 아키텍처 내부에서 데이터 동기화 및 요청 처리의 다양한 부분을 제어하는 인프라를 담당한다. 가상 미들웨어는 메시징 그리드(messaging grid), 데이터 그리드(data grid), 처리 그리드(processing grid), 배포 관리자(deployment manager) 등의 컴포넌트로 구성된다.

메시징 그리드

메시징 그리드(messaging grid)는 입력 요청과 세션 상태를 관리한다. 가상 미들웨어에 요청이 유입되면 메시징 그리드는 어느 활성 장치가 요청을 받아 처리할지 결정하여 해당 처리 장치로 요청을 전달한다. 이 컴포넌트는 보통 부하 분산이 가능한 일반 웹서버(예: HA 프록시, 엔진엑스)로 구현한다.


데이터 그리드

데이터 그리드(data grid)는 이 아키텍처 스타일에서 중요하고 필수적인 컴포넌트이다. 요즘은 데이터 그리드가 거의 대부분 복제 캐시로서 처리 장치에만 구현되어 있지만, 외부 컨트롤러가 필요한 복제 캐시 구현체나 분산 캐시를 사용할 경우, 데이터 그리드는 가상 미들웨어 내부의 데이터 그리드 컴포넌트와 처리 장치 모두에 위치한다. 아래 그림은 처리 장치 간 동기식 데이터 복제 흐름을 나타낸 것이다. 실제로 데이터 동기화는 비동기 방식으로 매우 신속하게, 대개 100밀리초 미만으로 이루어진다.


처리 그리드

처리 그리드(processing grid)는 가상 미들웨어에서 필수 컴포넌트는 아니지만, 다수의 처리 장치가 단일 비지니스 요청을 처리할 경우 요청 처리를 오케스트레이트하는 일을 한다. 또 종류가 다른 처리 장치 사이에 조정이 필요한 요청이 들어오면 처리 그리드가 두 처리 장치 사이에서 요청을 중재/조정한다.


배포 관리자

배포 관리자(deployment manager)는 부하 조건에 따라 처리 장치 인스턴스를 동적으로 시작/종료하는 컴포넌트이다. 응답 시간, 유저 부하를 계속 모니터링하다가 부하가 증가하면 새로운 처리 장치를 기동하고 반대로 감소하면 기존 처리 장치를 종료한다. 애플리케이션에서 다양한 확장성(탄력성) 요구사항을 구현하는 데 꼭 필요한 컴포넌트이다.

15.1.3 데이터 펌프

데이터 펌프(data pump)는 데이터를 다른 프로세서에 보내 데이터베이스를 업데이트하는 장치이다. 공간 기반 아키텍처에서는 처리 장치가 데이터를 데이터베이스에 직접 읽고 쓰지 않으므로 데이터 펌프는 반드시 필요하다. 또 데이터 펌프는 항상 비동기로 동작하면서 메모리 캐시와 데이터베이스의 최종 일관성을 실현한다. 처리 장치 인스턴스가 요청을 받고 캐시를 업데이트하면 처리 장치가 그 업데이트의 소유자가 되므로 데이터베이스 역시 데이터 펌프를 통해 최종 일관적으로 업데이트되도록 업데이트를 전송해야 합니다.


위 그림에서 보다시피 데이터 펌프는 대개 메시징 기법으로 구현한다. 공간 기반 아키텍처에서 메시징은 데이터 펌프를 구현하는 효과적인 방법이다. 메시징은 비동기 통신을 지원하고 전달을 보장하며 FIFO(선입 선출) 큐를 통해 메시지 순서도 유지한다. 또 메시징을 이용하면 처리 장치와 데이터 라이터를 분리할 수 있기 때문에 데이터 라이터를 사용할 수 없는 경우에도 처리 장치에서 무중단 처리가 가능하다.

15.1.4 데이터 라이터

데이터 라이터(data writer)는 데이터 펌프에서 메시지를 받아 그에 맞게 데이터베이스를 업데이트하는 컴포넌트이다. 데이터 라이터는 서비스나 애플리케이션, 데이터 허브로 구현할 수 있다. 데이터 라이터의 세분도는 데이터 펌프와 처리 장치의 범위마다 다르다.


도메인 기반의 데이터 라이터는 데이터 펌프 수와 무관하게 특정 도메인의 전체 업데이트를 처리하는 데 필요한 모든 데이터베이스 로직을 갖고 있다. 위의 그림을 보면 고객 도메인을 처리 장치 4개와 데이터 펌프4개로 처리하지만 데이터 라이터는 하나 밖에 없다.


위 그림처럼 처리 장치 클래스마다 자체 전용 데이터 라이터를 두는 경우도 있다. 각 데이터 라이터가 자신의 전용 데이터 펌프를 소유하고 해당 처리 장치의 데이터베이스 로직을 처리한다. 이 모델은 데이터 라이터가 너무 많은 단점이 있지만, 처리 장치, 데이터 펌프, 데이터 라이터가 나란히 정렬되어 확장성, 민첩성은 더 좋다.

15.1.5 데이터 리더

데이터 라이터가 데이터베이스 업데이트를 담당한다면 데이터 리더(data reader)는 데이터베이스에서 데이터를 읽어 리버스 데이터 펌프를 통해 처리 장치로 실어 나르는 컴포넌트이다. 공간 기반 아키텍처에서 데이터 리더는 세 가지 경우에만 작동된다.

  1. 동일한 이름의 캐시를 가진 모든 처리 장치 인스턴스가 실패하는 경우.
  2. 동일한 이름의 캐시 안에서 모든 처리 장치를 재배포하는 경우.
  3. 복제 캐시에 들어있지 않은 아카이브 데이터를 조회하는 경우.

데이터 리더도 데이터 라이터처럼 도메인 기반으로 할 수 있지만 특정 처리 장치의 클래스 전용으로 사용하는 게 보통이다. 서비스, 애플리케이션, 데이터 허브 모두 구현체는 데이터 라이터와 동일하다.

데이터 라이터와 데이터 리더는 본질적으로 데이터 추상 레이어(data abstraction layer)를 형성한다. 두 레이어의 차이점은 처리 장치가 데이터베이스의 테이블(또는 스키마) 구조를 얼마나 자세히 알고 있는가, 이다. 일반적으로 공간 기반 아키텍처는 데이터 추상 레이어 모델에 기반하므로 처리 장치마다 복제 캐시 스키마는 하부 데이터베이스의 테이블 구조와 다를 수 있고, 따라서 처리 장치에 영향을 미치지 않고서도 데이터베이스 증분 변경이 가능하며, 데이터 리더/라이터에 이미 변환 로직이 포함되어 있기 때문에 이런 증분 변경이 더 용이하다.

15.2 데이터 충돌

데이터 충돌은 한 캐시(캐시 A) 인스턴스에서 데이터가 업데이트되어 다른 캐시 인스턴스에 복제하는 도중에 동일한 데이터가 해당 캐시(캐시 B)에서 업데이트 되는 현상을 말한다. 결국, 캐시 B의 로컬 업데이트는 캐시 A에서 복제된 옛 데이터 때문에 덮어씌워지고, 반대로 캐시 A에서는 동일한 데이터가 캐시 B에서 발생한 업데이트 때문에 덮어씌워지는 불상사가 일어난다.

데이터 충돌 발생 빈도는 동일한 캐시를 포함한 처리 장치 인스턴스 수, 캐시 업데이트율, 캐시 크기, 캐시 제품의 복제 레이턴시 등 여러 팩터가 영향을 미친다. 데이터 충동률을 수학적으로 계산하는 공식은 다음과 같다.

충동률 = 서비스 인스턴스 수 * 업데이트율² / 캐시 크기 * 캐시 제품의 복제 대기 시간

예를 들어, 이 공식의 인잣값이 다음과 같이 주어졌다고 해보자.

  • 업데이트율 : 20 업데이트/초
  • 인스턴스 수 : 5
  • 캐시 크기 : 50,000로우
  • 복제 레이턴시 : 100밀리초
  • 업데이트 : 시간당 72,000
  • 충동률 : 14.4
  • 비율 : 0.02%

공식에 대입하여 계산해보면 업데이트는 시간 당 72,000개 발생하고 동일한 데이터에 대해 14개 업데이트가 충돌할 가능성이 높다. 비율(0.02%)이 낮은 편이므로 복제 캐시는 나쁘지 않은 선택이다.

대부분의 시스템은 정상적인 경우에 이렇게 오래 꾸준히 업데이트를 하지 않는다. 따라서 충동률을 계산할 때는 사용량이 가장 많은 시점의 최대 업데이트율에 따라 최소, 정상, 최대 충동률을 산출하는 것이 바람직하다.

15.3 클라우드 대 온프레미스 구현

공간 기반 아키텍처는 배포 환경 측면에서 독자적인 선택지가 있다. 전체 토폴로지는 클라우드 기반의 환경이나 온프레미스에 배포할 수 있다. 하지만 이 두 환경 사이에 어중간하게 배포할 수도 있는데, 이것이 다른 아키텍처 스타일에서는 찾아볼 수 없는 이 아키텍처의 특징이다.


물리 데이터베이스와 데이터를 온프레미스에 그대로 둔 상태로, 클라우드 기반의 매니지 환경에서 처리 장치와 가상 미들위에럴 통해 애플리케이션을 배포하는 하이브리드 클라우드가 가능하다는 것이 공간 기반 아키텍처의 장점이다.

15.4 복제 캐시 대 분산 캐시

공간 기반 아키텍처는 캐시 기술을 활용하여 애플리케이션 트랜잭션을 처리하고 데이터베이스에 직접 읽기/쓰기를 할 필요가 없어서 확장성, 탄력성 성능이 우수하다. 대부분의 공간 기반 아키텍처는 복제 캐시를 사용하지만 분산 캐시도 사용할 수도 있다.


복제 캐시는 공간 기반 아키텍처의 표준 캐시 모델이지만, 데이터량(캐시 크기)이 엄청나게 많거나 캐시 데이터가 너무 빈번하게 업데이트되는 등 복제 캐시를 사용할 수 없는 경우도 있다. 실제 내부 메모리 캐시가 100MB를 초과하면 각 처리 장치마다 메모리를 점유하기 때문에 탄력성, 확장성에 문제가 발생할 수 있다. 캐시 데이터 업데이트율이 매우 높은 경우에는 모든 처리 장치 인스턴스에서 데이터 일관성이 보장되도록 업데이트도 신속하게 이루어져야 하지만 데이터 그리드가 미처 이 속도를 따라잡지 못할 수도 있다.


위와 같이 분산 캐시를 구현하려면 중앙 캐시를 갖고 있는 전용 외부 서버 또는 서비스가 필요하다. 처리 장치는 데이터를 내부 메모리에 저장하는 대신, 전용 프로토콜을 통해 중앙 캐시 서버에 있는 데이터를 액세스한다. 모든 데이터가 한 곳에 있고 복제할 필요가 없으니 분산 캐시는 높은 수준의 데이터 일관성을 보장하지만, 캐시 데이터를 원격에서 가져와야 하므로 복제 캐시보다 성능이 낮고 시스템 전체 레이턴시가 증가한다.

결정 기준복제 캐시분산 캐시
최적화성능일관성
캐시 크기작다(100MB)크다(>500MB)
데이터 유형교적 정적임매우 동적임
업데이트 빈도비교적 낮음매우 높음
내고장성좋음나쁨

애플리케이션 전체적으로 일관된 단일 캐시 모델을 통해 타협점을 모색하되 각 모델의 장점을 최대한 활용해야 한다. 예를 들어, 현재 재고를 관리하는 처리 장치는 데이터 일관성을 위해 분산 캐시를, 고객 프로필을 유지하는 처리 장치는 성능, 내고장성을 우선시하여 복제 캐시를 선택한다.

15.5 니어 캐시

니어 캐시(near-cache, 준캐시)는 분산 캐시와 인모메로 데이터 그리드를 접합한 일종의 하이브리드 캐시 모델이다.


이 모델에서 분산 캐시는 풀 백킹 캐시(full backing cache), 각 처리 장치에 포함된 인메모리 데이터 그리드는 프런트 캐시(front cache)라고 한다. 프런트 캐시는 항상 풀 백킹 캐시보다 작은 서브세트를 담고 있고, 방출 정책을 통해 옜 항목을 삭제한 다음 최근 항목을 추가한다. 프런트 캐시는 갖아 최근에 사용한 항목이 포함된 MRU(Most Recently Used) 캐시 또는 가장 자주 사용한 항목이 포함되는 MFU(Most Frequently Used) 캐시로 사용한다. 새 항목을 추가할 공간이 필요할 때마다 무작위로 항목을 삭제하는 랜덤 교체도 프런트 캐시에 적용 가능한 방출 정책이다. 랜덤 교체는 가장 최근에 사용된 데이터와 가장 자주 사용된 데이터를 확실하게 분석할 수 없을 경우에 유용한 정책이다.

프런트 캐시는 항상 풀 백킹 캐시와 동기화되지만 각 처리 장치에 포함된 프런트 캐시는 동일한 데이터를 공유하는 다른 처리 장치와 동기화되지 않는다. 즉, 동일한 데이터 콘텍스트(예: 고객 프로필)를 공유하는 여러 처리 장치가 동일하지 않은 데이터를 각자의 프런트 캐시에 소유하게 될 수도 있다. 처리 장치마다 상이한 데이터를 프런트 캐시에 각게되고 처리 장치 간 성능과 응답성의 일관성이 결여된다. 따라서 우리는 공간 기반 아키텍처에서 니어 캐시 모델을 권장하지 않는다.

15.6 구현 예시

15.6.1 콘서트 티켓 판매 시스템

콘서트 티켓 판매 시스템은 평소에는 비교적 동시 유저 수가 적게 유지되닥 ㅏ인기 있는 콘서트의 티켓 발매가 시작되면 티켓을 사려는 동시 유저 수가 수백~수천단위로 급증하는 패턴을 보인다. 이러한 경우 공간 기반 아키텍처에서 지원되는 아키텍처 특성이 필요하다.

이런 부류의 시스템은 풀어야 할 난제가 한두가지가 아니다. 엄청난 동시 요청 수를 감당하려면 좌석 가능 여부가 가능한 한 신속하게, 지속적으로 업데이트돼야 한다. 시스템이 계속 중앙 데이터베이스에 동기적으로 액세스하면 머지않아 작동이 멎게 될 가능성이 높다. 일반적인 데이터베이스가 이 정도로 표준 트랜잭션을 수만개나 동시 처리하기는 매우 어렵다.

공간 기반 아키텍처는 이런 애플리케이션에서 꼭 필요한 고도의 탄력성을 제공하므로 콘서트 티켓 판매 시스템에 안성맞춤이다. 콘서트 티켓을 구매하는 동시 유저 수가 순간적으로 치솟으면 배포 관리자는 이 사실을 바로 인지하여 대량 요청을 감당할 수 있도록 다수의 처리 장치를 기동한다.

15.6.2 온라인 경매 시스템

온라인 경매 시스템도 고도의 성능과 탄력성이 필요하고, 유저 및 요청 부하가 예기치 않게 폭증하는 특징이 있다. 경매가 시작되면 얼마나 많은 사람들이 경매에 참여할지, 그리고 호가할 때마다 그들 중 동시 입찰자는 몇명이나 될지 미리 예측할 도리가 없다.

따라서 부하가 증가하면 처리 장치를 여럿 기동할 수 있는 공간 기반 아키텍처는 이런 종류의 문제 영역에 적합하다. 경매가 끝나면 사용하지 않은 처리 장치는 삭제하면 되고, 각 처리 장치를 각 경매마다 할당하면 입찰 데이터의 일관성도 보장할 수 있다. 또 데이터 펌프는 원래 비동기로 작동되므로 입찰 데이터를 긴 레이턴시 없이 다른 처리 장치(예: 입찰 이력, 입찰 분석, 감사)로 보낼 수 있다.

15.7 아키텍처 특성 등급

아키텍처 특성별점
분할 유형도메인+기술
퀀텀 수하나 또는 여러개
배포성⭐⭐⭐
탄력성⭐⭐⭐⭐⭐
진화성⭐⭐⭐
내고장성⭐⭐⭐
모듈성⭐⭐⭐
전체 비용⭐⭐
성능⭐⭐⭐⭐⭐
신뢰성⭐⭐⭐⭐
확장성⭐⭐⭐⭐⭐
단순성
시험성