reduce端缓存数据过多出现FGC,导致reduce生成的数据无法写到hdfs

reduce端缓存数据过多:FGC引发的SocketTimeoutException
某搜索推荐job在执行过程中,由于最后一个reduce任务的JVM老年代耗尽,频繁执行FGC,造成服务暂停,进而导致dfsclient超时无法写入HDFS。异常表现为SocketTimeoutException,分析可能原因包括:DN线程耗尽、网络带宽问题、dfsclient故障(本次因reduce OOM)。排除带宽问题后,确认是reduce内存溢出引起的dfsclient挂起。

     搜索推荐有一个job,1000多个map,200个reduce,运行到最后只剩一个reduce(10.39.6.130上)的时候,出现以下异常,导致job失败:

2014-12-04 15:49:04,297 INFO [main] org.apache.hadoop.mapred.Merger: Down to the last merge-pass, with 12 segments left of total size: 11503294914 bytes
2014-12-04 15:49:04,314 INFO [main] org.apache.hadoop.conf.Configuration.deprecation: mapred.task.id is deprecated. Instead, use mapreduce.task.attempt.id
2014-12-04 15:49:04,394 INFO [main] org.apache.hadoop.io.compress.CodecPool: Got brand-new compressor [.lzo_deflate]
2014-12-04 16:02:26,889 WARN [ResponseProcessor for block BP-1386326728-10.39.2.131-1382089338395:blk_1394149732_320469086] org.apache.hadoop.hdfs.DFSClient: DFSOutputStream ResponseProcessor exception  for block BP-1386326728-10.39.2.131-1382089338395:blk_1394149732_320469086
java.io.IOException: Bad response ERROR for block BP-1386326728-10.39.2.131-1382089338395:blk_1394149732_320469086 from datanode 10.39.5.193:50010
	at org.apache.hadoop.hdfs.DFSOutputStream$DataStreamer$ResponseProcessor.run(DFSOutputStream.java:819)
2014-12-04 16:02:26,889 WARN [ResponseProcessor for block BP-1386326728-10.39.2.131-1382089338395:blk_1394153869_320473223] org.apache.hadoop.hdfs.DFSClient: DFSOutputStream ResponseProcessor exception  for block BP-1386326728-10.39.2.131-1382089338395:blk_1394153869_320473223
java.io.IOException: Bad response ERROR for block BP-1386326728-10.39.2.131-1382089338395:blk_1394153869_320473223 from datanode 10.39.1.90:50010
	at org.apache.hadoop.hdfs.DFSOutputStream$DataStreamer$ResponseProcessor.run(DFSOutputStream.java:819)
2014-12-04 16:02:26,891 WARN [DataStreamer for file /dw_ext/recmd/mds6/mds_filter_relation_10/20141203/_temporary/1/_temporary/attempt_1415948652989_195149_r_000158_3/user-r-00158 block BP-1386326728-10.39.2.131-1382089338395:blk_1394149732_320469086] org.apache.hadoop.hdfs.DFSClient: Error Recovery for block BP-1386326728-10.39.2.131-1382089338395:blk_1394149732_320469086 in pipeline 10.39.6.130:50010, 10.39.5.185:50010, 10.39.5.193:50010: bad datanode 10.39.5.193:50010
2014-12-04 16:02:26,891 WARN [DataStreamer for file /dw_ext/recmd/mds6/mds_filter_relation_10/20141203/_temporary/1/_temporary/attempt_1415948652989_195149_r_000158_3/exposure-r-00158 block BP-1386326728-10.39.2.131-1382089338395:blk_1394153869_320473223] org.apache.hadoop.hdfs.DFSClient: Error Recovery for block BP-1386326728-10.39.2.131-1382089338395:blk_1394153869_320473223 in pipeline 10.39.6.130:50010, 10.39.1.89:50010, 10.39.1.90:50010: bad datanode 10.39.1.90:50010
java.io.EOFException: Premature EOF: no length prefix available
	at org.apache.hadoop.hdfs.protocolPB.PBHelper.vintPrefixed(PBHelper.java:1987)
	at org.apache.hadoop.hdfs.protocol.datatransfer.PipelineAck.readFields(PipelineAck.java:176)
	at org.apache.hadoop.hdfs.DFSOutputStream$DataStreamer$ResponseProcessor.run(DFSOutputStream.java:796)

2014-12-04 16:05:23,743 FATAL [main] org.apache.hadoop.mapred.YarnChild: Error running child : java.lang.OutOfMemoryError: Java heap space
	at java.util.Arrays.copyOf(Arrays.java:2734)
	at java.util.Vector.ensureCapacityHelper(Vector.java:226)
	at java.util.Vector.add(Vector.java:728)
	at rec.CommonUtil.pack_Treeset(CommonUtil.java:395)
	at rec.ConvertExposure10$MyReducer.collect_exposure(ConvertExposure10.java:259)
	at rec.ConvertExposure10$MyReducer.reduce(ConvertExposure10.java:329)
	at rec.ConvertExposure10$MyReducer.reduce(ConvertExposure10.java:234)
	at org.apache.hadoop.mapred.ReduceTask.runOldReducer(ReduceTask.java:444)
	at org.apache.hadoop.mapred.ReduceTask.run(ReduceTask.java:392)
	at org.apache.hadoop.mapred.YarnChild$2.run(YarnChild.java:167)
	at java.security.AccessController.doPrivileged(Native Method)
	at javax.security.auth.Subject.doAs(Subject.java:396)
	at org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1550)
	at org.apache.hadoop.mapred.YarnChild.main(YarnChild.java:162)
从异常上看,首先是reduce在往hdfs写数据时,发现建pipeline时,没有收到pipeline上最后一个节点的回应:
2014-12-04 16:02:26,889 WARN [ResponseProcessor for block BP-1386326728-10.39.2.131-1382089
<think>好的,我现在需要帮助用户解决Java后项目在Linux服务器上运行一段时间后出现的图片上传报错和缓存数据获取失败的问题,并且理解为什么重启能解决问题。首先,我要分步骤分析可能的原因,并给出排查方法。 首先,用户提到图片上传报错,可能的原因有很多。我需要考虑文件系统权限问题,比如上传目录的权限是否在运行过程中发生了变化,或者Tomcat用户是否有足够的权限写入目录。另外,磁盘空间不足也是一个常见问题,上传文件时如果磁盘满了就会失败。还有可能是文件句柄泄漏,导致系统无法打开新文件,这时候重启会释放句柄,暂时解决问题,但根本原因还是代码中的资源未正确释放。 接下来是缓存数据获取失败的问题。可能的原因包括内存泄漏,导致JVM的堆内存耗尽,进而影响缓存功能;缓存策略设置不当,比如缓存过期时间过长或过短;或者缓存存储介质的问题,比如使用内存缓存时,未正确管理导致数据丢失。此外,如果缓存依赖于外部服务(如Redis),网络问题或连接池耗尽也可能导致获取失败。 然后,为什么重启能暂时解决问题?重启会释放被占用的资源,比如内存、文件句柄、数据库连接等,同时重置应用状态,清除临时错误。但重启只是临时措施,必须找到根本原因才能彻底解决。 接下来,用户可能需要具体的排查步骤。对于图片上传问题,可以检查日志中的具体错误信息,查看是否有权限拒绝、磁盘空间不足或文件句柄超限的记录。使用命令如`df -h`检查磁盘空间,`lsof | grep tomcat`查看文件句柄使用情况。对于缓存问题,需要检查JVM内存使用情况,使用工具如jstat或VisualVM监控内存,查看是否有内存泄漏迹象。同时检查缓存配置,确保缓存策略合理,并验证外部缓存服务的连接状态。 另外,用户提供的引用中提到Tomcat重启后无法访问的问题,可能与环境配置或资源泄漏有关。比如引用[1]中的情况,客户重启服务器后程序无法访问,可能涉及服务启动顺序或依赖项未正确加载。引用[2]中的Docker镜像配置,需要注意基础镜像和启动命令是否正确。引用[3]中的i18n配置虽然不直接相关,但配置文件错误也可能导致其他功能异常。 总结下来,需要从资源泄漏、配置错误、外部依赖等方面入手,结合日志分析和系统监控工具,逐步排查问题根源。同时,建议用户实施监控和定期维护,避免问题再次发生。</think>### 问题排查与分析步骤 #### 一、图片上传报错的可能原因及排查方法 1. **文件系统权限问题** - **现象**:上传目录权限变更导致写入失败,或临时文件目录权限不足。 - **排查方法**: - 检查上传目录的权限:`ls -ld /path/to/upload/dir`,确保Tomcat用户(如`tomcat`或`www-data`)有写入权限。 - 查看日志中是否包含`Permission denied`错误[^1]。 2. **磁盘空间不足** - **现象**:上传时返回`No space left on device`错误。 - **排查方法**: - 使用`df -h`检查磁盘使用率,重点关注挂载点(如`/var`或`/tmp`)。 - 清理日志文件或临时文件(如Tomcat的`work`目录)。 3. **文件句柄泄漏** - **现象**:上传失败时日志提示`Too many open files`,重启后暂时恢复。 - **排查方法**: - 查看系统文件句柄限制:`ulimit -n`。 - 检查进程打开的文件数:`lsof -p <Tomcat_PID> | wc -l`。 - 通过代码审查确认文件流是否未正确关闭(如`InputStream`或`OutputStream`)。 4. **临时目录失效** - **现象**:系统临时目录(如`/tmp`)被清理或权限变更。 - **解决方法**: - 在代码中显式指定上传临时目录,并在配置文件中固化路径。 --- #### 二、缓存数据获取失败的可能原因及排查方法 1. **内存泄漏导致堆内存耗尽** - **现象**:`OutOfMemoryError`或频繁Full GC,缓存数据无法加载。 - **排查方法**: - 使用`jstat -gc <PID>`观察GC情况,关注`FGC`(Full GC次数)和`OU`(老年代使用量)。 - 通过内存分析工具(如`jmap`或VisualVM)生成堆转储文件,分析内存泄漏对象。 2. **缓存策略配置错误** - **现象**:缓存过期时间过短或未命中导致频繁穿透到数据库。 - **解决方法**: - 检查缓存框架(如Redis、Ehcache)的配置,确认`TTL`(生存时间)和容量限制。 3. **外部缓存服务异常** - **现象**:Redis连接超时或连接池耗尽。 - **排查方法**: - 检查Redis服务状态:`systemctl status redis`。 - 查看连接池配置(如`maxTotal`和`maxIdle`),使用`netstat -ant | grep 6379`确认连接数。 4. **本地缓存未同步** - **现象**:分布式环境中本地缓存与中心缓存数据不一致。 - **解决方法**: - 使用Redis Pub/Sub机制或Spring Cache的`@CacheEvict`注解实现缓存一致性。 --- #### 三、重启为何能暂时解决问题? 1. **释放资源** - 重启会关闭所有文件句柄、数据库连接和线程池,清除内存泄漏积累的无效对象[^1]。 2. **重置状态** - 临时文件目录、内存缓存等状态恢复到初始值,规避运行时积累的脏数据。 3. **服务重连** - 重建与数据库、Redis等外部服务的连接,修复因网络波动导致的连接失效。 --- #### 四、长期解决方案 1. **代码层面** - 使用`try-with-resources`确保文件流关闭。 - 添加内存泄漏监控(如`WeakHashMap`或LeakCanary工具)。 2. **系统层面** - 增加磁盘空间监控(如Prometheus + Grafana)。 - 调整文件句柄限制: ```bash # 修改/etc/security/limits.conf tomcat soft nofile 65535 tomcat hard nofile 65535 ``` 3. **部署优化** - 使用Docker容器化部署,通过健康检查自动重启异常实例[^2]。 - 配置日志轮转(如Logrotate)避免日志占满磁盘。 --- ### 相关问题 1. 如何监控Java应用的内存泄漏? 2. 在Linux服务器上如何快速定位文件句柄泄漏? 3. Tomcat日志分析有哪些常用工具? 4. 如何优化Redis连接池配置避免超时? [^1]: java项目在服务器上一直重启_重启服务器后程序无法访问。现在有一个java项目部署在windows2003(32位)系统的服务器上,使用jdk7和tomcat6。上周客户重装了系统,我重新安装了java环境,启动tomcat后程序正常运行。但是周五客户突然重启了服务器,他们自称什么都没有改变,但是现在tomact启动后程序无法正常访问。 [^2]: 自定义镜像结构 # 指定基础镜像 FROM java:8-alpine COPY ./docker-demo.jar /tmp/app.jar # 暴露接口 EXPOSE 8090 # 入口,java项目启动命令 ENTRYPOINT java -jar /tmp/app.jar docker build -t javaweb:2.0 空格. [^3]: 2.8配置i18n国际化文件messages.properties not.null=* 必须填写 user.jcaptcha.error=验证码错误 user.jcaptcha.expire=验证码已失效 user.not.exists=用户不存在/密码错误
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值