[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)上,但实际行为在不同节点上完全不同。核心职责包括:

  1. Spark Event Log 导出:从 HDFS 的 /var/log/spark/apps/ 扫描 Spark 事件日志,上传到 S3
  2. YARN Timeline Server 日志导出:从 HDFS 的 /tmp/entity-file-history/ 扫描 YTS 日志
  3. YARN 直接日志导出:从 HDFS 的 /tmp/entity-file-history/yarn-direct-logs/ 扫描
  4. 审计追踪:使用 HSQLDB 嵌入式数据库记录文件同步状态
  5. 凭证管理:通过 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 步:

  1. 输出启动消息到 /dev/console
  2. 创建目录: /emr/apppusher/{run,log,local,data}
  3. 设置目录权限: chown hadoop:hadoop, chmod 700
  4. 设置 umask 077
  5. 获取 Java 17 路径 (get_java_path 17)
  6. 检测 cgroup 版本 (v1 或 v2)
  7. 根据 cgroup 版本配置资源限制
  8. 启动 Java 进程(后台运行)
  9. 写入 PID 文件
  10. 等待 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 目录
posted @ 2026-03-23 20:48  zhaojie10  阅读(20)  评论(0)    收藏  举报