java.net.UnknownHostException

一、问题

线上有个 java.net.UnknownHostException : www.sunred.net 报错!
在服务器上直接 $ ping www.sunred.net 通信正常呀。

然后,怀疑接口不通,直接命令行调试下:

$ curl -d 'test=test'  -X POST  https://www.sunred.net/api/timing/admin

也是ok的!

咨询接口什么时候不通的,具体发生的什么状况?
得出真相:服务器那边的DNS解析服务器地址换了!!!!

这里 先理清 : Linux - JRE - JVM - JAR 四者的关系,如下图:
在这里插入图片描述
当我们的服务运行,发出对外请求,带有域名的请求:
在这里插入图片描述
上面的JAR就相当于是我们的一个服务。服务发起请求,其先通 JVM cache 找到 DNS 解析服务器的IP,DNS 解析完域名到 internet 找到目标服务ip地址,从而实现通信。

现在DNS解析服务器换了IP地址, Linux $ ping www.sunred.net 是新的DNS解析没有问题。但是 JVM 缓存旧 DNS IP, 去网段找不到 DNS 服务器了,域名自然就无法解析。 从而 出现: java.net.UnknownHostException

这就是 Linux 可以,JVM 不一定可以!!

【相关知识恶补下】
java对DNS解析IP进行缓存,默认缓存超时时间为-1(在重启JVM前永久缓存)。


  1. 在第一次访问某域名后将会缓存解析到的IP地址,之后直接从缓存里获得所需的信息(如IP地址),而无需再访问DNS服务器,
    但如果在进行支付的时候DNS解析IP的地址有变更的话,提交的地址仍为原解析的IP地址,这将会访问到无效的IP地址而无法进行支付.
  2. 建议在java虚拟机的设置中将缓存的时间设置为较小的时间,例如1分钟(60秒)

由于是全局的变量,在设置后会影响所有的应用程序,请先衡量一下对您平台所有的应用程序是否有影响后再进行设置

二、解决方案

清理jvm的DNS缓存,大家可以根据自己的情况选用。

1、 在首次调用InetAddress.getByName()前,设置java.security.Security.setProperty(“networkaddress.cache.ttl”, “0”);

2、修改jre/lib/security/java.security 下的 networkaddress.cache.ttl 属性

3、jvm启动参数中设置-Dsun.net.inetaddr.ttl=0,对服务启动脚本 如下设置后,重启服务即可!

 # 本次核心解决问题点
$ nohup java -agentpath:/home/jht/projects/project/libdecrypt.so 
 $JAVA_OPTS -Xms1024m -Xmx1024m -Dsun.net.inetaddr.ttl=0
  -jar $APP_HOME/$APP_MAINCLASS > /dev/null 2>&1 &

4、通过反射清理,如本文的clearCache方法

package xiaofei;
 
import java.lang.reflect.Field;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Map;
 
public class DNSCacheTest {
    /**
     * 1. 在首次调用InetAddress.getByName()前,设置java.security.Security.setProperty("networkaddress.cache.ttl", "0");
     * 2. 修改jre/lib/security/java.security 下的 networkaddress.cache.ttl 属性
     * 3. jvm启动参数中设置-Dsun.net.inetaddr.ttl=0
     * 4. 调用clearCache方法清除
     *
     * @param args
     * @throws UnknownHostException
     */
    public static void main(String[] args) throws UnknownHostException, NoSuchFieldException, IllegalAccessException {
        java.security.Security.setProperty("networkaddress.cache.ttl", "0");
        InetAddress addr1 = InetAddress.getByName("www.baidu.com");
        System.out.println(addr1.getHostAddress());
        //clearCache();
        //在下一行设置断点.
        //放在此处无效,因为类加载的时候就确定了这个值(应该在使用InetAddress.getByName之前设置)已经缓存了cache
        //java.security.Security.setProperty("networkaddress.cache.ttl", "0");
        InetAddress addr2 = InetAddress.getByName("www.baidu.com");
        System.out.println(addr2.getHostAddress());
        InetAddress addr3 = InetAddress.getByName("www.google.com");
        System.out.println(addr3.getHostAddress());
        InetAddress addr4 = InetAddress.getByName("www.google.com");
        System.out.println(addr4.getHostAddress());
        //clearCache();
    }
 
    public static void clearCache() throws NoSuchFieldException, IllegalAccessException {
        //修改缓存数据开始
        Class clazz = java.net.InetAddress.class;
        final Field cacheField = clazz.getDeclaredField("addressCache");
        cacheField.setAccessible(true);
        final Object obj = cacheField.get(clazz);
        Class cacheClazz = obj.getClass();
        final Field cachePolicyField = cacheClazz.getDeclaredField("type");
        final Field cacheMapField = cacheClazz.getDeclaredField("cache");
        cachePolicyField.setAccessible(true);
        cacheMapField.setAccessible(true);
        final Map cacheMap = (Map)cacheMapField.get(obj);
        System.out.println(cacheMap);
        cacheMap.remove("www.baidu.com");
    }
}

【不同 server 下的 配置】

设置方法:在命令启动JVM的时候设置参数"-Dnetworkaddress.cache.ttl=60 -Dsun.net.inetaddr.ttl=60"
例如:运行Test.class
java -Dnetworkaddress.cache.ttl=60 -Dsun.net.inetaddr.ttl=60 Test


Resin
第一个方式:
修改resin.conf,在 下,添加如下配置即可
-Dnetworkaddress.cache.ttl=60
-Dsun.net.inetaddr.ttl=60
第二个方式:
在linux /unix 下或编辑 httpd.sh
args=’-Dnetworkaddress.cache.ttl=60 -Dsun.net.inetaddr.ttl=60’


websphere
第一个方式:
选择服务器-> 应用程序服务器-> Server1-> 进程定义->Java 虚拟机。
滚动到通用 JVM 参数,添加:
-Dnetworkaddress.cache.ttl=60 -Dsun.net.inetaddr.ttl=60
单击确定以保存更改
第二个方式:
修改XML文件
IBM\WebSphere\AppServer\profiles\AppSrv01\config\cells\liangwgNode01Cell\nodes\liangwgNode01\servers\server.xml
在文件末尾,在属性“disableJIT=“false””之前的位置,
添加:genericJvmArguments="-Dnetworkaddress.cache.ttl=60 -Dsun.net.inetaddr.ttl=60"


Tomcat
第一个方式:
1:进入TOMCAT的bin目录下,找到tomcat5w.exe文件,双击,选择java,找到java options
在文本框里添加: -Dnetworkaddress.cache.ttl=60 -Dsun.net.inetaddr.ttl=60
第二个方式:
2: 进入TOMCAT的bin目录下,找到文件catalina.bat,增加:
JAVA_OPTS="-Xms256 -Xmx512 -Dnetworkaddress.cache.ttl=60 -Dsun.net.inetaddr.ttl=60"


Weblogic
Weblogic目录下的两个文件:
%Weblogic_home%\user_projects\domains\domain-name\startWebLogic.cmd(如果是UNIX系统,就是startWebLogic.sh )
%Weblogic_home%\user_projects\domains\domain-name\startManagedWebLogic.cmd
(如果是UNIX系统,就是startManagedWebLogic.sh

  • 8
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 该异常通常表示无法解析给定主机名或域名。这可能是由于以下原因之一: 1. 主机名或域名不存在或已更改。 2. DNS服务器不可用或不可访问。 3. 防火墙或代理服务器阻止了对主机的访问。 您可以尝试以下步骤来解决此问题: 1. 检查您正在使用的主机名或域名是否正确,如果不正确,请更正它们。 2. 检查您的DNS服务器是否可用,并且您的计算机可以访问它们。 3. 检查您的防火墙或代理服务器设置,确保它们允许与主机的通信。 如果您仍然遇到问题,请联系您的网络管理员或技术支持人员以获取帮助。 ### 回答2: java.net.UnknownHostException: userservice 是一个 Java 网络异常,表示找不到名为 userservice 的主机或域名。 这个异常通常发生在使用网络服务时,无法解析指定的域名或主机。出现这个异常通常有以下几种可能的原因: 1. 域名或主机名拼写错误:首先需要检查代码中所使用的域名或主机名是否拼写正确,并确保没有多余的空格或字母。 2. DNS 解析问题:如果域名或主机名是正确的,那可能是由于 DNS 无法解析该域名或主机名导致的问题。可以尝试使用其他 DNS 服务器或者直接使用该主机的 IP 地址来进行连接。 3. 网络连接问题:有时候,由于网络连接问题,可能无法正常访问指定的主机或域名。可以尝试使用其他网络连接,或者检查本地网络设置,确保网络连接正常。 通常来说,解决这个异常的方法是先检查域名或主机名是否正确,然后检查网络连接是否正常。如果这些都没有问题,可以尝试使用 IP 地址来进行连接,或者联系对应的网络管理员或服务提供商寻求帮助。 总之,java.net.UnknownHostException: userservice 异常表示无法解析指定的域名或主机名,需要检查拼写、网络连接和 DNS 解析等方面的问题来解决。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值