스파르타 Java 단기 심화 과정
코드카타
프로그래머스 136798 기사단원의 무기
https://school.programmers.co.kr/learn/courses/30/lessons/136798
— 문제 설명
숫자나라 기사단의 각 기사에게는 1번부터 number
까지 번호가 지정되어 있습니다. 기사들은 무기점에서 무기를 구매하려고 합니다.
각 기사는 자신의 기사 번호의 약수 개수에 해당하는 공격력을 가진 무기를 구매하려 합니다. 단, 이웃나라와의 협약에 의해 공격력의 제한수치를 정하고, 제한수치보다 큰 공격력을 가진 무기를 구매해야 하는 기사는 협약기관에서 정한 공격력을 가지는 무기를 구매해야 합니다.
예를 들어, 15번으로 지정된 기사단원은 15의 약수가 1, 3, 5, 15로 4개 이므로, 공격력이 4인 무기를 구매합니다. 만약, 이웃나라와의 협약으로 정해진 공격력의 제한수치가 3이고 제한수치를 초과한 기사가 사용할 무기의 공격력이 2라면, 15번으로 지정된 기사단원은 무기점에서 공격력이 2인 무기를 구매합니다. 무기를 만들 때, 무기의 공격력 1당 1kg의 철이 필요합니다. 그래서 무기점에서 무기를 모두 만들기 위해 필요한 철의 무게를 미리 계산하려 합니다.
기사단원의 수를 나타내는 정수 number
와 이웃나라와 협약으로 정해진 공격력의 제한수치를 나타내는 정수 limit
와 제한수치를 초과한 기사가 사용할 무기의 공격력을 나타내는 정수 power
가 주어졌을 때, 무기점의 주인이 무기를 모두 만들기 위해 필요한 철의 무게를 return 하는 solution 함수를 완성하시오.
— 제한 조건
- 1 ≤
number
≤ 100,000
- 2 ≤
limit
≤ 100
- 1 ≤
power
≤ limit
— 입출력 예
number | limit | power | result |
---|
5 | 3 | 2 | 10 |
10 | 3 | 2 | 21 |
입출력 예 #1
1부터 5까지의 약수의 개수는 순서대로 [1, 2, 2, 3, 2]개입니다. 모두 공격력 제한 수치인 3을 넘지 않기 때문에 필요한 철의 무게는 해당 수들의 합인 10이 됩니다. 따라서 10을 return 합니다.
입출력 예 #2
1부터 10까지의 약수의 개수는 순서대로 [1, 2, 2, 3, 2, 4, 2, 4, 3, 4]개입니다. 공격력의 제한수치가 3이기 때문에, 6, 8, 10번 기사는 공격력이 2인 무기를 구매합니다. 따라서 해당 수들의 합인 21을 return 합니다.
— 문제 풀이
class Solution {
public int solution(int number, int limit, int power) {
int answer = 1;
for(int i=2;i<=number;i++){
answer += cal(i, limit, power);
}
return answer;
}
public int cal(int num, int limit, int power){
int cnt = 2;
for(int i=2;i<=Math.sqrt(num);i++){
if(num%i==0){
if(i==Math.sqrt(num))cnt++;
else cnt += 2;
}
}
return (cnt > limit) ? power : cnt;
}
}
프로젝트 관리 - CI/CD와 AWS
CI/CD 란?
- CI ( Continuous Integration )
- 개발자가 변경한 코드를 자주 통합하고, 코드가 잘 작동하는지 자동으로 테스트하는 프로세스
- 코드 변경이 발생할 때마다 빌드 및 테스트를 수행하여 코드 품질을 유지하고 문제를 조기에 발견할 수 있게 함
- CD ( Continuous Delivery )
- CI의 결과물을 사용자에게 자동으로 배포하는 프로세스를 포함. 코드 변경이 통합되고 테스트를 통과하면, 이를 자동으로 스테이징 혹은 프로덕션 환경에 배포
- 지속적인 배포 ( Continuous Deployment ) 는 CI/CD의 확장 개념으로, 승인 절차 없이 자동으로 프로덕션 환경에 배포하는 것을 의미
CI/CD의 장단점
- 장점
- 빠른 피드백
- 코드 변경 후 즉각적인 빌드 및 테스트 결과를 확인할 수 있어, 개발자가 문제를 빠르게 인지하고 수정할 수 있음
- 자동화된 프로세스
- 빌드, 테스트, 배포 과정이 자동화되어 수동 작업을 줄이고, 인적 오류를 방지할 수 있음
- 일관된 배포
- 동일한 배포 프로세스를 통해 모든 환경(개발, 테스트, 스테이징, 프로덕션)에서 일관된 결과를 보장
- 높은 품질 유지
- 코드 품질을 지속적으로 검증하고, 잠재적인 문제를 조기에 발견하여 품질을 유지할 수 있음
- 개발 속도 향상
- 자동화된 파이프라인을 통해 개발 주기를 단축하고, 새로운 기능을 빠르게 사용자에게 제공할 수 있음
- 단점
- 비용 증가
- 개발자가 직접 배포하는 과정에 비해 CI/CD 환경을 따로 구축해야하기 때문에 비용이 발생할 수 있다
- 복잡성
- 초기 CI/CD 환경 구축을 위해 설정하는 과정이 복잡하며, 이후 지속적인 관리를 위한 노력이 필요
- GitHub Actions
- GitHub 저장소에 직접 통합되어 있는 CI/CD 도구로, YAML 파일을 사용하여 워크플로우를 정의할 수 있음
- 특징
- GitHub 저장소와의 강력한 통합
- 다양한 이벤트 기반 트리거
- 풍부한 커뮤니티 및 Marketplace 지원
- 무료 사용 가능 ( 제한된 런타임 제공 )
- Jenkins
- 오픈 소스 CI/CD Tool이며, 다양한 플러그인을 통해 기능을 확장할 수 있음
- 특징
- 많은 커스터마이징 가능
- 다양한 플러그인 지원
- 분산 빌드 및 다중 플랫폼 지원
- 대규모 프로젝트에 적합
Amazon ECS란?
- AWS Elastic Container Service는 docker app을 쉽게 배포하고 운영할 수 있도록 지원하는 완전관리형 Container Orchestration 서비스
- Kubernetes보다 사용하기 쉽고, 비용적으로도 저렴하기 때문에 소/중 규모의 프로젝트에 널리 사용
- Serverless로 구성할 수 있는데, 이렇게 하면 인스턴스(가상 서버)를 구성하고 관리할 필요 X
ECS의 구조
- 크게 ECR, ECS Cluster, ECS Service, ECS Task로 나누어져 있음
- ECR : Docker Image Repository
- ECS Cluster : 컨테이너를 실행하기 위한 Cluster로 여러 인스턴스로 이루어짐. 이 인스턴스에서 Docker Container가 분산 실행됨. Serverless로 할 경우에는 인스턴스도 필요 X
- ECS Service : Docker App의 실행 그룹
- ECS Task : ECS Server에 실제로 실행되는 docker container들을 Task라고 함
- 로드밸런서와, 모니터링, Auto Scailing 등의 요소도 있음.
CI/CD 실습
대규모 스트림 처리
대규모 시스템이란
- 인터넷 환경에서 수많은 사용자가 동시에 접속하고 상호작용할 수 있는 시스템
- 단순히 많은 사용자 처리하는 것뿐만 아니라, 안정성과 신뢰성을 유지하며 고성능을 제공해야함
동시 접속자와 초당 요청량(TPS)
- 사용자 수
- 대규모 시스템 설계할 때 가장 중요한 요소 중 하나
- 얼마나 많은 사용자가 시스템을 사용할 것인지 파악하는 것은 중요. 특히, 동시 접속자의 요청 수가 중요
- TPS ( Transactions Per Second )
- 초당 처리되는 트랜잭션의 수를 나타내는 지표. 시스템의 성능을 평가하는 중요한 지표중 하나, 대규모 시스템에서 중요한 역할을 함. 시스템이 얼마나 많은 요청을 동시에 처리할 수 있는지를 나타내며, 시스템의 처리 능력을 가늠할 수 있게 해줌
- 시스템이 초당 요청량(TPS)를 견딜 수 있어야 함
- 특정 시간대에 초당 접속자 요청량이 가장 많은 시간을 파악해야함. 이 정보는 시스템의 용량 계획을 세우는 데 매우 중요
- 예상치 못한 이벤트로 설계 예상 이상의 요청이 몰린다면 시스템이 중단될 수 있음
- 이러한 상황을 대비하기 위해 안정성을 높일 수 있는 다양한 방안을 마련해야 함
- App 수를 늘리는 방법
- 오류 상황에서 사용자가 대기할 수 있도록 대기열 설정하는 방법
- 오토 스케일링을 통해 시스템 자원을 동적으로 할당하여 부하를 분산하는 방법
요청 종류에 따른 최적화
- 데이터 제공 및 저장에서 가장 많은 시간을 소모하는 부분은 대부분 DB I/O기 때문에, 이 부분에서 최적화하는 것이 중요
- 읽기 요청 최적화
- 캐시 사용
- 모든 사용자가 같은 데이터를 요청하는 경우, 이를 레디스같은 인메모리 DB에 캐시로 올려두면 요청에 대한 응답 속도를 빠르게 할 수 있음
- 개인 데이터가 아니라면 캐시를 사용하여 데이터 로드에 시간 소요를 최소화 하는 방법이 중요
- 일반 DB에서 필터된 데이터를 가져오는 것보다 캐시에서 필터된 데이터를 가져오거나 App 로직에서 필터링 수행하는 것이 더 큰 성능상의 이점을 가짐
- 엣지 단에서 캐싱을 처리하면 적은 수의 App으로도 요청을 처리할 수 있음. 엣지 캐싱은 사용자와 가까운 곳에서 데이터를 제공하므로 네트워크 지연을 최소화하고, 사용자 경험을 향상시킬 수 있음
- 데이터 소실의 위험을 줄이기 위해 데이터의 유효성을 지속적으로 검증하고, 데이터가 손실되지 않았는지 확인해야 함. 또한, 캐시 계층에서 데이터 소실 시 재요청을 통해 DB에서 데이터를 다시 가져올 수 있게 해야함
- DB 사용 최적화
- DB 인덱싱
- 조회 성능을 크게 향상시킬 수 있는 방법. 읽기 성능을 최적화하고 쿼리 응답 시간을 줄임. 인덱스가 너무 많으면 쓰기 성능이 저하될 수 있으므로 주의 필요
- DB 샤딩( Sharding )
- DB를 여러 샤드로 분할하여 각각의 샤드가 독립적으로 쿼리를 처리하도록 하는 방법. 단일 DB에 대한 부하를 분산시킬 수 있으며, 읽기 요청에 대한 응답 속도를 향상시킬 수 있음
- 읽기 전용 DB
- 주로 읽기 요청을 처리하는 DB 인스턴스. 데이터를 주기적으로 동기화하여 최신 상태를 유지하며 읽기 요청을 처리.
- 쿼리 최적화
- SQL 쿼리를 효율적으로 작성하여 DB 읽기 성능을 향상시키는 방법.
- ex) 불필요한 조인 줄이고, 필요한 컬럼만 선택하며, 적절한 조건을 사용하는 쿼리
- 쿼리 실행 계획을 분석하여 병목 지점을 찾아내고 최적화
- 쓰기 요청 최적화
- 쓰기에서 가장 많은 시간을 소요하는 부분은 DB에서 데이터를 생성하는 부분. 이를 해결하기 위한 다양한 방법이 있음
- 비동기 처리
- 쓰기 요청을 비동기 방식으로 처리하면 DB에 직접 접근하지 않고 빠르게 응답 반환 가능
- 높은 트래픽을 처리할 때 유용
- 데이터 소실이나 오류를 방지하기 위해 큐에 데이터를 넣을 때 적절한 검증을 수행하고, 큐에 쌓인 데이터를 지속적으로 모니터링하여 실패한 요청을 재시도할 수 있는 매커니즘 마련 필요
- 데이터 순서를 보장하고, 중복 처리를 방지하기 위한 고유 식별자(ID) 사용해야 함
- 배치 처리
- 실시간으로 처리할 필요가 없는 쓰기 요청은 배치 처리를 통해 한꺼번에 처리할 수 있음
- ex) 일정 시간마다 큐에 쌓인 메시지 DB에 쓰는 방법
- 실시간 처리 부담을 줄이고, 시스템 자원을 효율적으로 사용할 수 있음
- 데이터 소실 방지를 위해 배치 작업 중 오류가 발생한 경우, 이를 기록하고 재시도할 수 있는 매커니즘 마련 필요
- 배치 작업의 상태를 모니터링하고, 배치 작업이 완료되었는지 확인하는 프로세스 마련 필요
- 분산 DB
- 단일 DB로 모든 요청 처리가 힘들다면, 분산 DB를 사용해서 부하를 분산하는 방법이 있음
- 데이터를 여러 개의 노드에 분산 저장하여 고가용성과 확장성을 제공
- 샤딩 기법을 통해 DB를 수평으로 분할하여 각 샤드가 독립적으로 쓰기 작업을 처리하도록 할 수 있음. 이를 통해 단일 노드의 부하를 줄이고, 시스템 전체 성능을 향상시킬 수 있음
- 데이터 일관성을 유지하기 위해 트랜잭션 관리와 데이터 동기화에 신경 써야 함.
- ex) 분산 트랜잭션, 이벤트 소싱 등을 통해 일관성 유지