ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

expdp导出报ORA-39064和ORA-29285?日志文件写入失败的排查指南

expdp导出报ORA-39064和ORA-29285?日志文件写入失败的排查指南 做Oracle DBA的朋友应该早就习惯了这样一个规律凡是用了expdp、impdp这些Data Pump工具报错从来都不是“一个”错误而是一串。ORA-39064和ORA-29285就是典型的连体婴儿错误。我今天记录的就是expdp按user导出时踩到的这个坑报错信息很明确但排查路径却有好几条。如果你也碰到这两个错误码这篇文章应该能帮你省下不少排查时间。这两个错误出现时expdp会在启动阶段直接中断不会进入真正的数据导出。一句话概括ORA-39064是Data Pump主进程写日志文件失败ORA-29285是底层UTL_FILE写入文件时报出来的具体错误。任何一个做Oracle数据迁移、数据库备份、应用上线前数据抽取的DBA、运维或开发都有概率遇到。下面我先把错误链拆开讲清楚再给出一套可以直接照做的排查和恢复步骤。1. 先把错误码看清楚ORA-39064和ORA-29285到底在报什么1.1 ORA-39064不是通用的导出失败它锁定的是日志文件ORA-39064的全称是“ORA-39064: Unable to write to log file”直译过来就是“无法写入日志文件”。注意这里的关键词是log file不是dump file。Data Pump工具的执行流程非常讲究顺序先创建日志文件并持续写入再扫描和导出表数据。日志文件一旦写不进去主控进程会立刻放弃整个会话所以你看到的现象就是导出启动后很快就中断而不是等到跑了一半才失败。ORA-39064要单独理解它代表的是Data Pump主进程在初始化阶段就出了问题。这个阶段还没进入数据扫描和表空间损坏、数据块坏块、约束失效这类问题完全无关。所以看到这个错误码第一反应不应该是“库是不是坏了”而应该是“文件系统是不是不能写”。方向若对了排查速度才会快。1.2 ORA-29285是Data Pump向UTL_FILE要到的底层答案ORA-29285的文本是“ORA-29285: error writing file”翻译过来就是写入文件时出错。这里的文件指的还是日志文件。Data Pump在记录日志时并不是像操作系统命令一样直接打开一个文件流去写而是调用了PL/SQL的UTL_FILE包。UTL_FILE是Oracle提供给PL/SQL读写操作系统文件的工具包它的底层写入动作一旦失败错误就会原封不动地传给上层Data Pump进程。所以这两个错误其实是一条错误链ORA-39064是上层现象ORA-29285是底层原因。看到ORA-29285脑子里应该立刻跳出三个候选根因磁盘空间满了、文件系统只读、没有写权限。很多时候光凭这两个错误码就能把问题范围压缩到“日志文件写入”这一个动作上排查效率会高出不少。1.3 为什么日志文件在expdp里比dump文件优先级更高这个问题我当年也困惑过为什么就不能先导出数据日志文件写不了等一会儿再说后来看多了Data Pump的执行机制才明白Data Pump的作业状态和对象列表都是围绕主表Master Table来维护的日志文件是否可写直接决定了这个作业能不能被完整追踪。如果日志都写不进去作业进度、对象状态、错误明细全都没法记录后续中断恢复和排障就无从谈起。所以Oracle选择在启动阶段就强制校验日志写入能力而不是等到跑了一半才发现问题。这其实是个很务实的设计——问题暴露得越早损失越小。这一点理解了你也就明白为什么ORA-39064会出现在所有其他导出错误之前。2. 为什么会触发这两个错误从根因推导排查方向2.1 目录对象授权是第一道门expdp命令里必须指定directory也就是Oracle数据库里的目录对象DIRECTORY。但要注意目录对象本身只是一个逻辑指针它指向操作系统上的一个真实路径。用户执行expdp时Oracle会检查这个用户对目录对象是否具备READ和WRITE权限。注意了从Oracle 11g开始Data Pump对目录对象权限的校验明显变严以前只要你有DBA角色就能绕过的日子已经不存在了。现在就算是SYSTEM用户如果目录对象的WRITE权限没给到日志照样写不进去。我见过太多翻车姿势排第一的是用DBA账号执行expdp指定了一个自定义目录对象但这个目录对象只授予了READ权限。Oracle在检查时会抛ORA-39064而不是直白告诉你“权限不足”因为权限检查链条里任何一个环节失败最终都会归到“写日志失败”这个大帽子下面。排第二的翻车姿势是目录对象的逻辑权限没有给全但你确实有DBA角色于是操作系统权限也够了结果却因为目录对象上缺WRITE权限导致失败。这两类问题都需要先从目录对象的授权入手查。2.2 OS文件系统权限是第二道门Oracle数据库进程在操作系统上是用oracle用户跑的。不管目录对象的逻辑权限怎么授最终写日志文件这个动作落在操作系统上就是“oracle用户能不能在某个目录里创建文件”。不能写就是不能写Oracle进程再怎么努力都没用。最常见的场景是目录路径是DBA用root用户提前创建的比如/u01/app/oracle/backup但创建后没有修改属主和权限默认属主是root权限755。这样一来oracle用户对这个目录只有读和执行权限没有写权限。expdp一执行ORA-39064和ORA-29285就同时冒出来。还有一种场景在Windows平台上比较典型目录对象指向的路径在C盘Program Files下面Oracle服务账户没有写权限。又或者目录所在文件系统被以只读方式挂载再或者服务器上启用了SELinuxoracle用户能看到的路径与SELinux策略允许的路径不一致导致写入被拦截。这些虽然少见但真遇到时排查难度比权限问题高不少。2.3 磁盘空间和inode容易被忽略的双重陷阱日志文件虽然只有几十KB到几MB但在expdp启动的时候必须创建并持续写入。如果目录所在文件系统的可用空间已经归零UTL_FILE一写就失败ORA-29285就冒出来了。特别是按user导出多个schema的场景日志文件一路滚动写入频率很高空间不足的症状会更明显。但空间检查要记得两条腿走路df -h看容量df -i看inode。很多Linux环境下磁盘空间看着还剩几十GB但inode已经满了同样会导致“无法写入文件”的报错。inode耗尽以后你连一个零字节的文件都创建不了但df -h却显示空间充足。这是最容易迷惑人的细节我建议排查时把两条命令的结果一起看掉缺一不可。2.4 RAC、NFS和ASM跨环境部署才遇到的隐藏雷区多节点RAC环境里目录对象对应的路径必须在所有节点上真实存在且权限一致。Data Pump的工作进程可能会被调度到任何节点如果你只在一个节点的本地目录里做了权限其他节点的相同路径不存在或权限不对日志写入就会在某些节点上失败。这种“时好时坏”的现象其实很危险容易让人误以为是偶发故障。NFS挂载路径也有类似问题。NFS默认的root_squash特性会把root用户压成nobody权限同时如果NFS共享目录的属主权限配置不当oracle用户写起来就会时好时坏。我曾经碰到过一个案例第一次expdp成功第二次同样的命令失败查了半天发现是NFS共享目录上oracle用户的uid和NFS服务端的uid不一致导致写权限判定失败。另外千万别把目录对象直接指向ASM磁盘组路径。expdp工具本身不直接支持写ASM裸路径日志文件也不能落在ASM磁盘组上。如果配置了这种目录启动时同样会报写入失败。正确的做法是先把ASM里的文件映射到文件系统路径再通过文件系统目录去使用。3. 实操从第1个错误码到成功导出的完整排查流程3.1 复现场景一条expdp命令引起的连环问题假设现在的场景是需要按user导出scott用户的数据于是执行了这么一条命令expdp system/oracle directoryDMP_DIR dumpfileuser_scott.dmp logfileuser_scott.log schemasscott结果屏幕一闪直接就给你来一段Export: Release 19.0.0.0.0 - Production ... Starting SYSTEM.SYS_EXPORT_SCHEMA_01: system/*** directoryDMP_DIR dumpfileuser_scott.dmp logfileuser_scott.log schemasscott ORA-39064: 无法写入日志文件 ORA-29285: 写入记录到日志文件时出错记住这个报错出现在启动阶段说明Data Pump主进程连接都没跑完就开始卡在日志文件上了。下面按顺序来排查顺序别乱因为前一步往往会直接决定后一步的方向。3.2 第一步核对目录对象指向和授权先用SQL查看目录对象指向的真实路径SELECT DIRECTORY_NAME, DIRECTORY_PATH FROM DBA_DIRECTORIES WHERE DIRECTORY_NAME DMP_DIR;正常情况下你得到的是类似这样的结果DIRECTORY_NAME DIRECTORY_PATH -------------- ---------------------------------- DMP_DIR /u01/app/oracle/backup然后查这个目录对象的授权情况SELECT GRANTEE, PRIVILEGE FROM DBA_TAB_PRIVS WHERE TABLE_NAME DMP_DIR;注意目录对象的权限是挂在对象权限里的。很多人习惯去查系统权限结果查不到这一步最容易踩空。如果查询结果里只有READ没有WRITE那问题就出在这。补授权GRANT READ, WRITE ON DIRECTORY DMP_DIR TO SYSTEM;如果执行expdp的不是SYSTEM而是普通用户比如SCOTT要导自己的数据命令就写成GRANT READ, WRITE ON DIRECTORY DMP_DIR TO SCOTT;这一步做完先不要急着跑expdp继续往下走把OS层面的验证也做了。3.3 第二步验证操作系统路径的真实权限拿到DIRECTORY_PATH以后立刻SSH到数据库服务器上验证路径权限ls -ld /u01/app/oracle/backup假如输出是drwxr-xr-x 2 root root 4096 Jun 10 14:22 /u01/app/oracle/backup你看属主是root权限755oracle用户只有rx没有w。这铁定写不了日志文件。这时候有两条路可以选。第一条路直接改属主和权限chown oracle:oinstall /u01/app/oracle/backup chmod 775 /u01/app/oracle/backup需要注意如果backup路径下已经有其他应用在写文件你得先确认这些应用对权限的要求避免因为属主变更影响到别人。生产环境里我更推荐“另起炉灶”——新建一个专门的导出目录重新映射目录对象互相隔离更安全mkdir -p /u01/app/oracle/expdp_log chown oracle:oinstall /u01/app/oracle/expdp_log chmod 775 /u01/app/oracle/expdp_log然后在SQL里重建目录对象CREATE OR REPLACE DIRECTORY DMP_DIR AS /u01/app/oracle/expdp_log; GRANT READ, WRITE ON DIRECTORY DMP_DIR TO SYSTEM;这里有个细节必须提醒CREATE OR REPLACE DIRECTORY会把目录对象之前的授权全部清掉所以重建之后必须重新授权。很多朋友改完路径后直接跑expdp依然报错就是因为忘了重新grant。3.4 第三步用两条命令排除空间与inode在服务器上执行df -h df -i输出里重点看Use%和IUse%。如果Use%到了100%或者IUse%到了100%日志文件写不了是必然的。这种场景下清理一下过期dump文件、归档日志或者把目录对象映射到空间更充裕的分区然后再执行expdp。有一个小技巧值得记住如果你只想快速知道某个目录能不能写直接在目录里创建临时文件touch /u01/app/oracle/expdp_log/test.txt如果touch成功说明OS层面没问题如果报Permission denied或者No space left on device那问题就在OS层不用急着重新跑expdp。确认完后记得删掉test.txt保持目录干净。3.5 第四步模拟写入并重新执行expdp上面几步都处理完之后重新执行expdp命令expdp system/oracle directoryDMP_DIR dumpfileuser_scott.dmp logfileuser_scott.log schemasscott这次应该就能看到正常的输出比如Starting SYSTEM.SYS_EXPORT_SCHEMA_01: ... Processing object type DATABASE_EXPORT/SCHEMA/TABLE/TABLE_DATA ... Job SYSTEM.SYS_EXPORT_SCHEMA_01 successfully completed at ...同时可以去日志目录下确认user_scott.log文件是否已经生成而且正在持续写入内容。日志文件在导出期间不应该一直是0字节如果一直是0字节或者半天不刷新那还要再深挖是不是Work Directory和参数配置有别的坑。3.6 完整复盘典型的20分钟排障记录我这里还原一次真实处理过程。某次执行expdp报的就是ORA-39064和ORA-29285。我先查DBA_DIRECTORIES发现目录对象指向的是/u01/app/oracle/backup再查DBA_TAB_PRIVS授权确实有READ和WRITE。但ls -ld一看backup目录属主是root权限755。我当时没有直接chown因为backup目录下面还有备份脚本在写归档文件动了属主可能影响其他作业。于是新建了/u01/oracle_backup/log目录chown oracle:oinstall然后重建LOG_DIR目录对象grant权限。整个过程大概20分钟其中10分钟花在确认有没有其他应用在用那个目录上。所以遇到生产环境宁可多花几分钟确认影响面也别贸然改权限。4. 常见问题速查与避坑经验4.1 常见场景对照表错误表现大概率根因快速验证方式expdp启动即报ORA-39064ORA-29285目录对象缺WRITE权限DBA_TAB_PRIVS查授权目录权限已授满仍报错OS路径属主是rootoracle不可写ls -ld查看属主权限权限正常df -h显示100%磁盘空间满df -hdf -h有富余仍报无法写入inode已满df -iNFS目录时好时坏root_squash或uid不一致mount查看挂载选项RAC环境某节点报错节点上路径缺失或权限不一各节点分别ls检查这个表是我这几年的排障经验浓缩出来的大部分情况都能命中其中一行。如果对不上再往冷门方向查。4.2 权限、空间都正常却仍然报错的冷门原因有一种情况真的能把人折腾到怀疑人生权限检查都正常、空间也正常、手动touch也成功但expdp依然报ORA-39064。这类问题的根源往往是“会话缓存”——尤其是在RAC环境里你用SQL*Plus查到的目录对象是从某个实例读取的而expdp连接到的可能是另一个实例路径信息自然对不上。解决方法是完全退出所有SQL*Plus和expdp会话重新登录数据库再确认一次DBA_DIRECTORIES里的路径。如果是RAC最好通过srvctl把服务重新检查一遍确认节点间目录对象一致。还有一种可能是并行度太高。ORA-39064虽然主要不是由parallel参数触发但极端情况下parallel设成100甚至200主控进程创建大量工作进程时可能撞上操作系统文件句柄上限也会伴随ORA-29285。遇到这种先把parallel调到4左右做基准测试能正常导出再把参数慢慢调高。4.3 哪些问题不要硬往ORA-39064上归因处理错误码时要有一个边界感。ORA-39064和ORA-29285只负责“日志文件写入”这一段expdp后续碰到的表空间不足、对象类型导入导出失败、字符集转换问题都不会长成这个报错的样子。如果你看到的是ORA-39166、ORA-31693这类错误码那就别在目录权限上打转了该去查对象过滤规则或者数据本身的问题。我在实际支持中经常看到有人把expdp的所有失败都归结为“目录权限不对”结果调了半天权限问题依旧。所以还是那句话错误码要先看清楚再匹配经验。ORA-39064和ORA-29285的最佳匹配对象就是“日志文件写入失败”别的先别联想。4.4 预防方案把日志目录和dump目录分开管理在真正生产环境里做数据导出我强烈建议不要把所有文件混在同一个目录对象下。更稳的做法是准备两个目录对象DMP_DIR 指向 dump文件的存放路径 LOG_DIR 指向 日志文件的存放路径导出命令这么写expdp system/oracle directoryDMP_DIR logfileLOG_DIR:user_scott.log dumpfileuser_scott.dmp schemasscott注意logfile前面带了目录对象前缀“LOG_DIR:”这样Oracle就会用LOG_DIR这个目录对象去写日志。这样做的好处有三个第一日志目录和dump目录空间可以分别规划第二排查问题时能快速定位到底是哪个目录出了问题第三生产环境如果对数据目录有读写审计要求日志目录独立出来也更好管理。配套的初始化脚本建议直接固化下来。我在新环境部署时习惯先跑一段mkdir -p /u01/oracle_backup/dump mkdir -p /u01/oracle_backup/log chown -R oracle:oinstall /u01/oracle_backup chmod -R 775 /u01/oracle_backup再进SQL执行CREATE OR REPLACE DIRECTORY DMP_DIR AS /u01/oracle_backup/dump; CREATE OR REPLACE DIRECTORY LOG_DIR AS /u01/oracle_backup/log; GRANT READ, WRITE ON DIRECTORY DMP_DIR TO SYSTEM; GRANT READ, WRITE ON DIRECTORY LOG_DIR TO SYSTEM;这套脚本拿到新环境直接跑一遍基本能规避95%的日志写入类报错。5. 从错误链看Data Pump的日志机制5.1 为什么Data Pump坚持先把日志写好再干活我一直觉得理解工具的错误链比记错误码本身更重要。Data Pump的执行流程其实围绕主表Master Table来设计先创建主表记录整个导出作业的状态、对象列表、进度信息再通过UTL_FILE把日志信息写进文件。日志文件是否可写决定了作业能否被完整追踪。如果从一开始就写不了日志后面所有对象的导出状态都无从记录中断恢复更是无从谈起。所以Oracle选择在启动阶段强制校验日志写入能力并且用ORA-39064直接拦住整个作业。这看起来有点“一刀切”但确实能帮你把问题限制在一个很小的范围里排除了日志写入问题以后你再往数据本身、权限授权、参数配置这些方向查每一步都有明确的验证手段。5.2 ORA-29285如何带着OS错误链穿透出来Oracle在UTL_FILE包的设计中有意保留了操作系统层的错误信息。Data Pump调用UTL_FILE时如果底层写入失败UTL_FILE会把错误码一路向上抛。这里要特别注意ORA-29285虽然看起来只有一个但它背后实际包含了OS错误链可以在alert日志或者expdp的trace文件中看到更完整的上下文。因此遇到ORA-29285别只看字面意思。如果报错信息里还有“ORA-27091: unable to queue I/O”这类OS层错误那就要去看存储、网络文件系统、磁盘控制器这些更底层的东西。相反如果只有ORA-39064和ORA-29285两个干净的错误码那就优先查权限和空间不需要过度联想。这个内容我个人在实际处理中反复验证过报错越“干净”越说明只是日志写入这一个动作的问题解决起来也越快。最后分享一个习惯我排查这类问题从来不会一上来就翻大而全的日志分析而是按“目录对象授权 → OS路径权限 → 磁盘空间和inode → 节点与挂载细节”这条顺序快速走一遍。大多数情况下走到第二步就能定位问题。真正花了几个小时都查不出来的场景基本都是卡在了RAC节点一致性或者NFS权限这类跨环境因素上。希望这套思路能帮你少走点弯路。
返回列表