# Java DNS Cache

2018-07-02  本文已影响0人  RyanEngineer

Cache Type

DNS的缓存类型分为两种:Positive和Negative,Positive用于缓存可以正常解析的域名,Negative用于缓存无法解析的域名。

        enum Type {Positive, Negative};

InetAddressCachePolicy

InetAddressCachePolicy(sun.net.InetAddressCachePolicy),表示缓存策略,这里特指缓存过期时间,

  private static int cachePolicy = -1;
  private static int negativeCachePolicy = 0;

  public static synchronized int get() {
    return cachePolicy;
  }

  public static synchronized int getNegative() {
    return negativeCachePolicy;
  }

cachePolicy和negativeCachePolicy都是静态变量,它们的数值也是通过静态代码块初始化的。

cachePolicy

    Integer var0 = (Integer)AccessController.doPrivileged(new PrivilegedAction<Integer>() {
      public Integer run() {
        String var1;
        try {
          var1 = Security.getProperty("networkaddress.cache.ttl");
          if (var1 != null) {
            return Integer.valueOf(var1);
          }
        } catch (NumberFormatException var3) {
          ;
        }

        try {
          var1 = System.getProperty("sun.net.inetaddr.ttl");
          if (var1 != null) {
            return Integer.decode(var1);
          }
        } catch (NumberFormatException var2) {
          ;
        }

        return null;
      }
    });
    if (var0 != null) {
      cachePolicy = var0;
      if (cachePolicy < 0) {
        cachePolicy = -1;
      }

      propertySet = true;
    } else if (System.getSecurityManager() == null) {
      cachePolicy = 30;
    }

cachePolicy取值来源于两个配置属性:

如果配置属性的值小于0,则cachePolicy为-1;如果配置属性没有被设置,则cachePolicy为30。也就是说,对于正常解析的域名,默认的缓存时间为30s。

:-1为永久缓存。

negativeCachePolicy

    var0 = (Integer)AccessController.doPrivileged(new PrivilegedAction<Integer>() {
      public Integer run() {
        String var1;
        try {
          var1 = Security.getProperty("networkaddress.cache.negative.ttl");
          if (var1 != null) {
            return Integer.valueOf(var1);
          }
        } catch (NumberFormatException var3) {
          ;
        }

        try {
          var1 = System.getProperty("sun.net.inetaddr.negative.ttl");
          if (var1 != null) {
            return Integer.decode(var1);
          }
        } catch (NumberFormatException var2) {
          ;
        }

        return null;
      }
    });
    if (var0 != null) {
      negativeCachePolicy = var0;
      if (negativeCachePolicy < 0) {
        negativeCachePolicy = -1;
      }

      propertyNegativeSet = true;
    }

negativeCachePolicy取值来源于两个配置属性:

如果配置属性的值小于0,则negativeCachePolicy为-1;如果配置属性的值没有被设置,则negativeCachePolicy为0。也就是说,对于无法解析的域名,默认的缓存时间为0s,即不缓存。

CacheEntry

CacheEntry(java.net.InetAddress.CacheEntry),表示一个缓存对象,包含两个实例属性:

    /**
     * Represents a cache entry
     */
    static final class CacheEntry {

        CacheEntry(InetAddress[] addresses, long expiration) {
            this.addresses = addresses;
            this.expiration = expiration;
        }

        InetAddress[] addresses;
        long expiration;
    }

Cache

Cache(java.net.InetAddress.Cache),表示一个缓存实例,包含两个实例属性:

        private LinkedHashMap<String, CacheEntry> cache;
        private Type type;

put

  1. 根据缓存类型,获取相应的缓存时间;如果缓存时间为0s,则put直接退出即可;
            int policy = getPolicy();
            if (policy == InetAddressCachePolicy.NEVER) {
                return this;
            }
  1. 如果不是永久缓存,则清理缓存中的过期对象;
            // purge any expired entries

            if (policy != InetAddressCachePolicy.FOREVER) {

                // As we iterate in insertion order we can
                // terminate when a non-expired entry is found.
                LinkedList<String> expired = new LinkedList<>();
                long now = System.currentTimeMillis();
                for (String key : cache.keySet()) {
                    CacheEntry entry = cache.get(key);

                    if (entry.expiration >= 0 && entry.expiration < now) {
                        expired.add(key);
                    } else {
                        break;
                    }
                }

                for (String key : expired) {
                    cache.remove(key);
                }

逐个遍历缓存中的对象(entry),判断是否过期;如果已过期(entry.expiration < now),则将域名加入到过期列表(expired);遍历完成之后,将过期列表中的域名统一从缓存中清除。

  1. 计算对象对象过期时间(expiration),将对象存入缓存;
            long expiration;
            if (policy == InetAddressCachePolicy.FOREVER) {
                expiration = -1;
            } else {
                expiration = System.currentTimeMillis() + (policy * 1000);
            }
            CacheEntry entry = new CacheEntry(addresses, expiration);
            cache.put(host, entry);

get

  1. 根据缓存类型,获取相应的缓存时间;如果缓存时间为0s,则get直接返回null即可;
            int policy = getPolicy();
            if (policy == InetAddressCachePolicy.NEVER) {
                return null;
            }

  1. 通过域名(host)获取相应的缓存对象(IP地址);
            CacheEntry entry = cache.get(host);
  1. 判断缓存对象是否过期;如果已过期,需要从缓存中移出(域名指向可能已发生变化),并返回null;
            // check if entry has expired
            if (entry != null && policy != InetAddressCachePolicy.FOREVER) {
                if (entry.expiration >= 0 &&
                    entry.expiration < System.currentTimeMillis()) {
                    cache.remove(host);
                    entry = null;
                }
            }

InetAddress getByName

InetAddress.getByName底层域名解析实际调用的方法为InetAddress.getAllByName0,主要包括两个核心逻辑:

通过DNS服务解析域名之后,无论是否能够正常解析,均需要更新缓存:

    // Cache the address.
    cacheAddresses(host, addresses, success);

    /*
     * Cache the given hostname and addresses.
     */
    private static void cacheAddresses(String hostname,
                                       InetAddress[] addresses,
                                       boolean success) {
        hostname = hostname.toLowerCase();
        synchronized (addressCache) {
            cacheInitIfNeeded();
            if (success) {
                addressCache.put(hostname, addresses);
            } else {
                negativeCache.put(hostname, addresses);
            }
        }
    }

:无法正常解析的域名,IP地址被缓存为unknown_array。

上一篇 下一篇

猜你喜欢

热点阅读