Cloud Modernization 29

3-Tier 네트워크, DB, Auto Scaling, Edge 서비스로 안정성 구성하기

안정성 구성이 여러 AWS 서비스 목록처럼 보이면 사용자가 접속하는 전체 경로가 그려지지 않는다.

근거 · 교안 p133-p137

3-Tier 네트워크, DB, Auto Scaling, Edge 서비스로 안정성 구성하기 ?? ???

1장: 사용자 요청의 내부 흐름 파악: 3-Tier 네트워크

솔라는 노트북 화면을 들여다보며 미간을 찌푸렸다. 화면에는 ‘안정적인 서비스 환경 구성’이라는 제목 아래 여러 기술 용어들이 나열되어 있었다. 네트워크, 데이터베이스, Auto Scaling, Route53, CloudFront… 이름들은 익숙했지만, 함께 모여 있으니 의미 없는 단어의 나열처럼 느껴졌다.

“분명 ‘함께 맞물려 작동한다’고 쓰여 있는데… 전혀 그림이 그려지지 않아.”

혼잣말을 들은 루나 언니가 조용히 다가와 솔라의 화면을 들여다보았다. 빼곡한 서비스 목록을 잠시 보던 루나는 아무 말 없이 커다란 빈 종이와 펜을 가져왔다.

“부품 목록만 봐서는 자동차 전체를 상상하기 어렵지. 한번 조립해 보자.”

루나는 종이 위에 큼직한 사각형 세 개를 가로로 나란히 그렸다. 그리고 각각 ‘Public’, ‘Web/App’, ‘DB’라고 이름을 붙였다.

“이게 우리 서비스의 가장 기본적인 3계층 구조야. 솔라, 네가 사용자라고 상상해 봐. 네가 보낸 요청 하나가 저 맨 끝에 있는 DB까지 어떻게 도착할까? 화살표로 길을 한번 그려볼래?”

솔라는 자신 있게 펜을 들었다. 간단해 보였다. 사용자를 나타내는 동그라미를 왼쪽에 그리고, 거기서부터 Public 상자로 화살표를 그었다. 다시 Public에서 Web/App으로, Web/App에서 DB로. 요청이 처리된 후 돌아오는 길은 그 반대로 그리면 될 터였다.

“자, 이렇게. 요청이 들어가서, 처리되고, 응답이 나오는 거지.”

솔라가 그린 그림은 단순하고 명쾌한 일직선이었다. 루나는 그림을 잠자코 보더니, 첫 번째 화살표, 즉 사용자가 Public 계층으로 들어가는 지점을 펜 끝으로 톡톡 두드렸다.

“좋아. 첫 번째 관문이네. 이 화살표는 뭘까? 전 세계 인터넷이라는 거대한 바다에서, 수많은 요청들이 어떻게 정확히 우리 서비스의 ‘Public’이라는 작은 항구로 들어올 수 있을까? 그 문은 뭐라고 부르지?”

“음… 문?” 솔라는 잠시 머뭇거렸다. 그냥 ‘연결’된다고만 생각했지, 그 ‘문’의 실체에 대해선 생각해 본 적이 없었다. 목록에 있던 단어들을 떠올려 봤지만 딱 들어맞는 게 없었다.

루나는 Public 상자의 테두리 한쪽에 작은 문 모양을 그려 넣고 ‘Internet Gateway’라고 적었다. “인터넷이라는 외부 세계와 우리 내부 네트워크를 연결하는 유일한 공식 출입문이야. 이 문이 없으면 아무도 들어오거나 나갈 수 없어.”

솔라의 눈이 동그래졌다. 단순한 화살표가 구체적인 이름을 가진 ‘문’으로 바뀌자, 막연했던 흐름이 조금 더 명확해지는 듯했다.

“좋아, 그럼 문을 통과한 요청은 Public 계층 안으로 들어왔어.” 루나는 말을 이었다. “그런데 Web/App 계층에는 보통 똑같은 일을 하는 웹 서버가 여러 대 있거든. 요청은 그중 어떤 서버로 가야 할까? 누가 그걸 정해주지?”

솔라는 Public과 Web/App 상자 사이에 있는 화살표를 내려다보았다. 자신의 그림에는 그저 하나의 선일 뿐이었다. “누군가… 교통정리를 해주나?”

“바로 그거야.” 루나는 Public 상자 안에 작은 저울 모양 아이콘을 그리고 ‘Elastic Load Balancer(ELB)’라고 썼다. 솔라가 그렸던 화살표를 지우고, Internet Gateway에서 ELB로, 다시 ELB에서 Web/App 상자 안의 여러 작은 서버 그림들로 향하는 여러 개의 화살표를 그렸다. “ELB는 들어온 요청들을 웹 서버들에게 공평하게 나눠주는 교통경찰 같은 역할을 해. 한 서버에만 일이 몰리지 않도록 말이야.”

이제 그림은 단순한 3단 구조가 아니라, 문을 통과해 들어온 요청이 교통경찰의 지시에 따라 여러 갈래 길로 나뉘는 모습이 되었다.

루나는 마지막으로 Web/App 상자를 가리켰다. “자, 이제 웹 서버가 요청을 처리하다 보니 DB에 저장된 정보가 필요해졌어. 그래서 DB 계층에 정보를 달라고 요청해야 해. 그런데 한 가지 규칙이 있어. DB 계층은 가장 중요하고 민감한 정보를 다루기 때문에, 외부 인터넷과 절대로 직접 통신할 수 없는 폐쇄된 공간이야. 그런데 만약 이 웹 서버가 소프트웨어 업데이트처럼 외부 인터넷에서 뭔가를 받아와야 한다면 어떻게 해야 할까? 밖으로 나갈 문이 없는데.”

솔라는 고민에 빠졌다. DB는 외부와 연결되면 안 되고, Web/App은 외부와 통신이 필요할 때가 있다. 모순이었다. “폐쇄된 방 안에서 바깥에 있는 물건을 가져와야 하는 상황이네… 누군가 대신 문을 열고 나가서 가져다줘야 하나?”

“정확해.” 루나는 빙긋 웃으며 Web/App 계층과 Public 계층 사이에 새로운 문을 그렸다. 하지만 이 문은 Internet Gateway처럼 양방향이 아니라, 안에서 밖으로만 나갈 수 있는 일방통행 화살표로 표시되었다. 그리고 ‘NAT Gateway’라고 적었다. “Web/App 서버 같은 내부의 구성원이 외부에 요청을 보낼 수는 있지만, 외부에서 먼저 말을 걸 수는 없게 만드는 특수한 문이야. 보안을 유지하면서 필요한 통신만 허용하는 거지.”

솔라는 수정된 그림을 가만히 내려다보았다. 처음 그렸던 밋밋한 세 개의 상자와 화살표는 온데간데없었다. 대신, 각기 다른 역할을 하는 ‘문(Internet Gateway)’, ‘교통경찰(ELB)’, ‘대리인(NAT Gateway)’들이 요청의 흐름을 만들고 제어하는 복잡하지만 논리적인 경로가 눈앞에 펼쳐져 있었다.

“아… 알겠다.” 솔라가 마침내 입을 열었다. “이 서비스들은 그냥 부품 목록이 아니었어. 요청이 지나가는 ‘길’ 그 자체를 만드는 거였구나. 3-Tier라는 건 단순히 공간을 세 개로 나눴다는 뜻이 아니라, 이런 게이트웨이와 로드 밸런서들이 만들어내는 데이터의 이동 경로, 즉 ‘흐름’이었던 거야.”

솔라는 이제 안정적인 서비스 구조가 단순한 서비스의 나열이 아님을 이해했다. 그것은 사용자 요청이 안전하고 효율적으로 여행할 수 있도록 설계된 잘 짜인 도로망과 같았다.

뿌듯함도 잠시, 솔라의 머릿속에 새로운 질문이 떠올랐다.

“언니, 이제 길은 알겠어. 그런데 만약 갑자기 차가 엄청나게 몰려서 도로가 꽉 막히면 어떡해? 아니면 중간에 다리(서버) 하나가 무너지면? 길이 있다는 것만으로 ‘안정적’이라고 할 수는 없잖아.”

2장: 각 계층의 자율적 안정성 확보: DB와 Auto Scaling

솔라의 질문이 끝나자, 루나는 대답 대신 붉은 펜을 집어 들었다. 그리고 방금 전까지 함께 완성했던 3-Tier 아키텍처 다이어그램 위로 펜을 가져갔다. 솔라가 칭찬했던, 잘 짜인 도로망 같던 그 그림이었다. 루나는 망설임 없이 DB 계층에 덩그러니 있던 ‘DB’ 상자에 굵은 X자를 그었다. 시스템의 심장부, 모든 데이터가 저장되는 가장 중요한 곳에 생긴 선명한 붉은 상처였다.

종이 위에 정적이 흘렀다. 솔라는 아무 말도 하지 못하고 그 X자만 쳐다보았다. 방금 전 솔라가 던졌던 ‘다리가 무너지면?’이라는 가상 질문이, 눈앞에서 벌어진 실제 사건이 된 것 같았다. 다리가 아니라, 데이터가 저장된 중앙 은행의 금고가 통째로 파괴된 셈이었다. 솔라가 겨우 입을 열었다.

“…언니, 지금 뭐 한 거야? 그렇게 되면… 그냥 다 끝나는 거 아니야? 요청이 아무리 잘 들어와도 데이터를 읽거나 쓸 수가 없는데.”

“그렇지. 이 상태라면 모든 게 멈추지.” 루나는 담담하게 말하며, X자가 쳐진 DB 상자 옆에, 조금 떨어진 곳에 새로운 상자를 하나 더 그렸다. 그리고 원래 상자와 새 상자를 점선으로 둘러싸고 각각 ‘AZ-A’, ‘AZ-B’라고 작게 적었다.

“만약에, 아주 똑같이 생긴 쌍둥이 금고가 다른 동네에 하나 더 있다면 어떨까?”

솔라는 새로운 그림을 보며 눈을 가늘게 떴다. “쌍둥이 금고? 백업 같은 거 말하는 거야?”

“비슷하지만, 조금 더 똑똑한 쌍둥이야.” 루나는 원래 DB(AZ-A)에서 새 DB(AZ-B)로 향하는 가는 화살표를 그리고, 그 위에 ‘복제’라고 썼다. “이 쌍둥이는 항상 원본 금고를 실시간으로 지켜보면서 모든 걸 똑같이 복사해 둬. 그래서 이걸 ‘읽기 전용 복제본(Read Replica)’이라고 불러. 평소에는 ‘데이터를 읽어가는’ 손님들을 이쪽으로 안내해서 원본 금고의 부담을 덜어주지.”

루나는 App 계층에서 DB 계층으로 향하던 화살표를 둘로 나누었다. 데이터를 쓰는(Write) 요청은 원래의 DB로, 데이터를 읽는(Read) 요청 대부분은 새로운 복제본 DB로 향하도록 길을 바꿨다.

“그러다가…” 루나는 X자가 쳐진 원래 DB를 펜 끝으로 가리켰다. “원본 금고에 문제가 생기면, 우리는 즉시 이 쌍둥이 금고를 새로운 원본으로 승격시키는 거야. 아주 잠깐의 서비스 중단은 있을 수 있지만, 시스템 전체가 멈추지는 않아. 이게 바로 ‘고가용성’ 구성이야. 하나의 부품이 고장 나도 전체가 죽지 않도록 만드는 거지.”

솔라의 머릿속에서 ‘DB 복제’라는 단어가 새로운 의미를 갖기 시작했다. 그것은 단순히 데이터를 백업하는 소극적인 기능이 아니었다. 평소에는 부하를 분산해 성능을 높이고, 비상시에는 즉시 대체재가 되어 서비스의 생명을 연장하는, 계층 자체의 ‘자율적인 생존 전략’이었던 것이다.

“그렇구나… 한쪽 다리가 무너져도 바로 옆에 예비 다리가 나타나는 거네. 그럼 차가 몰리는 문제는?” 솔라는 Web/App 계층을 가리켰다. “갑자기 사용자가 10배, 100배로 늘어나면 어떡해? 다리가 튼튼해도 차선이 2개뿐이면 결국 꽉 막힐 텐데.”

“좋은 비유야.” 루나는 Web/App 계층을 둘러싸고 있던 상자의 외곽선을 지우고, 대신 아코디언처럼 늘어날 수 있는 물결무늬 선으로 다시 그렸다. 그 안에는 작은 서버 그림이 세 개 그려져 있었다.

“만약 교통량이 늘어나는 걸 감지해서, 도로 스스로 차선을 2개에서 4개로, 4개에서 8개로 순식간에 늘릴 수 있다면 어떨까?”

“도로가 스스로 차선을 늘린다고? 그게 가능해?” 솔라는 믿기지 않는다는 표정을 지었다.

“‘Auto Scaling’이 바로 그 역할을 해.” 루나는 물결무늬 상자 옆에 작은 온도계 아이콘을 그렸다. “마치 온도 조절 장치 같아. 우리는 미리 규칙을 정해두는 거야. ‘서버들의 평균 작업량이 70%를 넘으면, 즉시 새로운 서버를 하나 더 만들어라. 반대로 30% 아래로 떨어지면, 불필요한 서버를 하나 없애서 비용을 아껴라.’ 라고.”

루나는 물결무늬 상자 안의 서버 그림을 몇 개 더 그렸다가, 다시 지우는 시늉을 했다. “이렇게 되면, 갑자기 트래픽이 몰려도 시스템이 알아서 서버 수를 늘려 요청을 감당하고, 트래픽이 줄면 다시 원래대로 돌아와. 사람이 일일이 지켜보거나 조작할 필요 없이, 이 계층이 스스로 용량을 조절하며 안정성을 유지하는 거지.”

솔라는 비로소 깨달았다. 이전에는 그저 개별 서비스 기능 목록으로 보였던 ‘DB 복제’와 ‘Auto Scaling’이 사실은 각 계층에 내장된 ‘자율 신경계’와 같다는 것을.

“알겠다…! 안정적인 구조라는 건, 그냥 튼튼한 길을 만드는 것에서 끝나는 게 아니었어. DB 계층은 복제본으로 스스로를 보호하고, Web/App 계층은 Auto Scaling으로 스스로의 크기를 조절하고… 각 계층이 외부 상황 변화에 알아서 적응하고 살아남는 능력을 갖추는 거구나. 전체 시스템이 하나의 유기체처럼 움직이는 거네.”

솔라는 완성된 다이어그램을 뿌듯하게 바라보았다. 견고한 경로, 스스로를 치유하는 DB, 신축적인 Web/App 계층까지. 이제 이 서비스는 웬만한 위기에는 끄떡없을 것처럼 보였다.

하지만 그림 전체를 조망하던 솔라의 눈에 한 가지 의문이 스쳤다.

“언니, 그런데 이 훌륭한 시스템은 전부 ‘하나의 지역’에 있는 거잖아. 만약 우리나라에서 만든 서비스라면, 저 멀리 미국에 있는 사용자가 접속할 때는 어떡하지? 그 사람이 보낸 요청이 여기까지 오는 데만 한참 걸릴 텐데. 우리 집이 아무리 튼튼해도, 손님이 오는 길이 너무 멀고 험하면 무슨 소용이야?”

3장: 사용자 접점의 지능적 분산: Edge 서비스 통합

루나는 솔라가 완성한 다이어그램을 테이블 중앙에 그대로 두었다. 완벽하다고 생각했던 그 구조도 위에는, 아직 해결되지 않은 거대한 빈 공간이 느껴졌다. 그녀는 말없이 근처에 있던 작은 지우개 하나를 집어 들었다.

그리고는 종이에서 한참 떨어진 테이블의 맨 끝, 미국에 있는 사용자라고 가정할 만한 먼 거리에 그 지우개를 톡 내려놓았다. 잘 짜인 내부 시스템이 그려진 종이와, 그곳에서 너무나도 멀리 떨어진 외로운 지우개. 그 사이의 광활한 물리적 거리가 이전 질문의 핵심—아무리 집이 튼튼해도 손님이 오는 길이 멀고 험하다면 무슨 소용인가—을 말없이 보여주고 있었다.

“좋아, 솔라. 저 미국에 있는 사용자가 우리 서비스의 웹 주소를 입력했어.” 루나가 펜으로 지우개를 가리키며 말했다. “네가 그린 이 완벽한 시스템까지 요청이 어떻게 도착하는지, 그 길을 한번 그려봐.”

솔라는 펜을 들고 잠시 망설였다. 답은 뻔해 보였다. 그녀는 지우개에서부터 시작해, 테이블을 가로지르는 길고 긴 직선 화살표를 그렸다. 화살표의 끝은 한국에 있는 서비스, 즉 다이어그램의 ‘Internet Gateway’에 닿았다.

“이렇게. 태평양을 건너는 해저 케이블을 따라서… 오겠지. 오래 걸리는 건 어쩔 수 없고.” 솔라가 말했다. 그녀에게 안정성이란 어디까지나 잘 구축된 내부 시스템의 문제였고, 접속 지연은 그저 감수해야 할 물리학의 영역처럼 느껴졌다.

“그럴까?” 루나가 솔라가 그린 긴 화살표의 중간쯤을 펜으로 툭툭 쳤다. “우리가 쇼핑몰에 접속할 때, 페이지의 모든 요소가 다 똑같은 속도로, 똑같은 곳에서 올까? 예를 들어, 매일 보는 회사 로고 이미지 파일과, ‘솔라 님, 환영합니다!’라고 뜨는 개인화된 문구가 같은 방식으로 배달될까?”

솔라는 미간을 찌푸렸다. 로고는 누구에게나 똑같이 보이는 ‘정적’인 파일이다. 하지만 ‘솔라 님’이라는 문구는 오직 솔라에게만 보이는 ‘동적’인 데이터다. 한 번도 그것들이 다른 경로로 올 수 있다는 생각은 해본 적이 없었다.

“자, 이번엔 길을 다르게 그려보자.” 루나는 새 종이를 꺼내는 대신, 원래의 다이어그램 바깥의 넓은 여백을 활용하기 시작했다. 그녀는 미국에 있는 ‘사용자’ 지우개와 한국에 있는 ‘메인 시스템’ 다이어그램 사이에, 세계 지도처럼 여러 개의 작은 ‘편의점’ 아이콘을 흩뿌려 그렸다.

“사용자가 우리서비스.com을 입력하는 순간, 가장 먼저 가는 곳은 우리 서버가 아니야. 가장 가까운 ‘주소 안내소’로 가지.” 루나는 사용자 바로 옆에 ‘Route 53’이라고 적힌 작은 표지판을 그렸다. “이 똑똑한 안내소는 사용자가 미국에 있다는 걸 확인하고, 한국에 있는 본점 주소가 아니라 미국 내에서 가장 가까운 ‘편의점’ 주소를 알려줘.”

“편의점?”

“응. 전 세계에 퍼져 있는 우리의 작은 지점, ‘CloudFront’라고 부르지.” 루나는 사용자와 가장 가까운 편의점 아이콘에 화살표를 연결했다. “이 편의점에는 사람들이 가장 자주 찾는 물건들이 미리 진열되어 있어. 로고 이미지, 웹사이트의 디자인을 구성하는 CSS 파일, 기본적인 기능을 하는 자바스크립트 파일 같은 것들 말이야. 이런 것들은 바뀔 일이 거의 없으니까.”

루나는 메인 시스템 옆에 ‘S3’라고 이름 붙인 거대한 창고 그림을 추가하고, 그 창고에서 전 세계의 편의점들로 물건을 공급하는 흐름을 점선으로 그렸다. “본사의 중앙 창고(S3)에서 이런 공용 물품(정적 콘텐츠)들을 전 세계 편의점(CloudFront)에 미리 다 깔아두는 거야.”

솔라는 펜을 들고 사용자 요청의 경로를 다시 그리기 시작했다. 사용자가 웹사이트를 요청하자, ‘로고 이미지’를 달라는 요청은 태평양을 건너지 않았다. 바로 옆 동네 편의점(CloudFront)에서 즉시 처리되었다. 물리적으로 가까우니 속도는 당연히 빨랐다.

“알겠다! 그러니까 자주 쓰는 물건들은 손님 집 근처에 미리 가져다 둬서, 굳이 본점까지 올 필요가 없게 만드는 거구나.”

“바로 그거야.” 루나가 대답했다. “하지만 ‘솔라 님, 환영합니다!’ 같은 메시지는 편의점에 미리 갖다 둘 수 없지. 그건 너만을 위한 개인적인 정보니까.”

루나는 편의점(CloudFront)을 가리켰다. “그런 ‘동적’인 요청이 오면, 편의점은 그제야 ‘아, 이건 본사에 직접 물어봐야 하는 건이네요’ 하면서 한국에 있는 우리 메인 시스템으로 가는 가장 빠른 전용 도로로 안내해 주는 거야.”

솔라의 펜은 마침내 긴 직선을 그어 테이블을 가로질렀다. 하지만 이전과는 달랐다. 모든 요청이 섞여 느릿느릿 가던 길이 아니었다. 이미지, 동영상 같은 무겁고 반복적인 요청들은 모두 집 근처에서 처리되고, 오직 ‘나의 정보’를 확인하는 가볍고 필수적인 요청만이 빠르고 효율적인 길을 따라 본사로 향했다. 그제야 솔라는 Route53, CloudFront, S3 같은 서비스들이 왜 ‘Edge’ 서비스라고 불리는지 깨달았다. 이들은 서비스의 가장자리, 즉 사용자와 가장 가까운 최전선에서 요청을 지능적으로 분산하고 필터링하는 관문이었던 것이다.

“이건… 그냥 성능 개선 도구 목록이 아니었어.” 솔라가 혼잣말처럼 중얼거렸다. “우리 시스템의 바깥 경계를 확장하고, 사용자를 가장 먼저 맞이하는 또 하나의 방어막이자 효율적인 안내 시스템이었구나.”

솔라는 벅찬 마음으로 펜을 다시 들었다. 그녀는 이제 사용자가 URL을 입력하는 순간부터 시작되는 전체 여정을 그릴 수 있었다.

사용자의 요청은 가장 먼저 Route53을 만나 가장 가까운 CloudFront Edge로 안내된다. CloudFront는 캐시된 정적 콘텐츠(이미지, CSS)를 즉시 사용자에게 전달한다. 개인화된 데이터가 필요한 동적 요청만이 3-Tier 아키텍처의 심장부(Internet Gateway -> ELB -> Web/App -> DB)로 향한다. 그 내부에서는 Auto Scaling 그룹이 트래픽에 맞춰 유연하게 서버를 늘리고, Read Replica DB가 읽기 요청을 분산 처리하며 안정성을 지킨다.

처음엔 그저 단어의 나열처럼 보였던 서비스 목록들이, 이제는 솔라의 손끝에서 하나의 거대한 유기체처럼 연결되어 그려지고 있었다. 솔라는 완성된 그림 전체를 커다란 사각형으로 둘러쌌다. 그리고 그 위에 제목을 적었다.

‘안정적인 서비스 아키텍처’

더 이상 흩어진 부품 목록이 아니었다. 사용자의 첫 클릭부터 데이터베이스의 깊은 곳까지, 모든 요소가 각자의 자리에서 어떻게 유기적으로 맞물려 ‘안정성’이라는 공동의 목표를 위해 일하는지에 대한 명확하고 통합된 청사진이었다. 솔라는 비로소 전체 그림을 보게 된 것이다.