[INFRA] EMR集群AppPusher组件功能和运行原理分析
请注意本文部分内容经过AI辅助生成,虽然经过笔者检查但是并不保证内容的正确性,请自行判断准确性,本文对相关后果不承担责任
本文主要分析 EMR 集群中的 AppPusher 组件。AppPusher 和 LogPusher 名字很像,但职责完全不同。LogPusher 负责收集本地文件系统上的日志文件,而 AppPusher 负责从 HDFS 上收集应用级的事件日志(Spark Event Log、YARN Timeline Server 日志),然后上传到 EMR 内部托管的 S3 桶,用于支持 EMR 控制台的 Persistent App UI 功能。
本文的测试环境是emr7.12版本,细节如下

AppPusher 的版本号是 applogpusher-1.28.0 / original-emr-log-analytics-metrics-1.44.0,主类是 aws157.apppusher.Main。
它运行在 EMR 集群的所有节点(Master + Core)上,但实际行为在不同节点上完全不同。核心职责包括:
- Spark Event Log 导出:从 HDFS 的
/var/log/spark/apps/扫描 Spark 事件日志,上传到 S3 - YARN Timeline Server 日志导出:从 HDFS 的
/tmp/entity-file-history/扫描 YTS 日志 - YARN 直接日志导出:从 HDFS 的
/tmp/entity-file-history/yarn-direct-logs/扫描 - 审计追踪:使用 HSQLDB 嵌入式数据库记录文件同步状态
- 凭证管理:通过 InstanceController 获取 STS 临时凭证
关键特性:
| 特性 | 说明 |
|---|---|
| 定时调度 | 每 120 秒(2 分钟)执行一次日志扫描和上传 |
| 多线程导出 | 使用多个线程池并发处理 Spark、YARN、YTS 日志 |
| 差量上传 | 通过 HSQLDB 审计数据库跟踪已上传文件,支持增量同步 |
| 凭证管理 | 通过 InstanceController 获取 STS 临时凭证(DebuggingSignedPolicy) |
| Cgroup 资源限制 | 使用 cgroup v1/v2 限制 CPU 和内存使用 |
| 优雅关闭 | 注册 Shutdown Hook,支持优雅停机 |
与 LogPusher 的区别
| 维度 | LogPusher | AppPusher |
|---|---|---|
| 职责 | 收集系统/服务日志文件 | 收集应用级日志和事件 |
| 运行节点 | 所有节点(Master + Core + Task) | 所有节点(Master + Core),但行为不同 |
| 数据源 | 本地文件系统日志目录 | HDFS 上的 Spark/YARN 事件日志文件 |
| 上传目标 | S3 日志 bucket(用户配置) | S3 appinfo bucket(系统管理) |
| 配置方式 | logpusher.properties + *.config | 无独立配置文件,通过 InstanceController 获取策略 |
进程信息,注意 JVM 参数:最大堆 1500MB,初始堆 300MB,OOM 时直接退出(由 systemd 自动重启)。
# 服务名称
apppusher.service
# 启动脚本
/usr/bin/apppusher
# 主进程 PID 文件
/emr/apppusher/run/apppusher.pid
# Java 进程信息
PID: 4197
JVM 参数: -Xmx1500m -Xms300m -XX:+ExitOnOutOfMemoryError -XX:MinHeapFreeRatio=10
JVM: Amazon Corretto 17.0.18
主类: aws157.apppusher.Main
Master和Core 节点的差异是理解 AppPusher 最关键的一点。AppPusher 在所有节点上部署并运行完全相同的代码,但实际行为由 InstanceController 是否持有 APP_INFO 凭证决定。
| 维度 | Master 节点 | Core 节点 |
|---|---|---|
| 代码/启动逻辑 | 相同 | 相同 |
| IC 有 APP_INFO 凭证 | 有(EMR 控制面推送) | 没有(控制面不推送) |
| 实际效果 | 正常扫描 HDFS、上传到 S3 | 每 120 秒空转,什么都不做 |
| HSQLDB 审计库 | data/ + ytsdata/ 已初始化 | 未创建(流程走不到初始化步骤) |
| 线程数 | 51 | 28 |
| 内存使用 | ~453 MB | ~213-228 MB |
Core 节点上的 AppPusher 每个周期的日志模式固定为:
[INFO] (pool-3-thread-1) SparkEventLogExporter - Attempting to create spark event log exporter
[INFO] (pool-7-thread-1) YarnTimelineServerLogExporter - Attempting to create Yarn timeline server event log exporter
[INFO] (pool-3-thread-1) InstanceControllerUtils - Unable to extract debugging signed policy
[INFO] (pool-3-thread-1) AppPusherUtils - No debugging policy found.
[INFO] (pool-7-thread-1) InstanceControllerUtils - Unable to extract debugging signed policy
[INFO] (pool-7-thread-1) AppPusherUtils - No debugging policy found.
[INFO] (main) AppPusherScheduler - Sleeping for 120 seconds
这是 EMR 的统一部署策略,即所有节点安装相同服务,通过控制面的凭证分发来控制哪些节点实际工作。
全集群 AppPusher 状态表,以一个 1 Master + 3 Core 的集群为例:
| 节点 | 类型 | IP | PID | 线程 | 内存 | 实际工作 |
|---|---|---|---|---|---|---|
| ip-192-168-25-65 | Master | 192.168.25.65 | 4197 | 51 | ~453 MB | 正常扫描上传 |
| ip-192-168-22-99 | Core | 192.168.22.99 | 4058 | 28 | ~228 MB | 空转 |
| ip-192-168-17-183 | Core | 192.168.17.183 | 4195 | 28 | ~213 MB | 空转 |
| ip-192-168-23-18 | Core | 192.168.23.18 | 4200 | 28 | ~214 MB | 空转 |
基础架构
注意:AppPusher 不连接任何 Spark 或 YARN 的 REST API,唯一的数据源是 HDFS 文件目录。
EMR 控制面 (54.222.11.1)
│
│ RPC: setDebuggingSignedPolicy (APP_INFO)
│ 推送 STS 临时凭证,仅推送给 Master 节点
▼
┌──────────────────────────────────────────────────────────────┐
│ Master 节点上的 AppPusher │
│ │
│ ┌──────────────────┐ │
│ │ InstanceController│ HTTP GET /getStatus │
│ │ localhost:8321 │──→ activeDebuggingPolicies[APP_INFO] │
│ └──────────────────┘ 含 accessKeyId/secretAccessKey/ │
│ │ sessionToken │
│ ▼ │
│ ┌──────────────────┐ ┌───────────────────┐ │
│ │ HDFS 数据源 │───→│ EMR 托管 S3 │ │
│ │ hdfs:///var/log/ │ │ prod.cn-north-1. │ │
│ │ spark/apps/ │ │ appinfo.src/ │ │
│ │ hdfs:///tmp/ │ │ j-{clusterId}/ │ │
│ │ entity-file- │ │ sparklogs/ │ │
│ │ history/ │ │ ytslogs/ │ │
│ └──────────────────┘ └───────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────┐ │
│ │ HSQLDB │ │
│ │ data/ │ ← Spark 文件同步状态 │
│ │ ytsdata/ │ ← YTS 文件同步状态 │
│ └──────────┘ │
└──────────────────────────────────────────────────────────────┘
线程模型
主线程 (AppPusherScheduler - main) ── 每 120 秒调度一次
│
├── pool-3: SparkEventLogExporter(初始化 + 凭证获取)
│ └── pool-4: LogExporter(扫描 HDFS Spark event log)
│
├── pool-7: YarnTimelineServerLogExporter(初始化 + 凭证获取)
│ └── pool-8: YarnLogExporter(扫描 HDFS YTS 日志)
│
├── main 线程: AppPusher(YARN 应用数据收集)
│
├── ShutdownPoller: 监控集群关闭信号
└── Shutdown Hook: JVM 关闭钩子
线程池职责
| 线程池 | 组件 | 职责 | HDFS 扫描路径 |
|---|---|---|---|
| pool-3 | SparkEventLogExporter | 获取凭证、初始化 HSQLDB、创建 LogExporter | - |
| pool-4 | LogExporter | 扫描 HDFS 上的 Spark event log 文件 | hdfs:///var/log/spark/apps/ |
| pool-7 | YarnTimelineServerLogExporter | 获取凭证、初始化 HSQLDB、创建 YarnLogExporter | - |
| pool-8 | YarnLogExporter | 扫描 HDFS 上的 YTS 日志(3 个目录) | hdfs:///tmp/entity-file-history/active/、done/、yarn-direct-logs/ |
HDFS 数据源详解
| HDFS 路径 | 写入者 | 内容 | 对应导出器 | S3 目标 |
|---|---|---|---|---|
/var/log/spark/apps/ |
Spark 应用 | Spark event log 文件 | LogExporter (pool-4) | sparklogs/ |
/tmp/entity-file-history/active/ |
YARN Timeline Server | 活跃应用的实体文件 | YarnLogExporter (pool-8) | ytslogs/ |
/tmp/entity-file-history/done/ |
YARN Timeline Server | 已完成应用的实体文件 | YarnLogExporter (pool-8) | ytslogs/ |
/tmp/entity-file-history/yarn-direct-logs/ |
YARN | 应用直接日志 | YarnLogExporter (pool-8) | ytslogs/ |
凭证三级传递链路
AppPusher 最核心的机制之一,AppPusher 自身不直接调用 STS,凭证由 EMR 控制面主动推送:
EMR 控制面 (54.222.11.1)
│
│ RPC: setDebuggingSignedPolicy
│ (定期推送,约每小时刷新)
│ 仅推送给 Master 节点,不推送给 Core 节点
│
▼
InstanceController (localhost:8321)
│ 1. 接收: "Received setDebuggingSignedPolicy from 54.222.11.1"
│ 2. 持久化: "save debugging policy to db"
│ 3. 暴露: HTTP GET /getStatus → JSON 响应
│
▼
AppPusher
1. HTTP GET http://localhost:8321/getStatus
2. 解析 JSON 中 activeDebuggingPolicies 数组
3. 提取 type=APP_INFO 的凭证
4. 用 accessKeyId/secretAccessKey/sessionToken 构造 S3 客户端
5. 上传到指定 bucket/prefix
/getStatus 响应结构
{
"activePolicies": [
"type: SYSTEM_LOG\nbucket: \"aws157-logs-prod-cn-north-1\" ...",
"type: USER_LOG\nbucket: \"aws-logs-{accountId}-cn-north-1\" ..."
],
"activeDebuggingPolicies": [
"type: APP_INFO\nbucket: \"prod.cn-north-1.appinfo.src\" ..."
]
}
Master 节点的 activeDebuggingPolicies 包含 APP_INFO 凭证,但是Core 节点的该数组为空。
DebuggingSignedPolicy 凭证结构如下,凭证每次调度周期(120 秒)都会重新获取,有效期约 1 小时,由 EMR 控制面定期刷新推送。
类型: APP_INFO
├── accessKeyId: ASIA...(STS 临时 Access Key)
├── secretAccessKey: ****(STS 临时 Secret Key)
├── sessionToken: ****(STS Session Token)
├── bucket: prod.cn-north-1.appinfo.src
├── keyPrefix: j-{clusterId}/
└── effectiveEndInstant: epoch 毫秒(约 1 小时有效期)
S3 上传目标
AppPusher 上传到的是 EMR 服务内部托管的 S3 桶,不是用户的 S3 桶:
s3://prod.cn-north-1.appinfo.src/
└── j-{clusterId}/
├── sparklogs/ ← Spark event log
└── ytslogs/ ← YARN Timeline Server 日志
三个 S3 桶的对比
| 桶 | 策略类型 | 写入者 | 用途 | 用户可见 |
|---|---|---|---|---|
aws-logs-{accountId}-cn-north-1 |
USER_LOG | LogPusher | 用户日志 | 用户自己的桶 |
aws157-logs-prod-cn-north-1 |
SYSTEM_LOG | LogPusher | EMR 系统日志 | EMR 内部 |
prod.cn-north-1.appinfo.src |
APP_INFO | AppPusher | 应用事件日志 | EMR 内部 |
AppPusher 上传的数据用于支持 EMR 控制台的 "Application history"(Persistent App UI)功能,让用户在 EMR 控制台上查看 Spark/YARN 应用的历史记录,即使集群已终止。
HSQLDB 审计数据库
AppPusher 使用两个独立的 HSQLDB 数据库实例来跟踪文件同步状态:
| 数据库 | 路径 | 用途 |
|---|---|---|
| Spark 审计库 | /emr/apppusher/data/audit |
跟踪 Spark 事件日志同步状态 |
| YTS 审计库 | /emr/apppusher/ytsdata/audit |
跟踪 YARN Timeline Server 日志同步状态 |
数据库文件结构
/emr/apppusher/data/
├── audit.script # DDL 和数据脚本
├── audit.properties # 数据库属性
├── audit.log # 事务日志
├── audit.lck # 锁文件(运行时)
└── audit.tmp/ # 临时目录
数据库配置
HSQL Database Engine 2.7.1
事务控制: LOCKS
隔离级别: READ COMMITTED
冲突回滚: TRUE
写延迟: 500 MILLIS
缓存大小: 10000
缓存行数: 50000
NIO: TRUE
日志大小: 50 MB
Hibernate ORM 配置
| 配置项 | 值 |
|---|---|
| 驱动 | org.hsqldb.jdbcDriver |
| URL (Spark) | jdbc:hsqldb:file:/emr/apppusher/data/audit |
| URL (YTS) | jdbc:hsqldb:file:/emr/apppusher/ytsdata/audit |
| 用户名 | emr |
| 方言 | org.hibernate.dialect.HSQLDialect |
| 连接池大小 | 20 (min=1) |
| 自动提交 | false |
注意:使用 Hibernate 内置连接池(非生产级),日志中会出现 HHH10001002: Using Hibernate built-in connection pool 警告,这是正常的。
同步策略
AppPusher 使用 applogpusher 库中的同步框架:
文件发现 (HdfsFileDiscovery)
│
▼
策略选择 (DefaultStrategyChooser)
│
├── 新文件 → 完整上传
└── 已存在文件 → 差量上传 (AppendDelta / UploadDelta)
│
▼
S3 同步 (S3SyncMechanism)
│
├── CustomTransferManager
│ ├── AppendCallable (追加上传)
│ └── DeltaCallable (差量上传)
│
▼
审计记录 (AuditInfoDb → HSQLDB)
Spark Event Log 导出流程
1. SparkEventLogExporter.run() [pool-3]
2. → instantiateSparkEventLogExporter()
3. → InstanceControllerUtils.getSystemPolicy() [HTTP GET /getStatus]
4. → 提取 APP_INFO 凭证 → 确定 S3 bucket/prefix
5. → 初始化 Hibernate + HSQLDB (/emr/apppusher/data/audit)
6. → 创建 LogExporter [pool-4]
7. → HdfsFileDiscovery.getFiles() [扫描 hdfs:///var/log/spark/apps/]
8. → S3SyncMechanism.sync() [上传到 S3 sparklogs/]
9. → AuditInfoDb.record() [记录审计信息]
YARN Timeline Server 日志导出流程
1. YarnTimelineServerLogExporter.run() [pool-7]
2. → instantiateLogExporter()
3. → InstanceControllerUtils.getSystemPolicy() [HTTP GET /getStatus]
4. → 提取 APP_INFO 凭证 → 确定 S3 bucket/prefix
5. → 初始化 Hibernate + HSQLDB (/emr/apppusher/ytsdata/audit)
6. → 创建 YarnLogExporter [pool-8]
7. → HdfsFileDiscovery.getFiles() × 3 次:
8. → hdfs:///tmp/entity-file-history/active/
9. → hdfs:///tmp/entity-file-history/done/
10. → hdfs:///tmp/entity-file-history/yarn-direct-logs/ [可能 FileNotFoundException]
11. → S3SyncMechanism.sync()
配置系统
与 LogPusher 不同,AppPusher 没有独立的 properties 配置文件。其行为主要由以下方式控制:
| 配置来源 | 路径 | 说明 |
|---|---|---|
| 启动脚本 | /usr/bin/apppusher |
JVM 参数、cgroup 配置 |
| Log4j 配置 | /etc/apppusher/apppusher-log4j2.xml |
日志格式和滚动策略 |
| 运行标志 | /etc/apppusher/run-apppusher |
启用/禁用标志(内容为 1) |
| systemd 单元 | /etc/systemd/system/apppusher.service |
服务管理配置 |
| InstanceController | localhost:8321 |
运行时动态获取策略和凭证 |
启动脚本详解 (/usr/bin/apppusher)
启动流程共 10 步:
- 输出启动消息到
/dev/console - 创建目录:
/emr/apppusher/{run,log,local,data} - 设置目录权限:
chown hadoop:hadoop,chmod 700 - 设置
umask 077 - 获取 Java 17 路径 (
get_java_path 17) - 检测 cgroup 版本 (v1 或 v2)
- 根据 cgroup 版本配置资源限制
- 启动 Java 进程(后台运行)
- 写入 PID 文件
- 等待 5 秒后退出启动脚本
环境变量:
LOG_FILE=/emr/apppusher/log/apppusher.out
PID_FILE=/emr/apppusher/run/apppusher.pid
APPPUSHER_HOME=/usr/share/aws/emr/emr-log-analytics-metrics
AWS_SDK_PATH=/usr/share/aws/aws-java-sdk-v2/*
CLASSPATH="${AWS_SDK_PATH}:${APPPUSHER_HOME}/lib/*:/home/hadoop/conf"
JVM 参数:
| 参数 | 值 | 说明 |
|---|---|---|
-Xmx1500m |
1500MB | 最大堆内存 |
-Xms300m |
300MB | 初始堆内存 |
-XX:+ExitOnOutOfMemoryError |
- | OOM 时直接退出 |
-XX:MinHeapFreeRatio=10 |
10% | 最小空闲堆比例 |
Cgroup 资源限制
Cgroup v2(当前使用 - AL2023):
memory.max = 2048M # 最大物理内存 2GB
memory.swap.max = 3072M # 最大 swap 3GB
cpu.max = 400000 1000000 # 40% CPU
实际资源使用对比:
| 资源 | 限制值 | 实际使用 |
|---|---|---|
| 物理内存 | 2048 MB | ~453 MB (Master) / ~213 MB (Core) |
| CPU | 40% 单核 | ~0.2% |
| 线程数 | 无限制 | 51 (Master) / 28 (Core) |
| 打开文件数 | 无限制 | 185 |
Log4j2 配置
<Configuration status="WARN" monitorInterval="30">
<Appenders>
<RollingFile name="DFRA"
fileName="/emr/apppusher/log/apppusher.log"
filePattern="/emr/apppusher/log/apppusher.%d{yyyy-MM-dd-HH}-%i.log.gz">
<PatternLayout>
<Pattern>%d{ISO8601} [%p] (%t) %c{1} - %m%n</Pattern>
</PatternLayout>
<Policies>
<TimeBasedTriggeringPolicy />
<SizeBasedTriggeringPolicy size="50 MB"/>
</Policies>
<DefaultRolloverStrategy max="5"/>
</RollingFile>
</Appenders>
</Configuration>
日志格式示例:
2026-03-22T10:52:13,533 [ERROR] (main) AppPusherScheduler - Not starting High level application history
│ │ │ │ │
│ │ │ │ └── 消息内容
│ │ │ └── 类名(简短)
│ │ └── 线程名
│ └── 日志级别
└── ISO8601 时间戳
滚动策略:每小时或 50MB 滚动,最多保留 5 个归档,gzip 压缩。
systemd 服务配置
[Unit]
Description=EMR process for collecting metrics/logs from the cluster.
After=libinstance-controller-java.service
[Service]
Type=forking
ExecStart=/usr/bin/apppusher
Restart=always
RestartSec=5
PIDFile=/emr/apppusher/run/apppusher.pid
[Install]
WantedBy=multi-user.target
关键点:After=libinstance-controller-java.service 确保在 InstanceController 之后启动,Restart=always 确保任何退出都自动重启。
核心 JAR 包和关键类
applogpusher-1.28.0.jar
| 包路径 | 说明 |
|---|---|
com.amazon.emr.apps.logexporter |
日志导出基础框架 |
com.amazon.emr.apps.logexporter.filediscovery |
HDFS 文件发现(HdfsFileDiscovery) |
com.amazon.emr.apps.logexporter.persistence |
HSQLDB 持久化状态管理 |
com.amazon.emr.apps.logexporter.strategy |
同步策略选择器 |
com.amazon.emr.apps.logexporter.sync |
S3 同步机制(含 Multipart Upload) |
com.amazon.emr.apps.logexporter.sync.transfer.internal.audit |
审计信息和 Hibernate 配置 |
original-emr-log-analytics-metrics-1.44.0.jar
| 包路径 | 说明 |
|---|---|
aws157.apppusher |
主调度器、HTTP 客户端、S3 上传器 |
aws157.apppusher.spark |
Spark 事件日志收集和导出 |
aws157.apppusher.yarn |
YARN 应用数据收集和 YTS 日志导出 |
aws157.apppusher.utils |
工具类(S3 客户端、InstanceController 通信) |
关键类说明
| 类名 | 说明 |
|---|---|
Main |
入口类 |
AppPusherScheduler |
主调度器,120 秒周期 |
AppPusherHttpClient |
与 InstanceController 通信的 HTTP 客户端 |
SparkEventLogExporter |
Spark 事件日志导出器 |
YarnTimelineServerLogExporter |
YARN Timeline Server 日志导出器 |
LogExporter |
通用日志文件导出器 |
ShutdownPoller |
关闭信号轮询器 |
InstanceControllerUtils |
InstanceController 交互工具 |
AppPusherS3Client |
S3 客户端封装 |
DebuggingSignedPolicyProvider |
STS 凭证提供者 |
关键依赖 JAR
| JAR | 版本 | 说明 |
|---|---|---|
applogpusher |
1.28.0 | 日志导出核心库 |
original-emr-log-analytics-metrics |
1.44.0 | AppPusher 主程序 |
hadoop-hdfs-client |
3.4.1-amzn-4 | HDFS 客户端 |
hadoop-common |
3.4.1-amzn-4 | Hadoop 通用库 |
hibernate-core |
5.4.24.Final | ORM 框架 |
hsqldb |
2.7.1 | 嵌入式数据库 |
httpclient |
4.5.13 | HTTP 客户端 |
aws-crt |
0.38.1 | AWS Common Runtime |
功能特性标志
Persistent App UI CM-CMK
- 日志中出现
Persistent App UI CM-CMK feature enabled时,表示 Spark 和 YTS 日志导出器会使用客户管理的 CMK(Customer Managed Key)进行加密上传。
High Level Application History
- 日志中出现
Not starting High level application history, feature is not enabled时,表示此特性当前未启用。启用后会收集更详细的应用历史信息。注意这条日志虽然是 ERROR 级别,但实际上是配置行为,不是真正的错误。
运维指南
常用命令
# 服务管理
sudo systemctl status apppusher
sudo systemctl start apppusher
sudo systemctl stop apppusher
sudo systemctl restart apppusher
# 进程检查
ps aux | grep apppusher | grep -v grep
cat /emr/apppusher/run/apppusher.pid
cat /proc/$(cat /emr/apppusher/run/apppusher.pid)/status | grep -E 'VmRSS|VmSize|Threads'
# 日志查看
sudo tail -f /emr/apppusher/log/apppusher.log
sudo grep -i error /emr/apppusher/log/apppusher.log
# Cgroup 检查
cat /apppusher-group/memory.max
cat /apppusher-group/cpu.max
cat /apppusher-group/cgroup.procs
# 网络连接
ss -tnp | grep $(cat /emr/apppusher/run/apppusher.pid)
已知问题及处理
1. YARN 直接日志目录不存在(持续)
[ERROR] YarnLogExporter - Unable to retrieve files
FileNotFoundException: File /tmp/entity-file-history/yarn-direct-logs does not exist.
- 每 120 秒出现一次
- 原因:HDFS 上该目录未创建
- 影响:仅影响 YARN 直接日志导出,其他功能正常
- 处理:当有 YARN 应用运行并产生直接日志后,目录会自动创建
2. 启动时 InstanceController 连接失败(已恢复)
[WARN] InstanceControllerUtils - Unable to get status from InstanceController
HttpHostConnectException: Connect to localhost:8321 failed: Connection refused
- 仅在启动时出现,因为 AppPusher 启动时 IC 尚未就绪
- 第二个调度周期(120 秒后)通常已恢复
3. SLF4J 绑定缺失
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
- 仅在 apppusher.out 中出现,不影响功能
4. Hadoop Native Library 警告
[WARN] NativeCodeLoader - Unable to load native-hadoop library
- HDFS 操作使用纯 Java 实现,性能略低但功能正常
5. Core 节点持续 "No debugging policy found"
- 这是正常行为,不需要处理
日志分析
Master 节点正常运行日志:
[INFO] (pool-4-thread-1) LogExporter - Retrieving files
[INFO] (pool-4-thread-1) LogExporter - Found 0 files
[INFO] (pool-8-thread-1) YarnLogExporter - Retrieving files
[INFO] (pool-8-thread-1) YarnLogExporter - Found 0 files
[INFO] (pool-8-thread-1) YarnLogExporter - Retrieving files
[INFO] (pool-8-thread-1) YarnLogExporter - Found 0 files
[INFO] (pool-8-thread-1) YarnLogExporter - Retrieving files
[ERROR] (pool-8-thread-1) YarnLogExporter - Unable to retrieve files ← 正常
[INFO] (main) AppPusherScheduler - Sleeping for 120 seconds
关键日志关键字:
| 关键字 | 含义 |
|---|---|
Sleeping for 120 seconds |
一个调度周期结束 |
Extracted debugging signed policy |
成功获取 STS 凭证 |
Found N files |
发现 N 个待同步文件 |
Unable to get status from InstanceController |
IC 连接失败 |
Persistent App UI CM-CMK feature enabled |
CMK 加密特性已启用 |
Shutdown Hook Attached |
关闭钩子已注册 |
健康检查脚本
#!/bin/bash
PID_FILE=/emr/apppusher/run/apppusher.pid
if [ -f "$PID_FILE" ] && ps -p $(cat $PID_FILE) > /dev/null 2>&1; then
echo "OK: AppPusher is running (PID: $(cat $PID_FILE))"
RSS=$(cat /proc/$(cat $PID_FILE)/status | grep VmRSS | awk '{print $2}')
echo "Memory RSS: ${RSS} kB"
LAST_LOG=$(tail -1 /emr/apppusher/log/apppusher.log | cut -d' ' -f1)
echo "Last log: $LAST_LOG"
ERRORS=$(grep -c '\[ERROR\]' /emr/apppusher/log/apppusher.log 2>/dev/null)
echo "Total errors: $ERRORS"
else
echo "CRITICAL: AppPusher is NOT running!"
exit 2
fi
目录结构
/emr/apppusher/ # 运行时主目录 (hadoop:hadoop, 700)
├── run/
│ └── apppusher.pid # PID 文件
├── log/
│ ├── apppusher.log # 当前日志
│ ├── apppusher.out # 标准输出/错误
│ └── apppusher.*.log.gz # 历史日志归档
├── data/ # Spark 审计数据库
│ ├── audit.script
│ ├── audit.properties
│ ├── audit.log
│ └── audit.lck
├── ytsdata/ # YTS 审计数据库
│ ├── audit.script
│ ├── audit.properties
│ ├── audit.log
│ └── audit.lck
└── local/ # 本地状态文件
/etc/apppusher/ # 配置目录
├── apppusher-log4j2.xml # Log4j2 配置
├── apppusher-log4j.properties # Log4j 1.x 配置
└── run-apppusher # 启用标志 (1)
/usr/bin/apppusher # 启动脚本
/etc/systemd/system/apppusher.service # systemd 单元文件
/apppusher-group/ # cgroup v2 目录

浙公网安备 33010602011771号