Back-End

대규모 시스템을 설계하기 전에 고려해봐야 할 것들

stars_one 2025. 3. 12. 23:19

 

대규모 시스템을 설계하기 전에는 어떤 것들을 고려해봐야 할까?

 

먼저 사용자수를 생각해봐야 할 것 같다.

 

대규모 시스템은 말그대로 많은 사용자들이 사용하는 시스템이니

사용자 수를 고려한 설계가 필요할 것이다.

 

우리는 모니터링을 통해서 하루에 몇명의 사용자들이 우리 서비스를 사용하는지 알 수 있다.

하지만 단순하게 하루 사용자수만 파악하는 것으로는 충분하지 않을 것 같다

 

하루 사용자 수가 아니라 우리는

동시 접속자에 포커스를 맞출 필요가 있다.

 

 


 

TPS를 고려하자

 

TPS는 초당 처리되는 트랜잭션의 수를 말한다

(Transaction Per Second)

 

얼마나 많은 요청을 동시에 처리할 수 있는 지를 확실히 알 수 있는 지표이기도 하다

 

그래서 우리는 특정 시간대에 초당 접속자 요청량이 가장 많은 시간대를 먼저 파악해야한다.

 

그 시간대가 하루 중 가장 많은 요청량이 몰리면

그 요청량의 1.5배 정도를 처리할 수 있도록 여유롭게 설계해주면

시스템이 예상치 못한 트래픽 급증에도 버틸 수 있을 것이다

 

예를들어 오전 10시에 초당 200건의 요청이 들어왔고,

하루 중 가장 많은 요청이 들어왔다고 가정한다면,

1.5배인 300건을 처리할 수 있도록 설계해주면 될 것이다.

 

물론 이는, 예시를 들어서 설명한 것이므로

충분한 기간을 설정하고 모니터링을 해야됨은 물론,

1.5배로 설정한 것도 예시에 불과하다.

 


 

읽기 요청 최적화

 

우리는 보통 쓰기/읽기 요청을 많이 보내는데,

 

해당 시스템이 쓰기 전용인지, 읽기 전용인지 파악하고 가는 것이 중요하다.

 

먼저 읽기 요청부터 생각해보자.

우리는 보통 캐시를 많이 사용한다.

 

모든 사용자가 같은 데이터를 요청하는 경우,

레디스의 캐싱전략을 사용하여 해당 데이터를 캐싱 해두면

 

데이터 조회도 상당히 빠르고, DB의 부하도 줄일 수 있다.

 

 

데이터 하나를 DB에서 조회하는데 걸리는 평균 응답 속도는 18~25ms 이다.

하지만 캐싱을 사용하면 평균 응답 속도는 8~10ms를 기록한다.

 

그래서 우리는 캐시를 사용하는 것이다.

 

데이터 하나만 조회해서 그렇지,

수많은 데이터를 조회할때는 어떨까?

캐싱전략은 미친 효율을 보여준다.

(물론, 캐시 갱신, 손실 방지 정책 등등 고려할 것이 많은 것이 함정이다)

 

캐싱 뿐만 아니라,

 

데이터 베이스 인덱싱 : 인덱스를 설계하여 읽기 성능을 최적화, 쿼리응답 시간 감소

데이터베이스 샤딩 : 데이터베이스를 여러 샤드로 분할하여 각각의 샤드가 독립적으로 쿼리를 처리하도록 하는 방법,

이를 통해 단일 데이터베이스에 대한 부하 분산이 가능하고 읽기 요청에 대한 응답속도를 향상시킬 수 있다.

읽기 전용데이터 베이스 만들기, 쿼리 최적화 등등이 있을 수 있다.

 

데이터 베이스의 수준에서 데이터를 분할해줄 수 있다. 

CREATE TABLE orders (
  order_id SERIAL PRIMARY KEY,
  customer_id INT,
  order_date DATE,
  amount DECIMAL
) PARTITION BY RANGE (order_date);

CREATE TABLE orders_2023_01 PARTITION OF orders FOR VALUES FROM ('2023-01-01') TO ('2023-02-01');
CREATE TABLE orders_2023_02 PARTITION OF orders FOR VALUES FROM ('2023-02-01') TO ('2023-03-01');

 

 

 


 

쓰기 요청 최적화

 

쓰기 요청에서 가장 많은 시간을 소요하는 것은 DB에 데이터를 생성하는 것이다

 

이 시간을 줄이기 위한 방법이 몇가지 있다.

 

비동기 처리 : 쓰기 요청을 비동기 방식으로 처리한다는 것은, 바로 DB에 데이터를 생성하지 않고,

큐에 넣어놓고 나중에 처리하는 방식이다. 데이터를 어느정도 쌓아두고 시간텀을 주어서 DB에 쓰기 요청을 보내는 것이다

 

배치 처리 : 굳이 실시간으로 처리할 필요가 없는 애들을 모아뒀다가 배치 처리를 통해서 한번에 처리하는 것이다

예를 들어 사용자들이 잘 접속하지 않는 자정에 하루동안 수집된 데이터들을 한번에 DB에 넣어주는 것이다

이렇게 되면 실시간 처리의 부담도 줄일 수 있어서 좋다

 

분산 DB : 단일 DB로 모든 쓰기 요청을 처리하기 어려우면 분산 DB를 사용하여 부하를 분산시킬 수 있다.

가령, 여러개의 DB인스턴스를 사용해서 각 인스턴스가 특정 사용자 그룹의 데이터를 처리할 수 있도록 할 수 있다.

 


 

데이터 일관성 유지

 

대규모 시스템에서는 데이터 일관성을 유지하는 것이 중요하다.

이를 위해 분산 트랜잭션, 이벤트 소싱, CQRS를 사용할 수 있다.

 

 

분산 트랜잭션 : 여러 시스템에 걸쳐서 트랜잭션이 발생하면, 모든 시스템이 해당 트랜잭션을 성공적으로 완료하거나,

모두 실패로 처리하도록 하는 것이다. 분산 트랜잭션이 필요한 이유는 MSA에서 여러 서비스가 독립적으로 운영되기 때문이다.

 

이벤트 소싱 : 데이터 상태변화를 이벤트로 기록하고, 해당 이벤트들을 순차적으로 재생하여 현재 상태를 파악하는 방법이다.

데이터 변경 자체가 아닌, 변경 이벤트를 저장한다

 

CQRS : 명령(Query)와 조회(Query)의 책임을 분리하는 디자인 패턴이다

읽기와 쓰기 작업을 서로 다른 모델로 분리하여, 각 작업에 최적화된 구조를 사용할 수 있도록 한다.

 


 

모니터링 로깅

 

대규모 시스템을 설계하고 개발하는 만큼, 모니터링과 로깅은 필수적으로 고려하자

 

시스템의 상태를 실시간으로 파악하고, 문제 발생 시 신속하게 대응할 수 있다.

 

어플리케이션, DB, 캐시 등 각 컴포넌트의 성능을 모니터링 하는데

보통 프로메테우스나 그라파나와 같은 도구를 사용한다

TPS, 응답시간, 에러율 등을 모니터링하고, 이상징후를 감지하면 알림까지 보내준다!

 

또한 우리는 로그도 계속 체크해야하는데,

Elasticsearch, Logstash, Kibana(ELK스택) 등을 사용하여 수집,저장,분석할 수 있다.

 

로깅은 시스템의 모든 중요한 이벤트를 기록하므로, 문제 발생 시 정확한 원인을 파악하는 데 큰 도움이 되니깐 반드시 하자!

728x90