Java自定义DNS解析器负载均衡实现
在上文Java自定义DNS解析器实践中,我们没有讲到org.apache.http.conn.DnsResolver具体如何实现负载均衡,今天我们就分享一下,负载均衡的具体实现。 InMemoryDnsResolver被淘汰
首先上期文章提到的org.apache.http.impl.conn.InMemoryDnsResolver类是无法实现负载均衡的,原因是这个实现类是将host和IP存在一个java.util.concurrent.ConcurrentHashMap中,然后解析的时候从java.util.concurrent.ConcurrentHashMap根据host获取到IP的,所以无法进行负载均衡。
使用的Demo如下: /** * 重写Java自定义DNS解析器,非负载均衡 * * @return */ private static DnsResolver getDnsResolver2() { InMemoryDnsResolver dnsResolver = new InMemoryDnsResolver(); try { logger.warn("调用一次"); dnsResolver.add("fun.tester", InetAddress.getByName("127.0.0.1")); } catch (Exception e) { e.printStackTrace(); } return dnsResolver;
其中org.apache.http.impl.conn.InMemoryDnsResolver#add方法源码如下: public void add(String host, InetAddress... ips) { Args.notNull(host, "Host name"); Args.notNull(ips, "Array of IP addresses"); this.dnsMap.put(host, ips); }
然后我们看一下org.apache.http.impl.conn.InMemoryDnsResolver#dnsMap相关初始化代码: /** * In-memory collection that will hold the associations between a host name * and an array of InetAddress instances. */ private final Map dnsMap; /** * Builds a DNS resolver that will resolve the host names against a * collection held in-memory. */ public InMemoryDnsResolver() { dnsMap = new ConcurrentHashMap(); } SystemDefaultDnsResolver
最终我放弃了自定义的org.apache.http.conn.DnsResolver接口的方案,选择了org.apache.http.impl.conn.SystemDefaultDnsResolver重写resolve方法的方案,具体实现如下: /** * 重写Java自定义DNS解析器,负载均衡 * * @return */ private static DnsResolver getDnsResolver() { return new SystemDefaultDnsResolver() { @Override public InetAddress[] resolve(final String host) throws UnknownHostException { if (host.equalsIgnoreCase("fun.tester")) { return new InetAddress[]{SourceCode.random(ips)}; } else { return super.resolve(host); } } }; }
其中ips是全局的静态变量,初始化方法如下: /** * 初始化DNS配置IP * * @return */ private static List getAddress() { try { return Arrays.asList( InetAddress.getByName("127.0.0.1"), InetAddress.getByName("0.0.0.0") ); } catch (Exception e) { FailException.fail("DNS IP解析失败!"); } return null; }
PS:如果你选择使用了自定义的DNS解析器,那么系统hosts配置的功能就会失效,所以谨慎使用。 测试
为了验证结果,我对com.funtester.httpclient.ClientManage#getDnsResolver方法进行了改造,每次获取到IP的时候我都打印出来。 /** * 重写Java自定义DNS解析器,负载均衡 * * @return */ private static DnsResolver getDnsResolver() { return new SystemDefaultDnsResolver() { @Override public InetAddress[] resolve(final String host) throws UnknownHostException { if (host.equalsIgnoreCase("fun.tester")) { InetAddress random = SourceCode.random(ips); logger.info(random); return new InetAddress[]{random}; } else { return super.resolve(host); } } }; } 单线程
下面看我的测试,首先分享测试用例: public static void main(String[] args) { String url = "http://fun.tester:12345/" def get = getHttpGet(url) def test = { getHttpResponse(get) } 10.times { test() } }
控制台输出: INFO-> 13.691 main ###### # # # # ####### ###### ##### ####### ###### ##### # # # ## # # # # # # # # #### # # # # # # #### ##### # #### ##### # # # # # # # # # # # # # # ##### # # # ###### ##### # ###### # # INFO-> 14.408 main /0.0.0.0 INFO-> 14.460 main 请求uri:http://fun.tester:12345/ , 耗时:451 ms , HTTPcode: 200 INFO-> 14.462 main 请求uri:http://fun.tester:12345/ , 耗时:2 ms , HTTPcode: 200 ****省略多余的内容****
可以看出,单线程请求HTTP服务,DNS只会解析一次,经过多次尝试,解析的IP会在设定的两个IP之间随机出现,但这明显不符合我们的需求。 多线程
测试用例如下: public static void main(String[] args) { String url = "http://fun.tester:12345/" def get = getHttpGet(url) def test = { fun { getHttpResponse(get) } } 10.times { test() } }
控制台输出: INFO-> 03.636 main ###### # # # # ####### ###### ##### ####### ###### ##### # # # ## # # # # # # # # #### # # # # # # #### ##### # #### ##### # # # # # # # # # # # # # # ##### # # # ###### ##### # ###### # # INFO-> 04.581 Deamon 守护线程开启! INFO-> 04.843 F-6 /0.0.0.0 INFO-> 04.843 F-4 /127.0.0.1 INFO-> 04.843 F-7 /0.0.0.0 INFO-> 04.844 F-2 /0.0.0.0 INFO-> 04.844 F-10 /0.0.0.0 INFO-> 04.844 F-1 /0.0.0.0 INFO-> 04.844 F-5 /127.0.0.1 INFO-> 04.844 F-3 /127.0.0.1 INFO-> 04.844 F-8 /0.0.0.0 INFO-> 04.844 F-9 /127.0.0.1 INFO-> 04.903 F-7 请求uri:http://fun.tester:12345/ , 耗时:309 ms , HTTPcode: 200 INFO-> 04.903 F-3 请求uri:http://fun.tester:12345/ , 耗时:309 ms , HTTPcode: 200 INFO-> 04.903 F-2 请求uri:http://fun.tester:12345/ , 耗时:309 ms , HTTPcode: 200 ****省略多余的内容****
这下我们就能看出每个线程都执行了一次org.apache.http.impl.conn.SystemDefaultDnsResolver#resolve方法,获取到了IP也是随机的,而且每次请求的耗时都是比较长的。这里让我心生疑惑,相当于每个线程请求都是重新重建了连接,于是就有了下面的测试。 单个连接
这里我把HttpClient的连接池的最大连接数改成了1:public static int MAX_PER_ROUTE_CONNECTION = 1;或者public static int MAX_TOTAL_CONNECTION = 1;,这个之前分享过,这里不多讲了,上用例: 用例同多线程用例
控制台输出: INFO-> 02.928 main ###### # # # # ####### ###### ##### ####### ###### ##### # # # ## # # # # # # # # #### # # # # # # #### ##### # #### ##### # # # # # # # # # # # # # # ##### # # # ###### ##### # ###### # # INFO-> 03.648 Deamon 守护线程开启! INFO-> 03.910 F-5 /0.0.0.0 INFO-> 03.961 F-6 请求uri:http://fun.tester:12345/ , 耗时:299 ms , HTTPcode: 200 INFO-> 03.961 F-5 请求uri:http://fun.tester:12345/ , 耗时:299 ms , HTTPcode: 200 INFO-> 03.961 F-4 请求uri:http://fun.tester:12345/ , 耗时:300 ms , HTTPcode: 200 INFO-> 03.961 F-7 请求uri:http://fun.tester:12345/ , 耗时:300 ms , HTTPcode: 200 INFO-> 03.961 F-3 请求uri:http://fun.tester:12345/ , 耗时:300 ms , HTTPcode: 200 INFO-> 03.961 F-2 请求uri:http://fun.tester:12345/ , 耗时:300 ms , HTTPcode: 200 INFO-> 03.961 F-1 请求uri:http://fun.tester:12345/ , 耗时:300 ms , HTTPcode: 200 INFO-> 03.961 F-9 请求uri:http://fun.tester:12345/ , 耗时:300 ms , HTTPcode: 200 INFO-> 03.961 F-8 请求uri:http://fun.tester:12345/ , 耗时:300 ms , HTTPcode: 200 INFO-> 03.961 F-10 请求uri:http://fun.tester:12345/ , 耗时:300 ms , HTTPcode: 200 WARN-> 04.673 Deamon 异步线程池关闭!
这里看到虽然我起了10个线程分别执行请求,但是每个请求的耗时都是非常长的,但是只有F-5这个线程执行了一次org.apache.http.impl.conn.SystemDefaultDnsResolver#resolve方法,由于HttpClient只有一个连接。所以应当是每个连接创建的时候会调用org.apache.http.impl.conn.SystemDefaultDnsResolver#resolve方法,而每个线程请求耗时比较高,原因是因为每个线程去获取到链接资源之后,会重新进行建联的过程导致的。
实践出真知,奇怪的知识又增加了。 「Have Fun ~ Tester !」
决策参考微信新增时刻视频和公众号好看按钮1微信版本更新新增时刻视频和公众号好看按钮事件12月21日晚,微信更新7。0。0版本,新增时刻视频功能公众号的点赞按钮变成好看,用户可在看一看里浏览朋友认为好看的文章在聊天详情页中
竖视频迎来风口,竖屏剧将是视频网站争夺的新领地2018年,短视频无疑是互联网和视频领域的爆款,用户数使用时长市场规模都在高速增长。根据2018年中国网络视听发展研究报告显示,截至今年6月,短视频用户规模为5。94亿,占网络视频
决策参考爱奇艺会员规模破1亿腾讯视频付费用户近9000万1爱奇艺会员规模破1亿,中国视频网站进入亿级会员时代事件近日,爱奇艺公布了其最新会员规模数据,爱奇艺会员数量突破1亿,中国视频付费市场正式进入亿级会员时代。2019年内容储备方面,
比亚迪e2热销中优惠高达8000元给生活稳稳幸福感,2021款e2家庭纯电优选。配备高安全长寿命刀片电池严苛测试,关心和保障您的每次出行NEDC401KM超长续航满足日常上下班代步,户外郊游需求,畅行无忧直上绿牌,
宋PLUS新能源售14。68万元起欢迎试驾驭见皆引领!全球首款宽体超混SUV领航上市!宋PLUSDMi上市价14。68万起(综合补贴后)创新采用骁云插混专用1。5L高效发动机高效EHS电混系统,达到短途用电经济节省,长途用
庆余年读后的感觉之前看过电视剧庆余年,拍的不错,只不过最吸引我的不是剧情,而是里面对武道中人的分级挺有意思,什么大宗师,九品上,九品,八品对于一个也曾经有武侠梦的男人来说挺有吸引力的,可惜第二季还
高级工程师如何使用6寸专业电脑?感觉智商被碾压GPDMicroPC是一台针对专业工程师用的6寸工具电脑,出场默认安装Win10专业版系统,因为机身自带RS232和RJ45网线接口,实际用途可以说是十分广泛。而国内有网友拿到机器
这么小的掌上游戏电脑,玩魔兽世界怀旧服什么感觉,简直太爽了以前从来没想过,魔兽世界这样大型的网络游戏,有一天可以端在手上玩,现在GPDWIN2游戏掌机却真正做到了,一台6寸屏的掌上游戏电脑,单手拿起毫不费力,却能够完美的运行魔兽世界怀旧服
8寸超级掌机性能超硬核,电脑AAA游戏大作玩出了手游感觉屏幕仅有8英寸,处理器是冰湖英特尔I51035G7,16G超大运行内存3733高频内存,这就是GPDWINMax超级掌上游戏机,机器还没正式开售,预计在5月20号京东开始预售。这次
CSGO居然玩出了手游的感觉,8寸超级掌机性能太硬核GPDWINMax还有几天就要预售了,你们是不是感到很兴奋呢,最新消息就是5月18日在国外开启众筹,比国内早两天,国内则要等到5月20日,不过对于国内用户来说,好消息就是预售价格4
现在的客户要求高,维修师傅感觉压力山大(原创)客户下午吃饭时提出海尔32寸液晶电视三无故障维修,并且要求晚上务必修好,说真的,我感觉亚历山大,首先因为状况不明,加之配件不齐全,不过办法总比困难多,硬着头皮顶吧,打开后盖,开机查