

기계 번역으로 제공되는 번역입니다. 제공된 번역과 원본 영어의 내용이 상충하는 경우에는 영어 버전이 우선합니다.

# 체크포인트
<a name="troubleshooting-checkpoints"></a>

체크포인트는 애플리케이션의 상태가 내결함성을 갖는지 확인하는 Flink의 메커니즘입니다. 이 메커니즘을 통해 Flink는 작업이 실패할 경우 연산자의 상태를 복구할 수 있으며 애플리케이션에는 오류 없는 실행과 동일한 의미를 부여합니다. Managed Service for Apache Flink를 사용하면 애플리케이션의 상태가 디스크에 작동 상태를 유지하는 내장형 키/값 저장소인 RocksDB에 저장됩니다. 체크포인트를 가져오면 상태가 Amazon S3에도 업로드되므로 디스크가 손실되더라도 체크포인트를 사용하여 애플리케이션 상태를 복원할 수 있습니다.

자세한 설명은 [상태 스냅샷은 어떻게 작동하는가?](https://nightlies.apache.org/flink/flink-docs-master/docs/learn-flink/fault_tolerance/#how-does-state-snapshotting-work) 섹션을 참조하세요.

## 체크포인트 단계
<a name="troubleshooting-checkpointing-stages"></a>

Flink의 체크포인트 연산자 하위 태스크에는 5대 단계가 있습니다:
+ 대기 [**시작 지연**] – Flink는 스트림에 삽입되는 체크포인트 장벽을 사용하므로 이 단계의 시간은 연산자가 체크포인트 장벽에 도달할 때까지 기다리는 시간입니다.
+ 정렬 **[정렬 지속 시간**] – 이 단계에서 하위 작업은 하나의 장벽에 도달했지만 다른 입력 스트림으로 들어오는 장벽을 기다리고 있습니다.
+ 동기화 체크포인트 [**동기화 지속 시간**] – 이 단계는 하위 작업이 실제로 연산자의 상태를 스냅샷하고 하위 작업의 다른 모든 활동을 차단하는 단계입니다.
+ 비동기 체크포인트 [**비동기 지속 시간**] – 이 단계의 대부분은 상태를 Amazon S3에 업로드하는 하위 작업입니다. 이 단계에서는 하위 작업이 더 이상 차단되지 않고 레코드를 처리할 수 있습니다.
+ 승인 – 일반적으로 짧은 단계이며 단순히 하위 작업이 JobManager에 승인을 보내고 위탁 메시지(예컨대, Kafka 싱크와 함께)를 수행하는 단계입니다.

 이러한 각 단계(승인 단계 제외)는 Flink WebUI에서 사용할 수 있는 체크포인트의 기간 지표에 매핑되므로 긴 체크포인트의 원인을 파악하는 데 도움이 될 수 있습니다.

체크포인트에서 사용할 수 있는 각 지표의 정확한 정의를 보려면 [이력 탭](https://nightlies.apache.org/flink/flink-docs-release-1.13/docs/ops/monitoring/checkpoint_monitoring/#history-tab)으로 이동하십시오.

## 조사 중
<a name="troubleshooting-checkpoints-investigating"></a>

긴 체크포인트 기간을 조사할 때 가장 중요한 것은 체크포인트의 병목 현상, 즉 어떤 연산자와 하위 작업이 체크포인트에 가장 오래 걸리고 해당 하위 작업의 어느 단계에 오랜 시간이 걸리는지입니다. 이는 작업 체크포인트 태스크에서 Flink WebUI를 사용하여 확인할 수 있습니다. Flink의 웹 인터페이스는 체크포인트 문제를 조사하는 데 도움이 되는 데이터와 정보를 제공합니다. 자세한 설명은 [체크포인트 모니터링](https://nightlies.apache.org/flink/flink-docs-release-1.13/docs/ops/monitoring/checkpoint_monitoring/)을 참조하십시오.

 가장 먼저 살펴볼 것은 Job 그래프에서 각 연산자의 **단대단 지속시간**입니다. 이를 통해 어떤 연산자가 체크포인트에 걸리는 시간이 소요되며 추가 조사가 필요한지 확인할 수 있습니다. Flink 설명서에 따르면 지속시간의 정의는 다음과 같습니다:

*트리거 타임스탬프부터 가장 최근 승인까지 남은 시간(또는 아직 승인이 수신되지 않은 경우 해당 없음). 전체 체크포인트의 단대단 지속 시간은 체크포인트를 승인하는 마지막 하위 작업에 의해 결정됩니다. 이 시간은 일반적으로 단일 하위 작업에서 상태를 실제로 체크포인팅하는 데 필요한 시간보다 큽니다.*

체크포인트를 위한 다른 지속시간은 또한 그 시간이 어디에 사용되는지에 대한 보다 세밀한 정보를 제공합니다.

**동기화 지속 시간**이 길면 스냅샷 중에 문제가 발생한 것입니다. 이 단계에서는 SnapshotState 인터페이스를 구현하는 클래스를 얻기 위해 `snapshotState()`을 호출합니다. 이것은 사용자 코드일 수 있으므로 스레드 덤프가 이 문제를 조사하는 데 유용할 수 있습니다.

**비동기 지속 시간**이 길면 상태를 Amazon S3에 업로드하는 데 많은 시간이 소요되고 있음을 알 수 있습니다. 이는 상태가 크거나 업로드되는 상태 파일이 많은 경우 발생할 수 있습니다. 이런 경우에는 애플리케이션이 상태를 어떻게 사용하는지 조사하고 가능한 경우 Flink 네이티브 데이터 구조가 사용되고 있는지 확인하는 것이 좋습니다 ([관건 상태 사용](https://nightlies.apache.org/flink/flink-docs-master/docs/dev/datastream/fault-tolerance/state/#using-keyed-state)). Managed Service for Apache Flink는 Amazon S3 호출 횟수를 최소화하는 방식으로 Flink를 구성하여 호출이 너무 오래 걸리지 않도록 합니다. 다음은 연산자의 체크포인트 통계 예입니다. 이전 연산자 체크포인트 통계에 비해 **비동기 지속 시간**이 상대적으로 길다는 것을 알 수 있습니다.

![\[체크포인트 조사\]](http://docs.aws.amazon.com/ko_kr/managed-flink/latest/java/images/checkpoint.png)


**개시 지연**이 높으면 대부분의 시간이 체크포인트 장벽이 연산자에게 도달하기를 기다리는 데 소비되고 있다는 것을 알 수 있습니다. 이는 애플리케이션에서 기록을 처리하는 데 시간이 오래 걸리고 있다는 것을 의미하며, 이는 작업 그래프를 통해 장벽이 느리게 흐르고 있음을 의미합니다. 이는 일반적으로 Job이 역압을 받거나 연산자가 계속 바쁠 경우에 해당합니다. 다음은 두 번째 KeyedProcess 연산자가 사용 중인 JobGraph의 예입니다.

![\[체크포인트 조사\]](http://docs.aws.amazon.com/ko_kr/managed-flink/latest/java/images/checkpoint2.png)


Flink Graphs 또는 TaskManager 스레드 덤프를 사용하여 무엇이 그렇게 오래 걸리는지 조사할 수 있습니다. 병목 현상이 확인되면 Flame-graph 또는 스레드 덤프를 사용하여 더 자세히 조사할 수 있습니다.

## 스레드 덤프
<a name="troubleshooting-checkpoints-investigating-thread-dumps"></a>

스레드 덤프는 플레임 그래프보다 약간 낮은 수준에 있는 또 다른 디버깅 도구입니다. 스레드 덤프는 특정 시점의 모든 스레드의 실행 상태를 출력합니다. Flink는 Flink 프로세스 내 모든 스레드의 실행 상태인 JVM 스레드 덤프를 사용합니다. 스레드 상태는 스레드의 스택 트레이스와 몇 가지 추가 정보로 표시됩니다. 실제로 플레임 그래프는 여러 개의 스택 트레이스를 연속으로 빠르게 캡처하여 작성합니다. 그래프는 이러한 트레이스를 바탕으로 만든 가시화이므로 일반적인 코드 경로를 쉽게 식별할 수 있습니다.

```
"KeyedProcess (1/3)#0" prio=5 Id=1423 RUNNABLE
    at app//scala.collection.immutable.Range.foreach$mVc$sp(Range.scala:154)
    at $line33.$read$$iw$$iw$ExpensiveFunction.processElement(<console>>19)
    at $line33.$read$$iw$$iw$ExpensiveFunction.processElement(<console>:14)
    at app//org.apache.flink.streaming.api.operators.KeyedProcessOperator.processElement(KeyedProcessOperator.java:83)
    at app//org.apache.flink.streaming.runtime.tasks.OneInputStreamTask$StreamTaskNetworkOutput.emitRecord(OneInputStreamTask.java:205)
    at app//org.apache.flink.streaming.runtime.io.AbstractStreamTaskNetworkInput.processElement(AbstractStreamTaskNetworkInput.java:134)
    at app//org.apache.flink.streaming.runtime.io.AbstractStreamTaskNetworkInput.emitNext(AbstractStreamTaskNetworkInput.java:105)
    at app//org.apache.flink.streaming.runtime.io.StreamOneInputProcessor.processInput(StreamOneInputProcessor.java:66)
    ...
```

위는 Flink UI에서 단일 스레드에 대해 가져온 스레드 덤프의 스니펫입니다. 첫 번째 줄에는 다음을 포함하여 이 스레드에 대한 몇 가지 일반 정보가 포함되어 있습니다:
+ 스레드 명칭 *KeyedProcess (*1/3) \$10
+ 스레드의 우선순위 *prio=5*
+ 고유 스레드 ID *ID=1423*
+ 스레드 상태 *실행 가능*

 스레드 명칭은 일반적으로 스레드의 일반적인 용도에 대한 정보를 제공합니다. 연산자 스레드는 연산자와 명칭이 같기 때문에 연산자 스레드는 그 명칭으로 식별할 수 있으며 스레드가 어떤 하위 작업과 관련되어 있는지를 나타냅니다. 예컨대, *KeyedProcess (1/3)\$10* 스레드는 *KeyedProcess* 연산자 출신으로서 (3개 중) 첫 번째 하위 태스크에서 온 것입니다.

스레드는 몇 가지 상태 중 하나일 수 있습니다.
+ 신규 – 스레드가 생성되었지만 아직 처리되지는 않았음.
+ 실행 가능 – 스레드가 CPU에서 실행 중임.
+ 차단됨 – 스레드가 다른 스레드에 의한 잠금 해제를 기다리고 있음.
+ 대기 – `wait()`, `join()`, 또는 `park()` 메서드를 사용함으로써 스레드가 대기 중임.
+ TIMED\$1WAITING – 스레드가 sleep, wait, join 또는 park 메서드를 사용하여 대기 중이지만 대기 시간은 최대로 설정되어 있음.

**참고**  
Flink 1.13에서는 스레드 덤프에 있는 단일 스택 트레이스의 최대 깊이가 8로 제한됩니다.

**참고**  
스레드 덤프는 읽기가 어렵고 여러 샘플을 채취하여 수동으로 분석해야 하므로 Flink 애플리케이션에서 성능 문제를 디버깅할 때 최후의 수단이어야 합니다. 가능하면 플레임 그래프를 사용하는 것이 좋습니다.

### Flink의 스레드 덤프
<a name="troubleshooting-checkpoints-investigating-thread-dumps-flink"></a>

Flink에서는 Flink UI의 왼쪽 탐색 표시줄에서 **작업 관리자** 옵션을 선택하고 특정 작업 관리자를 선택한 다음 스레드 덤프 탭으로 이동하여 **스레드 덤프**를 가져올 수 있습니다. 스레드 덤프는 다운로드하거나 즐겨 사용하는 텍스트 편집기 (또는 스레드 덤프 분석기) 에 복사하거나 Flink 웹 UI의 텍스트 보기 내에서 직접 분석할 수 있습니다 (하지만 이 마지막 옵션은 약간 복잡할 수 있습니다).

스레드 덤프를 수행할 작업 관리자를 결정하려면 특정 연산자를 선택한 경우 **TaskManager** 탭의 스레드 덤프를 사용할 수 있습니다. 이는 연산자가 연산자의 여러 하위 작업에서 실행되고 있으며 다른 작업 관리자에서 실행될 수 있음을 나타냅니다.

![\[스레드 덤프 사용\]](http://docs.aws.amazon.com/ko_kr/managed-flink/latest/java/images/checkpoint4.png)


덤프는 여러 스택 트레이스로 구성됩니다. 하지만 덤프를 조사할 때는 연산자와 관련된 것이 가장 중요합니다. 연산자 스레드는 연산자와 이름이 같을 뿐만 아니라 해당 스레드가 어떤 하위 작업과 관련되어 있는지 알 수 있기 때문에 쉽게 찾을 수 있습니다. 예를 들어 다음 스택 트레이스는 *KeyedProcess* 연산자에서 가져온 것이며 첫 번째 하위 태스크입니다.

```
"KeyedProcess (1/3)#0" prio=5 Id=595 RUNNABLE
    at app//scala.collection.immutable.Range.foreach$mVc$sp(Range.scala:155)
    at $line360.$read$$iw$$iw$ExpensiveFunction.processElement(<console>:19)
    at $line360.$read$$iw$$iw$ExpensiveFunction.processElement(<console>:14)
    at app//org.apache.flink.streaming.api.operators.KeyedProcessOperator.processElement(KeyedProcessOperator.java:83)
    at app//org.apache.flink.streaming.runtime.tasks.OneInputStreamTask$StreamTaskNetworkOutput.emitRecord(OneInputStreamTask.java:205)
    at app//org.apache.flink.streaming.runtime.io.AbstractStreamTaskNetworkInput.processElement(AbstractStreamTaskNetworkInput.java:134)
    at app//org.apache.flink.streaming.runtime.io.AbstractStreamTaskNetworkInput.emitNext(AbstractStreamTaskNetworkInput.java:105)
    at app//org.apache.flink.streaming.runtime.io.StreamOneInputProcessor.processInput(StreamOneInputProcessor.java:66)
    ...
```

이름이 같은 연산자가 여러 개 있는 경우 혼란스러울 수 있지만 연산자의 이름을 지정하여 이러한 문제를 피할 수 있습니다. 예제:

```
....
.process(new ExpensiveFunction).name("Expensive function")
```

## [플레임 그래프](https://nightlies.apache.org/flink/flink-docs-release-1.13/docs/ops/debugging/flame_graphs/)
<a name="troubleshooting-checkpoints-investigating-flame-graphs"></a>

플레임 그래프는 목적지 코드의 스택 트레이스를 가시화하는 유용한 디버깅 도구로, 이를 통해 가장 빈번한 코드 경로를 식별할 수 있습니다. 스택 트레이스를 여러 번 샘플링하여 생성합니다. 플레임 그래프의 x 축은 다양한 스택 프로필을 보여주고, y 축은 스택 깊이와 스택 트레이스에서의 호출을 보여줍니다. 플레임 그래프에서 단일 직사각형은 스택 프레임을 나타내며, 프레임 너비는 스택에서 해당 사각형이 나타나는 빈도를 나타냅니다. 플레임 그래프 및 사용 방법에 대한 자세한 설명은 [플레임 그래프](https://www.brendangregg.com/flamegraphs.html)를 참조하십시오.

Flink에서는 연산자를 선택한 다음 **FlameGraph** 탭을 선택하여 웹 UI를 통해 연산자에 대한 플레임 그래프에 액세스할 수 있습니다. 샘플이 충분히 수집되면 플레임 그래프가 표시됩니다. 다음은 체크포인트에 많은 시간이 걸렸던 ProcessFunction의 플레임 그래프입니다.

![\[플레임 그래프 사용\]](http://docs.aws.amazon.com/ko_kr/managed-flink/latest/java/images/checkpoint3.png)


이것은 매우 간단한 플레임 그래프로, 모든 CPU 시간이 ExpensiveFunction 연산자의 `processElement`내의 foreach 룩에 소비되고 있음을 보여줍니다. 또한 라인 번호도 확인할 수 있어 코드 실행이 이루어지는 위치를 파악하는 데 도움이 됩니다.