1. 先从一次“打印机什么都没出”的工单说起
前几天半夜两点多,客户的一台关键票据打印机突然不出东西了。业务员在SAP里点打印,前端打印机一点反应都没有,但屏幕上的假脱机请求状态一直停留在Waiting for output formatter,怎么刷新都不动。更麻烦的是,这个卡住的请求还把后面的几十个打印任务全堵住了。业务那边急得不行,大半夜把电话打到我这儿来。
说实话,这类问题在SAP Basis运维里不算罕见,但因为它横跨了应用服务器、前端打印服务、数据库、网络好几个层面,排查起来特别容易被带偏。很多人第一反应就是“重启打印服务器”,运气好能解决,运气不好第二天又卡住。这背后其实藏着一些系统性的根因,不挖出来,问题就反复发作。
这篇文章我想把这个状态从头到尾讲透——它到底是怎么产生的、哪些环节最容易出问题、怎么一步步定位到根因、以及怎么从架构和配置层面做长期治理,而不是每次都靠重启救火。内容偏向实操,适合SAP Basis、NetWeaver管理员、以及负责打印流程的IT支持同事参考,开发顾问也可以看看,因为有些定位过程需要翻一下输出控制的数据表结构。
先说结论:Waiting for output formatter 表示请求已经成功生成,正在等待前端格式化和设备输出,但这一步没有在预期时间内完成。至于为什么没完成,才是整个问题真正的开始。
2. Spool请求的完整生命周期:理解状态之前,先看它走了多远
很多人一看到Waiting for output formatter就慌,其实只要理解了一个Spool请求从创建到打印输出经过的几个关键阶段,你自然就知道该去哪个环节查。
2.1 请求从生成到输出,中间经历了什么
一个Spool请求的生命周期大致是这样:
- 应用服务器端请求创建:用户在某个事务里触发打印,SAP应用服务器上的工作进程把输出数据写入数据库表
TST01(请求头)和TST03(数据块),此时请求状态会短暂处于Created或Being Created。 - 格式化阶段(Formatting):应用服务器调用输出格式化模块,把ABAP内部的数据转换成设备可识别的格式(比如PCL、PostScript、ZPL、文本RAW格式)。这个阶段完成后,请求会进入“已完成格式化,待输出”的状态。
- 前端节点接管(Output):SAP应用服务器和前端Spool Server建立连接,把格式化后的数据和输出指令传给前端打印服务,也就是常说的SAPLPD(SAP Print Daemon)。前端打印服务把数据最终送到物理打印机或打印队列。
- 完成状态:前端确认输出成功,写回状态,请求从TST01里归档或被标记Completed。
“Waiting for output formatter”这个状态,通俗讲就是:格式化已经做完了,数据包已经准备好,但在第3步卡住了——要么是连不上前端打印服务,要么是前端服务接收了但没处理完,长时间没有回执。
2.2 卡住的状态里其实藏着两种不同性质
我在排障时习惯把这个状态再细分成两种:
- 瞬时等待:前端设备繁忙、大数据量的报表正在传输、打印机正在处理上一个作业。这种情况下请求会在几秒到几分钟内自动完成,属于正常状态。
- 死等:前端服务根本不在线、请求线程被阻塞、数据库表出了问题。这种情况下请求可以卡上几小时甚至隔夜都不动,后面的任务越积越多,最终拖垮整个Spool系统。
判断是哪种,直接看系统里同时卡住的数量和时间跨度。一个请求卡了几分钟很正常,十几个请求全部卡在同一个节点上超过半小时,那绝对是出事了。
我见过不少管理员一看到Waiting就直接去重启服务,反而把一些本来能正常完成的请求也掐断了。所以第一步永远是先观察,再动手。
3. 卡住之后,我用什么顺序排查:从应用视角到数据库底表
定位这个问题的关键不是记住某个事务码,而是理解请求在数据库、应用节点、前端服务这三个层面分别有什么可查的痕迹。下面是我自己总结的一套排查顺序,基本可以覆盖绝大多数场景。
3.1 从SP01看请求的状态细节和时间线
SP01是排查这类问题的起点。选中卡住的请求,双击进入详情。重点看两个地方:
- 状态标签页:确认当前状态确实是Waiting for output formatter,同时看旁边有没有附带的其他错误信息。
- 输出控制标签页:这里会显示请求上次尝试输出的时间点、输出设备逻辑名称、目标主机名,以及是否存在多次“Output attempted”记录。
如果发现系统在反复重试输出,那基本可以判断是前端或者网络层面的问题;如果完全没有任何重试记录,那问题可能出在应用服务器自身。
3.2 AL08和SM50:看看谁在处理这个请求
有时候卡住不是因为前端挂了,而是应用服务器上的Spool任务进程本身出了问题。去AL08看当前活动用户会话,找到字典型用户SAP_SPO的会话;再去SM50看工作进程,重点观察两个东西:
- 有没有进程的状态长时间处于Running且CPU占用极高,像在死循环;
- 有没有进程在处理RSPO开头的函数模块,比如
RSPO_*相关任务,长时间不释放。
我们遇到过一种情况:应用服务器上某个对话框进程在处理一个超大报表(一个请求几十万行,格式化成PCL后数据量接近1GB)时,数据库读取和格式化耗时过长,导致后续所有发往同一前端的请求全部排队。这种问题靠重启前端没用,真正解决得从限制报表输出行数或者优化打印格式入手。
3.3 借助ST22和系统日志,别放过间接报错
如果SM50里看不出明显异常,下一个动作就是去查ST22(ABAP转储)和SM21(系统日志)。Waiting for output formatter这个状态本身不报错,但它往往是一连串问题的最终表象。底下的真实报错可能发生在:
- 前端打印服务连接超时;
- RFC调用失败;
- 平台级文件写入失败;
- 数据库临时表空间不足导致数据块写入失败。
我之前遇到过一次很隐蔽的情况:ST22里有一条关于CX_SY_READ_SRC_LINE的转储记录,看起来跟打印毫无关系,但实际上是格式化某个报表时程序中存在读取源码空行的异常,导致输出进程直接终止,请求就停在中间状态。排查这类问题一定不要只看跟Spool相关的日志,要养成按时间窗口交叉查看的习惯。
提示:排障窗口内如果大量请求集中在同一输出设备上,先看设备;如果分散在多个设备上,优先排查前端服务和应用服务器本身。这个分类能省很多时间。
3.4 数据库侧:TST01、TST03、TST04的状态与数据量
SAP的Spool请求最终是存在数据库里的,而且表结构和请求状态直接反映卡住的原因。建议用SE16N或SE11检查以下三张核心表:
| 表名 | 作用 | 排障重点 |
|---|---|---|
| TST01 | Spool请求头,记录每个请求的状态、时间、设备 | 看RSTATE(请求状态)字段和输出重试次数 |
| TST03 | 请求的数据块,实际格式化后的内容 | 数据量是否异常巨大,有没有碎片化块 |
| TST04 | Spool请求的格式化参数和历史记录 | 检查格式化进程ID和时间戳变化 |
用SQL查一下TST01里卡住请求的数量:
SELECT RSTATE, COUNT(*) FROM TST01 WHERE SDATE = '20240101' GROUP BY RSTATE;还应该留意TST03表的大小,以及数据库临时表空间(TEMP TS)的使用率。Spool数据在输出完成后会从TST03删除,但如果请求卡住,数据块就一直留在表里,长此以往表膨胀会拖慢整个Spool的读写性能,形成恶性循环。
3.5 前端节点状态:RZ04和SAPLPD进程是最后的要害
聊完应用和数据库,再看前端。这里的“前端”不一定是你面前那台电脑,而是承载打印服务的Spool Server,在以前的老架构里常叫soc1之类的名字。用RZ04检查实例配置,确认Spool组件服务是否激活。
更直接的方法是登录到前端打印服务器,检查操作系统的SAPLPD服务/守护进程状态:
- Linux:
ps -ef | grep saplpd或者检查lpd相关进程; - Windows:在服务管理器里看 “SAP Print Daemon” 或类似名称的服务是否处于Running状态。
帮大家避个坑:SAPLPD服务有时候进程还在,但已经无响应了。这种“僵尸在线”状态最坑人,因为从SAP应用服务器看,连接是可以建立的,但发送的数据没有进程处理。我处理过一个客户,他那边前端机器装了第三方的打印管理软件,和SAPLPD抢打印端口,结果就是SAPLPD服务频繁假死。所以在前面那一串排查里,我特别强调看请求是否在反复重试——重试说明通道能通,但没人干活。
4. 真实故障复盘:一个数据库锁引发的“打印大塞车”
理论讲完,分享一个我印象特别深的实际案例。这个案例里,Waiting for output formatter只是表面现象,真正的根因埋得很深,排查过程比较有代表性。
4.1 客户环境与故障现象
客户是制造业,SAP ECC运行在Linux + Oracle上,前端打印节点有两个,几十台网络打印机。某天上午十点左右,故障出现了:
- 所有通过某个前端节点输出的作业全部卡住;
- 卡住状态清一色是Waiting for output formatter;
- 重启SAPLPD服务和前端节点上的SAP实例,问题依旧;
- 切换输出设备把请求路由到另一个前端节点,可以正常打印。
单单看现象,绝大多数人都会锁定在“这个前端节点挂了”,但从应用层面去连它的服务、端口、服务状态,又全都正常。这就是典型的表面健康、实际故障。
4.2 顺着时间线定位到数据库会话
我当时的排查思路是倒着来的:既然前端节点表面正常,那就看SAP应用服务器在向前端传数据时阻塞在哪。于是我在Oracle里查了当时的活跃会话,结果发现了异常——应用服务器的进程长期等待一条SQL,这条SQL就是从TST03表读取数据块然后发送给前端节点的语句。
再往下看,这条SQL等待的事件是enq: TX - row lock contention,也就是行级锁竞争。说明有另一个会话锁住了TST03里的数据行,一直没提交或回滚,导致读取数据的会话只能无限期等待。而这个持锁的会话,正是之前某个已经断开的调试会话留下的“僵尸锁”。
4.3 根因解读与临时处理
这种行锁通常情况下不会出现,因为SAP自己会合理控制锁范围。但如果之前有人在后台调试过Spool输出相关的函数模块(比如单步跟踪RSPO函数),或者某个异常程序在循环里更新了TST03又中途退出,就可能遗留锁。
处理方式分两步:
- 临时解锁:在Oracle里定位到阻塞会话,确认锁来源后杀掉持锁会话,释放TST03上的行锁。注意,必须确认会话没有在执行关键任务,杀错了会引发别的问题。
- 彻底清理:把卡住的请求在SP01里统一删除,然后对TST01、TST03做一次健康检查,确认没有大量残留数据块。
4.4 这个案例给我的两个经验
第一,前端节点“看着正常”不代表真的正常,连接能建立只是最底层的前提,数据传过去的链路里任何一环都可能成为瓶颈。第二,Spool卡住的时候,数据库会话的等待事件是最容易定位根因的切入点。以后大家再遇到类似情况,建议习惯性去数据库层面看一眼当时的等待事件,别只停留在SAP应用层反复重启。
Oracle的话,可以直接查:
SELECT SID, EVENT, WAIT_CLASS, SECONDS_IN_WAIT, STATUS FROM V$SESSION WHERE STATE = 'WAITING' AND EVENT LIKE '%enq%';其他数据库(HANA、SQL Server)也有类似的会话等待视图,时间允许的话顺手看一眼,总没坏处。
5. 当队列已经堵死的紧急处置:先让业务跑起来
排查根因可以慢慢来,但业务不能等。作为运维,我们的第一原则永远是先恢复生产,再分析病根。下面这套紧急处置流程,我在好几个客户现场用过,有效的核心是“先做隔离和疏导,再做清理”。
5.1 把卡死的请求批量断开或转移到备用设备
如果同一台打印机或同一个前端节点下堆积了大量请求,建议先在SP01里按设备或主机筛选出所有卡住的任务,然后分三步:
- 标记为删除:选中所有卡住的请求,右键选择删除(或直接点删除按钮)。如果请求删不掉,可以改用菜单中的“Administration -> Delete”来强制删除。
- 变更输出设备路由:在SPAD里找到对应的输出设备,临时把前端主机切换到备用节点,或者把访问方法从远程打印改为前端直接打印(视具体设备架构而定)。
- 通知用户重打:等设备确认可用后,让用户重新触发打印。SAP不会自动重新提交之前卡住的请求,这点必须跟业务讲清楚,让用户重新操作一次。
5.2 修改资源的输出优先级,别让大作业堵住小作业
卡堵发生后的另一个常见问题是:一张小票据排在几个超大报表后面,一等就是半小时。这时候可以在SPAD里调整设备参数,给不同类型的请求设置不同的输出优先级。具体做法是:在设备配置的Output Attributes里,将票据类的Spool请求优先级调高,将批量大报表调低。
这样做不只是治标,日常运维里也建议这么做——防止某个超大报表输出时把整条打印链路拖垮。我之前服务过的物流行业客户,每天凌晨会批量输出几百张拣货单,每张单子数据量虽小,总量不小。最开始没设置优先级,经常出现一张几千页的月度报表插队,把拣货单队伍堵死的情况。后来统一规划了优先级策略,这个问题再没出现过。
5.3 前端服务重启的正确姿势,避免二次伤害
当前端SAPLPD确实无响应时,重启是必须的。但这里的“正确姿势”值得一提:
- 先清理系统里已积压的本地打印队列(就是操作系统层面的打印任务),再重启SAPLPD,否则服务起来后又立刻处理一堆过期的任务;
- 重启后先发一个测试页,确认链路通了再通知业务批量重打;
- 生产环境操作前,先确认没有正在输出的大型作业,或者直接挑业务低谷期执行。
5.4 删不掉、清不掉的顽固请求,怎么处理底层表
偶尔会碰到连SP01里强制删除都删不掉的请求,这时候请求所在的行在TST01/TST03里可能已经被污染了。常规做法是:在SP01里先尝试把请求状态改成Rel(Release)再删除,如果还是不行,就需要在数据库层面对TST01/TST03中对应状态字段做修正。
这里必须强调:直接改表是最后手段,务必先做完整备份,并且只能改状态标记字段,不能动其他数据。如果你对表结构不够熟,建议联系SAP支持或者找有经验的同事协助,不要独自操作。
6. 根因分类图鉴:最常见的六类诱因和它们的判断特征
前面零零散散提到了不少根因。为了让你在实际排障时有个“对号入座”的参考,我系统性地梳理了六类最常见的诱因,每一类都给出特征和判断方法。
| 根因分类 | 典型特征 | 关键判断方法 | 常见场景 |
|---|---|---|---|
| 前端SAPLPD服务假死或崩溃 | 单节点下的设备全卡,服务进程在但无响应 | 查看系统服务状态,尝试发测试页 | Windows服务器上第三方软件冲突 |
| 网络连接问题 | 请求偶发卡住,切换备用节点后恢复 | ping/telnet测试前端端口,检查防火墙策略 | 跨网段、跨VLAN部署,防火墙策略变更 |
| 数据库表膨胀或锁竞争 | 所有节点均受影响,数据库等待事件异常 | 查TST03表大小、V$SESSION等待事件 | 长期未清理Spool历史数据、异常遗留锁 |
| 应用服务器格式化进程阻塞 | 单个应用实例下的请求卡住,CPU异常高 | SM50查看进程状态和最近执行的函数模块 | 超大报表输出、格式化模块性能瓶颈 |
| 设备本身故障 | 单台设备卡住,其他设备正常 | 直接在打印机上打印测试页 | 打印机离线性故障、打印队列挂起 |
| Spool表与索引损坏 | 请求无法更新状态,删除也失败 | 数据库层面检查TST01/TST03索引 | 异常断电、数据库恢复后的一致性损坏 |
这个表看起来简单,但实际排障里最大的问题就是:症状可能同时来自多个分类。比如前端服务挂掉会导致大量请求堆积,堆积又加剧数据库压力,最后数据库锁也出来了。所以排查时一定记得按时间顺序把各个环节串起来看,别急着归因到单一因素。
7. 治理方案:从救火到防火,把Spool稳定做上去
问题解决只是第一步。如果同样的故障反复出现,那说明系统架构或运维流程里有系统性缺陷。下面这几条,是我经过多个项目沉淀出来的治理经验。
7.1 定期清理Spool历史数据,保持表健康
很多SAP系统对Spool数据不够重视,TST01和TST03越积越大。数据量大到一定程度,写入和删除都变慢,锁冲突概率大幅上升。SAP标准事务码SP12就是用来按条件删除旧的Spool请求的,强烈建议把它纳入日常运维计划。
我的建议是:至少每个月跑一次SP12清理三个月之前的已完成请求。如果系统打印量大,可以考虑缩短到两周一次。同时留意SP12里的“Test Mode”选项,执行前可以先预览删除数量,确认影响范围再正式执行。
另外,SP12里可以对TST01/TST03的表存储做重组(reorganization),这一步能有效缓解表碎片化问题,但执行时间较长,建议安排在周末维护窗口。
7.2 在前端服务器上对SAPLPD做监控和自动拉起
既然SAPLPD假死是重要诱因,那就应该对它的状态做监控。Windows平台可以用计划任务定期检查服务状态;Linux平台可以用systemd或自写脚本守护进程。
我给你一个简单的Linux守护思路:
#!/bin/bash if ! pgrep -x saplpd > /dev/null; then echo "sapLPD is not running, restart now" /usr/sap/hostctrl/exe/sapstartsrv pf=/usr/sap/<SID>/SYS/profile/START_LPD fi计划任务每两分钟检查一次,进程不在就自动拉起。Windows平台类似,用PowerShell的Get-Service判断状态,异常时执行Start-Service即可。
7.3 用事务码SPAD统一规划输出设备和访问方式
很多时候打印问题跟设备配置本身有关。SAP支持多种输出访问方式,最常见的有:
- U(Universal)方式:数据先输出到前端主机的操作系统打印队列,由系统打印服务接管后续发送。
- E(External)方式:外部打印管理系统控制输出,SAP只负责把数据交给外部接口。
- X(Extended)方式:不做额外格式化,直接把格式化好的数据传给目标打印机。
一些老系统上还在用的C(Local Printing)方式只适用于直接在应用服务器上连接打印机,现在已经很少用了。
常见的坑是:管理员把访问方式从U改成E,或者反过来,但没同步调整前端的配套服务,结果作业一多就卡。修改设备配置以后,务必在SPAD里做一次“连接测试”,确认前端能正常接收数据再投入使用。
7.4 把超大报表挡在打印链路之外
前面反复提到超大报表是Spool系统的隐形杀手。几百MB的格式化数据经过网络传输,很容易在某一环超时。治理思路有两个方向:
- 业务侧限制:控制报表输出的最大行数,超限就弹窗提示用户导出文件,而不是打印成纸件;
- 技术侧分流:为超大报表单独配置一台专用输出设备,访问方式走外部打印服务,避免占用SAP标准Spool链路。
7.5 打通SAP与网络打印机的状态回传机制
最后分享一个拓展开的实践经验:能提前发现打印机故障或离线的方案,可以让Waiting for output formatter问题大幅减少。
很多现代网络打印机支持SNMP、Web服务或Jabber等协议上报状态。SAP侧可以通过BC-SPO相关的功能或者第三方打印中间件,把打印机状态(缺纸、卡纸、离线)实时同步到Spool管理员界面。这样当打印机出现异常时,管理员会第一时间收到通知,在用户发起打印之前就介入处理,而不是等几十个请求堆积成山再救火。
这个改动需要网络团队、打印硬件方和SAP团队协同,但一次投入,长期收益非常大。我们公司在一家制造企业落地过整套方案,上线后打印支持工单量下降了大概四成,其中很大一部分是因为提前发现了设备故障。
8. 排障工具箱:这些事务码、表和命令,建议收藏
为了方便你以后快速查阅,我把本文涉及的核心工具汇总成表。按排查顺序用下来,绝大多数Waiting for output formatter问题都能定位到具体环节。
SAP事务码
| 事务码 | 用途 |
|---|---|
| SP01 | 查看和管理Spool请求,改状态、删请求 |
| SPAD | 管理和测试输出设备,查看访问方式和前端配置 |
| SP12 | 清理和重组Spool历史数据 |
| AL08 | 查看活动用户会话,检查SAP_SPO用户会话 |
| SM50 | 查看工作进程状态,定位格式化进程的异常行为 |
| SM21 | 系统日志,排查隐性告警 |
| ST22 | ABAP转储分析,捕捉格式化异常 |
| RZ04 | 实例配置管理,确认前端Spool服务激活状态 |
| DBACOCKPIT | 数据库管理,查看表大小、锁、等待事件 |
核心数据表
| 表名 | 作用 |
|---|---|
| TST01 | Spool请求头,状态、时间、设备、重试记录 |
| TST03 | Spool请求数据块,对应请求所处的数据内容 |
| TST04 | 格式化参数和输出日志的辅助信息 |
| TST02 | 设备与Spool服务器配置信息 |
常用命令和查询
-- 统计TST01中各状态请求数量(按日期筛选) SELECT RSTATE, COUNT(*) FROM TST01 WHERE SDATE = TO_CHAR(SYSDATE, 'YYYYMMDD') GROUP BY RSTATE; -- 查看数据库的锁等待会话 SELECT SID, EVENT, WAIT_CLASS, SECONDS_IN_WAIT, STATUS FROM V$SESSION WHERE STATE = 'WAITING' AND EVENT LIKE '%enq%';Linux前端查看LPD状态:
ps -ef | grep saplpdWindows前端查看服务状态:
Get-Service | Where-Object {$_.Name -like "*sap*lpd*"}记住,这些工具最大的价值是帮你快速缩小范围,真正定位根因还是要靠对数据的交叉验证和实操经验。
9. 关于“有效策略使你无法连接到此打印队列”这类报错的关联说明
排障过程中,不少同事会把Spool卡住跟打印机面板上提示的错误消息联系起来,尤其是类似系统提示“有效策略使你无法连接到此打印队列”的情况。严格来说这不是同一个层面的东西,但在实际运维中它们经常同时出现。
这个提示更多是操作系统打印客户端与打印服务器之间的连接策略问题,比如组策略限制了用户连接某个共享打印队列、驱动不兼容导致连接被拒、或者打印服务器的队列权限配置有误。在SAP场景里,它的出现通常意味着:应用服务器所在的Windows前端主机在操作系统层面就无法把任务投递到目标打印机,那么SAP侧的Spool数据自然就停在等待输出的阶段。
遇到这种情况,建议按这个顺序查:
- 打印机端口是否正确:检查SAP输出设备里配置的打印目的地是IP地址、主机名还是共享名。
- 操作系统驱动与端口:在前端打印服务器上,确认打印机驱动安装正常,端口类型(TCP/IP、共享)与实际环境匹配。
- 连接策略:检查本机策略或域策略中是否有关于打印机连接的权限限制,必要时将前端服务器账号加入打印机的访问白名单。
- 测试页:先在操作系统层面打印测试页,如果测试页都出不来,问题不在SAP,先把底层连接搞定再说。
一个很常见的场景:服务器重启后,Windows自带防火墙恢复了默认策略,把打印服务依赖的端口(如9100、631、139等)挡住了。SAPLPD虽然能启动,但投递不出数据。此时在打印服务器上放行对应端口就能立竿见影。
我个人踩过最大的坑是:客户打印机之前用的对应端口自定义的,比如9101、9102,重建系统后防火墙规则只放行了默认9100,导致打印机在SAP里看着一切正常,但请求永远发不出去。把这个端口核对清楚,能省下你折腾一晚上。
10. 写在最后:没有一劳永逸,但有迹可循
处理了这么多年Spool问题,我最大的体会是:SAP打印系统的稳定性,七分靠架构治理,三分靠排障能力。很多团队天天在救火,却从不停下来问问“为什么每周都要救一次火”。其实每一场火背后,都有一条可以前置预防的线索。
如果你现在正被Waiting for output formatter折磨,建议先把这篇文章里的排查顺序走一遍,大概率能定位到问题层级。如果走完还找不到,欢迎带着你的环境信息来交流。Spool问题的变量很多,每套系统的网络、打印设备、前端部署方式都不一样,有时候真的需要坐下来把环境和日志摊开,一点一点捋。这也是这一行最有意思的地方——总是在特定环境里玩捉迷藏,但你只要耐心,总能揪出那个藏在最深处的肇事者。