대규모 트래픽을 커버하는 첫 페이지 만드는 법..
보통 DB를 연결할 때 대규모 설계는 어떻게 하시나요?
잘 만들었다는 전제 하에 동접 3000명 이하는
어떤 DBMS를 사용해도 문제 없이 돌아갑니다.
여기서 이미 터졌다면 이 콘텐츠를 보기 전에 DB의 기초부터 보셔야 합니다.
아.. 개발 코드가 터졌다구요? 그럼 개발자를 때리셔야지요..
만약 3000명을 넘겼다면?
이제 Write/Read를 분리해서
1 CRUD + n개의 READ Replica를 만들겠죠?
보통 Read Replica는 5개가 최대라고 보시면 됩니다.
누가 연구한 자료가 있었는데...
6번째 레플리카를 만든느 순간 마스터가 되는 서버의 효율 저하 때문에
5번째에서 6번쨰로 올릴때의 성능이 급격히 줄어든다는 연구 결과가 있습니다.
때문에 Azure에서도 replica설정할 때 5대까지 밖에 설정 못하게 되어 있지요.
유저의 행동 패턴에 따라 다르긴 하지만,
1 CRUD + 5 Read Replica의 경우 동접 15000명 정도는 커버 합니다.
즉, 동접 15000명 에서 다시 터져서 저를 부르는 경우가 많지요..
이 때부터는
회원 DB, 게시판DB, 서비스DB, 과금 DB 등등 으로 성격, 서로의 연관도에 따라 나누기 시작합니다.
물리적으로 DB가 나눠지면 Join을 못하거나 Linked Table또는 LinkDB등의 연결자를 이용해서 JOIN이 되기도 합니다.
그에 따라 성능 차이가 생기지만 가장 중요한 포인트는
서로 다른 물리적 테이블의 JOIN은 인덱스를 타지 않는다!
라는 것입니다. 즉, JOIN할 테이블들을 최소한으로 만든 뒤에 JOIN을 걸지 않으면 NoSQL처럼 느려터져 죽습니다.
양이 많은 DB에서 양이 적은 테이블을 가져와서 JOIN을 해야겠지요..
이렇게 해서 동접 10만명까지 커버를 했다 칩시다.
여기서 일반적인 동접의 기준도 서비스마다 다릅니다.
웹 서비스는 20분 이내에 한 번이라도 클릭한 유저를 동접에 카운트 하지만,
온라인 게임등은 소켓을 열어놓고 있기 때문에
순간 동접을 그자리에서 카운트 합니다.
그리고 서비스에 따라 다르지만 보통 100만 액티브 유저가 있으면 최대 동접은 10만인 경우가 많습니다.
자, 동접 10만이 넘어가서 위태위태 합니다.
그 다음부터는 어떻게 해야 유저를 커버할 수 있을까요?
바로 가장 많이 몰리는 탑 페이지를 분산시켜야지요..
탑 페이지가 분산되더라도 결국 DB는 똑같이 읽지 않느냐?
하시겠죠?
맞습니다. 분산이 아니라 여기서 부터는 캐싱을 해야 합니다.
앞쪽에 CDN 사이트 캐시나 역 프록시를 이용하는 등의 캐싱하는 방법도 있지만,
전통 적인 방법이 가장 강력합니다.
탑 페이지에서 모든 유저에게 공통적인 게시판, 이벤트 등등의 데이터는 백그라운드에서 1분 마다 HTML화 시키고,
계정 별 변경되는 정보만 DB화를 해서 가져오면,
이미 위의 최적화 위에 이걸 하게 되므로, 동접 약 100만 까지는 커버 할 수 있습니다.
즉 유저가 직접 바라보는 것은 단순화된 HTML이지 DB는 최소한의 정보만 바라보게 되거든요..
그럼 100만이 넘으면?
여기서 부터 Sharding이 필요한데요..
이건 제가 한 것이 아니고 카카오팀이 애니팡 2000만명 커버할 때 사용했던 방법인데 듣고서 감탄했습니다.
그 동안 제대로 된 샤딩만을 생각했는데,
제대로 샤딩 알고리즘으로 최적화를 하게 되면, 비용과 알고리즘에 따른 복잡성 때문에 오히려 인프라 관리가 어려워 지는데,
게임 서비스의 특성상 빠른 유저 이탈 등에 맞추어 샤딩을 아주 단순화를 시켰더라구요..
그냥 서버 한대에 모든 기능을 때려 넣고 유저를 3만명으로 맞춥니다. 유저 3만명은 한 대에 들어갈 최대 동접 3천명일 때의 이야기 입니다. 서비스에 따라 맞추셔야지요..
그리고 그 서버 자체를 늘리고 유저번호는 30001~60000까지는 서버 2, .. 이렇게 3만명씩 잘라 넣습니다.
그렇게 단순화를 하고 나니 요즘같은 클라우드 시대에는 차라리 작은 스펙의 VM을 수평적으로 확장하고 데이터를 샤딩한 다음에 서비스가 길어지면서 유저가 빠져나가는 패턴을 보고 통합을 하는 방식을 쓰면
최고의 효율은 아니지만 가성비가 뛰어난 설계에서 개발, 운영이 편리한 샤딩이 되더라구요.
서로 다른 서버간의 유저의 소통은 중계 서버를 만들어서 그 중계서버가 중계를 하지요..
물론 샤딩 기법은 서비스의 특성마다 다르지만.. 단순화가 최고란 이야기를 하는 것입니다.
그 이후부터는 저도 샤딩의 고정관념을 벗어나서
이 방식을 개량한 단순샤딩을 많이 쓰고 있습니다.
원래 샤딩은 엄청나게 쌓이는 로그 같은 데이터를 쪼개서 성능 저하가 생기지 않으면서 대규모 데이터를 처리하도록 만든 것이지만, 역시 너무 고정관념만 가지고는 참신한 아이디어를 이길 수 없다는 것을 알았습니다.
이 이후는 몇천만 유저가 들어와서 견뎌내는 시스템을 저렴하게 만들 수 있게 되었지요..
예전에는 동접에 비례해서 비용이 늘었는데 말입니다.
그리고, 대규모 처리를 할 때
굳이 ALB나 ELB를 쓰시는 분이 계십니다.
Azure의 Front Door나 AWS의 Route 53, BIGIP의 F5 및 CDNetworks에서 사용하는 GLB는 모두 DNS기반의 로드밸런서 입니다.
DNS기반의 LB와 L4/L7기반의 LB시리즈는 결정적인 차이가 있습니다.
장비에 서비스용 트래픽이 오느냐 아니면 방향만 가리키고 트래픽은 안받느냐 입니다.
즉, L4/L7기반의 장비인 ELB, ALB등등은 장비에 트래픽이 오기 때문에 대규모 서비스에는 그 트래픽에 비례한 장비 비용이 발생합니다. 때문에 부하에 따른 가격 상승폭이 크지요..
하지만 Route53같은 DNS기반의 부하분산은 서버의 위치만 알려주고 실제 트래픽은 서버의 트래픽으로 직접 가기 때문에 부하분산장치가 저가형 리소스로도 충분해지기 때문에 비용이 적게 발생합니다. 수억회의 리퀘스트에도 단돈 몇 달러로 처리가 되지요.
제가 한국인의 기업 수십곳에 Route53을 쓰세요 하고 말했는데,
개발자 들이 한 명도 납득 못하고 그냥 ELB나 ALB를 쓰시더라구요..
결정적인 차이는 있습니다.
Route 53은 세션 관리가 안되기 때문에 별도 세션관리용 서버가 필요합니다.
하지만 ELB나 ALB역시 세션을 자기서버에서 관리한다면 Sticky가 되기 때문에 부하분산이 원활하게 되지 않지요.
때문에 결국 Route53에서도 쓰이는 Redis같은 메모리 저장장치가 필요하게 되지요..
ELB를 쓰면 단지 초기에 개발만 편합니다.
이 단지 초기에 개발만 편하기 때문에
제가 말한 대규모를 위한 설계에는 콧방귀를 뀌고 알아먹을 생각을 안하지요.
제가 이건 몇만 정도면 터지겠네요..
하고 빠져 나오면..
대 부분 그 정도에 터지면서 제게 어떻게 알았냐고 말씀하시는데..
그러니까.. 하루이틀 장사 해봤냐구요.. 무슨 무당이 근거 없는 예언한 줄 아시나봐요..
이렇게 대규모 처리를 시스템에서 코드까지 봐가면서 해보다보니,
남들이 못보는 부분이 보일 뿐인데..
좀 제 말을 들어주시는 한국분이 많아졌으면 좋겠다 싶은 생각에 제자랑을 또 하게 됬습니다.
댓글
댓글 쓰기