Today I Learned
대규모 시스템을 알아보고, 데이터 베이스 최적화와 데이터 일관성 유지에 대하여 공부하자!!
스포❗ - 내용이 길지만 어려운 내용은 없습니다ㅎ.. 맘 편히 읽어도 될 거 같아요 👏
[ 대규모 시스템 ]
- 인터넷 환경에서는 수백만 명의 사용자가 동시에 접속하고 상호작용할 수 있는 시스템을 구축해야 하는 상황이 자주 발생합니다.
- 이러한 시스템은 단순히 많은 사용자를 처리하는 것뿐만 아니라, 안정성과 신뢰성을 유지하면서 고성능을 제공해야 합니다.
[ 스케일 업 / 스케일 아웃 ]
- 스케일 업(scale up): 수직적 규모 확장은 서버에 고사양 자원(더 좋은 CPU, 더 많은 RAM)을 추가하는 것을 뜻합니다.
- 스케일 아웃(scale out): 수평적 규모 확장은 더 많은 서버를 추가하여 성능을 개선하는 행위를 뜻합니다.
서버로 유입되는 트래픽의 양이 적을 때는 수직적 확장이 좋은 선택이며, 이 방법의 가장 큰 장점은 단순함이다. 그러나 스케일 업에는 심각한 단점이 존재하며, 수직적 규모 확장의 단점으로 인하여 대규모 애플리케이션을 지원하는 경우는 수평적 규모 확장이 보다 적절하다.
[ 동시 접속자 ]
- 대규모 시스템을 설계할 때 가장 중요한 요소 중 하나는 사용자 수입니다.
- 얼마나 많은 사용자가 시스템을 사용할 것인지 파악하는 것이 중요합니다.
- 더욱 중요한 것은 동시 접속자의 요청 수입니다.
[ TPS ]
TPS (Transactions Per Second)는 초당 처리되는 트랜잭션의 수를 나타내는 지표입니다. 이는 시스템의 성능을 평가하는 중요한 지표 중 하나로, 특히 대규모 시스템에서 중요한 역할을 합니다. TPS는 시스템이 얼마나 많은 요청을 동시에 처리할 수 있는지를 나타내며, 시스템의 처리 능력을 가늠할 수 있게 해줍니다.
- 시스템이 초당 요청량(TPS) 을 견딜 수 있어야 합니다.
- 이를 위해서는 일간 접속량이 아닌, 특정 시간대에 초당 접속자 요청량이 가장 많은 시간을 파악해야 합니다. 이 정보는 시스템의 용량 계획을 세우는 데 매우 중요합니다.
- 시스템이 예상치 못한 최대 부하를 견딜 수 있도록 하는 것이 중요합니다.
- 시스템이 예기치 않은 트래픽 급증에도 견딜 수 있는 여유 공간을 제공할 수 있어야 합니다.
- 예상치 못한 이벤트로 인해 설계 예상 이상의 요청이 몰린다면 시스템이 중단될 수 있습니다.
- 애플리케이션의 수를 늘려 이를 방지.
- 오류 상황에서 사용자가 대기할 수 있도록 대기열을 설정.
- 자동 스케일링을 통해 시스템의 자원을 동적으로 할당하여 부하를 분산.
[ 요청 종류에 따른 개발 ]
시스템이 읽기 전용인지, 쓰기 및 업데이트를 위한 것인지도 중요합니다. 이를 파악하고 처리 속도를 빠르게 하여 응답한다면 보다 많은 사용자를 수용할 수 있습니다.
- 데이터 제공 및 저장에서 가장 많은 시간을 소모하는 부분은 대부분 DB에서 데이터를 조회하거나 쓰는 것입니다.
- 요청 종류에 따라 이 부분의 허들을 최소화하는 것이 중요합니다.
[ 읽기 요청 최적화 ]
캐시를 사용하자!
- 모든 사용자가 같은 데이터를 요청하는 경우(ex. 공지사항), 이를 해소하기 위해 DB의 데이터를 레디스 같은 캐시에 올려두면 요청에 대한 응답 속도를 빠르게 할 수 있습니다.
- 캐시를 사용하면 데이터를 빠르게 제공할 수 있으며, DB의 부하를 줄일 수 있습니다.
레디스 캐시를 사용할때 무엇을 조심해야 할까? 🤔
- 데이터 소실의 위험을 줄이기 위해 데이터의 유효성을 지속적으로 검증하고, 데이터가 손실되지 않았는지 확인해야 합니다.
- 캐시 계층에서 데이터 소실 시 재요청을 통해 데이터베이스에서 데이터를 다시 가져올 수 있도록 해야 합니다.
[ 데이터 베이스 사용 최적화 ]
- 데이터베이스 인덱싱
- 데이터베이스에서 데이터를 더 빠르고 효율적으로 검색하기 위해 사용하는 기술입니다.
- 조회 성능(검색 속도)을 크게 향상시킬 수 있는 방법입니다.
- 주의: 인덱스가 너무 많으면 쓰기 성능이 저하될 수 있다는 것입니다.
- 데이터베이스 샤딩
- 데이터베이스를 여러 샤드로 분할하여 각각의 샤드가 독립적으로 쿼리를 처리하도록 하는 방법입니다.
- 각 분할된 작은 데이터베이스를 "샤드(Shard)"라고 부릅니다.
- 이를 통해 단일 데이터베이스에 대한 부하를 분산시킬 수 있으며, 읽기 요청에 대한 응답 속도를 향상시킬 수 있습니다.
- ex) 사용자의 데이터를 여러 샤드에 분산 저장하여 읽기 성능을 최적화할 수 있습니다.
- 정리: 확장성과 성능향상, 부하분산의 이점을 얻을 수 있다
- 읽기 전용 데이터베이스
- 주로 읽기 요청을 처리하는 데이터베이스 인스턴스입니다.
- 데이터를 주기적으로 동기화하여 최신 상태를 유지하면서 읽기 요청을 처리합니다.
- 이 방법은 주 데이터베이스에 대한 읽기 부하를 줄이고 성능을 최적화할 수 있습니다.
- 쿼리 최적화
- SQL 쿼리를 효율적으로 작성하여 데이터베이스의 읽기 성능을 향상시키는 방법입니다.
- ex) 불필요한 조인을 줄이고, 필요한 컬럼만 선택하며, 적절한 조건을 사용하는 것이 중요합니다.
- 쿼리 실행 계획을 분석하여 병목 지점을 찾아내고, 이를 최적화할 수 있습니다.
[ 쓰기 요청 최적화 ]
쓰기에서 가장 많은 시간을 소요하는 부분은 DB에 데이터를 생성하는 부분입니다.
이를 해결하기 위한 다양한 방법이 있습니다.
- 비동기 처리
- 작업을 수행할 때, 작업의 완료를 기다리지 않고 다음 작업을 진행할 수 있도록 하는 프로그래밍 방식입니다.
- 쓰기 요청을 비동기 방식으로 처리하면 DB에 직접 접근하지 않고도 빠르게 응답을 반환할 수 있습니다.
- ex) 메시지를 바로 DB에 쓰지 않고, 큐에 넣어 나중에 처리하는 방법이 있습니다.
- 비동기 처리는 특히 높은 트래픽을 처리할 때 유용합니다
- 배치 처리
- 실시간으로 처리할 필요가 없는 쓰기 요청은 배치 처리를 통해 한꺼번에 처리할 수 있습니다.
- ex) 특정시간에 하루 동안 수집된 로그 데이터를 한 번에 DB에 저장하는 방식으로 사용할 수 있습니다.
- 분산 DB
- 단일 DB로 모든 쓰기 요청을 처리하기 어렵다면, 분산 DB를 사용하여 부하를 분산시킬 수 있습니다.
- ex) 여러 개의 DB 인스턴스를 사용하여 각 인스턴스가 특정 사용자 그룹의 데이터를 처리하도록 할 수 있습니다.
분산 DB 사용 시 데이터 일관성을 유지하기 위해 트랜잭션 관리와 데이터 동기화에 신경 써야 합니다.
분산 트랜잭션이나 이벤트 소싱을 사용하여 데이터 일관성을 유지할 수 있습니다.
[ 데이터 일관성 유지 ]
대규모 시스템에서는 데이터 일관성을 유지하는 것이 중요합니다.
이를 위해 분산 트랜잭션, 이벤트 소싱, CQRS 등의 기법을 사용할 수 있습니다.
- 분산 트랜잭션
- 여러 분산된 데이터 소스에 걸쳐 트랜잭션을 수행하는 작업입니다.
- ex) 여러 마이크로서비스나 데이터베이스에서 데이터를 동시에 업데이트하는 경우가 이에 해당합니다.
분산 트랜잭션이 필요한 이유는 마이크로서비스 아키텍처에서 여러 서비스가 독립적으로 운영되기 때문입니다.
- 분산 트랜잭션의 장점
- 데이터 일관성 보장
- 분산된 여러 데이터 소스에 걸쳐 일관된 데이터 상태를 유지할 수 있습니다. 모든 트랜잭션이 성공적으로 완료되거나 모두 실패하도록 보장합니다.
- 확장성
- 분산 트랜잭션을 통해 여러 시스템이 독립적으로 동작하면서도, 필요한 경우 협력하여 일관된 상태를 유지할 수 있습니다. 이를 통해 시스템의 확장성을 높일 수 있습니다.
- 복구 가능성
- 트랜잭션 실패 시 롤백 메커니즘을 통해 상태를 복구할 수 있어, 시스템 안정성을 높일 수 있습니다.
- 데이터 일관성 보장
- 분산 트랜잭션의 단점
- 복잡성 증가
- 분산 트랜잭션을 구현하고 관리하는 것은 복잡합니다. 특히, 여러 시스템 간의 트랜잭션 동기화와 데이터 일관성을 유지하는 것은 어려운 작업입니다.
- 성능 저하
- 2PC와 같은 프로토콜을 사용할 경우, 트랜잭션의 준비와 커밋 단계에서 지연이 발생할 수 있습니다. 이는 시스템의 성능을 저하시킬 수 있습니다.
- 복구의 어려움
- 분산 트랜잭션 실패 시, 모든 시스템에서 일관된 상태로 롤백하는 것이 어려울 수 있습니다. 특히, 부분적으로 실패한 트랜잭션을 처리하는 데 어려움이 있을 수 있습니다.
- 복잡성 증가
- 2PC (Two-Phase Commit)
- 준비 단계(Prepare Phase): 각 참여 노드는 트랜잭션 준비 상태를 확인하고, 준비 완료를 마스터 노드에 알립니다.
- 커밋 단계(Commit Phase): 마스터 노드는 모든 참여 노드가 준비되었음을 확인하고, 트랜잭션을 커밋하도록 지시합니다. 만약 준비가 완료되지 않은 노드가 있다면 트랜잭션을 롤백합니다.
- 이벤트 소싱
- 상태 변화를 이벤트로 기록하고, 해당 이벤트를 재생하여 현재 상태를 유지합니다. 이를 통해 분산 트랜잭션의 일관성을 유지할 수 있습니다.
나름 요약해서 작성을 했다고 생각했지만 내용이 상당히 길어졌다. 어려운 내용보다는 대규모 스트림 처리에 있어서 어쩌면 당연한 얘기들인 것 같다. 오늘은 이론에 대해서 공부를 했는데, 이론을 공부할수록 재밌어 보여서 빨리 사용하고 실습해 보고 싶다는 생각이 든다. 🧑💻
읽어주셔서 감사합니다 😊
'해피 코딩 > Today I Learned' 카테고리의 다른 글
[TIL 12] RabbitMQ 이론 정복하기 (0) | 2024.08.16 |
---|---|
[TIL 11] Chater 1. 과제와 피드백 내용 (0) | 2024.08.15 |
[TIL 9] 캐싱 개념과 캐싱 전략 이해하기 (0) | 2024.08.12 |
[TIL 8] @ManyToOne, @OneToMany 정복하기 (1) | 2024.08.10 |
[TIL 7] 부족한 부분 채워 나가기 (0) | 2024.08.08 |