개요

- AWS Managed Flink에서는 사용자가 정의할 수 있는 설정이 제한적입니다.

- 사용자가 Parallelism 과 ParallelismPerKPU를 입력하면 이에 맞춰서 필요한 KPU가 계산되고

- 1 KPU 당 1 vCPU, 4GB메모리를 기준으로 AWS 에서 적당하게 컨테이너를 기동합니다.

 

내용

-  Flink는 TaskManager 와 slot을 기반으로 병렬처리를 제어하는데

- AWS Managed Flink는 KPU를 중심으로 제어하게 됩니다. (과금단위 이기 때문에)

- 이를 좀 더 자세히 살펴보고 원하는 세팅을 만들기 위해서 수치를 어떻게 제어해야 하는지 이해하는 것이 목적입니다.

 

Amazon MSF 리소스 구성 요소 간의 관계

I. KPU (Kinesis Processing Unit): 물리적 리소스 단위

KPU는 Amazon Managed Service for Apache Flink가 애플리케이션 호스팅 환경을 위해 프로비저닝하는 기본 컴퓨팅 리소스 단위입니다.
요소
사양
세부 정보 (출처)
CPU
1 vCPU
컴퓨팅 코어 1개.
메모리
4 GB
총 4 GB의 메모리를 제공합니다.
- 힙 메모리
3 GB/KPU
JVM 힙 메모리 할당에 사용됩니다.
- 네이티브 메모리
1 GB/KPU
네이티브 코드 할당을 위해 예약되며, Managed Memory (RocksDB State Backend와 같은 네이티브 프로세스에 사용)의 기반이 됩니다.
디스크 공간
50 GB/KPU
실행 중인 애플리케이션 상태 저장을 위한 디스크 공간이 제공됩니다.
오케스트레이션
추가 1 KPU
애플리케이션 당 오케스트레이션 목적으로 추가 KPU 1개가 부과됩니다.
Managed Memory의 총 용량은 할당된 총 KPU 수에 비례하여 증가합니다. 1 KPU가 1 GB의 네이티브 메모리를 제공하므로, KPU가 늘어날수록 애플리케이션 전체의 Managed Memory 풀이 커집니다.
- 예) 16 KPU에서 20 KPU로 증가했을 때 Managed Memory 용량 5G -> 6G 
 

II. Parallelism (병렬 처리 수준): 논리적 작업 수

Parallelism 속성은 Apache Flink 애플리케이션의 기본 병렬 처리 수준(Parallelism)을 설정합니다.
요소
설명
제어 방식 및 기본값
Parallelism
애플리케이션 전체의 기본 병렬 실행 수준을 정의합니다.
별도로 재정의하지 않는 한, 모든 연산자(Operator), 소스(Source), 싱크(Sink)는 이 병렬 처리 수준으로 실행됩니다
.
기본값은 1이며, 기본 최대 한도는 256입니다.
MaxParallelism
상태 저장 애플리케이션이 상태 손실 없이 확장할 수 있는 최대 병렬 처리 수준을 정의합니다.
상태가 처음 생성될 때 설정되며, 일반적으로 Parallelism 일 때 기본값은 128입니다
Parallelism 값은 전체 작업(Task)의 수를 결정합니다. 이는 Task Slot의 총 수와 동일하게 간주됩니다.
 

III. ParallelismPerKPU: KPU 당 슬롯 밀도 (자원 활용도)

ParallelismPerKPU단일 KPU 내에 할당될 수 있는 Task Slot의 수를 정의하는 속성입니다.
요소
설명
제어 방식 및 영향
ParallelismPerKPU
단일 KPU에 할당되는 병렬 태스크(Task Slot)의 수.
기본값은 1이며, 최대값은 8입니다.
용도
I/O Bound 작업에 유용합니다.
이 값을 높게 설정하면 동일한 KPU 내에서 더 많은 병렬성을 제공하여 KPU 리소스를 완전히 활용할 수 있습니다
.
예를 들어, I/O Bound 애플리케이션에서 ParallelismPerKPU를 1에서 4로 증가시키면, 동일한 KPU 리소스로 4배의 병렬성까지 확장 가능합니다.
- I/O Bound 작업이 아닐경우 ParallelismPerKPU를 높이게 되면 할당받는 CPU , Memory 가 부족해서 오류가 발생할 수 있으니 작업을 모니터링하면서 적정한 수치로 조정해야 합니다.
 
 

IV. Apache Flink 의 Task Manager 및 Task Slot

Apache Flink는 애플리케이션 실행을 Job Manager가 관리하며, 이는 다시 Task Manager가 관리하는 태스크(tasks)로 분리됩니다.
요소
설명
관계
Task Manager
애플리케이션의 실제 연산을 실행하는 주체이며, 각 Task Manager는 KPU 리소스 내에서 실행됩니다.
Task Manager의 성능은
CPU UtilizationHeap Memory Utilization과 같은 CloudWatch 지표를 통해 모니터링할 수 있습니다.
Task Manager의 수는 할당된 총 KPU 수에 따라 결정됩니다
(AWS 서비스가 자동 프로비저닝).
Task Slot
Apache Flink가 리소스를 할당하는 단위입니다.
Task Slot은
subtask (실행 스레드와 유사한 개념)를 수용합니다.
Task Manager 당 할당되는 슬롯의 수로 병렬도 제어.
 

- 이부분에서 주의해야 할점이 있습니다 !!!

Amazon MSF 환경의 리소스 할당 모델은 Flink 자체적인 개념과 약간 다릅니다.
 

1. ParallelismPerKPU와 Task Slot의 정의

Amazon MSF 환경에서 리소스 할당의 핵심 규칙은 다음과 같습니다:
1. Task Slot (태스크 슬롯): Apache Flink 환경은 Task Slot이라는 단위로 애플리케이션에 리소스를 할당합니다.
2. KPU와 슬롯 할당: Managed Service for Apache Flink는 애플리케이션에 리소스를 할당할 때, 하나 이상의 Apache Flink Task Slot을 단일 KPU에 할당합니다.
3. ParallelismPerKPU의 역할: 단일 KPU에 할당되는 슬롯의 수는 애플리케이션의 ParallelismPerKPU 설정값과 동일합니다
 
 

2. Task Manager와 KPU의 관계

Apache Flink의 Job Manager는 애플리케이션 실행을 태스크(tasks)로 분리하며, 각 태스크는 Task Manager에 의해 관리됩니다. MSF 환경에서 Task Manager는 KPU가 제공하는 컴퓨팅 리소스(1 vCPU, 4 GB 메모리) 내에서 실행됩니다.
 
일반적으로, Task Manager는 컴퓨팅 자원(KPU)의 경계를 따라 실행되며, 각 Task Manager는 해당 KPU에 할당된 Task Slot을 사용합니다.
따라서, 만약 시스템이 개의 KPU를 할당하고 각 KPU가 독립적인 Task Manager 인스턴스를 실행한다면 , "Task Manager 당 슬롯 수 = ParallelismPerKPU"라는 관계가 성립합니다.
 

3. ParallelismPerKPU를 1로 설정했는데도 Task Manager에 슬롯이 하나 이상 할당된 것처럼 보이거나, 혹은 여러 개의 Task Manager가 확인된 이유는 애플리케이션의 총 병렬 처리 수준(Parallelism)과 KPU 개수 때문입니다.

 
예시: ParallelismPerKPU가 1이고, 할당된 KPU가 20
    ◦ 할당된 KPU: 20개.
    ◦ Task Manager 수: 20개의 Task Manager가 실행된다면
    ◦ Task Slot 할당: 각 KPU(Task Manager)는 ParallelismPerKPU 설정에 따라 1개의 Task Slot을 가집니다.
    ◦ 총 Task Slot: 개.
 
 
하지만 일반적으로 20개보다 적은 수의 Task Manager 가 실행됩니다.
 
AWS가 내부적으로 여러 KPU 리소스를 하나의 논리적/물리적 Task Manager 프로세스에 통합하기 때문입니다
 
즉, 단일 Task Manager 인스턴스에 할당된 슬롯 수가 ParallelismPerKPU 값보다 많게 보입니다.
 
 

정리

구분
순수 Apache Flink 환경
Amazon Managed Service for Apache Flink (MSF) 환경
기본 리소스 단위
Task Manager (작업 실행 및 슬롯 호스팅)
KPU (Kinesis Processing Unit) (과금 및 용량 프로비저닝 단위)
병렬도 정의 기준
Task Manager 내의 Task Slot
KPU당 할당된 Task Slot 수 (ParallelismPerKPU)
실제 실행 컨테이너
Task Manager 프로세스
Task Manager (AWS가 여러 KPU 리소스를 통합하여 실행 가능)
메모리 확장
Task Manager 메모리 설정(taskmanager.memory.managed.fraction) 조정
총 KPU 수 증가에 따라 Managed Memory 총량 증가
 사용자는 ParallelismParallelismPerKPU 두 가지 주요 속성을 설정하여, Managed Service for Apache Flink가 프로비저닝할 최종 리소스 크기와 내부 실행 구조를 간접적으로 제어합니다. 일반적인 Flink가 TaskManager 단위로 관리하는 부분과 약간의 개념차이가 있음을 이해하면 됩니다.
 

1. 총 할당된 KPU 계산 (리소스 및 메모리 결정)

Amazon MSF 애플리케이션에 할당되는 총 KPU 수는 다음 공식에 의해 결정됩니다.
 
{KPU} = {Parallelism} / {ParallelismPerKPU}
 
 
 Managed Memory: 총 Managed Memory 용량은 이 할당된 KPU 수에 정비례하여 증가합니다
(1 KPU당 약 1 GB의 네이티브 메모리 제공).
 

2. 총 Task Slot 수 (실행 능력)

 
 
Task Slot의 역할: 각 Task Slot은 연산자(Operator)의 병렬 인스턴스(Subtask)를 실행하는 데 사용될 수 있습니다.
Operator Parallelism: 각 연산자별 병렬 처리 수준(Operator Parallelism)은 기본적으로 애플리케이션의 Parallelism 값과 동일합니다. 이는 필요하다면 각 연산자가 사용 가능한 모든 Subtask(Task Slot)를 사용할 수 있음을 의미합니다.
 

3. Task Manager의 개수/메모리 제어 정리

항목
사용자가 직접 제어하는가?
제어 방법 및 결과
KPU 개수
아니요.
ParallelismParallelismPerKPU 설정을 통해 간접적으로 계산되어 할당됩니다.
KPU 수를 늘리려면 Parallelism을 늘리거나 ParallelismPerKPU를 낮춰야 합니다.
Task Manager 개수
아니요.
KPU 할당에 따라 AWS 서비스에 의해 자동 관리됩니다
.
Task Manager는 할당된 KPU 리소스 내에서 애플리케이션의 태스크를 실행합니다.
총 Managed Memory
아니요.
할당된 총
KPU 수에 비례하여 크기가 결정됩니다.
Managed Memory 용량을 늘리려면 KPU 수를 늘려야 합니다.
Task Slot 개수
예.
ParallelismPerKPU를 통해 Task Manager당 슬롯 수를 제어하고, Parallelism을 통해 총 슬롯 수를 제어합니다.
Parallelism을 늘리는 것은 총 Task Slot 수를 늘리는 가장 직접적인 방법입니다.

 

실제 예시

- Parallelism 20, ParallelismPerKPU 1 = 총 20 KPU

1. 리소스 할당 (KPU 기준)

Amazon MSF에서 1 KPU1 vCPU4 GB의 메모리를 제공합니다. 이 4 GB 메모리 중 1 GB는 RocksDB State Backend와 같은 네이티브 프로세스를 위한 네이티브 메모리(Managed Memory의 기반)로 예약됩니다.
항목
20 KPU가 제공하는 총 예상 리소스
생성 결과 (3 TM 합산)
총 vCPU
vCPU
CPU
총 Physical Memory
GB
GB
총 Managed Memory
GB (네이티브 메모리 할당 기준)
GB
 

2. Task Manager 개수 및 Slot 할당 검증

A. 총 Task Slot 수

애플리케이션의 총 병렬 처리 수준(Total Task Slots)은 설정된 Parallelism 값과 같습니다.
설정: 20 KPU, ParallelismPerKPU = 1.
계산된 Parallelism (총 슬롯): .
생성 결과: 3개 Task Manager에   개의 활성 슬롯
 

B. Task Manager당 슬롯 개수와 ParallelismPerKPU의 차이

생성 결과 (3개의 Task Manager가 각각 7개의 슬롯을 가짐)가 다른 이유는
 
1. KPU는 리소스 단위, Task Manager는 실행 컨테이너
AWS Managed Flink는 KPU를 리소스를 할당하는 기본 단위로 사용하지만, 실제 Task Manager 프로세스(컨테이너)는 여러 KPU의 리소스를 하나로 묶어(Grouping) 실행
2. 그룹화:
    ◦ 총 리소스: 20 KPU
    ◦ 실행 Task Manager: 3개
    ◦ Task Manager당 할당된 평균 KPU: .
3. 슬롯 계산
    ◦ ParallelismPerKPU = 1 이므로, Task Manager당 예상되는 슬롯 수는 Task Manager가 포함하는 KPU 수와 같아야 합니다.
    ◦ Task Manager당 슬롯 수 KPU에 해당하며, 개의 TM이 KPU (총 20 KPU)로 나뉘어 할당되었다고 해석할 수 있습니다.
    ◦ 즉, 하나의 Task Manager 인스턴스가 7개의 KPU 리소스를 관리하며, 이 때문에 7개의 슬롯을 가지게 된 것
 
  20 KPU 리소스를 3개의 Task Manager 인스턴스에 통합하여 실행하는 AWS Managed Flink의 내부적인 리소스 그룹화 정책

AWS Managed Flink 네트워크 오류 원인 분석 및 튜닝 가이드

 
오늘은 AWS MSF(Managed Service for Apache Flink) 애플리케이션에서 발생한 오류(예: RemoteTransportException: Connection unexpectedly closed by remote task manager)의 원인과 해결 방안을 분석합니다.


애플리케이션 로그를 보면 10월 16일 오후 10시 21분 24초에 remote task manager error가 발생했고, 이후 partial recovery 후 다시 TaskManager 연결 오류가 반복되는 모습을 확인할 수 있었습니다.

이러한 로그는 TaskManager 간 통신이 불안정함을 나타내며, 주된 원인으로 메모리/리소스 부족, GC 지연, Heartbeat 타임아웃 등이 의심됩니다.

로그

closed by task manager

 

원인 분석

  • 메모리 부족 및 리소스 고갈: AWS MSF 문서에 따르면, TaskManager가 할당된 메모리를 초과하거나 CPU/메모리 과부하에 걸리면 TaskManager 프로세스가 비정상 종료되고, 이로 인해 RemoteTransportException이 발생할 수 있습니다 .
    • 예를 들어, KPU(Kinesis Processing Unit)당 메모리(4GiB, 이 중 3GiB는 힙 메모리)가 부족하면 OOM(OutOfMemory)으로 TaskManager가 죽을 수 있습니다  . 이 경우 Flink가 TaskManager 연결이 끊어졌다고 보고 오류를 출력합니다.
    • 현재 처리하고 있는 내부 Key 값 및 State의 용량이 크기 때문에 heapMemory사용량이 90%를 유지하고 있어서 원인 중 하나일 것으로 예상합니다.
  • GC(Garbage Collection) 지연: 장시간 Full GC가 발생하면 TaskManager가 일정 시간 응답하지 못해 JobManager에 Heartbeat를 제때 보내지 못합니다. Flink 커뮤니티의 해결책에 따르면, 이러한 경우 TaskManager가 ‘unresponsive’ 상태로 간주되어 슬롯이 해제되고, 결국 연결이 끊어집니다.
    • 이를 방지하려면 G1GC와 같은 빠른 GC를 사용하거나 TaskManager 메모리 설정을 조정해 GC 시간을 단축해야 합니다 . 또한, 필요시 akka.watch.heartbeat.pause와 같이 Heartbeat 시간을 늘려 JobManager의 타임아웃을 늘리는 방안도 고려할 수 있습니다.
    • AWS MSF는 이미 G1GC 적용이 되어 있었습니다.
  • Data Skew (데이터 불균형)
    • 특정 TaskManager 또는 Subtask에 비정상적으로 많은 데이터가 집중되어 처리 부하가 쏠릴 수 있습니다.
    • 이 현상은 다음과 같은 이유로 RemoteTransportException과 같은 네트워크 오류로 이어질 수 있습니다.
      • 특정 TaskManager만 메모리 과부하
        • 동일한 데이터 분포를 가정하고 병렬 처리를 수행하지만, 실제로는 일부 키(key)나 파티션에 데이터가 몰리면 해당 TaskManager만 힙 메모리가 1GB 이상까지 치솟습니다.
      • 백프레셔(Backpressure) 전파:
        • 특정 Subtask가 느려지면 상류(upstream)의 데이터 송신 속도가 제한되고, 네트워크 버퍼가 포화되어 Task 간 통신 오류Partial Recovery가 반복됩니다.
      • 네트워크 셔플 불균형:
        • Flink는 keyBy, rebalance, broadcast 연산 시 네트워크를 통해 데이터를 재분배합니다. 이때 데이터 스큐가 있으면 특정 TaskManager의 네트워크 I/O가 폭증하며, 네트워크 버퍼 부족과 연결 끊김이 함께 발생할 수 있습니다.
    • 내부적으로 각 이벤트를 시나리오와 매핑하는 처리를 하고 있는데 특정 시나리오의 이벤트가 많이 발생하고 있어서 역시 의심이 되는 부분입니다.
    • 시나리오 매핑이후는 개별Key를 통해서 keyBy연산으로 하고 있기 때문에 체이닝이 적절하게 동작하고 있습니다.
  • 네트워크 버퍼 부족: 병렬처리가 높아지거나 연산자 체이닝이 해제되면 셔플(shuffle)이 증가해 네트워크 버퍼 소모가 커질 수 있습니다. AWS 문서에는 네트워크 버퍼가 부족해지면 Insufficient number of network buffers 오류가 발생할 수 있으며, 이를 해결하기 위해 parallelismPerKPU를 낮춰 TaskManager당 메모리(및 버퍼)를 늘리거나 연산자 체이닝을 활용할 것을 권장하고 있습니다 
    • 참고로 한 플로우에서 필요한 버퍼 개수는 (slots_per_TM)^2 * number_of_TMs * 4 공식으로 대략 산출할 수 있습니다.
    • 즉, TaskManager의 슬롯 수나 셔플 횟수가 많을수록 네트워크 버퍼가 대폭 늘어납니다.
  • Heartbeat 타임아웃: Flink의 Heartbeat 설정이 너무 짧거나 네트워크 지연이 있으면 TaskManager와 JobManager 간 연결이 끊길 수 있습니다.
    • 이 경우 AWS MSF에서는 heartbeat.timeout 설정을 지원 티켓으로 늘릴 수 있으며 , 위에서 언급한 GC 지연 대응책(Heartbeat 지연 허용)도 도움이 됩니다.
  • 기타 원인: TaskManager 노드의 일시적 네트워크 장애, 컨테이너 리소스 제한(예: CPU 쿼터 초과), 코드 레벨 메모리 누수 등도 원인이 될 수 있습니다.
    • TaskManager 로그에서 OOM 오류나 비정상 종료 메시지를 확인하고, 메모리 누수 가능성을 코드 리뷰로 점검해야 합니다.

 

해결 방안 및 튜닝 가이드

    • KPU 및 병렬성 조정: KPU 리소스를 늘리거나 TaskManager당 할당되는 작업 수(ParallelismPerKPU)를 줄여 각 작업에 더 많은 메모리를 할당합니다.
      • AWS 문서에 따르면 하나의 KPU는 1 vCPU와 4GiB 메모리(힙 3GiB, 네이티브 1GiB), 50GiB 스토리지를 제공합니다 .
      • 예를 들어, ParallelismPerKPU=4(기본)인 경우 KPU당 4개의 슬롯에 약 1GiB씩 메모리가 분할되지만, ParallelismPerKPU=2로 낮추면 슬롯당 약 2GiB를 확보할 수 있습니다.
      • 전체 병렬도(Parallelism)가 고정되어 있다면 ParallelismPerKPU를 낮추면 필요한 KPU수가 증가하여 리소스가 더 할당됩니다 .
      • AWS도 PPK를 낮춰 메모리당 할당량을 높이는 방안을 제시하고 있으며, 이를 통해 메모리 부족으로 인한 OOM 재시작을 줄일 수 있습니다. (단, PPK를 낮추면 비용이 늘어나므로 병렬도를 적절히 조정하거나 오토스케일링을 활용해야 합니다.)
    • Data Skew 완화
      • Key 균등화 전략 적용 (keyBy 연산 시 key 값의 불균형이 발생하는 경우)
        • 해시 기반 샘플링 후 파티션 재조정
        • “composite key” (예: userId_mod_10) 기반 가상 key 확장
        • rebalance() → map() 단계 삽입을 통해 균등 분배 가능 
    • Aggregation 단계 분리
      • 데이터가 한 TaskManager로 몰리는 경우, 1차 로컬 집계(Local aggregation) → 2차 글로벌 집계(Global aggregation) 구조로 바꾸면, 네트워크 트래픽 및 skew 부담을 크게 줄일 수 있음
    • Metrics 기반 모니터링 : 특정 TaskManager만 유독 높아서 key 분포 불균형 확인함
      • numRecordsIn, busyTimeMsPerSecond, heapMemoryUsed 메트릭을 TaskManager 단위로 비교하여 Skew 구간을 확인
  • Operator 체이닝 활용 및 네트워크 최적화: 가능한 Operator들을 체이닝하여 별도 서브태스크로 분리될 필요가 없도록 합니다.
    • MSF 문서에 따르면 체이닝은 동일 서브태스크 내에서 연산자들을 묶어 실행함으로써 네트워크 호출을 줄이고 리소스를 절약합니다.
    • 반대로 체이닝을 해제하거나 인위적으로 새 체인을 시작하면 불필요한 셔플이 증가합니다. 실제 사례에서도 체이닝 해제가 네트워크 부담을 크게 늘려 오류 원인이 되므로, 가능하면 체이닝을 활성화할 것을 권장합니다.
    • 또한, 앞서 언급한 네트워크 버퍼 부족을 피하기 위해 플로우를 단순화하고 셔플 단계를 최소화하는 것도 중요합니다.
  • I/O 바운드 워크로드 고려: 외부 서비스와의 블로킹 I/O가 많은 경우, 오히려 ParallelismPerKPU를 높여 KPU 리소스를 최대한 활용하는 것이 효율적일 수 있습니다 .
    • 즉, 네트워크 지연이 주요 병목이라면 병렬 슬롯을 늘려 I/O 대기 동안 더 많은 작업을 병렬 처리하도록 조정합니다.
    • 하지만 현재는 TaskManager 재시작 문제가 우려되므로, 우선은 안정적인 메모리 확보에 중점을 두고 PPK를 낮추었습니다.
  • 모니터링 강화 및 추가 점검: CloudWatch의 주요 메트릭을 면밀히 모니터링합니다.
    • cpuUtilization, heapMemoryUtilization 등은 전체 리소스 사용률을 보여주며 문제 지표가 될 수 있습니다.
    • 또한 oldGenerationGCTime과 같은 GC 메트릭을 살펴보면 GC 지연 여부를 판단할 수 있습니다. 장애가 발생할 때는 CloudWatch Downtime, FullRestarts 값도 확인합니다.
    • TaskManager JVM 로그에서 GC 타임, 힙 사용량, OOM 에러를 찾아보고, 코드에 메모리 누수 가능성은 없는지 검토해야 합니다.
      • TaskManager 로그를 보고 싶으면 Flink구성에서 로그항목 [Application]으로 설정해야 합니다.
    • Heartbeat 타임아웃이 잦다면 heartbeat.timeout 설정을 AWS 지원 티켓으로 늘려보는 것도 고려할 수 있습니다 .
  • 추가 적인 점검 사항
    • 일시적인 AWS 네트워크 장애 가능성도 염두에 두고, 다른 애플리케이션이나 Kinesis 스트림의 상태(예: 지연, 스로틀링)도 확인해 봅니다.
    • 코드 레벨에서는 대용량 데이터 처리 시 메모리 소비가 급증하지 않는지, Checkpointing 지연으로 백프레셔가 걸리지는 않는지도 함께 살펴봅니다.

 

결론

 
이번 오류는 단순한 네트워크 불안정이 아니라,

  • TaskManager 메모리 부족
  • Data Skew로 인한 특정 TaskManager 과부하
  • GC 지연 및 Heartbeat 누락
  • 복합적으로 작용한 결과입니다.

 
현재 발생한 오류를 해결하기 위해서는 메모리 확보, DataSkew 해소 및 네트워크 통신 부하 완화가 주요 내용입니다.

다음과 같은 액션을 수행했습니다.

  1. ParallelismPerKPU 재조정
    1. TaskManager 슬롯 수를 줄여 각 슬롯이 더 많은 메모리를 갖도록 합니다.
    2. PPK를 4에서 2로 낮추어 슬롯당 메모리 할당량을 늘림 (1G -> 2G)
  2. 전체 병렬도 검토
    1. PPK를 낮춘 뒤에 처리량이 부족하다면, 전체 병렬도(Parallelism) 자체를 늘려 필요한 KPU 수를 확장
  3. Data Skew 해소
    1.  DataStream에서 .rebalance() 수행 후 이후 map() 하도록 파이프라인 수정
  4. 비용 대비 효율 검토
    1. 리소스 조정으로 비용이 상승할 수 있으므로, 변경 전후의 KPU 사용량과 애플리케이션 처리율을 비교하여 최적점을 찾습니다
  5. 모니터링 강화
    1. heapMemoryUtilization, oldGenerationGCTime, cpuUtilization, fullRestarts 주요 메트릭을 CloudWatch에서 계속 감시하고, 설정 변경 후 리소스 압박이 해소되었는지 검증이 필요 !!

 
이상으로 발생한 TaskManager 관련 오류 원인을 분석하고 해결 방안을 공유합니다.

다음 글에서는 AWS Managed Flink에서 KPU, Parallelim 의 관계와 TaskManager에 할당되는 관계를 알아보도록 하겠습니다.
https://icthuman.tistory.com/entry/%EC%8B%A4%EC%8B%9C%EA%B0%84-%EB%8D%B0%EC%9D%B4%ED%84%B0%EC%B2%98%EB%A6%AC-%EA%B5%AC%ED%98%84-4-Parallelism-ParallelismPerKPU


 
참고: AWS MSF 공식 문서 및 Flink 자료
- https://docs.aws.amazon.com/managed-flink/

 

https://docs.aws.amazon.com/managed-flink/

docs.aws.amazon.com

- https://nightlies.apache.org/flink/flink-docs-release-1.20/docs/deployment/memory/mem_setup_tm/

 

Set up TaskManager Memory

Set up TaskManager Memory # The TaskManager runs user code in Flink. Configuring memory usage for your needs can greatly reduce Flink’s resource footprint and improve Job stability. The further described memory configuration is applicable starting with t

nightlies.apache.org

 

1.삶은 풀어야 할 숙제가 아니라 겪어봐야 할 신비다
문제는 당신 안에 있다
나만의 고유한 삶을 살자
의미와가치는 평판에 달려 있지 않다


2.배움을 멈추지 않는 한 우리는 계속 성장할 것이다
앎을 실천함으로써 삶을 바꾸자
바꿀수 없는것에 매이지 말고, 바꿀 수있는것에 살아라


3.인생은 빗속에서 춤추는 법을 배우는 것
해결할 수 있는 일은 근심할 필요가 없다
해결할 수 없는 일 또한 근심할 필요가 없다.

반드시라는 마음을 내려놓고
물 흐르듯이

욕망, 두려움 을 초월한다면 자유롭다

'인문학' 카테고리의 다른 글

겸손(자신있게 고개숙일 수 있는 마음)  (3) 2025.08.29

[어떻게 어른이 되는가]-엄성우 지음 

 

1. 겸손이란 무엇일까.

신이 아니기에 모든면에서 완벽하지 않고,

그런 불완정성을 스스로 인지할 수 있기에 다른 동물과 구분이 된다.

자신의 가치와 남의 가치를 비교하지 않는 것으로 출발

 

2. 왜 겸손해야 할까.

남을 불쾌하게 하지 않고 자신도 미움받지 않는다.

자기평가에 연연하지 않고 진정으로 중요한 것을 추구한다.

귀한 배움을 얻기 위해서는 남의 잘난척 정도는 가볍게 받아줄수도 있는 여유로운 태도가 필요할수도 있다. (이것도 겸손)

겸손만큼 쉽고 안전한 덕목이 없다.

 

3. 겸손은 예의나 친절함과 어떻게 다를까

예의 바름은 대부분 겉으로 드러나는 것.

겸손은 친절과는 다르다. 친절하게 태도를 가질수는 있으나

겸손은 결국 스스로를 어떻게 여기는가에 내면에서 나오는 소리에 달려있음

내적겸손을 갖추어야 외적겸손이 자연스럽게 발현된다.

 

4. 겸손한 사람은 자신에 대해 잘 알까?

자신의 탁월함을 알고도 겸손할 수 있는가.

내가 뛰어나다고 해서 내가 남보다 가치가 있는 것은 아니다. 탁월성을 안다고 겸손하지 못한것은 아님.

오히려 자신이 가진 힘과 영향력을 제대로 알지 못해서 생기는 문제도 있다. (가진자의 횡포, 상처주는 막말)

자신이 가진 탁월함을 제대로 알아야 적절히 활용하며 그에 걸맞는 행동을 할 수 있다.

 

"너 자신을 알라"

"내가 모른다는 사실이라도 알면 지혜로울 수 있다"

 

5. 겸손한 사람은 스스로를 어떻게 의식할까?

지나치게 자신을 의식하면 겸손하지 못할 수 있다.

"겸손이란 자신을 하찮게 생각하는 것이 아니라 자신에 대해 너무 많은 생각을 하지 않는 것이다" - C.S. 루이스

자신의 가치를 알맞게 가늠하는 사람은 꼭 필요한 경우가 아니면 자신을 화제의 중심에 두지 않는다.

 

"우리는 우리에 대해 무슨 이야기를 하는지보다 우리에 대한 이야기 자체에 더 신경을 쓰고,

우리를 어떻게 부르는지와 상관없이 사람들 입에 오르내린다는 사실로 만족스러워 한다. " - 몽테뉴

쓸데없는 것에 기뻐하는 사람들

 

우리는 자신의 것이 아닌 것에 대해서 과시하지 않아야 한다.

 

6. 감사와 겸손, 겸손과 자기비하, 겸손과 오만

보통 겸손한 사람은 감사를  잘한다. 하지만 감사할 줄은 알지만 겸손하지 못한 사람도 있다. 

진짜 겸손한 사람은 자신을 중심에 두려는 성향이 적어서, 남을 돕거나 진리를 추구하는 등

인생의 중요하고 가치있는 일을 실천해 나가는 사람.

---------

겸손과 자기비하는 마치 비슷해보이지만 다르다.

자신을 스스로 깎아 내리려는 성향이 선의,용기 등 다른 덕목을 발휘하는데 방해가 되는를 기준으로 본다면

자기비하는 그 부정적인 태도로 자신과 그 주위에 악영향을 미친다.

 

예를 들어서 상을 받거나 축하를 받을때 스스로 깎아내린다면, 혹은 자신이 받은 상의 가치를 깎아 내린다면

그 상을 준사람, 받은 또 다른 사람, 또 그 상을 받지 못한사람과 그 상을 받도록 도와준 모든 사람에게 실례

 

겸손은 자신을 낮추는 태도가 아닙니다. 자신에게 엄격한 것도 아니며,

자신을 깎아 내린다는 것은 결국 자신과 비슷한 위치에 있는 사람도 깎아내리는 것이 되기 때문이다.

 

자신을 드러내는 행동이 반드시 오만한 것은 아니다.

자랑에도 이유가 있다면 겸손에 어긋나지 않으며

 

결국 겸손은 자기비하와 오만 사이의 중용이다.

"덕 이란 모자람과 지나침의 양 극단 사이의 중용" - 아리스토텔레스

 

** 자존감의 크기가 아니라 자존감의 근거에 달려있다.

겸손하지 못한 사람은 Better에 중점을 두고,

겸손한 사람은 Good에 중점을 둔다. 즉, 가치있고 의미있는 것을 추구하고 실현함으로써 높아진 자존감을 얻게 되는 것

 

'인문학' 카테고리의 다른 글

삶이 풍요로워지는 여덟번의 동양 고전수업 #1  (0) 2025.09.14

Flink State vs 외부 저장소를 활용한 값 관리: 어떤 선택이 더 합리적일까?

 

개요

실시간 데이터 처리 파이프라인에서 흔히 등장하는 과제 중 하나는 “사용자 피로도, Aggregation등” 값 관리입니다.
예를 들어, 마케팅 알림이나 이벤트 푸시 발송 시스템에서 동일 사용자에게 너무 많은 알림이 전달되지 않도록 시간/횟수 기반 제약을 두어야 할 필요도 있고, 일정 시간내의 이벤트 Aggregation등의 처리가 필요한 경우도 있습니다.
 
이를 구현하는 방법은 크게 두 가지로 나눌 수 있습니다.

  1. Flink State를 통한 관리
  2. Redis 등 외부 저장소를 통한 관리

 실제 운영 환경에서 이 두 가지 접근법을 모두 검토했으며, 각 방식의 장단점과 보완 방법을 정리해 보았습니다.
 


Flink State 기반 관리

 

동작 방식

  • Flink의 KeyedProcessFunction 또는 RichFlatMapFunction에서 ValueState, ListState, MapState 등을 활용.
  • 사용자별 키(userId)로 state를 유지하고, 이벤트 처리 시 조건을 체크.
  • checkpoint/restore 메커니즘을 통해 exactly-once 보장 가능.

 

장점

  • 일관성 보장: Flink state는 checkpoint와 함께 관리되어 장애 상황에서도 데이터 유실 최소화.
  • 처리 성능 최적화: 외부 호출 없이 JVM 내부 메모리/로컬 RocksDB로 state 접근 → 지연(latency) 최소화.
  • 운영 단순화: 외부 저장소 장애와 무관하게 파이프라인 내에서 관리 가능.

 

단점

  • 확장성 한계: State 크기가 커질수록 checkpoint 부하가 증가.
  • 비즈니스 연계성 부족: 파이프라인 외부 서비스(예: CRM, 백오피스)에서 동일 피로도 정책 확인 어려움.
  • 운영 가시성 부족: state는 Flink 내부에 있어 모니터링/조회가 불편.
  • 복원 불안정 : Operator나 내부 Class등의 변경이 생길경우 복원이 정상적으로 되지 않음

 

보완 방법

  • TTL(State Time-to-Live)을 활용해 불필요한 state 자동 정리.
  • State backend(RocksDB) 튜닝으로 대규모 데이터 관리 가능.
  • 필요 시 side-output 등으로 state snapshot을 외부 DB로 export하여 조회용 데이터 구축.

 


외부 저장소(Redis 등) 기반 관리

동작 방식

  • 이벤트 처리 시 Redis에 사용자별 카운터 / 타임스탬프를 저장.
  • 피로도 체크 시 Redis 조회 → 조건 충족 시 이벤트 처리, 아니면 drop.
  • Redis의 INCR, EXPIRE 등을 활용하여 TTL 기반 제어 가능.

 

장점

  • 외부 접근성 우수: CRM, 백오피스, API 등 다양한 외부 시스템에서 즉시 참조 가능.
  • 운영 유연성: Redis 데이터만 보면 전체 상태 확인 가능.  (Prefix 를 이용, 전체 Keys는 운영중 절대 안됨!)
  • 확장성: Redis Cluster 등으로 수평 확장 가능.
  • 안정성 : Flink App의 재부팅 / 결함으로부터 자유로움

 

단점

  • 일관성 취약: Flink 처리 중 실패/재처리 시 Redis 값이 중복 증가할 수 있음.
  • 성능 부담: 외부 I/O 호출로 인해 latency 증가 가능.
  • 운영 복잡성: Redis 장애 시 파이프라인도 영향 받을 수 있음.

 

보완 방법

  • 원자적 연산(GET+INCR) 사용 및 Lua Script 기반 트랜잭션 처리.
  • 배치 보정 파이프라인: 하루/주 단위로 Redis 카운트를 원천 이벤트 로그와 맞추어 정합성 보정.
  • 모니터링/알림 : Redis Replica/Cluster 구성을 통한 가용성 확보

 


보관하는 값의 종류에 따른 차이점

 

운영 중 겪었던 문제

처음에는 모든  데이터를 Flink state로 관리하려 했습니다.
하지만 장애 복구 시 state 복원 크기가 커지면서 문제가 발생했습니다.

  • 복원 사례: 수십 GB 단위 state를 가진 잡이 재시작될 때→ 그동안 KPU(Flink 작업 슬롯)를 넉넉하게 늘려야만 안정적인 복구 가능
  • → 운영 비용과 복잡성이 증가
  • → Checkpoint restore 시간이 수십 분 이상 소요

이 경험을 통해 모든 값을 state에 넣는 건 정답이 아님을 깨달았습니다.
 

State로 관리하면 좋은 값들

State는 Flink의 강력한 무기입니다. 특히 **“스트림 내에서 바로 계산되는 값”**에는 최적화되어 있습니다.

  • 누적 값 (counters): 예) 특정 키(userId)의 이벤트 누적 개수
  • 평균/합/통계치 (aggregation): 예) 지난 5분간 클릭률 평균
  • 세션/윈도우 기반 임시 상태: 예) 10분 세션 동안 발생한 이벤트 패턴
  • 비교적 작은 사이즈의 데이터: 예) 단일 사용자 최근 5개 이벤트 저장

➡️ 이런 값들은 Flink checkpoint/restore와 exactly-once 보장이 잘 맞아떨어집니다.
 

외부 저장소로 관리하면 좋은 값들

반면, **“외부에서 참조가 필요하거나, 중복 증가가 치명적이지 않은 값”**은 Redis 같은 외부 저장소가 더 적합합니다.

  • Fatigue (발송 제약):→ CRM/운영툴에서 실시간 확인 가능
    • 중복으로 값이 과증가해도 보수적으로 동작 (안 보내는 쪽으로 기울어 안전)
  • 장기 보존이 필요한 값:→ Redis/DB에 두면 조회와 보정(batch pipeline) 용이
    • Flink state에 두면 checkpoint 부하 ↑
  • 운영 가시성이 중요한 값:
    • 운영자가 즉시 확인하고 조정해야 하는 데이터 (예: 사용자별 발송 제한 카운터)

➡️ 이런 값들은 Flink state보다 외부 저장소 + 보정 파이프라인이 더 안정적입니다
 

결론 및 선택 가이드

  • Flink State 중심 전략: 성능과 일관성이 가장 중요할 때 선택.
    • 알림 피로도 관리가 파이프라인 내부 로직에 국한되고, 외부에서 별도 조회 필요성이 적을 경우 적합.
  • Redis 중심 전략: 운영 가시성, 보수적 동작, 외부 연계성
    • 단, 재처리/중복 처리 리스크를 줄이기 위한 보완책이 필수.

맺음말

결국, fatigue 관리의 초점이 “실시간 정확성”인지 “운영 편의성”인지에 따라 선택지가 달라집니다.
저의 고민과 정리를 바탕으로, 비슷한 고민을 하고 계신 분들께 도움이 되길 바랍니다.

AWS Managed Flink + Kinesis DataStream 실시간 데이터 처리 시스템 개요

 

1. 개요

 

최근 데이터 처리 환경은 “실시간”이라는 키워드가 핵심입니다.

대용량 이벤트 스트림을 빠르게 수집하고, 실시간으로 분석·가공한 뒤 다양한 시스템에 전달해야 하는 요구가 있어서

AWS에서 제공되고 있는 Amazon Kinesis DataStream와 **Amazon Managed Service for Apache Flink(이하 Managed Flink)**를 활용해봤습니다.

 

이번 글에서는 이 두 서비스를 활용해 실시간 데이터 파이프라인을 구축하는 기본 개념과 설계 포인트를 정리해봅니다.

 


 

2. 서비스 개요

 

2.1 Amazon Kinesis

Kinesis는 AWS의 완전관리형 스트리밍 데이터 서비스입니다. (Kafka 와 유사하다고 생각하시면 됩니다.)

이 중 **Kinesis Data Streams(KDS)**를 사용하면 초당 수백 MB~GB급 이벤트를 안정적으로 수집·버퍼링할 수 있습니다.

 

특징

  • 샤드(Shard) 단위로 처리량 확장 가능 -> 파티션 과 유사
  • 순서 보장 및 재처리 지원
  • 초당 수천 TPS 가능
  • SDK, Firehose, CLI 등 다양한 연동 방식

 


 

2.2 Amazon Managed Flink

 

Apache Flink를 완전관리형으로 제공하는 서비스입니다.

Managed Flink를 사용하면 클러스터 관리나 배포 인프라 고민 없이, Flink 애플리케이션 개발에 집중할 수 있습니다.

단, 기본 Flink와 다르게 조정할 수 없는 Configuration 들이 있으니 공식문서를 참조해야 합니다.

 

특징

  • Flink 버전 업그레이드 및 인프라 관리 자동화
  • Kinesis, S3, DynamoDB 등 AWS 서비스와 Native 연동
  • Checkpoint/Savepoint를 통한 상태(State) 복구 지원
  • Scaling 자동화(Parallelism 조정)

 

3. 시스템 아키텍처 개요

  1. Producer: 실시간 Event 수집 Platform
  2. Kinesis Data Streams: 실시간 데이터 Queue
  3. Managed Flink: 실시간 데이터 처리(Enrichment, Filtering, Aggregation)
  4. Sink: 결과 저장(S3)

 

4. 구현 시 주요 고려사항

4.1 데이터 모델 & 직렬화

  • Flink와 Kinesis 간 전송 데이터는 기본사용은 kryo사용(reflect방식)으로 성능이 떨어지기 때문에 추후 스키마 진화를 생각하면 Avro, Protobuf 등 직렬화 포맷 선택하는것이 유리하다.

4.2 상태 관리(State Management)

  • Flink는 Keyed StateOperator State를 제공
  • 상태 크기가 커질수록 Checkpoint 주기와 저장소 성능이 중요하다.
  • AWS에서는 기본적으로 S3에 Checkpoint/Savepoint 저장하며 사용자는 접근이 불가능하다.

4.3 Checkpoint / Savepoint 전략

  • Checkpoint: 장애 시 자동 복구
  • Savepoint: 버전 배포·롤백 시 수동 복구
  • 체크포인트 주기는 1분~5분 권장, 처리량과 지연 시간에 따라 조정

4.4 Source/Sink Connector

  • Source: KinesisStreamsSource 또는 Flink Kinesis Connector
  • Sink: S3 로 기본사용

4.5 확장성(Scaling)

  • Kinesis는 샤드 수로 확장
  • Flink는 parallelism 조정 
  • 병목 지점(Shard → Flink 병렬도) 일치 여부 체크 필요
  • Parallelism과 KPU가 자동으로 계산되는데  4.2의 상태관리와 연관되어 재기동시 backpressure , 지연이 발생하지 않도록 처리시간 + 복원시간을 고려해야 한다.

 


5. 운영 팁

  1. CloudWatch + Managed Flink Metrics로 레이턴시, 백프레셔(backpressure) 모니터링
  2. Kinesis 샤드 모니터링 → 샤드 split/merge 자동화 스크립트 준비
  3. Flink 애플리케이션 버전 관리 → Git + CI/CD (CodePipeline, CodeBuild) 연동 , Flink재기동은 자동보다는 수동을 추천
  4. Data retention: Kinesis는 최대 7일, 그 이상은 S3에 Raw Data 저장
  5. 배포 전 로컬 환경에서 Flink MiniCluster로 테스트
  6. Flink 내 ProecssFunction에 대해서는 Harness를 이용해서 최대한 Test Code를 작성해둔다.

 

6. 간단한 예제 플로우

  • Source: Kinesis에서 JSON 데이터 읽기
  • KeyBy: UserId 단위 처리
  • ProcessFunction: 룰 매핑, 데이터 보강
  • Sink: S3 저장
DataStream<Event> source = env
    .fromSource(kinesisSource, WatermarkStrategy.noWatermarks(), "Kinesis Source")
    .map(json -> parseJson(json));

source
    .keyBy(Event::getUserId)
    .process(new CustomEnrichmentFunction())
    .addSink(s3Sink);

 

7.  결론

AWS Managed Flink + Kinesis 조합은 실시간 데이터 분석 파이프라인을 빠르고 안정적으로 구축할 수 있는 강력한 도구입니다.

인프라 운영 부담을 줄이고, 비즈니스 로직에 집중할 수 있다는 점이 가장 큰 장점입니다.

 

다만, 체크포인트 전략, 상태 크기 관리, Kinesis 샤드 수 조정 등 운영 노하우가 중요하니, 충분히 검증 / 모니터링을 후 본격 도입하는 것을 추천드립니다.

OAuth 2.0 Resource Server에서 JWT 토큰을 검증하고 권한을 처리하는 방법에 대해 알아보겠습니다. Spring Security를 사용하여 Resource Server를 구성하고, JWT 토큰의 scope와 roles 클레임을 권한으로 변환하는 과정을 살펴볼 것입니다. 또한, 자주 발생하는 SSL 관련 오류와 그 해결 방법에 대해서도 다룰 예정입니다.

 

Authorization_code vs Client_credentials

OAuth 2.0의 Authorization Code 방식과 Client Credentials 방식은 서로 다른 사용 사례와 흐름을 가지고 있습니다. 두 방식의 주요 차이점은 다음과 같습니다:
  • Authorization Code 방식:
    • 사용자 개입이 필요한 인증 흐름
    • 웹 애플리케이션이나 모바일 앱에서 주로 사용
    • 리소스 소유자(사용자)의 동의를 얻어 액세스 토큰을 발급
    • 보안성이 높고 refresh token을 사용할 수 있음
  • Client Credentials 방식:
    • 클라이언트 애플리케이션이 직접 자신의 자격 증명으로 인증
    • 서버 간 통신이나 백그라운드 작업에 주로 사용
    • 사용자 컨텍스트 없이 클라이언트 자체의 권한으로 액세스 토큰을 얻음
    • 간단하지만 사용자 특정 데이터에 접근할 수 없음

 

OAuth2 Authorization Server Setup

Spring Boot와 Spring Security를 사용하여 OAuth 2.0 Authorization Server를 구현하기 위해서는 다음과 같은 핵심 설정이 필요합니다:
  • spring-boot-starter-oauth2-authorization-server 의존성을 추가합니다
  • @EnableAuthorizationServer 어노테이션을 사용하여 OAuth 2.0 권한 부여 서버 구성을 활성화합니다
  • AuthorizationServerConfigurerAdapter를 상속받는 구성 클래스를 생성하고, 클라이언트 세부 정보, 토큰 저장소, 보안 제약 조건 등을 설정합니다
  • ClientDetailsServiceConfigurer를 사용하여 클라이언트 ID, 시크릿, 권한 부여 유형, 스코프 등을 정의합니다
  • JWT 토큰을 사용하는 경우, JwtAccessTokenConverter TokenStore를 구성하여 토큰 생성 및 검증 로직을 커스터마이즈할 수 있습니다
  • 사용자 인증을 위해 UserDetailsService를 구현하고, 비밀번호 인코딩을 위한 PasswordEncoder를 설정합니다
이러한 설정을 통해 기본적인 OAuth 2.0 Authorization Server를 구현할 수 있으며, 필요에 따라 추가적인 커스터마이징이 가능합니다.

 

Configuring Resource Server with JWT

 
JWT를 사용하는 리소스 서버 구성은 Spring Security의 OAuth 2.0 지원을 통해 간단히 설정할 수 있습니다. 주요 단계는 다음과 같습니다:
  • application.yml 파일에 spring.security.oauth2.resourceserver.jwt.issuer-uri 속성을 설정하여 JWT 발급자 URI를 지정합니다
  • @EnableWebSecurity 어노테이션과 함께 SecurityFilterChain 빈을 구성하여 JWT 인증을 활성화합니다
  • JwtDecoder 빈을 커스터마이즈하여 토큰 유효성 검사 로직을 추가할 수 있습니다
  • 필요한 경우 JwtAuthenticationConverter를 구현하여 JWT 클레임을 Spring Security의 권한으로 매핑합니다
이러한 설정을 통해 리소스 서버는 Authorization Server에서 발급한 JWT를 검증하고, 토큰에 포함된 스코프나 역할에 따라 접근 제어를 수행할 수 있습니다
 
 
What is Scope and Role
OAuth 2.0에서 scope와 role은 접근 제어를 위한 중요한 개념이지만, 그 용도와 적용 방식에 차이가 있습니다:
  • Scope: 클라이언트 애플리케이션이 사용자 리소스에 접근할 수 있는 범위를 정의합니다. 예를 들어, 'read:profile', 'write:email' 등으로 세분화된 권한을 나타냅니다.
    • Scope는 OAuth 2.0 프로토콜의 표준 부분으로, 인증 서버에서 관리됩니다.
  • Role: 사용자의 조직 내 역할이나 권한 수준을 나타냅니다. 예를 들어, 'admin', 'user', 'manager' 등이 있을 수 있습니다
    • Role은 주로 애플리케이션 내부에서 정의되고 관리됩니다.
적절한 사용:
  • Scope는 클라이언트 애플리케이션의 권한을 제한하는 데 사용합니다. 예: 'read:books'
  • Role은 사용자의 전반적인 권한 수준을 정의하는 데 사용합니다. 예: 'librarian'
두 개념을 조합하여 더 세밀한 접근 제어를 구현할 수 있습니다. 예를 들어, 'librarian' 역할을 가진 사용자에게만 'write:books' 스코프를 허용하는 방식으로 사용할 수 있습니다
 
 

Handling Roles and Scopes in Tokens

OAuth 2.0 토큰에서 역할(roles)과 범위(scopes)를 처리하는 것은 리소스 서버의 중요한 기능입니다. Spring Security에서는 JwtAuthenticationConverter를 사용하여 이를 구현할 수 있습니다:
  • JWT 토큰의 'scope' 클레임을 Spring Security의 권한으로 자동 변환합니다.
  • 커스텀 'roles' 클레임을 처리하려면 JwtAuthenticationConverter를 확장하여 구현합니다.
  • GrantedAuthoritiesMapper를 사용하여 클레임을 세분화된 권한으로 매핑할 수 있습니다.
  • 보안 구성에서 @PreAuthorize 또는 hasRole() 메소드를 사용하여 엔드포인트별 권한을 설정합니다.
이러한 방식으로 토큰의 역할과 범위를 효과적으로 처리하여 세밀한 접근 제어를 구현할 수 있습니다.

Customizing Token Claims

JWT 토큰의 클레임을 커스터마이즈하는 것은 OAuth 2.0 인증 서버에서 중요한 기능입니다. Spring Security에서는 OAuth2TokenCustomizer 인터페이스를 구현하여 이를 수행할 수 있습니다
 
- @Bean 메서드를 통해 OAuth2TokenCustomizer를 구현합니다.
- customize 메서드 내에서 context.getClaims()를 사용하여 JWT 클레임에 접근합니다.
- claims.put() 메서드로 커스텀 클레임을 추가하거나 기존 클레임을 수정합니다.
- 사용자의 권한이나 역할을 클레임으로 추가하려면 context.getPrincipal()에서 정보를 추출합니다

 

이 방법을 통해 리소스 소유자의 추가 정보나 애플리케이션 특정 데이터를 토큰에 포함시킬 수 있어, 리소스 서버에서 더 세밀한 접근 제어가 가능해집니다.
 

Resolving Errors

OAuth 2.0 구현 시 JwtDecoder와 SSL 관련 오류를 해결하는 방법은 다음과 같습니다:
  • JwtDecoder 오류: NimbusJwtDecoder.withJwkSetUri()를 사용하여 JWK Set URI를 명시적으로 설정합니다.
    • 이때 URI가 올바른지 확인하고, 필요한 경우 커스텀 RestTemplate을 구성하여 추가적인 헤더나 인증을 처리할 수 있습니다.
  • SSL 인증서 오류: 개발 환경에서는 server.ssl.key-store-type=PKCS12 server.ssl.key-store=classpath:keystore.p12를 설정하여 자체 서명된 인증서를 사용할 수 있습니다.
  • 프로덕션 환경에서는 신뢰할 수 있는 인증 기관에서 발급한 유효한 SSL 인증서를 사용해야 합니다.
이러한 설정을 통해 대부분의 JwtDecoder 및 SSL 관련 오류를 해결할 수 있으며, 안전하고 신뢰할 수 있는 OAuth 2.0 인증 흐름을 구현할 수 있습니다.
 
 

Setting Up JWK URI for Validation

  • application.yml 파일에 spring.security.oauth2.resourceserver.jwt.jwk-set-uri 속성을 추가합니다.  이 URI는 일반적으로 https:///.well-known/jwks.json 형식을 따릅니다.
  • 보안 구성 클래스에서 JwtDecoder 빈을 커스터마이즈하여 JWK URI를 명시적으로 설정할 수 있습니다
    • JWT 토큰 검증을 위한 JWK (JSON Web Key) URI 설정은 OAuth 2.0 리소스 서버 구현의 중요한 부분입니다.
이러한 설정을 통해 리소스 서버는 Authorization Server에서 제공하는 공개 키를 사용하여 JWT 토큰의 서명을 검증할 수 있으며, 토큰의 무결성과 신뢰성을 보장할 수 있습니다.

 

개요


AWS RDS와 DynamoDB의 비용 및 성능 비교는 데이터베이스 선택 시 중요한 고려사항입니다. 이 분석에서는 두 서비스의 비용 구조, 성능 특성, 그리고 대규모 쓰기 작업 시나리오에서의 비용 효율성을 살펴보았습니다. 또한 고가용성을 위한 중복 구성 시의 비용과 Spring Boot와의 연동 방법에 대해서도 논의하였습니다.

 

AWS RDS vs DynamoDB 비용비교

 
AWS RDS와 DynamoDB의 비용 비교에서, 25백만 건의 500바이트 레코드(총 12.5GB)를 기준으로 분석한 결과, DynamoDB가 RDS보다 상당히 높은 비용을 보였습니다. DynamoDB의 월간 비용은 $937.5로 추정되며, 이는 주로 쓰기 작업에 따른 비용입니다. 반면 RDS의 월간 비용은 $198.24로, 인스턴스 비용과 쓰기 작업 비용을 포함합니다. 이러한 차이는 DynamoDB의 쓰기 중심 요금 체계와 RDS의 인스턴스 기반 요금 구조의 차이에서 비롯됩니다.
      • DynamoDB: 쓰기 작업당 $1.25/백만 건, 스토리지 비용 $0.25/GB/월
      • RDS: 인스턴스 비용(예: db.t3.medium) + 쓰기 작업 비용 $0.20/백만 건

고가용성 구성 시, DynamoDB의 비용은 $1,406.25로 증가하며, RDS Multi-AZ는 $297.36로 증가합니다

선택은 애플리케이션의 요구사항, 확장성 필요, 그리고 운영 팀의 역량을 고려하여 이루어져야 합니다. DynamoDB는 글로벌 확장성과 관리 용이성에서 우위를 보이며, RDS는 복잡한 쿼리와 트랜잭션 지원에 더 적합합니다.
 
 

추가적으로 비용에서 고려할 수 있는 부분

AWS 데이터베이스 서비스의 비용을 고려할 때, 다음과 같은 추가적인 요소들을 염두에 두어야 합니다:
  • 데이터 전송 비용: AWS 리전 간 또는 인터넷으로의 데이터 전송에 따른 추가 비용이 발생할 수 있습니다.
  • 백업 및 복구: RDS의 경우 자동 백업과 수동 스냅샷에 대한 추가 스토리지 비용이 발생할 수 있으며, DynamoDB는 온디맨드 백업과 특정 시점으로의 복구(PITR) 기능에 대한 비용이 추가될 수 있습니다.
  • 성능 최적화: RDS의 경우 쿼리 최적화를 통해 성능을 향상시키고 비용을 절감할 수 있습니다. 예를 들어, AI 기반 최적화 도구를 사용하여 쿼리 성능을 23배까지 향상시킨 사례가 있습니다.
  • 서버리스 옵션: Amazon Athena와 같은 서버리스 쿼리 서비스를 사용하면 데이터 스캔량에 따라 비용이 청구되며, S3 Express One Zone 스토리지 클래스를 활용하여 쿼리 성능을 최대 2.1배 향상시킬 수 있습니다.
이러한 요소들을 고려하여 총소유비용(TCO)을 산정하고, 애플리케이션의 요구사항에 맞는 최적의 데이터베이스 솔루션을 선택해야 합니다.
 
 

Spring Boot 환경에서 DynamoDB 를 사용할때 설정해야 하는 부분

Spring Boot 환경에서 DynamoDB를 사용할 때는 다음과 같은 주요 설정을 고려해야 합니다:
  • 의존성 추가: spring-boot-starter-data-dynamodb와 AWS SDK 의존성을 pom.xml에 추가합니다.
  • DynamoDB 클라이언트 구성: AmazonDynamoDB 빈을 생성하고, 리전, 엔드포인트, 인증 정보를 설정합니다.
  • 리포지토리 인터페이스 정의: @EnableDynamoDBRepositories 어노테이션을 사용하여 DynamoDB 리포지토리를 활성화하고, CrudRepository를 확장한 인터페이스를 생성합니다.
  • 엔티티 매핑: @DynamoDBTable, @DynamoDBHashKey, @DynamoDBRangeKey 등의 어노테이션을 사용하여 Java 객체를 DynamoDB 테이블에 매핑합니다.
  • 트랜잭션 관리: DynamoDB의 제한된 트랜잭션 지원을 고려하여, 필요한 경우 @Transactional 어노테이션을 사용하되 주의가 필요합니다.
이러한 설정을 통해 Spring Boot 애플리케이션에서 DynamoDB를 효과적으로 사용할 수 있으며, 개발 생산성을 높일 수 있습니다.
 
 

DynamoDB 사용과 Application Integration에서 고려사항

DynamoDB를 애플리케이션에 통합할 때 성능과 비용 최적화를 위해 고려해야 할 주요 사항들은 다음과 같습니다:
  • 지연 시간 관리: DynamoDB는 일반적으로 10-20ms의 낮은 지연 시간을 제공하지만, 반복적인 다중 항목 작업의 경우 일관된 평균 성공 요청 지연 시간을 보장합니다.
  • 데이터 모델링: 애플리케이션의 액세스 패턴에 맞춰 효율적인 파티션 키와 정렬 키를 설계하여 읽기/쓰기 성능을 최적화합니다.
  • 배치 작업 활용: 여러 개의 개별 요청 대신 BatchGetItem 또는 BatchWriteItem 작업을 사용하여 처리량을 향상시키고 비용을 절감합니다.
  • 글로벌 테이블 고려: 다중 지역 배포가 필요한 경우, 글로벌 테이블을 사용하여 지연 시간을 줄이고 데이터 일관성을 유지할 수 있습니다.
  • 캐싱 전략: Amazon DynamoDB Accelerator(DAX)를 활용하여 읽기 성능을 향상시키고 DynamoDB 요청 비용을 절감합니다.
  • 비용 모니터링: AWS Cost Explorer를 사용하여 DynamoDB 사용량을 지속적으로 모니터링하고 필요에 따라 용량을 조정합니다.

이러한 고려사항들을 적절히 적용하면 DynamoDB를 효율적으로 활용하여 애플리케이션의 성능을 최적화하고 운영 비용을 절감할 수 있습니다.


 

DynamoDB 비용 최적화 전략

DynamoDB 비용 최적화를 위해서는 다음과 같은 전략을 고려할 수 있습니다:
  • 적절한 용량 모드 선택: 온디맨드 용량 모드는 트래픽 예측이 어려운 경우에 유용하며, 프로비저닝된 용량 모드는 일정한 트래픽 패턴에 더 경제적입니다
  • 스토리지 클래스 최적화: 자주 액세스하지 않는 데이터의 경우 Standard-Infrequent Access(IA) 스토리지 클래스로 전환하여 스토리지 비용을 절감할 수 있습니다.
  • 효율적인 쿼리 설계: Scan 작업 대신 Query 작업을 사용하고, 적절한 인덱스를 설정하여 읽기 용량 단위(RCU) 사용을 최소화합니다.
  • 데이터 수명 주기 관리: TTL(Time to Live) 기능을 활용하여 불필요한 데이터를 자동으로 삭제하고 스토리지 비용을 절감합니다.
  • 모니터링 및 최적화: AWS Cost Explorer를 활용하여 비용 구조를 분석하고, 필요에 따라 용량을 조정합니다.

이러한 전략을 적용하면 DynamoDB 사용 비용을 크게 절감할 수 있으며, 특히 대규모 데이터를 다루는 경우 더욱 효과적입니다.


+ Recent posts