上传文件至S3时遇java.net.UnknownHostException问题求助
问题分析:间歇性
java.net.UnknownHostException连接Amazon S3 问题描述
上传文件至Amazon S3时,间歇性抛出java.net.UnknownHostException: bucketName.s3.ap-south-1.amazonaws.com异常。异常有时在重新部署WAR包后恢复,有时自行消失。当前使用AWS Java SDK 1.12.305版本,需排查该异常属于代码问题、DNS问题还是AWS相关问题。
代码片段
连接S3客户端方法
public static AmazonS3 connectToAmazonS3(String accessKeyID, String secretAccessKey) { LOGGER.info("Connect to the amazon s3 service using the credentials"); try { final BasicAWSCredentials awsCreds = new BasicAWSCredentials(accessKeyID, secretAccessKey); final AmazonS3 s3Client = new AmazonS3Client(awsCreds); LOGGER.info("Successfully connected to Amazon S3 service"); return s3Client; } catch (Exception e) { LOGGER.error("Error occured while connecting to Amazon S3 service" + e, e); } LOGGER.info("Connection not established with Amazon S3 service"); return null; }
上传文件至S3方法
public static void uploadFileToAmazonS3(final AmazonS3 s3Client, final String bucketName, final String keyName, String cmdStr) { LOGGER.info("Started upload file to Amazon S3 for key: " + keyName); try { byte[] contentAsBytes = cmdStr.getBytes(EPSCommonConstants.CHARSET_UTF8); ByteArrayInputStream contentAsStream = new ByteArrayInputStream(contentAsBytes); ObjectMetadata metadata = new ObjectMetadata(); metadata.setContentLength(contentAsBytes.length); PutObjectRequest req = new PutObjectRequest(bucketName, keyName, contentAsStream, metadata); s3Client.putObject(req); } catch (AmazonServiceException ase) { LOGGER.error("Caught an AmazonServiceException, which " + "means your request made it " + "to Amazon S3, but was rejected with an error response" + " for some reason.", ase); LOGGER.error("Error Message: " + ase.getMessage() + " " + "HTTP Status Code: " + ase.getStatusCode() + " " + "AWS Error Code: " + ase.getErrorCode() + " " + "Error Type: " + ase.getErrorType() + " " + "Request ID: " + ase.getRequestId()); } catch (AmazonClientException ace) { LOGGER.error( "Caught an AmazonClientException, which " + "means the client encountered " + "an internal error while trying to " + "communicate with S3, " + "such as not being able to access the network." + "Error Message: " + ace.getMessage(), ace); } catch (IOException ioe) { LOGGER.error("Caught an IOException Error Message: " + ioe.getMessage(), ioe); } }
排查方向
1. DNS相关问题(最可能)
UnknownHostException本质是无法解析目标域名,间歇性出现且自行恢复的特征完全匹配DNS解析故障:
- 应用服务器本地DNS缓存过期或失效,重启JVM(重新部署WAR包)会清除旧缓存,可能恢复解析
- 网络运营商或本地DNS服务器的解析服务不稳定,出现间歇性解析失败
- 异常发生时,可在应用服务器上执行
nslookup bucketName.s3.ap-south-1.amazonaws.com或dig bucketName.s3.ap-south-1.amazonaws.com,手动验证域名解析是否正常
2. 代码/客户端配置问题
当前代码存在潜在优化点,虽不直接导致间歇性异常,但可能加重解析负担:
- 未指定S3区域:
AmazonS3Client默认使用US East 1区域,而bucket在ap-south-1,SDK自动重定向可能增加解析风险,建议初始化时指定区域:final AmazonS3 s3Client = AmazonS3Client.builder() .withCredentials(new AWSStaticCredentialsProvider(awsCreds)) .withRegion(Regions.AP_SOUTH_1) .build(); - 客户端实例管理:频繁创建
AmazonS3实例可能引发连接池或DNS缓存问题,建议复用客户端实例(单例模式) - JVM DNS缓存设置:可通过调整
networkaddress.cache.ttl(正缓存时长)和networkaddress.cache.negative.ttl(负缓存时长)参数,避免缓存过期的无效解析结果
3. AWS相关问题(可能性极低)
AWS S3区域性解析故障概率极低,可通过AWS状态页面查看ap-south-1区域S3服务状态。另外,确认bucket名称符合S3命名规则(特殊字符可能导致解析异常,但不会是间歇性的)
总结
优先排查DNS解析问题,其次优化代码中的客户端配置与实例管理,最后确认AWS服务状态。
内容的提问来源于stack exchange,提问作者Sanket Vidwans
相关产品推荐
相关产品推荐

