728x90

 

들어가며

프록시 (Proxy) 란 한 마디로 대리 기사라고 표현할 수 있다. 프록시 서버는 클라이언트가 자신을 통해서 다른 네트워크 서비스에 간접적으로 점속할 수 있게 해주는 컴퓨터 시스템이나 응용 프로그램을 가리킨다.
 
 
 

Forward Proxy

클라이언트가 프록시 서버에 요청을 보내고, 프록시 서버가 요청을 받아 실제 서버로 전달한다.
 

Reverse Proxy

클라이언트가 실제 서버(또는 서비스)의 주소를 모르고, 대신 프록시 서버의 주소로 요청을 보내면, 프록시 서버가 요청을 적절한 백엔드 서버로 전달한다.
 
 
 

AS-IS

 
변경 전 구조는 위 그림과 같다. 공유기에서 바로 해당하는 프록시가 있는 포트로 포트포워딩 해주는 구조였다. 
 
해당 구조는 작업하기에 편했지만, 서버의 포트를 많이 열어 주어야 하기 때문에 생길 보안이슈로 부담스러웠다.
 

  • 공격 표면 증가: 여러 포트를 열어 두면 그만큼 공격자가 침입할 수 있는 경로가 많아져서, 해커가 특정 포트를 타겟으로 하는 공격(예: 포트 스캐닝, DoS 공격)을 시도할 가능성이 높아짐.

  • 취약점 노출: 열려 있는 포트가 사용하는 서비스나 소프트웨어에 보안 취약점이 있다면, 이를 통해 쉽게 침입할 수 있음. 특히 포트가 열려 있으면 버전 정보나 서비스 정보가 노출될 가능성이 있어 공격에 취약함.

 
뿐만 아니라 추가적인 이슈로는 유지보수, 서버 리소스, 스케일링 복잡성, 인증서 관리의 복잡성 등의 추가적인 이슈가 예상됐다.
 
첫 번째로, 유지보수성에 단점이 있다. 각각의 프로젝트에서 docker-compose 파일로 관리를 해야 하고 nginx.conf 파일도 따로 관리를 하는 부분이 번거로웠다. 설정 변경할 때 또한 일관성을 유지 하기에 어려움이 있었다. 각 프로젝트에서 일일히 수정 작업이 들어가니 애를 먹었다. 

그리고 두 번째로, 이 구조는 네트워크 오버헤드 발생할 수 있을 것 같다. 각 서버 마다 Nginx를 통해 통신을 해야 하는데 이는 불필요한 통신이 많아지기 때문에 대용량 트래픽 처리에 좋지 않아 보인다.

세 번째로, 서버 리소스 낭비이다. Nginx 인스턴스가 WAS마다 별도로 존재하면 서버 자원을 많이 소비한다.
 
네 번째로, 스케일링 복잡성이다. 이는 유지보수성이랑도 연관 되는데 시스템 확장 시 각 Nginx를 별도로 조정해야 하므로, 스케일링이 번거롭고 관리 포인트가 늘어날 수 있다.
 
다섯 번째로, 인증서 관리의 복잡성이다. 각각의 Nginx에 적용을 해야 하는 공수가 있다. 공유 스토리지를 사용하는 방법도 있는데 덕지덕지 붙여지는 느낌이라 꺼려졌다.

그래서 다음과 같이 단일 Nginx로 통합되는 구조로 변경 해보았다.
 
 
 

TO-BE

 
 
이렇게 변환하니 많은 변화가 생겼다.
 
CI/CD의 변화, 단일 프록시로 통합, 설정 중앙화, 유연한 스케일링, 유지보수성 등 좋아짐.
 
기존 CI/CD는 각 애플리케이션 저장소에서 각각 이미지화 해서 Nginx와 함께 서버가 띄어졌다면, 변경 된 후 하나의 docker compose 파일로 관리 되어서 배포 될 때 마다 해당 파일을 참조하여 빌드할 수 있게 됐다.
 
하나의 docker-compose 파일로 관리 하게 되어서 서버 구조를 한 눈에 볼 수 있어서 더 편했다. 더 나아가 각각 컨테이너가 논리적으로 하나의 network으로 묶인 상태이면 각각이 내부적으로 container name으로 호출할 수 있는 구조가 되어서 외부와 단절시킬 수 있는 큰 장점이 있다고 생각 되었다. 그래서 보안적으로도 큰 이점이 있다고 생각했다. (도커 내부적으로 DNS를 운영 하기 때문에 가능한 부분이다) 그리고 단일  docker-compose 파일로 관리 하는 것은 scale up/out 다 용이했다.
 
단일 프록시로 통합 되어서 서버 리소스를 절약할 수 있었고, 분산 된 설정을 한 곳에서 유지보수 할 수 있어서 훨 편했다.
 

728x90

 

Hypervisor 정의

하이퍼바이저(Hypervisor)는 하나의 물리적 컴퓨터에서 여러 개의 가상 머신(VM, Virtual Machine)을 실행할 수 있게 해주는 소프트웨어입니다. 이를 통해 각 가상 머신은 독립된 운영 체제를 실행할 수 있으며, 하드웨어 자원을 공유합니다. 하이퍼바이저는 가상 머신과 실제 하드웨어 사이의 중재자 역할을 하며, 가상화 기술의 핵심 요소입니다.

 

Container 정의

컨테이너(Container)는 애플리케이션과 그 실행에 필요한 라이브러리, 의존성, 설정 파일 등을 하나의 독립된 단위로 묶어 운영 체제의 커널을 공유하면서도 서로 격리된 환경에서 실행되도록 하는 기술입니다. 컨테이너는 애플리케이션과 그 환경을 패키지화하기 때문에, 개발 환경에서 테스트 환경, 그리고 프로덕션 환경까지 동일하게 실행될 수 있습니다. "Write Once, Run Anywhere"의 개념을 실현 합니다.

 

 

 

 

 

Hypervisor 와 Container 비교

  • 컨테이너는 도커라는 베이스 위에 소스코드 이미지가 실행되어서 각각 독립 된 상태로 띄어진다. 그리고 가볍다. (각각 독립 된 상태이기 때문에 서로에게 영향을 주지 않는다.)

 

  • 가상머신은 하이퍼바이저 위에 각각의 가상머신이 각각 독립 된 상태로 실행된다. 각각의 가상머신은 OS 등 세팅이 되기 때문에 무거운 상태이다. 그래서 하나하나가 무겁다.

 

  • 컨테이너는 가상머신을 만들지 않아도 되는 이미지를 실행만 하면 되는 것이기 때문에 가몁고 scale out과 배포에 큰 장점이 있다.

 

  • 그래서 컨테이너는 필요할 때 언제든 빠르게 추가할 수 있다.

 

  • 컨테이너는 하나의 OS 커널을 공유하기 때문에 각각이 완전한 격리가 이루어지지 않기 때문에 보안 이슈가 있을 수 있다. 반면 하이퍼바이저는 하드웨어 레벨에서 격리되므로 보안적으로는 하이퍼바이저가 우위에 있다. 

 

 

'서버 > 클라우드 컴퓨팅' 카테고리의 다른 글

Hadoop: MapReduce + HDFS  (0) 2021.12.16
MapReduce: Fault Tolerance, Locality, Large-Scale Indexing  (0) 2021.12.16
MapReduce: Programming Model  (0) 2021.12.16
MapReduce  (0) 2021.12.16
빅데이터 Parallelization의 문제점  (0) 2021.11.09
728x90

 

배경

이 포스팅에서는 DLQ로 SQS의 fifo queue로 채택을 했다. 해당 DLQ는 source queue와 lambda를 바라보고 있다. 해당 DLQ에 이벤트가 쌓이는 케이스는 대표적으로 source queue와 lambda 사이에 통신이 안될 때, lambda에서 처리 로직 중 에러가 발생 했을 때 가 된다고 생각해서 DLQ의 필요성을 느껴서 비치했다.

실패한 이벤트에 대해서 후처리를 해야 하는 거는 분명히 필요하지만, lambda 이후에 fifo DLQ를 비치하는것에 문제가 있었다. SQS fifo 타입의 장점 중 하나인 이벤트 중복 제거를 해친다는 점에서 문제가 있었다.

 

https://aws.amazon.com/ko/blogs/compute/new-for-aws-lambda-sqs-fifo-as-an-event-source

 

 

해결

람다에서 재시도를 할 때 중복 이벤트가 DLQ에 들어갈 수 있다. 여기서 의문이 들 수 있는 부분이 DLQ는 fifo 타입인데 어떻게 중복으로 들어가냐는 말인데 이벤트 content가 아무리 같다고 하더라도 fifo queue에 들어가는 이벤트가 중복인지 아닌지를 판단하는 부분이 GroupId, Deduplication Id으로 판단 한다. 그러나 해당 이벤트의 content를 기반으로 중복 이벤트 처리를 할 수도 있다. Content-based de-duplication 을 활성화 하면 되긴 한다. 그러나 굳이 DLQ가 있어야 할까? 라는 생각이 들었다. 더 cost가 저렴한 RDB/NoSQL 등으로도 처리가 가능하다고 생각했다. 그리고 후처리 까지 써드파티에 의존하기가 꺼려졌다. 그래서 실패한 이벤트에 대한 후처리는 DB로 처리하기로 결정했다.

해당 처리는 복잡한 조인이나 집계 쿼리 같은 것들이 필요가 없고 빠른 읽기/쓰기가 요구되어서 RDB 보다 NoSQL인 MongoDB로 하기로 했다. 데이터의 id를 실패한 이벤트의 messageId 로 설정하며 데이터 정합성을 더했다. 그리고 DLQ의 리드라이브를 대체하여 애플리케이션에서 특정 API 호출 시 dead letter 가 쌓인 MongoDB에 아직 미해결 된 이벤트들을 찾아서 다시 호출 해서 source queue로 다시 넣어 프로세스를 흐름에 편승하게끔 하게 해결했다.

 

AS-IS TO-BE

 

 

결론

최고 50% 가까이 개선 됐다.

배포 전 배포 후


 

(* 비슷한 데이터 처리량을 토대로 비교 했음.)

 

회사에서 또 다른 유의미한 발전을 이루어서 뿌듯했다.

 

+ Recent posts