본문 바로가기
Infra

시스템 확장에 대해 생각해보기

by yzzzzun 2021. 9. 3.

  지금까지 회사 업무를 하면서 대규모 트래픽에 대한 확장성에 대해 경험할 일이 없다 보니 부족함을 많이 느끼고 있었는데요. 그래서 이번 기회에 우아한 테크 캠프, 강의, 책 등 다양한 루트로 얻게 된 정보들을 바탕으로 시스템의 확장에 대해 생각해보고 알아야 할 것들에 대해 큰 틀에서 정리해보려 합니다 🤔

 단일 서버 구조를 개선하는 과정

단일 서버 구조

  단일 서버 구조로 사용자 요청에 대해 하나의 서버로 처리되고 있는 상태가 가장 기초적인 구성 방식인데요. 서비스가 성장해 Client에서 요청하는 수가 증가한다고 생각해봅시다. 하나의 서버가 더 많은 일을 처리해야 하는 상황이 생기겠죠. 그러면 서버의 몸집을 키우던 수를 늘리던 선택하게 됩니다.

Scale-up vs Scale-out

  수직적으로 규모를 확장할지 수평적으로 규모를 확장할지 선택하게 되는데요. Scale-up은 CPU나 RAM을 추가해서 성능을 업그레이드하는 겁니다. 그러면 좋아진 성능만큼 잘 처리하겠죠. Scale-out은 수평적인 확장인데요. 서버를 여러 개로 추가해서 일을 나눠서 할 수 있게 합니다.

  Scale-up은 무한정 리소스를 늘릴 수 없다는 단점이 있구요. 결과적으로 단일 서버가 유지되면 SPOF(Single Point of Failure)가 생겨 시스템 운영시 치명적일 수 있습니다. 그래서 대규모 애플리케이션에는 Scale-out이 적절합니다.

  Scale-out을 위해 Loadbalancer를 적용해 트래픽을 고르게 분산시킬 수 있고, 여러 애플리케이션 중 하나가 장애가 발생하더라도 나머지 worker instance들이 트래픽을 처리할 수 있습니다.

Scale-out

DB I/O 는 괜찮은가?

  각 worker instance들이 열심히 트래픽을 처리하다보면 DB에 I/O트래픽이 많아져 결국 DB계층에도 부하가 발생할 수 있는데요. 그러면 각 서버가 DB를 개별적으로 가지는 구조는 어떨까요?

DB를 각각 구성하여 부하를 줄이는 설계는 어떨까

  이건 결과적으로 DB가 데이터를 다르게 가지고있어 정합성이 깨지는 치명적인 문제가 발생합니다. 그러면 DB의 부하는 어떻게 처리해야 할까요??

Replication(Master-Slave)

  DB를 Master와 Slave로 구성하고, Master에서는 write작업을 Slave에서는 Read작업을 담당하도록 하여 부하를 분산할 수 있습니다. Master에서 Write를 하면 로그에 기록했다가 Slave에 로그를 전달해 데이터를 추가하게 됩니다.

Replication

  이렇게 Master-Slave로 구성하게 되면 부하를 분산할 수 있고, 둘 중 하나가 장애가 발생하더라도 서비스 운영에는 문제가 없습니다. 그렇지만 약간의 문제점들은 있는데요. Master에서 Write를 하고 Slave로 로그를 전달하는 과정에 Slave가 멈춘다면 데이터가 유실될 수 있고, 데이터가 일치하지 않는 상황들이 발생할 수 있습니다.

  지금까지 시스템 확장의 중요한 기준은 SPOF라는 생각이 들었습니다. 하나인 경우 결국 장애가 발생하면 시스템에 문제가 발생하게 된다는 점을 기억하고 다중화해야 한다는 걸 기억하면 좋을 것 같습니다.

Latency의 개선

  어느정도 안정적인 시스템 환경을 구축한 것 같지만 부하가 발생하면 Latency가 튀는 부분들이 생기게 됩니다.

웹 계층에서 Latency가 발생할 수 있고, DB I/O에서 병목이 생겨 Latency가 발생할 수 있는데요. WebPageTest, PageSpeed 같은 도구들을 통해 웹 성능을 테스트하고, K6나 Artilery 등 Stress Test 도구를 통해 부하 테스트를 진행해보면 어느 수준부터 병목이 생기는지 확인하고 개선할 수 있습니다. 지연시간에 대해서는 데이터를 Cache 하고 필요할 때 빠르게 가져올 수 있도록 하면 개선이 가능합니다.

각 계층마다 Cache를 적용

Cache 적용하기

  우선 Latency는 캐시를 통해서 개선이 가능합니다. Cache는 자주 참조되는 값을 메모리에 두고 빠르게 처리될 수 있도록 하는 저장소입니다. 캐시를 사용할때는 어떤 상황에서 캐시를 할지, 만료시간, 일관성이 유지되는지, 메모리의 크기, 데이터 방출(Eviction)에 대해 고려하고 사용해야 합니다. 주로 자주 Read 하지만 변경이 적은 데이터에 대해 캐시를 하게 되고 각 상황에 맞게 고려해서 캐시를 설정합니다. 어떤 계층을 캐시 하던 해당 사항들을 고려하게 될 겁니다.

  웹 계층의 경우 정적 파일들, 이미지, 비디오, CSS, JS 파일 등을 CDN에 캐시 해서 서버로 접근하는 트래픽을 줄여주고, DB에 접근하는 트래픽은 메모리 캐시를 통해서 부하를 줄이고 Latency를 개선할 수 있습니다.

Data 계층의 확장

  DB에 부하가 더 늘어나면 DB를 확장해야 하는데요. DB Sharding을 통해 수평적으로 규모를 확장하게 됩니다. 샤딩은 키값에 따라 여러 DB로 분산해서 데이터를 저장하기 때문에 부하를 줄일 수 있습니다.

DB Sharding

하지만 샤딩을 통해 추가적으로 해결해야할 문제들이 발생할 수 있는데요. 샤딩한 DB가 똑같이 데이터가 많아져 다시 샤딩을 해야 하는 재 샤딩 문제, 특정 ID에 대한 쿼리가 집중되는 유명인사(핫스팟 키) 문제, 샤딩된 테이블을 조인할 때 어려움들이 발생할 수 있습니다.

Data의 무손실

  데이터가 유실되면 안 된다고 하면 MQ의 도입을 고려해야 합니다. Message Queue가 메시지의 무손실을 보장하는 비동기 통신 컴포넌트인데요. 별도의 큐에 저장되어있어 장애가 나더라도 큐에 데이터가 쌓여있어 유실되지 않습니다. MQ를 적용하면 서버 간 결합을 약하게 가져갈 수 있어 안정적인 확장을 도모할 수 있습니다.

대규모 시스템 구성

  부가적으로 MQ를 통해 로그, 메트릭 정보, 자동화를 위한 장치를 추가할 수 있습니다. 시스템이 커질수록 로그와, 메트릭 정보들, CI, CD의 자동화를 통해 생산성과 비즈니스 성장에 도움이 되는 시스템을 구성할 수 있습니다.

메트릭은 호스트 단위, 종합, 핵심 비즈니스 메트릭이 있습니다.
호스트 단위 메트릭 : CPU, 메모리, 디스크 I/O 등
종합 메트릭 : DB계층 성능, 캐시 성능
핵심 비즈니스 메트릭 : Daily Active User(일별 능동 사용자), 수익, 재방문 등

Wrap-up

  대규모 애플리케이션을 위한 시스템 구성에서 성능도 중요하지만 가장 우선적으로 고려해야 할 내용은 SPOF라는 생각이 들었는데요. 결국 실패 지점에서 장애가 발생해 서비스가 중단되면 그것보다 치명적인 건 없을 테니까요. 결국 모든 계층들은 다중화라는 작업을 거쳐야 하고 어떻게 해야 트래픽을 줄여줄 수 있을지에 대한 고민들, 데이터를 유실하지 않을 방법들, Latency를 줄이는 방법들, 서비스를 운영하는데 도움이 될 정보 수집들을 고려한다면 대규모 애플리케이션 시스템 구성을 이해하는데 도움이 될 거라 생각합니다.

Reference..
가상 면접 사례로 배우는 대규모 시스템 설계 기초 - 인사이트

 

댓글