DB·NAS·Kafka 세 원천의 수집 PG 전체에 일시 장애 자동 재시도를 넣기 위해 정한 Retry 표준과, ExecuteStreamCommand 로 CDE 잡을 호출하는 흐름에서 겪은 두 문제(변수값이 엉뚱하게 치환되는 문제, 큐에 쌓인 FlowFile 수만큼 잡이 중복 제출되는 문제)를 정리한다.
각 프로세서 우클릭 → Configure → RELATIONSHIPS 탭에서 failure 를 Retry 로 바꾸고 아래 값을 준다.
| 프로세서 | Attempts | Back Off Policy | Max Back Off |
|---|---|---|---|
| PutHDFS / MoveHDFS / PutKudu / PutSQL | 3 | Penalize | 30 sec |
| ExecuteSQLRecord (정규 스케줄) | 2 | Penalize | 30 sec |
| ExecuteSQLRecord (재수행) · ExecuteStreamCommand | 적용 제외 |
Yield 는 프로세서 전체를 멈추므로 외부 시스템이 완전히 죽었을 때만 쓴다.kudu-operations-timeout-ms)이 따로 정한다. 처음 10초로 잡았다가 30초로 통일했다.여러 노드가 같은 HDFS 파티션에 쓰는 3리전 PG 는 PutHDFS 진입 커넥션에 Single node 를 걸어 두지 않으면 재시도가 충돌을 반복한다. failure 가 이미 다른 프로세서(알림 등)로 연결돼 있으면 Retry 로 바꾸는 순간 그 연결이 풀리므로 최종 실패 경로를 다시 붙여야 한다.
${dagname} 이 Variables 에 설정한 값이 아니라 다른 값으로 치환됐다면 FlowFile 속성이 이겼기 때문이다. NiFi EL 은 다음 순서로 값을 찾는다.
상류 UpdateAttribute 가 같은 이름의 속성을 만들면 Variables 값은 무시된다. ExecuteStreamCommand 는 실행 시 치환이 끝난 인자를 execution.command.args 속성에 기록하므로 Data Provenance 의 Attributes 탭에서 실제로 넘어간 값을 바로 확인할 수 있다. Variables 는 NiFi 1.28 에서 deprecated 이며 Parameter Context(#{name})는 FlowFile 속성에 덮어써지지 않으므로 그쪽으로 옮기는 편이 낫다.
| 속성 | 권장 | 이유 |
|---|---|---|
| Ignore STDIN | true | 바이너리 콘텐츠가 bash 의 stdin 으로 밀려들어 파이프가 막힌다 |
| Output Destination Attribute | 지정 | 미지정이면 명령의 stdout 이 FlowFile 콘텐츠를 덮어써 원본이 빈 파일이 된다 |
| Max Attribute Length | 4096 이상 | 256 이면 execution.error 가 잘려 원인을 못 본다 |
| 동적 프로퍼티 | PATH, HOME, KRB5CCNAME, HTTPS_PROXY, NO_PROXY, JAVA_HOME | 로그인 셸이 아니라 .bash_profile 을 읽지 않는다 |
수동으로는 되는데 NiFi 에서만 실패하면 sudo -u nifi env -i /bin/bash script.sh 로 재현해 본다. wrapper 스크립트가 exit $? 로 curl 의 코드를 그대로 넘기면 6 은 DNS 해석 실패다.
ExecuteStreamCommand 는 FlowFile 한 건마다 한 번 실행된다. 큐에 33건이 있으면 같은 DAG 가 33번 제출되고, CDE 는 동시 Spark 잡 제출 60개를 넘으면 HTTP 429 (CLI exit 77)를 돌려준다. 테이블 적재는 N 건이되 잡 트리거는 1 건이어야 하면 앞에 MergeContent(Correlation Attribute = dagname, Max Bin Age 5 min)를 두거나 Wait/Notify(fragment.identifier / fragment.count)를 쓴다. DetectDuplicate 로 ${dagname}-${part_ymd} 캐시 키를 걸면 하루 1회만 통과시키는 안전장치가 된다. 큐에 retryCount 속성이 붙은 FlowFile 이 많으면 새 데이터가 아니라 재시도 루프가 도는 것이니 RouteOnAttribute 로 상한을 둔다.