프로세서를 하나 정지시켰을 뿐인데 노드가 클러스터에서 떨어져 나간다.
Failed to replicate request PUT /nifi-api/processors/<processor-id>/run-status
to <node>:<port> due to java.net.SocketTimeoutException: timeout
NiFi 클러스터는 조정자가 없는 대칭 구조로, UI 에서 들어온 변경 요청을 클러스터 조정자가 모든 노드에 복제 하고 전원이 성공해야 적용한다. 한 노드가 제한 시간 안에 응답하지 못하면 그 요청은 실패하고, 응답하지 못한 노드는 연결이 끊긴 것으로 처리된다. 프로세서 정지 같은 가벼운 작업이라도 예외가 아니다.
응답이 늦는 실제 원인은 대개 노드의 상태다. 긴 Full GC, 스레드 고갈, 거대한 flow.json 직렬화, 디스크 지연이 겹치면 수십 초 동안 HTTP 응답을 못 준다.
grep -E 'Disconnect|Failed to replicate|GC' /var/log/nifi/nifi-app.log | tail -50
jcmd $(pgrep -f org.apache.nifi.NiFi) GC.heap_info
/opt/nifi/bin/nifi.sh diagnostics --verbose /tmp/nifi-diag.txt
nifi-app.log 에 응답하지 못한 노드가 어느 쪽인지 남는다. 그 노드에서 GC 로그와 스레드 덤프를 확인한다. 힙이 작아 Full GC 가 길어지는 것이 가장 흔하다.
타임아웃 값은 nifi.properties 에서 올릴 수 있다. 근본 원인을 고치기 전의 완충 조치로만 쓴다.
nifi.cluster.node.connection.timeout=30 sec
nifi.cluster.node.read.timeout=30 sec
nifi.cluster.node.protocol.max.threads=50
떨어져 나간 노드는 UI 의 클러스터 화면에서 Connect 로 다시 붙인다. 그래도 붙지 않으면 그 노드만 재기동한다. 플로우가 어긋나 거부되면 그 노드의 flow.json.gz 를 지우고 다시 띄워 클러스터 플로우를 받게 한다. 정본이 살아 있는 쪽에서는 지우지 않는다.
프로세서나 포트를 정지시켰는데 활성 스레드 표시가 남아 있는 경우다. 정지는 새 작업을 스케줄하지 않는다 는 뜻이며, 이미 실행 중인 스레드가 끝나기를 기다린다. 외부 시스템 응답을 기다리는 소켓이나 끝나지 않는 쿼리가 물려 있으면 그 스레드는 영원히 끝나지 않는다.
먼저 무엇을 붙잡고 있는지 확인한다.
jstack $(pgrep -f org.apache.nifi.NiFi) | grep -A 30 'Timer-Driven Process Thread'
정지한 뒤에도 남아 있는 스레드는 우클릭 메뉴의 Terminate 로 강제 종료할 수 있다. Terminate 는 Stop 이후에만 활성화되며, 세션을 롤백하므로 처리 중이던 FlowFile 은 입력 큐로 돌아온다.
사이트 투 사이트 입력 포트라면 상대 쪽 Remote Process Group 이 계속 밀어 넣고 있는지도 본다. 보내는 쪽을 멈추지 않으면 받는 포트는 계속 새 전송을 받아들인다.
재발을 줄이려면 원격 호출 프로세서에 타임아웃을 반드시 준다. InvokeHTTP 의 Connection Timeout · Read Timeout, ExecuteSQL 의 Max Wait Time, ExecuteStreamCommand 의 Execution Timeout 이 그것이다. 기본값이 0(무한)인 속성이 있으므로 그대로 두지 않는다.