앱 및 API 확장을 위한 애플리케이션 제공 패턴

오늘날 앱과 API를 확장하는 데 있어 핵심은 적절한 부하 분산 알고리즘을 선택하는 것이 아닙니다. 20년이 넘는 애플리케이션 딜리버리 기술의 발전 과정에서 비교적 변함없이 유지되어 온 것은 부하 분산 알고리즘입니다. 이러한 알고리즘의 주된 이점은 가용성을 유지하는 데 있으며, 성능에 미치는 영향은 아무리 크게 보아도 미미합니다.

그렇다고 해서 알고리즘 선택이 중요하지 않다는 뜻은 아닙니다. 결국 라운드 로빈은 API나 애플리케이션에 가장 적합한 선택인 경우가 드물지만, 최소 연결과 최고 응답 속도 중 무엇을 선택하느냐는 디지털 서비스의 아키텍처보다 전반적인 성능과 가용성에 미치는 영향이 적습니다. 

여기서는 디지털 서비스를 설계하고 운영하는 데 필요한 6가지 핵심 역량 중 하나로 앱 딜리버리의 중요성이 격상된 데 따라, 앱 딜리버리를 아키텍처 관점에서 살펴보겠습니다. 

로드 밸런싱 알고리즘이란 무엇인가요?

로드 밸런싱 알고리즘은 가용성을 보장하고 성능을 향상하기 위해 리소스 풀 전체에 부하를 분산하는 프로그래밍 방식입니다.

부하 분산 알고리즘은 특정 리소스를 선택하는 방식과 고려할 변수를 정의합니다.

라운드 로빈은 가장 간단한 알고리즘으로, 알려진 리소스 집합을 순서대로 순회합니다. 리소스가 A, B, C 세 개라면 라운드 로빈은 첫 번째 요청을 A로, 두 번째 요청을 B로, 세 번째 요청을 C로 라우팅합니다. 그런 다음 선택 과정이 처음부터 다시 시작됩니다.

최소 연결은 ‘부하가 증가하면 성능이 저하된다’는 두 번째 운영 원칙에 기반한 알고리즘입니다. 따라서 최소 연결 알고리즘은 연결 수(부하)가 가장 적은 리소스를 선택합니다. 이 알고리즘에는 여러 변형이 있으며, 그중 대표적인 것이 가중 최소 연결로, 리소스별 용량 차이를 고려할 수 있습니다.

최단 응답 시간은 성능이 최우선일 때 사용됩니다. 로드 밸런서는 수동 또는 능동 방식으로 각 리소스의 응답 시간을 파악하고, 요청이 들어올 때마다 가장 빠른 리소스를 선택합니다. 이 알고리즘은 라스트 마일이나 사용자 네트워크 환경에는 영향을 미치지 않으므로 사용자 응답 시간을 보장하지 않습니다.

소스 IP는 네트워크 부하 분산에서 유래한 알고리즘으로, 소스(클라이언트) IP의 단순한 해시값을 사용하여 리소스를 선택합니다. 이 알고리즘은 주어진 소스 IP에 대해 항상 동일한 리소스를 선택합니다. 하지만 단일 프록시/IP 주소에서 접속하는 모든 사용자가 동일한 리소스로 전달되는 ‘메가 프록시’ 문제에 취약하여 더 이상 선호되지 않습니다. 이로 인해 대상 리소스에 과부하가 발생하여 성능이 저하되고, 결국 장애로 이어질 수 있습니다.

부하 분산 알고리즘은 애플리케이션 제공 아키텍처의 중요한 요소이지만, 애플리케이션이나 디지털 서비스의 성능 및 확장성에는 전반적인 아키텍처 접근 방식보다 미치는 영향이 적습니다.

앱 딜리버리란 무엇인가요?

앱 딜리버리는 앱, API 및 디지털 서비스를 위한 확장 가능하고 고성능인 아키텍처를 설계하는 분야입니다. 핵심 구성 요소로서 로드 밸런싱에 크게 의존하지만, 레이어 7 라우팅과 같은 최신 기능을 통합하고 일반적인 아키텍처 패턴을 활용하여 성능과 리소스 활용 효율성을 최적화합니다.

로드 밸런싱은 구현 세부 사항이고 아키텍처는 설계 프로세스라는 점을 명확히 구분하기 위해 의도적으로 앱 딜리버리라는 용어를 사용합니다.

왜 확장해야 할까요?

스케일링은 비즈니스 성과를 달성하기 위한 기술적 대응입니다. 즉, 고객 만족도와 전환율을 높이고 매출을 창출하기 위해 디지털 서비스를 구성하는 워크로드의 가용성과 성능을 유지해야 한다는 의미입니다. 특히 마지막 부분이 중요한데, 당사의 연구에 따르면 오늘날 대다수 기업(58%)은 전체 매출의 절반 이상을 디지털 서비스에서 창출하고 있습니다.

또한 퍼블릭 클라우드를 비즈니스 연속성(BC)에 활용하는 경우를 예로 들어 보겠습니다. BC는 퍼블릭 클라우드의 주요 활용 사례 중 하나이며, 그 핵심에는 글로벌 규모의 구현, 즉 글로벌 부하 분산이 있습니다. 장애 조치는 애플리케이션 딜리버리의 핵심 기능으로, 전체 사이트에 적용하면 요청을 한 위치에서 다른 위치로 신속하게 전환할 수 있습니다. 기업의 디지털 서비스가 지속적으로 가용한 상태를 유지하는 것은 기술적 대응을 통해 달성되는 비즈니스 성과입니다.

어떻게 확장할 수 있을까요?

이 질문에 답하는 것에서 애플리케이션 제공 아키텍처를 살펴보는 기술적 여정이 시작됩니다. 확장 방식에는 수직 확장(스케일 업)과 수평 확장(스케일 아웃)의 두 가지 모델이 있습니다.

수직 확장은 시스템에 더 많은 처리 능력을 추가하면 용량이 증가한다는 원칙에 기반합니다. 이 확장 방식은 주로 모놀리식 애플리케이션과 독립형 시스템에 적합합니다. 인프라를 제외하면 대부분의 조직은 더 이상 수직 확장에 의존하지 않습니다. CPU나 RAM을 추가하거나 네트워크 용량을 늘리는 등 물리적 환경을 변경해야 하기 때문입니다. 특히 퍼블릭 클라우드 환경에서는 가상화를 통해 수직 확장을 훨씬 빠르게 수행할 수 있지만, 소프트웨어와 시스템을 새로운 가상 머신으로라도 마이그레이션해야 한다는 점은 운영에 지장을 줄 수 있습니다.

수평 확장은 사용 가능한 전체 리소스를 늘려 처리 능력을 추가하는 아키텍처 접근 방식입니다. 애플리케이션, 서비스 또는 시스템의 여러 인스턴스에 처리 능력을 분산하여 이를 구현합니다. 리소스를 마이그레이션하는 대신 복제하는 방식이므로 오늘날 가장 일반적으로 사용되는 확장 방법입니다. 또한 수평 확장은 수직 확장보다 더 다양한 아키텍처 옵션을 제공하므로 모든 애플리케이션과 API에 더 적합합니다.

따라서 최신 앱 제공 패턴이 수평 확장 원칙을 기반으로 하는 것은 당연합니다.

앱 제공 패턴

단순히 수평 확장을 선택하는 것만으로 논의가 끝나는 것은 아닙니다.

결정이 내려지면(일반적으로 기본적으로 내려지는 결정입니다) 구현에 관한 아키텍처 결정을 내릴 때 추가적인 사항을 고려해야 합니다. 이러한 결정을 내리는 가장 간단한 방법은 스케일 큐브의 관점에서 접근하는 것입니다. 이는 The Art of Scalability에서 설명합니다.

간단히 말해, 스케일 큐브에는 x, y, z라는 세 개의 축이 있습니다. 각 축은 하나의 부하 분산 아키텍처 패턴에 대응합니다. 이러한 각 패턴은 다양한 유형의 애플리케이션과 API에서 성능 및 가용성과 관련된 특정 목표를 달성하는 데 적합합니다.

디지털 서비스는 성능과 리소스 소비를 동시에 최적화하기 위해 여러 패턴을 통합한 아키텍처를 사용할 가능성이 높습니다. 이 접근 방식에서는 모든 구성 요소와 구성 요소 간의 상호 작용 방식, 그리고 요청이 사용자에서 앱으로 전달되었다가 다시 사용자에게 돌아오는 흐름을 모두 고려해야 하므로 시스템적 사고가 필요합니다.

X축 눈금

X축 패턴은 가장 기본적인 패턴입니다. 수평 복제를 기반으로 하며, 대부분의 작업은 부하 분산 알고리즘을 통해 처리됩니다. 가장 단순한 패턴으로, 제가 단순 부하 분산(Plain Old Load Balancing, POLB)이라고 부르는 방식을 구현합니다.

이렇게 부르는 이유는 아키텍처가 단순하여, 애플리케이션 계층에서 요청 및 응답과 상호 작용할 수 있는 최신 로드 밸런서의 고급 기능을 전혀 활용하지 않기 때문입니다.

이 패턴에서는 애플리케이션을 복제하고, 구성된 부하 분산 알고리즘의 결정에 따라 요청을 특정 인스턴스로 전달합니다.

이 패턴은 TCP(계층 4)와 함께 사용되는 경우가 많으므로 HTTP(계층 7) 검사에 의존하는 다른 패턴보다 성능상 이점이 있습니다. 특히 연결을 프록시하는 대신 서로 이어 붙일 수 있어, 초기 연결 이후에는 로드 밸런서가 사실상 네트워크 홉 역할을 하게 됩니다. 그 결과 전반적인 성능은 향상되지만, 초기 연결 이후에는 로드 밸런서가 요청과 응답을 검사하거나 이에 따라 조치할 수 없게 됩니다. X축 아키텍처는 가용성 보장에 탁월하고 높은 성능을 제공할 수 있으므로 방화벽 및 애플리케이션 게이트웨이와 같은 인프라 및 보안 서비스를 확장하는 데 자주 사용됩니다.

다양한 기존 애플리케이션(모놀리식, 3계층 웹 및 클라이언트-서버)은 최신 애플리케이션 제공 아키텍처에 활용할 수 있는 보다 세분화된 구성 요소로 분해되는 경우가 드물기 때문에 이 패턴을 사용하여 확장하는 경향이 있습니다.

Y축 확장

이 패턴은 기능 분해를 기반으로 하며, 애플리케이션 전송의 애플리케이션 계층(계층 7) 기능을 활용하여 전체 시스템이 아닌 기능 단위로 확장합니다. Y축 패턴은 계층 7 라우팅이 애플리케이션 전송 아키텍처의 핵심 도구로 활용되는 최초의 패턴입니다.

일반적으로 y 및 z 기반 패턴은 계층 7 라우팅을 활용해 풀을 선택한 다음, 부하 분산 알고리즘을 사용해 특정 리소스를 선택합니다. 이는 계층 7 라우팅을 사용하지 않는 기본 x 패턴과는 다릅니다.

이 패턴은 일반적으로 HTTP와 같은 계층 7에서 작동하며, 특정 변수를 사용해 애플리케이션 또는 서비스의 특정 인스턴스로 트래픽을 분산하는 것을 전제로 합니다. 예를 들어 URI에서 /login 패턴이 발견되면 로드 밸런서는 구성된 부하 분산 알고리즘에 따라 로그인 요청만 처리하는 애플리케이션 인스턴스 풀에서 인스턴스 하나를 선택합니다. 이 변수는 요청 헤더나 요청 페이로드에 포함된 어떤 값이든 사용할 수 있습니다. 이를 통해 에이전트 기반 라우팅, API 라우팅 및 콘텐츠 기반 라우팅(이미지, 스크립트 등)이 가능합니다.

애플리케이션 인스턴스는 복제본일 수 있습니다. 요청의 변수로 식별할 수 있는 애플리케이션 사용량의 편차가 있을 때 흔히 사용됩니다. 예를 들어, 로그인 기능과 결제 기능은 URI, HTTP 헤더의 값 또는 요청 페이로드의 값을 기준으로 요청에서 구분할 수 있습니다. Y축 패턴을 적용하면 기존 애플리케이션을 기능,에 따라 확장할 수 있습니다. 따라서 다른 기능의 예상 성능을 유지하면서 사용량이 많은 기능을 처리하는 데 더 많은 리소스를 할당할 수 있으므로 리소스 활용 효율이 향상됩니다.

기존 애플리케이션을 기능별로 확장하기 위해 y축 패턴을 사용하기 시작한 것은 오늘날 애플리케이션을 기능별로 분해하는 마이크로서비스가 널리 보급되기 전입니다. y축 패턴은 여전히 마이크로서비스에 적용할 수 있으며, 실제로 오늘날 인그레스 컨트롤러에서 이 패턴을 구현하고 있습니다. 통찰력 있는 독자라면 API가 HTTP(계층 7) 구조를 기반으로 하므로 이 패턴이 API에도 적용된다는 점을 알아차릴 것입니다. 따라서 API 게이트웨이가 이 기본 패턴을 활용하는 것은 당연합니다.

이 패턴은 eBay를 통해 널리 알려졌으며 Web 2.0 초창기에 주목받았습니다. 당시 eBay의 확장성 아키텍처는 기능을 별도의 애플리케이션 풀로 분할하는 방식을 포함했습니다. 판매 기능은 한 애플리케이션 서버 집합에서, 입찰 기능은 다른 집합에서, 검색 기능은 또 다른 집합에서 처리했습니다. 전체적으로 약 16,000대의 애플리케이션 서버를 220개의 서로 다른 풀로 구성했습니다. 이를 통해 각 기능의 수요와 리소스 사용량에 따라 각 풀을 서로 독립적으로 확장할 수 있었습니다. 또한 리소스 종속성을 격리하고 합리화할 수 있었습니다. 예를 들어 판매 풀은 비교적 적은 수의 백엔드 리소스와만 통신하면 되었습니다.

Y축 패턴은 이미지와 같은 다양한 유형의 콘텐츠 요청을 하나의 리소스 풀에 분배하고, 다른 콘텐츠 유형은 다른 리소스 풀에 분배하는 데에도 사용할 수 있습니다.

y축을 사용해 부하를 분산하면 디지털 서비스의 각 구성 요소를 개별적으로 확장할 수 있으므로, 리소스 활용 측면에서 x축 패턴보다 훨씬 효율적입니다. 또한 서비스 또는 애플리케이션 계층에서 구성을 최적화할 수 있으며, 웹 서버나 앱 서버의 특정 변수를 조정해 주어진 콘텐츠 유형에 맞게 최적화함으로써 성능을 향상할 수 있습니다.

Z축 확장

Z축 패턴은 소셜 미디어와 인터넷 전반의 폭발적인 성장에 대응해야 할 필요성 때문에 널리 사용되기 시작했습니다. 기본적으로는 Y축 확장 패턴에 추가적인 세분화를 적용한 방식으로, 일반적으로 사용자 이름이나 기기 식별자 같은 특정 변수를 기준으로 나눕니다.

이 패턴은 데이터 샤딩에서 파생된 기법을 사용하여 아키텍처를 차별화할 수 있게 해줍니다.

“데이터베이스 샤드, 또는 간단히 샤드란 데이터베이스나 검색 엔진의 데이터를 수평으로 분할한 것입니다. 각 샤드는 부하를 분산하기 위해 별도의 데이터베이스 서버 인스턴스에 저장됩니다. 데이터베이스 내 일부 데이터는 모든 샤드에 존재하지만, 일부는 단일 샤드에만 존재합니다.”

위키백과1

이 패턴은 데이터베이스에서 사용하는 원칙을 적용하여 요청에 포함된 특정 데이터를 기준으로 요청을 분산합니다. 데이터 계층의 병목 현상을 해결하는 데 도움이 될 뿐만 아니라 데이터 주권 규정 준수를 보장하는 수단으로도 사용할 수 있습니다. 식별 가능하고 일반적으로 고유한 변수를 사용하여 수평으로 확장된 리소스 풀에 요청을 라우팅합니다. 이 패턴은 일반적으로 특정 서비스나 애플리케이션에 대한 요청량이 매우 많은 경우처럼 높은 처리량이 필요할 때 사용됩니다.

Z축 패턴은 수백만 대에 이를 수 있는 엣지 및 IoT 디바이스를 관리하는 데 특히 유용합니다. 디바이스 식별자를 요청 샤딩의 기준 패턴으로 사용하면 데이터 전송 속도를 크게 향상할 수 있습니다. 이 데이터는 각 디바이스에 고유하므로 안전하게 샤딩할 수 있으며, 구성을 원격 위치(클라우드 또는 데이터 센터)에 저장하는 디바이스에 특히 유용합니다.

이 패턴은 부하가 높은 상황에서 데이터 액세스로 인해 성능이 크게 저하될 수 있으므로 성능을 개선하는 데 도움이 됩니다. 따라서 데이터 액세스를 더 많은 인스턴스에 분산하면 부하가 감소하고 그에 따라 성능이 향상됩니다. 이를 위해서는 데이터 무결성에 세심한 주의를 기울여야 하며, 공유 데이터를 샤딩하는 데 사용할 경우 일관성 문제가 발생할 수 있습니다. Meta는 샤딩이라는 주제를 부각했습니다. 이는 전체 아키텍처의 일부로 서비스 샤딩을 개발하면서 이루어졌습니다. 고성능의 확장 가능한 앱 제공 아키텍처를 개발하는 데 세심한 주의를 기울인 사례는 앱 제공을 더 큰 아키텍처 내의 공식 계층으로 인식함으로써 상당한 이점을 얻을 수 있음을 잘 보여줍니다.

비주 데이터 소스에 액세스하는 서비스의 경우, z축 패턴을 사용하면 시스템 전반의 데이터 품질에 큰 영향을 주지 않으면서 처리량을 높일 수 있습니다. 이 접근 방식은 애플리케이션 또는 API의 특정 인스턴스를 데이터 소스에 연결하기 위한 코드를 추가할 필요성을 줄여 줍니다. 대신 인스턴스 수준의 데이터 커넥터 구성과 앱 전송 라우팅을 함께 활용하여 올바른 데이터 소스가 사용되도록 합니다.

확장성의 비결은 앱 딜리버리 아키텍처입니다

오늘날 디지털 서비스가 제공되는 환경에서 단 하나의 애플리케이션 제공 패턴만으로 고성능의 안정적인 디지털 서비스를 설계하는 경우는 드뭅니다. 이는 디지털 서비스 자체의 복잡성과 더불어 기기, 사람, 소프트웨어를 아우르는 ‘사용자’의 다양성이 갈수록 커지고 있기 때문입니다.

따라서 아키텍처 접근 방식에서는 사용자에게 최적의 경험을 제공하기 위해 디지털 서비스 전반에 걸쳐 애플리케이션 제공 패턴을 가장 효과적으로 활용하는 방안을 고려합니다.

디지털 서비스를 구성하는 서비스와 애플리케이션에 따라 크게 달라지므로 ‘옳은’ 또는 ‘그른’ 아키텍처 솔루션은 없습니다. 다만 이러한 솔루션이 로드 밸런싱 알고리즘에만 기반해서는 안 됩니다.

실제로 지금까지 알고리즘 선택에 대한 언급이 없었다는 점에 주목해야 합니다. 부하 분산 패턴 내에서 부하를 어떻게 분배할지 선택하는 것은 특정 앱이나 API에 적합한 아키텍처를 선택하는 것만큼 중요하지 않기 때문입니다.

이는 애플리케이션 제공이 하나의 전문 분야로 자리 잡도록 이끄는 요인 중 하나입니다. 오늘날 애플리케이션 제공 및 보안이 활용되고 구현되는 방식은 단순히 웹 서버를 확장하는 수준을 훨씬 뛰어넘습니다. 구현 방식에 따라 성능과 가용성이 달라질 수 있으며, 궁극적으로 비즈니스 성과의 성패를 좌우할 수도 있습니다. 따라서 조직은 애플리케이션 제공을 설계 도구 상자에 포함된 전략적 아키텍처 도구로 접근해야 합니다.

로드 밸런싱은 확장성을 위한 핵심 기술 요구 사항으로 여전히 중요합니다. 앱 딜리버리 패턴과 이러한 패턴이 로드 밸런싱을 활용하는 방식을 이해하면 디지털 서비스의 확장성과 성능을 고려한 아키텍처를 설계하는 데 더 나은 관점을 얻을 수 있습니다. 특히 해당 서비스가 하이브리드 형태로 제공되고 API와 최신 앱 및 기존 앱이 혼합되어 있을 가능성이 높은 경우 더욱 그렇습니다.


각주

1 위키백과