NiFi 起不来、登不上、节点被挤掉:一份按日志定位的排错清单

4 阅读24分钟

NiFi 起不来、登不上、节点被挤掉:一份按日志定位的排错清单

这是「NiFi 生产集群」系列的第 5 篇,也是这套环境从 2022 年上线到 2026 年,所有"救火"记录的汇总。

上一篇:FTP→HDFS 与 CSV→Parquet,附坏数据、漏文件与双写 下一篇:NiFi 集群长期运维:并发线程、content 仓库、日志与漏洞面

这一篇按"症状 → 日志关键字 → 根因 → 处置"组织。建议收藏当手册用:出问题时不用从头读,直接按报错里的关键字搜。

0. 先按这个顺序定位

NiFi 的报错有个特点:表层症状和根因往往隔了两三层。UI 打不开,可能是证书、可能是授权、可能是 ZK、也可能是 JVM 堆太小。先按下面的顺序排除,比乱翻日志快:

不在
在
不通
通
证书
登录失败
空白或403
超时或500
打不开/起不来
进程还在?
看 logs/nifi-app.log 最后 100 行
以及 nifi-bootstrap.log
9443 端口通?
看 Jetty 启动日志 / 端口占用
浏览器报错类型
keystore / truststore / CN
Kerberos / krb5.conf / 身份映射
authorizer / users.xml
JVM 堆 / 集群通信 / primary 负载
按关键字查下面章节

先记住三个"一定先看"的文件:

tail -200 /opt/nifi/logs/nifi-app.log     # 主日志,启动失败看这里
tail -100 /opt/nifi/logs/nifi-user.log    # 登录、授权失败看这里
tail -50  /opt/nifi/logs/nifi-bootstrap.log  # 进程级失败(起不来、web server 没起来)看这里

0.1 六族分类:先判断是"哪一类身份错了"

几年下来我把这些故障归成六族,先归类再查细节,能省掉一半时间:

族典型关键字本质本篇章节
文件族UninheritableFlowException、FlowSynchronizationException、partially updated节点本地的 flow 和集群不一致1
配置族Invalid nifi.web.https configuration、Remote input HTTPS、BindExceptionnifi.properties / 端口写错2
认证族Cannot locate KDC、Clock skew、Pre-authenticationKerberos 层3
节点身份族is already connected、not authorized to join the cluster节点身份重复或白名单缺失4、5
容量族No space left、archive file size constraints、GC overhead limit磁盘 / 内存不够10、11
主机族UnknownHostException、Permission denied(本地文件)、Socket closed主机侧的 hosts / 属主 / 内存12、13

一个经验:只要日志里出现"身份"两个字相关的报错(节点身份、证书 DN、用户主体、flow 版本),就说明这台机器在集群眼里"是另一个人"或者"是另一个版本的自己"。这类问题的共同点是——日志不会告诉你哪一行错了,只会说"连不上""未授权""不能继承" 。

0.2 动手前先保留现场

排到一半最怕的事:一着急把 flow.xml.gz 删了,问题没解决,现场也没了。所以第一步永远是:

# 1) 打包日志和时间线(出了问题先做这个,30 秒)
tar czf /tmp/nifi-logs-$(date +%H%M).tar.gz -C /opt/nifi/logs .
​
# 2) 记下当前状态:进程、端口、节点在集群里的角色
ps -ef | grep -i nifi | grep -v grep
ss -lntp | grep -E '9443|11443|6342|10443'
grep -E 'nifi.cluster.is.node|nifi.cluster.node.address|nifi.state.management.embedded.zookeeper.start' /opt/nifi/conf/nifi.properties

先备份再动手,这条在删 flow 文件那一节尤其重要(见 1.4)。

1. 文件族:UninheritableFlowException 与其他三种 flow 报错

这是 25 台规模下最常见的一类,也是唯一一类大概率能靠删两个文件解决的。它值得放在第一位讲。

1.1 四种报错,同一件事

报错完整片段说明
本地 flow 与集群不同org.apache.nifi.controller.UninheritableFlowException: Failed to connect node to cluster because local flow is different than cluster flow.节点以为自己还是旧的 flow
本地 flow 只更新了一半FlowSynchronizationException: Failed to connect node to cluster because local flow controller partially updated. Administrator should disconnect node and review flow for corruption.同步过程中断,本地 flow 是"半成品"
集群 flow 无法被继承Proposed flow is not inheritable by the flow controller and cannot completely replace the current flow due to: Inheriting cluster's flow would mean removing connection with ID ...集群要下发的 flow 会删掉本地一条连接
不能删这个进程组java.lang.IllegalStateException: Cannot delete Process Group because OutPut Port 3f903d5e-... has at least one outgoing connection to a component outside of the Process Group. Delete this connection first拓扑结构冲突,通常跟在上面三条后面

同一时间,nifi-bootstrap.log 里往往还有一句看起来毫无关系的:

nifi.StdErr Failed to start web server: Already closed or has not been started

这句是结果不是原因:flow 没加载成功,Controller 没起来,Jetty 自然也就没起来。别去查 9443 端口。

1.2 根因

NiFi 集群的 flow 以 primary 节点为准,向下同步给其他节点。节点启动时会问一句"我这台本地的 flow 和集群的一样吗",三种情况会答"不一样":

  1. 节点离线期间集群改过 flow。停了三天,期间别人加了个处理器,本地的 flow.xml.gz 还停在三天前。
  2. 节点在同步过程中被强杀。同步写到一半进程没了,本地留下一个"半个 flow",这就是 partially updated。
  3. 这台机器本来就是从别处拷过来的(整包拷贝),它自带的 flow 和当前集群没有任何关系。

1.3 处置:停服务 → 删两个文件 → 重启

# 1) 先停,必须先停
cd /opt/nifi/bin
sh nifi.sh stop
sh nifi.sh status      # 确认真的停了,别在运行中删文件
​
# 2) 删掉本地 flow 缓存
cd /opt/nifi/conf
rm -rf flow.xml.gz
rm -rf flow.json.gz
​
# 3) 重启,节点会向 primary 重新拉一份 flow
cd /opt/nifi/bin
sh nifi.sh restart

启动后看日志,正常的顺序是:Flow Service started → Node connected → 集群页面里这台从 CONNECTING 变 ACTIVE。

为什么必须先停再删:NiFi 运行时会周期性地把内存里的 flow 写回 flow.xml.gz/flow.json.gz。你在它跑着的时候删,它几秒后又给你写回去一份同样坏的,等于白删——而且你会以为是"删了没用"。

1.4 什么时候不能删

primary 节点不能删。primary 的 flow 就是集群的权威版本,删了等于把整张数据流删掉,其他节点会跟着同步成空的。

删之前确认两件事:

# 1) 这台是不是 primary?(集群页面看节点列表,主节点有标记;或看日志)
grep -i 'primary' /opt/nifi/logs/nifi-app.log | tail -5
​
# 2) 最近有没有导出过 template?(跨集群恢复只认 template)
ls -lt /opt/nifi/conf/templates/ 2>/dev/null | head

单机模式(nifi.cluster.is.node=false)下同样不能删。这种环境里 flow.xml.gz 是唯一的数据流存储,删掉就是从零开始,只能靠之前导出的 template 重建。

1.5 预防

  • 变更窗口内不要单独重启某一台。集群在改 flow 的时候重启节点,就是主动制造 partially updated。
  • 每次大改动前导出 template(第 2 篇 3.1 有讲);flow.json.gz 顺手也进备份。
  • 扩容/换证书这类需要长时间停机的操作,先停全部流程、再停节点(第 2 篇"扩容前,先把流程全停")。

2. 配置族:能起来但起不来

2.1 Invalid nifi.web.https configuration in nifi.properties

现象:nifi 起不来,启动后 1 分钟内自动挂掉。

日志:

java.lang.IllegalStateException: Invalid nifi.web.https configuration in nifi.properties
    at org.apache.nifi.web.server.connector.FrameworkServerConnectorFactory.<init>(...)
Caused by: org.apache.nifi.security.util.TlsException: The truststore properties are not valid
    at org.apache.nifi.security.util.SslContextFactory.getTrustManagers(...)

根因:开了 HTTPS(nifi.web.https.port 有值),但 nifi.security.truststore 路径/类型/口令任一为空或不对。

处置:两种方向,二选一。

A. 要 HTTPS(生产必须):把 nifi.properties 里这 7 项补齐,路径指向真实存在的 jks:

nifi.security.keystore=./conf/keystore.jks
nifi.security.keystoreType=jks
nifi.security.keystorePasswd=<KEYSTORE_PASS>
nifi.security.keyPasswd=<KEYSTORE_PASS>
nifi.security.truststore=./conf/truststore.jks
nifi.security.truststoreType=jks
nifi.security.truststorePasswd=<KEYSTORE_PASS>

B. 只是本地试玩,不要 HTTPS:把上面 7 项全部置空,同时把 nifi.web.https.port 也置空、只留 nifi.web.http.port,重启即可。

注意:NiFi 1.15.3 之后,新建安全集群可以不用手工填这些值(UI 向导或 toolkit 会生成)。但从旧版本升级上来的实例仍然要求手工配齐,别被版本说明误导。

另一个隐蔽点:nifi.security.keystorePasswd 和 nifi.security.keyPasswd 是两个属性,很多模板里只写了一个。只写 keystore 口令不写 key 口令,某些版本的 JDK 会拒绝加载密钥。

2.2 Remote input HTTPS is enabled but nifi.web.https.port is not specified

现象:服务能起来,但前台打不开;或者改了 HTTP 之后启动直接报错。

日志:

Caused by: java.lang.RuntimeException: Remote input HTTPS is enabled but nifi.web.https.port is not specified.
    at org.apache.nifi.util.NiFiProperties.getRemoteInputHttpPort(NiFiProperties.java:596)
    at org.apache.nifi.controller.FlowController.<init>(FlowController.java:585)

根因:nifi.remote.input.secure=true(站点到站点走 HTTPS)时,NiFi 会校验 nifi.web.https.port 必须有值。你把 HTTPS 端口清了、只留 HTTP,矛盾就出来了。

处置:三种组合,别混。

场景remote.input.secureweb.https.portremote.input.http.enabled
全 HTTPS(生产)true9443true
全 HTTP(仅内网测试)false空true
不启用 HTTP 形式的 S2Strue9443false

最常见的错法是"想退回 HTTP",只改了 nifi.web.*,忘了 nifi.remote.input.secure 还是 true。

2.3 BindException: Cannot assign requested address

现象:节点起不来,或者 ZK 起不来;日志里是一句很短的绑定失败。

日志:

Exception while listening to address nifi-node-07.example.com:3888,
java.net.BindException: Cannot assign requested address

根因:端口或者地址绑不上,三种可能:

  1. 端口被占了。ZK 的 3888 最常见——同一台机器上跑了别的 ZK,或者上次的进程没死干净。
  2. server.N 里写的主机名在本机解析不到。ZK 只会尝试绑定配置里写的那几个地址,hosts 里没有这个名字,就 Cannot assign requested address。
  3. nifi.cluster.node.address 写的主机名和本机实际主机名不一致,集群协议端口绑不上。

处置:

# 先看端口被谁占了
ss -lntp | grep -E '3888|2888|22181'

# 再看名字能不能解析
getent hosts nifi-node-01.example.com

# 三个 zk 节点的 myid 必须唯一,且和 server.N 对应
cat /opt/nifi/state/zookeeper/myid
grep '^server.' /opt/nifi/conf/zookeeper.properties

改完端口,别忘了 nifi.zookeeper.connect.string 要全集群同步改一遍,否则一半节点还在连旧端口。ZK 配置的细节在第 2 篇 3.5.1 节。

2.4 systemctl 托管 NiFi:握手失败和 6342 断开的真凶

这一条独立成节,因为它长得完全像证书问题,但证书一点问题都没有。

现象(一次集中爆发):

  • 集群前台查询不正常,节点状态在 Connected / Not connected 之间抖;
  • 节点间复制请求失败:
javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
Failed to replicate request GET /nifi-api/flow/current-user ... to nifi-node-11.example.com:9443
  • 负载均衡通道异常:
ConnectionLoadBalanceServer Failed to communicate over Channel /nifi-node-11.example.com:6342::...
java.net.SocketException: Socket closed
  • 停止时补一句:Controller hasn't terminated properly... Might need to kill the program manually.

排查:异常集中在一台节点上;查它的启动方式,发现是用 systemctl start nifi 拉起的(/usr/lib/systemd/system/nifi.service,里面带 Restart=always)。做了一次对照:

启动方式结果
systemctl start nifi前台查询异常复现,节点状态抖动
/opt/nifi/bin/nifi.sh start前台恢复正常,节点全部 Connected

根因:先别急着把它归成"systemd 有 bug"。合理的解释是启动环境不一致:nifi.sh 会读 conf/bootstrap.conf 并设置一套环境(JAVA_HOME、ulimit、pid 文件、日志重定向),systemd 走的是另一套(Environment=、KillMode=、TimeoutStopSec=);再加上 Restart=always,你在执行 nifi.sh stop 的时候 systemd 会把进程又拉起来,形成"半启动半停止"的抖动——握手失败和 6342 断开都是抖动期间的表象。

处置:

systemctl stop nifi
systemctl disable nifi
systemctl mask nifi          # 防止被别的依赖或运维脚本再拉起来
/opt/nifi/bin/nifi.sh start

判断方法:

systemctl is-enabled nifi                 # enabled 就是有人在托管
ps -o cmd= -p $(pgrep -f 'nifi.Bootstrap' | head -1)
systemctl show nifi -p Restart,KillMode,TimeoutStopSec

如果确实必须用 systemd 托管:先把 nifi.sh 与 service 文件的环境差异对齐(JAVA_HOME、ulimit -n、LimitNOFILE、KillMode=process、TimeoutStopSec 放大到能优雅停机),在测试集群灰度通过后再上生产。不要在生产上边试边改。

3. 认证族:登不上

3.1 一张表看完 Kerberos 报错

日志关键字根因处置
Clock skew too great节点时间偏差 > 5 分钟chronyc sources -v,修时间同步
Server not found in Kerberos database主体名 / realm 写错,或 KDC 里没这个主体kadmin.local -q "listprincs" 核对
Pre-authentication information was invalid密码错重设主体密码
GSS initiate failed / No valid credentialskeytab 路径 / 权限 / keytab 与主体不匹配kinit -kt <keytab> <principal> 手工验证
Cannot locate KDCkrb5.conf 丢了 realm/KDC 配置,或被别的文件覆盖见 3.2,这是最凶的一个
登录页一直转圈Kerberos 认证成功但 users.xml 里没这个身份见 7.1

手工验证 keytab 的标准三步:

klist -k /home/nifi/nifi.keytab                 # 看 keytab 里到底有哪些主体
kinit -kt /home/nifi/nifi.keytab nifi/nifi@EXAMPLE.COM
klist                                           # 看票据是否拿到、realm 对不对

3.2 Cannot locate KDC:一个配置文件如何把整个集群拖下水

这是两年里我见过破坏力最大的单点故障,值得完整复盘一次。

现象(按时间顺序):

  1. 平台告警:某节点 /opt 挂载点使用率 100%,触发阻断告警。
  2. 业务反馈:NiFi 集群登录不了。
  3. UI 提示:The supplied username and password are not valid.——看起来像密码错了,其实不是。
  4. 后台:nifi-app.log 增长速度异常,几分钟就把 /opt 写满;日志里刷的是:
Caused by: sun.security.krb5.KrbException: Cannot locate KDC
java.lang.SecurityException: Cannot locate KDC

紧接着是大量 FlowFile 冲突、处理线程中断的日志(因为磁盘满了,什么也写不下去)。

根因链:

/etc/krb5.conf 被覆盖(少了 realm 与 KDC 地址)
        ↓
NiFi 无法向 KDC 认证,每次登录/每次票据续期都失败
        ↓
失败重试 + 每条都写 ERROR 堆栈 → 日志暴涨
        ↓
/opt 被写满 → 磁盘满 → NiFi 所有写操作失败 → 登录彻底不可用

注意这条链上的因果很容易看错:磁盘满不是根因,是结果。如果只清磁盘,半小时后还会满。

处置:

# 1) 先从一台正常节点取一份正确的 krb5.conf
scp nifi-node-01:/etc/krb5.conf /tmp/krb5.conf.good
diff /tmp/krb5.conf.good /etc/krb5.conf     # 看清楚少的是什么

# 2) 全量比对,确认到底几台被改了
ansible -m shell -a 'md5sum /etc/krb5.conf' nifi -o

# 3) 回滚(copy 带 backup=yes,出问题还能翻回去)
ansible -b -m copy \
  -a 'src=/tmp/krb5.conf.good dest=/etc/krb5.conf owner=root group=root mode=0644 backup=yes' nifi

# 4) 清掉被日志打满的目录,再确认认证
ansible -m shell -a 'df -h /opt' nifi -o

三条经验:

  • krb5.conf 是集群里最脆的文件。它不属于 NiFi,任何装了 hadoop 客户端、任何配置管理脚本、任何人工"统一环境"的动作都可能覆盖它。我们后来把它和 core-site.xml、hdfs-site.xml 一起纳入了 md5 巡检。
  • 登录页说"用户名密码无效"时,先看 KDC 通不通,再看密码对不对。kinit 一次就知道答案。
  • 日志速率本身要监控。正常几百行/分钟,故障时几万行/分钟;/opt 一定要单独看容量(第 6 篇有日志治理的配置)。

3.3 登录页报"用户名密码无效"的三层原因

这个提示是 NiFi 最会误导人的一句话,它对应三种完全不同的原因:

层真实原因怎么验证
KDCkrb5.conf 错、KDC 不可达、时间偏差kinit <principal> 手工试
主体主体口令被 -randkey 随机化了(用 xst 导 keytab 时没加 -norandkey)kadmin.local -q "cpw <principal>" 重设已知口令
授权认证过了,但 users.xml 里没有这个身份grep -i '<identity>' conf/users.xml

第 2 种最容易踩:kadmin.local -q "xst -k nifi.keytab nifi/host" 默认会把主体口令随机掉,而 NiFi 的 Kerberos 登录页要的是"主体 + 密码",口令被随机掉之后 UI 就永远登不进去,但 keytab 是好的、服务端认证是通的。第 1 篇第 3 节提过这个参数。

4. 节点身份族:一直 CONNECTING / 被别的节点挤下线

4.1 现象

集群页面节点数不对;新起的节点把老节点顶成 DISCONNECTED;日志里节点反复注册、被拒绝、再注册。25 台的时候最难受——你根本分不清是哪台被顶了,只看得到节点数在 25 上下跳。

日志关键字:

Node ... is already connected
Unable to communicate with node ...
This node is not authorized to join the cluster
Received fatal alert: certificate_unknown

4.2 根因(按出现频率)

1)整包拷贝了老节点的安装目录(最常见)

conf/flow.json.gz、conf/nifi.properties、证书、state/ 一起被复制,新节点带着和老节点完全相同的身份注册。ZooKeeper 的节点表只认一个位置,后注册的把先注册的顶掉。

真实经过:第一次扩容为了省事,在老节点上 tar czf 打了整个 /opt/nifi 拷到新节点解压启动。新节点上线后,集群里原来一台老节点变成 DISCONNECTED——看起来像"新加入的把原有的挤掉了"。当时怀疑 tar 包里带了缓存或者某个唯一标识(flow、state、证书 DN 都在里面),没有逐项深究;换成官网原始安装包、全新解压、只拷配置模板之后,一次就加进去了。后续两轮扩容重复验证过这个结论。

处置:新节点用同版本安装包全新解压,只拷配置模板和 template,绝不拷 flow / state / 证书 / repository。详见第 2 篇 2.1。

2)只有部分节点重签了证书

双向 TLS,老节点 truststore 里没有新 CA,握手直接失败。

处置:全集群一起重签、一起分发(第 2 篇 3.2、3.3)。

3)Node Identity 不是全量

每个节点的 authorizers.xml 都要有全部节点的 DN,少一条就少一个能连进来的节点。

处置:补齐并 md5sum 校验所有节点一致(25 台时只能用脚本,见第 2 篇 3.6)。

4)DN 多/少一个空格

CN=host, OU=NIFI 与 CN=host,OU=NIFI 是两个身份。

处置:用证书 Owner 原样粘贴;或用 nifi.security.identity.mapping.* 做规范化(第 1 篇第 6 节)。

4.3 三分钟判定流程

# 1) 这台节点在集群里叫什么、连的哪个 primary
grep -E 'nifi.cluster.node.address|nifi.zookeeper.connect.string' /opt/nifi/conf/nifi.properties

# 2) 它的证书 DN 是什么
keytool -list -v -keystore /opt/nifi/conf/keystore.jks -storepass '<KEYSTORE_PASS>' | grep -m1 'Owner:'

# 3) authorizers.xml 里有没有这一条(注意空格)
grep -c 'Node Identity' /opt/nifi/conf/authorizers.xml
grep -F 'CN=nifi-node-04.example.com, OU=NIFI' /opt/nifi/conf/authorizers.xml

# 4) 和别的节点比一眼
md5sum /opt/nifi/conf/authorizers.xml

第 4 步的价值在于:25 台里只要有一台的 md5 和别的不一样,问题就在那台,不用猜。

5. 证书族

5.1 浏览器报"证书与主机名不匹配"

CN 是 FQDN,你却用 IP 访问。处置:统一用域名访问;或在证书里加 SAN(tls-toolkit 的 -n 传的是主机名,IP 访问本来就不该被支持)。

5.2 unable to find valid certification path

客户端(浏览器、curl、S2S 对端)不信任服务端证书。处置:把 CA 根证书(nifi-cert.pem)导入客户端信任库,或 curl 加 -k 临时验证。

5.3 certificate_unknown / handshake_failure:换了 keystore 没换 truststore

现象:节点之间互相报握手失败,集群页面节点陆续掉线;前台查询也开始异常。

日志:

WARN [Process Cluster Protocol Request-18] o.a.n.c.p.impl.SocketProtocolListener
Failed processing protocol message from nifi-node-07.example.com due to Received fatal alert: certificate_unknown

javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
Failed to replicate request GET /nifi-api/flow/current-user ... to ...:9443

根因:只换了 keystore.jks(节点自己的证书),truststore.jks 还是旧 CA;或者反过来,只有几台更新了 truststore。双向 TLS 里,任何一边的 truststore 缺了对方的 CA,握手就断。

处置:全量重签 + 全量分发 + 全量校验指纹(第 2 篇 3.3)。校验的输出必须是"只有一行、计数 25":

for n in $(seq 1 25); do
  h=$(printf 'nifi-node-%02d' "$n")
  printf '%s ' "$h"
  ssh "$h" "keytool -list -keystore /opt/nifi/conf/truststore.jks -storepass '<KEYSTORE_PASS>' -v 2>/dev/null | grep -m1 'SHA256:'"
done | awk '{print $2}' | sort | uniq -c

如果 uniq -c 出来两行,就说明集群里同时存在两套 CA——这时候不要修单台,直接按"全量重签"重来一次,否则你会一直修不完。

这一条还有个变体:证书换了、authorizers.xml 里的 Node Identity 还是旧 DN,于是握手能过、授权过不去,表现为 not authorized to join the cluster。两组东西必须一起换。

5.4 证书过期

两年一签的证书最容易在"某天早上突然全挂"时被想起。处置:

# 查 25 台证书到期时间,一眼看全
for n in $(seq 1 25); do
  h=$(printf 'nifi-node-%02d' "$n")
  printf '%s: ' "$h"
  ssh "$h" "keytool -list -v -keystore /opt/nifi/conf/keystore.jks -storepass '<KEYSTORE_PASS>' \
    | grep 'Valid from' | head -1"
done

提前一个月重签,流程同扩容(全量重签 + 全量分发 + 改 Node Identity)。把"剩余天数 < 90"做进巡检,比记在日历上可靠。

6. Unable to decrypt / 敏感属性解不开

现象:节点能起,但某些处理器报凭据错误;或者 flow 加载时日志刷解密失败。

根因:nifi.sensitive.props.key 不一致。这个 key 加密了 flow 里所有敏感属性(数据库密码、keytab 口令、SSL 上下文里的密码),换 key 等于换锁。

处置:

# 用原来那个值,在每台上重设
/opt/nifi/bin/nifi.sh set-sensitive-properties-key '<SENSITIVE_KEY>'

如果原 key 已经丢了:只能重新录入所有敏感属性(NiFi 无法解密旧值)。所以这个 key 必须和证书一起进密码管理。

一个和它很像但不同的报错:Configuration does not have security enabled, keytab and principal will be ignored。这不是 key 的问题,而是读到的 core-site.xml 是一份没开 kerberos 的配置(典型场景:目标集群的配置文件被本平台的同名文件覆盖)。处置是检查处理器里 Hadoop Configuration Resources 指向的那两个 xml 到底是谁的(第 4 篇"双写两个 HDFS 集群"一节)。

7. 授权族:能登录,但进去一片空白

7.1 根因

Kerberos 认证只解决"你是谁",授权要另外配:

  1. 身份字符串不匹配:Kerberos 主体是 etl_user_01@EXAMPLE.COM,users.xml 里写的是 etl_user_01 或大小写不同;
  2. 用户在 users.xml 里,但没有 /flow 策略;
  3. 有 /flow,但没有任何进程组的 view 策略(根组没有、自己的组也没 Override)。

处置:

# 看这个身份在不在 users.xml
grep -i 'etl_user_01' /opt/nifi/conf/users.xml

# 看它有哪些策略
grep -n 'etl_user_01' /opt/nifi/conf/authorizations.xml

然后在 UI 里按第 3 篇的"最小授权组合"补齐。

7.2 Unable to locate initial admin ... to seed policies

现象:服务起来了,但没人能进;日志里:

org.apache.nifi.authorization.AuthorizationException:
Unable to locate initial admin <identity> to seed policies

根因:authorizers.xml 里声明的初始管理员,和实际登录的身份对不上。三种写法容易错:

  1. Initial Admin Identity 为空,或者还是模板里的占位值;
  2. 身份字符串拼错(少了 realm 后缀、大小写不同);
  3. 用新式 StandardManagedAuthorizer 时,只写了 Initial Admin Identity,没写 Initial User Identity 1(前者在 accessPolicyProvider,后者在 userGroupProvider,两个都要)。

处置:改 authorizers.xml 补齐身份,重启。注意 seed 只发生一次——users.xml / authorizations.xml 已经生成之后,改配置不会再 seed,只能在 UI 里手工补权限,或者备份后删掉这两个文件重新生成。第 3 篇 3.6 节有完整写法。

7.3 组件灰显、队列不消化:不是权限,是 DISABLED

现象:业务说流程不跑,队列一直涨;用户权限看下来 view / modify / operate 全有。

根因:这条流程依赖的 Controller Service(CSVReader、SchemaRegistry 之类)被置成了 DISABLED——某次变更或版本升级后状态丢了,依赖它的处理器就永远不跑。

区分方法:

表现无权限DISABLED
UI 上组件看不到/点不动,提示 not authorized能看见、能点,但灰显
日志not authorized / 403Controller Service ... is disabled
处置授策略Enable 服务,再 Restart 处理器

详见第 3 篇 4.6 节。

8. 登录后 302 到错误地址 / 静态资源 404

现象

页面能打开,但登录后跳到 https://内网IP:9443/...,或者 CSS/JS 全 404。

根因

前面挂了 nginx / 负载均衡,NiFi 不知道对外地址。

处置

# 对外访问的 host:port,用于生成跳转地址、校验 Host 头
nifi.web.proxy.host=nifi.example.com:9443
# 反向代理的上下文路径(如 /nifi/),必须配
nifi.web.proxy.context.path=/nifi

同时确认 nginx 的 location 与 proxy.context.path 一致,并且转发了 Host 头。

9. ZK 族:选主、myid、状态丢失

现象根因处置
启动卡在 Waiting for cluster to elect primary nodeZK 连不上、或选主超时检查 nifi.zookeeper.connect.string、22181 端口、election.max.wait.time
ZK 报 myid 冲突两个节点 myid 相同每个节点唯一,且与 server.N 对应
集群状态反复重建节点时间不一致 / 网络抖动先修时间,再看交换机侧丢包
新节点不跑 ZK 却带了 state/zookeeper拷配置时带过来的删目录,embedded.zookeeper.start=false
BindException ...:3888端口被占 / server.N 里的名字解析不到见 2.3

冷启动建议先起 ZK 三台,等 ACTIVE 后再分批(每批 5~6 台)加节点,比 25 台一起冲快得多。

9.1 ListSFTP 存不了 state:ConnectionLoss

这条值得单列,因为它不报错、只丢数据:

WARNING ListSFTP[id=6402381b-...] Unable to save state due to java.io.IOException:
Failed to obtain value from ZooKeeper for component with ID 6402381b-... with exception code CONNECTIONLOSS
Caused by: org.apache.zookeeper.KeeperException$ConnectionLossException:
KeeperErrorCode = ConnectionLoss for /nifi/components/6402381b-...
If NiFi is restarted before state is saved, or if another node begins executing this Processor,
data duplication may occur.

根因:ZK 会话抖动,处理器状态写不进去。后果不是服务中断,是重复采集——重启后状态回到上一个保存点,已经被处理过的文件会被再拉一遍。

处置:

  1. 短期:确认 ZK 三台的负载和 GC,看是不是某台 ZK 在重启;CONNECTIONLOSS 如果是持续的,说明 ZK 已经不稳了。
  2. 长期:把内置 ZK 换成外置 ZK 集群。25 个节点的集群状态、flow 版本、primary 选举都压在 3 台内置 ZK 上,ZK 的写是串行的,节点越多心跳越密集(第 2 篇 5.1)。
  3. 下游要能容忍重复:HDFS 侧按分区 + 文件名覆盖,或者用 DetectDuplicate 按文件名过滤。

9.2 UnknownHostException:ZK 连不上的真凶常在 /etc/hosts

现象:业务反馈部分节点掉线,前台看到一批节点服务掉线。

日志:

ERROR [main-SendThread(nifi-node-06.example.com:2181)] o.a.zookeeper.client.StaticHostProvider
Unable to resolve address: nifi-node-06.example.com:2181
java.net.UnknownHostException: nifi-node-06.example.com: Name or service not known

根因:/etc/hosts 里没有 NiFi 集群的主机名映射。这台机器的 hosts 被人改过(或者装系统时就没写),ZK 客户端解析不到对端。

这里有个非常有用的细节:报错里的端口是 2181,而你配的是 22181——说明 state-management.xml 里的 Connect String 还是默认值,没跟着改。两个问题叠在一起了:hosts 缺映射 + 配置漏改。看到端口不对,先别怀疑网络,去看配置文件。

处置:

# 1) 从一台正常节点取 hosts,比对差异
scp nifi-node-01:/etc/hosts /tmp/hosts.good
diff /tmp/hosts.good /etc/hosts

# 2) 全量分发(先备份)
ansible -b -m copy -a 'src=/tmp/hosts.good dest=/etc/hosts owner=root group=root mode=0644 backup=yes' nifi

# 3) 确认解析恢复
ansible -m shell -a 'getent hosts nifi-node-06.example.com' nifi -o

恢复后掉线节点会自己重新连回来,不用重启 NiFi。预防:把 /etc/hosts 纳入和 krb5.conf 同一套 md5 巡检——这两类文件被改,表现都是"莫名掉线"。

10. 容量族:磁盘与 content repository

10.1 盘满 = 全局暂停

现象根因处置
流程突然全部暂停content/flowfile repository 所在盘满df -h,清理 content_repository/archive
No space left on device同上缩短 nifi.content.repository.archive.max.retention.period
出处查询很慢provenance 索引过大调小 max.storage.size 或缩短保留时间

NiFi 对磁盘满的处理是"暂停一切",不会给你留缓冲。content_repository 单独挂盘,并且加监控。

10.2 archive 达到阈值:不是写失败,是主动节流

Unable to write flowfile content to content repository Container content2
due to archive file size constraints; waiting for archive cleanup.
Total number of file currently archived = 10707

这条不是 ERROR 而是 WARNING,含义是:archive 目录达到了 nifi.content.repository.archive.max.usage.percentage(我们是 70%),NiFi 开始"等清理",写入变慢,整个集群的吞吐跟着掉。

处置:

# 缩短保留时间,让 archive 自己更快滚动
nifi.content.repository.archive.max.retention.period=12 hours
nifi.content.repository.archive.max.usage.percentage=70%

再手动清一批(先 -ls 看,再删):

find /data01/nifi/content_repository/*/*/* -type f -mtime +3 -ls | head
nohup find /data01/nifi/content_repository/*/*/* -type f -mtime +3 | xargs rm -rf &

注意:只能删 archive 里的历史文件,不能删正在用的 content。清理完观察队列有没有恢复消化。

10.3 root 属主:一个权限错误如何让整条流程卡死

现象:流程在 list 阶段卡住,后续队列里没有任何文件;把某台节点停掉后,流程立刻恢复正常且稳定。

排查:对比两台节点的目录结构,发现出问题那台的 /data*/nifi/content_repository/ 下面,有一部分文件和 archive 目录同级(正常应该全在 archive 里),而且 archive 的属主是 root。

根因:中途有人用 root 启动过 NiFi,写出来的目录和文件属主是 root;之后用 nifi 用户启动,nifi 用户对 root 属主的目录没有写权限,content 写不进去,处理器就卡在那里——不报错,只是不动。

处置:

# 1) 全量修属主
chown -R nifi:nifi /data01/nifi
chown -R nifi:nifi /data02/nifi
chown -R nifi:nifi /data03/nifi

# 2) 删掉那些"不在 archive 目录里"的野生文件(先看再删)
find /data01/nifi/content_repository/ -maxdepth 2 -mindepth 2 -type f -not -path "*/archive/*" | head
nohup find /data01/nifi/content_repository/ -maxdepth 2 -mindepth 2 -type f -not -path "*/archive/*" -delete &

经验:NiFi 这类"卡住但不报错"的问题,八成是权限或磁盘。先 ls -al 看属主,再 df -h 看空间,比读日志快。

10.4 日志把 /opt 写满

见 3.2。结论重复一次:磁盘满通常是日志速率问题,清理只是止血,滚动策略和监控才是治本(第 6 篇第 4 节)。

11. JVM 族:三种看起来毫不相干的报错

11.1 三副面孔

同一台机器,堆用默认值时能同时出现这三种报错:

# 1) 主日志
java.lang.OutOfMemoryError: GC overhead limit exceeded

# 2) 前台
java.net.SocketTimeoutException: timeout

# 3) REST 接口 500
{"servlet":"jerseySpring",
 "cause0":"java.lang.NoClassDefFoundError: Could not initialize class org.springframework.web.context.request.async.WebAsyncManager",
 "url":"/nifi-api/flow/current-user","status":"500"}

第一个像 GC 调优问题,第二个像网络问题,第三个像 classpath / 环境坏了。其实是同一件事:堆太小,JVM 在反复 Full GC,应用线程基本没机会跑。类加载失败是 GC 把 Metaspace 或类初始化挤掉之后的连带现象。

11.2 怎么确认

# 1) 看进程实际用的堆参数(不是配置文件里写的,是生效的)
ps -ef | grep -i nifi | grep -v grep | tr ' ' '\n' | grep -- '-Xm'

# 2) 看堆使用(jstat 不用停服务)
jstat -gcutil $(pgrep -f 'nifi.Bootstrap' | head -1) 1000 5

# 3) 看 bootstrap.conf 里到底改没改
grep -E 'java.arg.(2|3)' /opt/nifi/conf/bootstrap.conf

如果 -Xmx 还是 512m 或者 1g,而 flow 里有几十个处理器在跑,基本就可以定案了。

11.3 处置

# conf/bootstrap.conf
java.arg.2=-Xms10240m
java.arg.3=-Xmx10240m
java.arg.4=-XX:MetaspaceSize=512m
java.arg.5=-XX:+HeapDumpOnOutOfMemoryError
java.arg.6=-XX:HeapDumpPath=/data01/nifi/dump

改完 sh nifi.sh restart。25 台要统一改,只改出问题那台会让负载全压到它身上(堆大的节点更"能扛",调度器不知道这件事,但队列会往它身上堆)。

一条顺序上的经验:碰到"接口超时 500 + 前台转圈 + GC 报错"同时出现,先看堆,再查网络、证书、DNS。反过来查,会浪费掉一整个下午。

12. 主机族:不在 NiFi 里的那些故障

12.1 属主错误:jar 和日志变成 root

现象:某台节点服务掉线,重启后又掉;日志里没有明确的认证/证书错误。

根因:这台机器上部分 jar 包和日志文件的属主是 root(有人用 root 拷过文件、或者用 root 跑过一次服务)。NiFi 以 nifi 用户运行,读不了 logs/ 下 root 属主的文件就写不了日志,某些 jar 属主不对则加载失败。

处置:

chown -R nifi:nifi /opt/nifi
chown -R nifi:nifi /data01/nifi /data02/nifi /data03/nifi

预防:所有 Ansible copy/file 任务显式写 owner=nifi group=nifi;不用 root 启动服务(第 6 篇第 8 节)。

12.2 主机内存缓存太多,写盘卡住把机器夯死

现象:节点彻底无响应,SSH 都慢,NiFi 进程还在但什么都不干;重启主机后一切正常。

根因:这台机器上有大量文件写入(content repository 是重写场景),page cache 攒得太多,writeback 时被阻塞,整机进入 D 状态。表现和"NiFi 挂了"完全一样。

处置与预防:

# 看有多少脏页在等落盘
grep -E 'Dirty|Writeback' /proc/meminfo

# 看是不是有进程长时间处于 D 状态
ps -eo pid,stat,comm | awk '$2 ~ /D/'
  • 降低 vm.dirty_ratio / vm.dirty_background_ratio(比如 10 / 5),让脏页更早落盘,代价是写入抖动更明显但不会夯死。
  • content repository 的盘用 SSD 或者至少别和系统盘共用。
  • 加 node_exporter 的 node_pressure_io_stalled 类指标监控,比等业务报障早。

12.3 时间不同步

Clock skew too great 见 3.1。补一句:时间偏差不只影响 Kerberos,也会让证书校验、ZK 会话、日志时间线全部错乱,排查时先把 date 对齐。

13. SSH / SFTP 族

SFTP 相关的报错是这套环境里最"会骗人"的一类,因为它同时有三个完全不同的根因。

13.1 Received SSH_MSG_UNIMPLEMENTED while exchanging keys

日志:

ERROR [sshj-Reader-/10.20.30.31:22] net.schmizz.sshj.transport.TransportImpl
Dying because - Received SSH_MSG_UNIMPLEMENTED while exchanging keys
net.schmizz.sshj.transport.TransportException: Received SSH_MSG_UNIMPLEMENTED while exchanging keys

ERROR [Timer-Driven Process Thread-6] o.a.nifi.processors.standard.FetchSFTP
... org.apache.nifi.processors.standard.socket.ClientConnectException: SSH Client connection failed [[10.20.30.31:22]]
Caused by: net.schmizz.sshj.transport.TransportException: Received SSH_MSG_UNIMPLEMENTED while exchanging keys

这个报错我们遇到过两次,根因完全不同:

根因 A:sshj 库版本缺陷。 NiFi 1.17.0 的 nifi-standard-nar 里带的是 sshj 0.33.0,某些服务端(老版本 OpenSSH、或者配置了少见的 kex 算法)在密钥交换阶段会回一个未实现的报文,sshj 直接断开。NiFi 后续版本升级了 sshj,修掉了这个问题。

我们当时的处置是手工替换 NAR 里的 jar:

# 1) 把新 jar 放到 standard NAR 解包目录的 bundled-dependencies 下
ansible -m copy -a 'src=/data/pkg/sshj-0.38.0.jar
  dest=/opt/nifi/nifi-1.17.0/work/nar/extensions/nifi-standard-nar-1.17.0.nar-unpacked/NAR-INF/bundled-dependencies/
  owner=nifi group=nifi mode=0664' nifi -o

# 2) 旧 jar 改名备份(不要删)
ansible -m shell -a 'mv .../sshj-0.33.0.jar .../sshj-0.33.0.jar_bak' nifi -o

# 3) 重启
sh /opt/nifi/nifi-1.17.0/bin/nifi.sh stop
sh /opt/nifi/nifi-1.17.0/bin/nifi.sh start

这个方案的代价必须讲清楚:work/nar/extensions/ 是 NiFi 从 NAR 包解压出来的运行时目录,升级版本或清理 work 目录时会被覆盖,替换就白做了。要么把它写进升级检查清单(每次升级后重做一遍),要么做一个自定义 NAR 把 sshj 版本固定下来——后者才是长久方案。

根因 B:集群各节点的 JDK 版本不一致。 第二次遇到同样的报错,查了一圈 sshj 版本都一样,最后发现是节点之间 JDK 版本不同:不同 JDK 支持的 TLS 加密套件和算法不同,密钥交换协商失败,表现就是 SSH_MSG_UNIMPLEMENTED。

# 一次看全 25 台的 java 版本和 home
ansible -m shell -a 'java -version 2>&1 | head -1; echo $JAVA_HOME' nifi -o
ansible -m shell -a 'alternatives --config java 2>/dev/null | head -5' nifi -o

处置:把所有节点统一到同一个 JDK 版本(alternatives + /etc/profile 的 JAVA_HOME 都要改,并且注意 nifi 用户登录时的环境是否读到了新值——su - nifi 之后再 java -version 确认一次),然后重启服务。

怎么区分 A 和 B:先看 25 台的 java -version 是否一致(1 分钟)。一致就是库的问题,不一致就是 JDK 的问题。这个顺序比先翻 sshj 的 changelog 快得多。

13.2 Timeout expired: 30000 MILLISECONDS

net.schmizz.sshj.transport.TransportException: Timeout expired: 30000 MILLISECONDS
ClientConnectException: SSH Client connection failed [[10.20.30.31:22]

根因:远端 SFTP 响应慢(负载高、网络抖动、磁盘 IO 顶住),30 秒建连/握手没完成。注意它常常和 HDFS 侧的 slow waitForAckedSeqno 同时出现——那就不是单点问题,是集群整体负载高(第 4 篇第 5 节)。

处置:

  • 把 FetchSFTP/ListSFTP 的 Connection Timeout 从 30s 调到 10–20s,快速失败、快速重试,比挂着 30s 占线程好;
  • 给重试队列加 back pressure,避免远端抖一下就把本地堆满;
  • 业务侧降并发,别用"加节点"解决远端慢的问题。

13.3 not.found / permission.denied

ERROR ListSFTP[id=...] Failed to perform listing on remote host due to
Could not perform listing on /data08/sftpfile/xxx because could not find the file on the remote server

ERROR ListSFTP[id=...] Unable to get listing from /1212bak; skipping:
org.apache.nifi.processors.standard.util.PermissionDeniedException:
Could not perform listing on /1212bak due to insufficient permissions

这两类基本是上游问题:文件还没生成(not.found)、目录权限没给(permission.denied)。关键不是消灭报错,是确保它不丢数据——检查这些关系是不是被配成了 terminate(第 4 篇第 4 节)。

13.4 关系配 terminate:最贵的一个配置

comms.failure、not.found、permission.denied 三个关系如果 auto-terminate,等于"拉不到就丢",业务侧只会看到"少了几条文件",而 NiFi 侧一片绿色。这三类一律改成 retry,并给重试队列限量。

14. 数据族:文件写坏了

14.1 MalformedRecordException / EOF reached before encapsulated token finished

ERROR PutParquet[id=096a3848-...] Failed to write due to java.io.IOException:
org.apache.nifi.serialization.MalformedRecordException: Error while getting next record
Caused by: java.io.IOException: (startline 328401) EOF reached before encapsulated token finished

根因:源文件有问题——被截断(上游写到一半)、带残留的反斜杠/引号导致列结构崩掉、列数和 schema 不符。Record Reader 逐行解析,遇到坏行整批失败,不是跳过那一行。

处置:在 Record Reader 之前拦。三种方案的能力边界见第 4 篇 3.4 节,结论是 ExecuteScript 预校验最靠谱,ReplaceText 只能做固定替换,UpdateRecord 来不及(坏行进不到 record 级)。

14.2 is not a Parquet file. Expected magic number at tail

java.lang.RuntimeException: viewfs://.../biz_a_2025010106_<uuid>.snappy.parquet
is not a Parquet file. Expected magic number at tail, but found [-48, -19, -53, 94]

根因:文件写了一半(节点重启、磁盘满、超时中断),Parquet 的尾部 magic number(PAR1)没写进去。文件存在、有大小,但读不了。

判定:

hadoop fs -tail -c 4 <file> | hexdump -C     # 末尾必须是 50 41 52 31
hadoop fs -cat <file> | head -c 4            # 开头也必须是 PAR1

处置:删掉坏文件,重跑那个批次。不要试图修复——NiFi 没有内置的"写完后校验 HDFS 文件"能力,缺的那半截数据只能重采(第 4 篇 7.3 有完整校验方法)。

14.3 队列卡在 list 阶段

现象是"流程不报错、队列也不涨、就是没数据进来"。三个方向:

  1. List 组件本身没扫到(文件命名窗口错过,第 4 篇 2.6);
  2. content repository 写不进去(属主/空间,见 10.3);
  3. 处理器不是 RUNNING(有人 Stop 了没启,或者 DISABLED 的服务拖住了它,见 7.3)。

看 Provenance 按组件过滤,一眼就能分清是"没进来"还是"进来了没出去"。

15. UI 超时 / API 500:最难定位的一类

这一条我们没有完全闭环,如实写下来,因为它可能是很多人会遇到的形态。

现象:

  • UI 和接口 /nifi-api/flow/process-groups/root?uiOnly=true 返回 HTTP 500;
  • 服务端日志里集群请求复制失败,java.net.SocketTimeoutException: timeout;
  • 节点间通信/协调阶段超时,页面加载不出来。

已排除:Kerberos/keytab(认证是通的)、DNS(nslookup/dig 正常且耗时低)、GC(没有长时间停顿)、防火墙(端口未阻断)。

做过的尝试:把某节点的 nifi.cluster.node.address 从 hostname 改成 IP,无效。

后来的情况:第二天自己恢复了。推测是当时 primary 节点太忙(请求复制都要经过它),切换之后就好了——但这只是推测,没有证据。

如果再来一次,我会按这个顺序查:

  1. primary 节点的 GC 和线程池(jstat、线程 dump 看是否有大量 Process Cluster Protocol 线程阻塞);
  2. nifi.cluster.protocol.timeout 与 nifi.cluster.node.connection.timeout 是否需要调大(默认偏短,25 台规模下调度压力大);
  3. 请求复制路径上的网络(curl -k https://<peer>:9443/nifi-api/access/config -w '%{time_total}',从每个节点测一遍);
  4. 是否有个别处理器占了全部 timer 线程(线程 dump 里数 Timer-Driven Process Thread 的占用)。

诚实的结论:这一类"集群通信超时"没有单一根因,它更像是"负载 + 超时阈值 + primary 单点"三者叠加出来的表现。能做的不是找一个开关,而是把 primary 的负载压下来、把超时阈值调到匹配规模、把 UI 访问从 primary 上挪开。

16. 端口:五个必须通的口子

# 9443 被谁占了
ss -lntp | grep 9443

# 集群协议端口通不通(从节点 A 测节点 B)
nc -zv nifi-node-02.example.com 11443

# S2S 端口
nc -zv nifi-node-02.example.com 10443

NiFi 用到的端口一共五个,扩容/搬迁时漏开一个就够排查半天:

端口用途
9443Web UI / REST
11443集群节点协议
6342负载均衡
10443站点到站点(S2S)
22181内置 ZooKeeper 客户端

另外三个容易忽略的:2888(ZK 选主)、3888(ZK 心跳)、以及 nifi.remote.input.socket.port 对应的裸 TCP 端口(默认和 10443 同段但走不同协议)。安全扫描也最爱扫这几个,第 6 篇第 5 节讲怎么处置。

17. 一张速查表

日志关键字一句话根因去哪节
UninheritableFlowException本地 flow 与集群不一致1
FlowSynchronizationException / partially updated同步中断留下半个 flow1
Proposed flow is not inheritable集群 flow 会删掉本地连接1
Failed to start web server: Already closed上游是 flow 没加载,别查端口1.1
Invalid nifi.web.https configurationhttps 开了但 truststore 没配2.1
truststore properties are not valid同上2.1
Remote input HTTPS is enabled but ...secure 与 https 端口矛盾2.2
BindException: Cannot assign requested address端口占用或 server.N 名字解析不到2.3
Cannot locate KDCkrb5.conf 被覆盖3.2
Clock skew too great时间不同步3.1
Server not found in Kerberos database主体不存在/写错3.1
Pre-authentication information was invalid密码错(或被 randkey 了)3.1、3.3
is already connected节点身份重复(多半是拷了安装包)4.2
not authorized to join the clusterNode Identity 缺失/不一致4.2
certificate_unknowntruststore 没跟着换5.3
handshake_failure双向 TLS 不互信(也可能是启动方式,见 2.4)5.3
unable to find valid certification path客户端不信任 CA5.2
Unable to decryptsensitive props key 不一致6
Configuration does not have security enabled读到了没开 kerberos 的 core-site6
登录后空白身份不匹配或无 /flow 策略7.1
Unable to locate initial admin初始管理员身份对不上7.2
Controller Service ... is disabled不是权限,是状态7.3
302 到内网 IP没配 proxy.host/context.path8
选主卡住ZK 连不上/myid 冲突9
ConnectionLoss(ListSFTP state)ZK 会话抖动,会重复采集9.1
UnknownHostException(ZK)/etc/hosts 缺映射9.2
流程全部暂停磁盘满10.1
archive file size constraintsarchive 到阈值,主动节流10.2
队列卡住但不报错目录属主是 root10.3
GC overhead limit exceeded堆太小(默认值)11.1
WebAsyncManager NoClassDefFoundError同上,不是框架坏了11.1
SocketTimeoutException: timeout先看堆,再看负载11.1、15
Permission denied(本地文件)属主错(root)12.1
主机无响应、SSH 也慢page cache 写回阻塞12.2
SSH_MSG_UNIMPLEMENTEDsshj 版本缺陷 或 JDK 不一致13.1
Timeout expired: 30000 MILLISECONDS远端慢/集群整体负载高13.2
MalformedRecordException / EOF ... token源文件坏行/截断,整批失败14.1
Expected magic number at tailParquet 写了一半14.2
process-groups/root 500 + 复制超时primary 负载/超时阈值15

18. 小结

这套环境跑下来,真正致命的错误只有几类,且全部和"身份"有关:

  1. 证书身份:CN/DN 不一致、只有部分节点换证书;
  2. 节点身份:整包拷贝导致两个节点同身份;
  3. 用户身份:Kerberos 主体与 users.xml 不一致;
  4. flow 身份:节点本地 flow 与集群版本不一致,靠删 flow.xml.gz/flow.json.gz 复位;
  5. 主机身份:/etc/hosts、krb5.conf 这些"不属于 NiFi 但决定 NiFi 能不能起来"的文件被改掉。

前四类是 NiFi 自己的概念,最后一类是它借来的地基。配置项写错,日志会直接告诉你哪一行;这五类错了,日志只会说"连不上""未授权""不能继承",然后让你查一整天。

所以配 NiFi 安全和排障时,最值得花时间的事不是背参数,而是把这几类身份画成一张表对齐:证书 DN、Node Identity、用户主体、flow 版本、主机名与 hosts。对着表逐项打勾,比翻日志快得多。