이번엔 지금 운영하고 있는 서비스를 한번 개선해보고자 간단하게 혼자서 공부할겸 건드려본다!
현재 서비스 구조
Client → CloudFront → S3 (정적 파일) → ALB → EC2(server1~3)
서비스 | 위치(EC2) | 특징 |
webapp | server2, server3 | 타임리프 + Spring Boot (정적 파일 포함) |
admin | server1 | 타임리프 + Spring Boot (정적 파일 포함) |
data | server1, 2, 3 | REST API 서비스(SpringBoot) |
recommand | server2, server3 | 캐싱(ehCache) |
batch | server1 | Spring 스케줄러 기반 통계 배치. |
channel | server2, server3 | 채팅 웹소켓 + RabbitMQ |
대략 간단하게 이런 구조로 되어있다.
✓ 문제점
1. 비용 비효율
- 여러 EC2 인스턴스에서 개별적으로 운영중
- 유휴 리소스가 발생하거나 고정된 인스턴스 크기로 인해 비효율 발셍
2. 관리부담
- 각 WAS 에 여러 서비스가 혼잡/배포되어있어 관리가 복잡함(JAR 패키지로 각 EC2에 수동 배포.)
- 트래픽 증가시 확장이 어려움(특히 특정서비스.. 실제로 그래서 행사때 매번 일일이 ec2를 확장시켜서 진행한다.. 비용 눈물 ㅠㅠ)
3. 고립성부족
- 서로 다른 성격의 서비스(admin,batch) 가 동일한 인스턴스에서 실행
- 모놀리식에 가까운 배치작업
4. 캐싱 및 메시징 관리 문제
- ehCache와 RabbitMQ가 EC2에서 관리되며, 고가용성 및 확장성 제한.
✓ 리팩토링 방향
리팩토링 목표
- 컨테이너화: 모든 서비스(Docker 컨테이너)로 전환.
- 관리형 서비스 활용: RabbitMQ, 캐싱, 배치 작업 등 AWS 관리형 서비스로 이전.
- 확장성: 트래픽 증가에 따라 서비스별로 독립적으로 확장 가능.
- 배포 자동화: CI/CD 파이프라인을 통해 효율적인 배포와 업데이트.
1. 서비스 컨테이너화
현재 상황
각 서비스가 Spring Boot JAR로 배포되어 EC2에서 실행.
개선 방향
☑️ Docker 컨테이너로 전환:
- 각 서비스를 Docker 이미지로 변환
- Dockerfile 작성
☑️ ECS(Fargate) 또는 EKS(Kubernetes)로 관리
- ECS(Fargate) : 서버 관리없이 컨테이너 실행, 서비스별로 독립실행 및 확장가능
- EKS(Kubernetes) : 복잡한 배포 및 확장시 유리
2. 서비스별 리팩토링
☑️ webapp , admin
- 타임리프를 제거하고, 프론트엔드는 Nuxt.js 와 같은 SPA/SSR 프레임워크로 전환.
- 정적 리소스(CSS, JS, 이미지)를 S3로 이전.
- CloudFront와 S3를 연동해 전송 속도 최적화(CDN)
Client → CloudFront (정적 파일) → ALB → nuxtJS → Spring Boot API → Aurora DB
☑️ 문자발송 서비스
- 비동기로 처리
- RabbitMQ 또는 Amazon SQS를 사용해 메시지를 큐에 저장.
- 문자 발송 프로세스를 Lambda로 처리.
- Aws Lambda : 무료 사용량 (월 100만 요청, 40만 GB-초 실행)으로 소규모 배치 작업에서는 매우 저렴.
- 짧은 작업(15분 이하)에 최적화
- 실행 시간만큼만 과금
☑️ data(API 서비스)
- Docker 컨테이너화
- ECR(Amazon Elastic Container Registry) 또는 Docker Hub에 이미지 업로드
- ClaudWatch 기반 Auto Scaling
☑️ recommand(ehCache)
- ElastiCache(Redis)로 전환
- ehCache 대신 네트워크 기반 캐싱.
- 다수의 서비스에서 공유 가능하며, 성능과 확장성이 뛰어남.
☑️ batch
- AWS Lambda -> 간단히 작업이 아니기에 적합하지 않음.
- Apache Airflow -> 복잡한 워크플로 관리에 용이, 장기 실행 작업가능, 하지만 비쌈
- EC2 기반 스프링 스케쥴러 -> 기존코드로 사용가능, 컨테이너화만 하면 가능.
☑️ channel(채팅 서비스)
이건 그대로 WebSocket서버와 RabbitMQ 그대로 EC2에서 두면 됨
- Docker로 컨테이너화 : RabbitMQ를 Docker Compose로 함께 실행하면 네트워크 설정이 간소화
3. 데이터베이스(Aurora)
현재 상황
Aurora(MySQL) 사용 중.
개선 방향
기본적으로 오로라DB는 모든 요청을 Writer인스턴스로 전달하기에 읽기/쓰기 분리하는 작업을 한다.
☑️ 읽기/쓰기 분리
- 읽기 작업은 Reader 인스턴스로 분산하여 Writer 인스턴스의 부하를 줄임.
☑️ Console에서 Aurora 클러스터의 Reader Endpoint를 확인.
- Reader Endpoint는 자동으로 모든 Reader 인스턴스에 로드 밸런싱:
- Writer Endpoint: your-cluster.cluster-instance-1.rds.amazonaws.com
- Reader Endpoint: your-cluster.cluster-ro.rds.amazonaws.com
☑️ Spring Boot에서 읽기/쓰기 분리
- Spring Boot에서 데이터소스를 읽기/쓰기 전용으로 분리.
- Dynamic DataSource 구성
☑️ Connection Pool 관리(RDS Proxy)
- RDS Proxy를 사용해 DB 연결 효율 개선 및 대기 시간 최소화.
- 연결 재사용을 통해 효율성을 극대화.
- DB 연결 수 제한 초과 방지.
- AWS IAM 인증과 연계하여 보안 강화.
✔️ 요약
항목 | 효과 |
성능 개선 | 정적 파일 CDN 제공, 읽기/쓰기 분리, 캐싱 도입, RabbitMQ로 비동기 처리. |
확장성 | Auto Scaling, RDS Proxy, ElastiCache로 트래픽 증가 시에도 안정적인 확장 가능. |
운영 효율성 | 컨테이너화, 서버리스(Lambda), 관리형 서비스(ElastiCache)로 운영 부담 감소. |
비용 최적화 | S3/CloudFront, Lambda, 읽기/쓰기 분리를 통해 리소스 효율 극대화. |
유지보수 용이성 | 프론트엔드와 백엔드의 완전한 분리, 기존 배치 작업 및 API 코드의 재활용. |
✔️ CI/CD 배포 전략
☑️ CI/CD 파이프라인 구성(Jenkins)
1) 코드 푸시 이벤트로 파이프라인 트리거
- Jenkins: Git Webhook을 설정하여 코드가 푸시되면 Jenkins Job이 실행되도록 설정.
2) Docker 이미지 빌드 및 업로드
- Docker 이미지를 빌드하고, 태그를 설정하여 ECR에 업로드.
3) Docker 이미지 테스트
- Docker로 빌드된 이미지를 실행하여 애플리케이션의 기본 동작을 테스트
4) ECS 배포 자동화
- Docker 이미지를 ECR에 업로드한 후 ECS 서비스를 업데이트하여 새 이미지를 배포.
여기서 잠깐 헷갈려 개념을 짚고 간다.
- ECR이란?
Docker 이미지를 저장하고 관리하는 서비스
ECR은 AWS에서 제공하는 컨테이너 이미지 저장소로, Docker Hub와 유사한 역할
-ECS란?
ECS는 컨테이너 오케스트레이션 서비스
✔️ 모니터링 및 알림
1) CloudWatch 모니터링
- ECS Task Metrics : CPU/Memory 사용률, 실패한 요청 수 등 모니터링.
- Log Aggregation: E CS Task의 로그를 CloudWatch Logs에 자동 수집.
'IT' 카테고리의 다른 글
[AWS] 웹 공격에 캡차 추가하기 (0) | 2024.11.24 |
---|---|
[AWS] ECS vs EKS (0) | 2024.11.24 |
[AWS] 내맘대로 AWS Cloud 구축/설계하기(1) (1) | 2024.11.22 |
[AWS] S3 Mount vs Storage (0) | 2024.11.03 |
초거대 AI 시대, 개발자의 운명은... (0) | 2024.03.15 |