技术标签: At least two sentinels should be de DNS redisson 3.8 redis
本文主要针对第5点进行分析和解决。
sentinel://redis:26379,redis:26380?masterNames=mymaster&poolSize=100&poolName=xxx
nameserver 127.0.0.1
search aaa.bbb ostechnix.lan
(在这里,aaa.bbb是解析不了的)
$ ping redis
PING redis.ostechnix.lan (127.0.0.1) 56(84) bytes of data.
64 bytes from localhost (127.0.0.1): icmp_seq=1 ttl=64 time=0.026 ms
64 bytes from localhost (127.0.0.1): icmp_seq=2 ttl=64 time=0.057 ms
$ nslookup redis
Server: 127.0.0.1
Address: 127.0.0.1#53
Name: redis.ostechnix.lan
Address: 127.0.0.1
$ src/redis-cli -h redis -p 26379
redis:26379> sentinel sentinels mymaster
1) 1) "name"
2) "127.0.0.1:26380"
3) "ip"
4) "127.0.0.1"
5) "port"
6) "26380"
...
$ src/redis-cli -h redis -p 26380
1) 1) "name"
2) "127.0.0.1:26379"
3) "ip"
4) "127.0.0.1"
5) "port"
6) "26379"
java程序使用redisson-3.8.2尝试连接redis,出现了错误
Exception in thread "main" org.redisson.client.RedisConnectionException: At least two sentinels should be defined in Redis configuration!
at org.redisson.connection.SentinelConnectionManager.<init>(SentinelConnectionManager.java:159)
at org.redisson.config.ConfigSupport.createConnectionManager(ConfigSupport.java:195)
at org.redisson.Redisson.<init>(Redisson.java:122)
at org.redisson.Redisson.create(Redisson.java:161)
...
打开redisson的debug日志:
2018-11-21 18:11:53 [main] WARN o.r.c.SentinelConnectionManager - Can't connect to sentinel server. Unable to connect to: redis://redis:26379
...
2018-11-21 18:12:03 [main] WARN o.r.c.SentinelConnectionManager - Can't connect to sentinel server. Unable to connect to: redis://redis:26380
Well, 为何 redis-cli 能连接得上sentinel,而java程序会出错?java程序在使用以前的版本redisson-2.5.1的时候是一切正常的。
重新看一次debug日志,发现了一个奇怪的地方:
2018-11-21 18:11:48 [main] DEBUG i.netty.resolver.dns.DnsQueryContext - [id: 0xda4ab0e7] WRITE: [49889: /127.0.0.1:53], DefaultDnsQuestion(redis.aaa.bbb ostechnix.lan. IN A)
2018-11-21 18:11:48 [main] DEBUG i.netty.resolver.dns.DnsQueryContext - [id: 0xda4ab0e7] WRITE: [34575: /127.0.0.1:53], DefaultDnsQuestion(redis.aaa.bbb ostechnix.lan. IN AAAA)
解释一下:
IN A:代表主机名到 IPv4 地址的映射
IN AAAA:代表主机名到 IPv6 地址的映射
“ostechnix.lan.” 最后的点,代表根,“lan.” 表示lan为根下的第一级域
再来看这个域名 “redis.aaa.bbb ostechnix.lan.”,有点奇怪,域名中间为何会出现空格?
回头看/etc/resolv.conf文件,发现
search aaa.bbb ostechnix.lan
解释一下:
search:各项间以空格或者tab分隔,当域名没有以点结尾时,需要从这里追加各项,作为完全限定域名再发送DNS请求。
很明显,在解析search项的时候,没有用空格分隔开各项,导致DNS请求的域名存在错误。
查看redisson的源码,发现RedisClient的resolvAddr方法会对地址进行解析,如果/etc/resolv.conf里面存在多个DNS server的配置,会给每个配置都建立一个DnsNameResolver(这部分是属于netty-4.1.30.Final的源码)。
查看DnsNameResolver的源码:
static {
String[] searchDomains;
try {
List<String> list = PlatformDependent.isWindows()
? getSearchDomainsHack()
: UnixResolverDnsServerAddressStreamProvider.parseEtcResolverSearchDomains();
searchDomains = list.toArray(new String[0]);
} catch (Exception ignore) {
// Failed to get the system name search domain list.
searchDomains = EmptyArrays.EMPTY_STRINGS;
}
DEFAULT_SEARCH_DOMAINS = searchDomains;
...
}
searchDomains 是通过UnixResolverDnsServerAddressStreamProvider.parseEtcResolverSearchDomains() 来解析的
查看该方法源码:
static List<String> parseEtcResolverSearchDomains(File etcResolvConf) throws IOException {
String localDomain = null;
List<String> searchDomains = new ArrayList<String>();
FileReader fr = new FileReader(etcResolvConf);
BufferedReader br = null;
try {
br = new BufferedReader(fr);
String line;
while ((line = br.readLine()) != null) {
if (localDomain == null && line.startsWith(DOMAIN_ROW_LABEL)) {
int i = indexOfNonWhiteSpace(line, DOMAIN_ROW_LABEL.length());
if (i >= 0) {
localDomain = line.substring(i);
}
} else if (line.startsWith(SEARCH_ROW_LABEL)) {
int i = indexOfNonWhiteSpace(line, SEARCH_ROW_LABEL.length());
if (i >= 0) {
searchDomains.add(line.substring(i));
}
}
}
} finally {
if (br == null) {
fr.close();
} else {
br.close();
}
}
Well,看来是netty对于search的解析有了新的想法,认为search是每项一行,所以木有再对每行进行空格或者tab的切割
searchDomains.add(line.substring(i));
把 UnixResolverDnsServerAddressStreamProvider 的源码 copy 到应用中,按照相同的package路径放置,然后修改 parseEtcResolverSearchDomains 方法,对每行进行split
修改/etc/resolv.conf文件,把search改成每行一项,譬如:
nameserver 127.0.0.1
search aaa.bbb
search ostechnix.lan
如果你自己搭建了DNS server来模拟上述的实验,有可能还是出错,说连接不了sentinel。
以实验为例,每个DnsNameResolver在上述改动后,都会拿到2个domain(aaa.bbb 和 ostechnix.lan)。
你可以尝试改变这2个domain的顺序,譬如:
search ostechnix.lan aaa.bbb
或者
search ostechnix.lan
search aaa.bbb
再一次实验,就会发现这次竟然通过了。
Well,是不是很神奇?
调试一下 DnsResolveContext的 resolve方法
searchDomainPromise.addListener(new FutureListener<List<T>>() {
private int searchDomainIdx = initialSearchDomainIdx;
@Override
public void operationComplete(Future<List<T>> future) {
Throwable cause = future.cause();
if (cause == null) {
promise.trySuccess(future.getNow());
} else {
if (DnsNameResolver.isTransportOrTimeoutError(cause)) {
promise.tryFailure(new SearchDomainUnknownHostException(cause, hostname));
} else if (searchDomainIdx < searchDomains.length) {
Promise<List<T>> newPromise = parent.executor().newPromise();
newPromise.addListener(this);
doSearchDomainQuery(hostname + '.' + searchDomains[searchDomainIdx++], newPromise);
} else if (!startWithoutSearchDomain) {
internalResolve(hostname, promise);
} else {
promise.tryFailure(new SearchDomainUnknownHostException(cause, hostname));
}
}
}
});
顺带说一下,这个方法会一个一个searchDomain的去尝试。
着重调试:
promise.tryFailure(new SearchDomainUnknownHostException(cause, hostname));
你会发现,当发送DNS请求(redis.aaa.bbb)到自己的DNS时,会出现5000ms的超时错误。
可以在命令行进行尝试:
$ nslookup redis.aaa.bbb 127.0.0.1
Server: 127.0.0.1
Address: 127.0.0.1#53
** server can't find redis.aaa.bbb: SERVFAIL
忽略这个错误,注意测量一下耗时,是不是早就过了5s?
结合上面的代码,当出现timeout错误时,下一个domain是不会继续去连接的,所以当顺序为"[aaa.bbb, ostechnix.lan]"时,程序一样报错。
那这个5000ms的限制是哪里加入的咧?
再次调试源码,发现DnsNameResolver是由DnsNameResolverBuilder来构造的
public final class DnsNameResolverBuilder {
...
private long queryTimeoutMillis = 5000;
...
copy源码到应用目录,改一下这个数字,完事
文章浏览阅读702次。犹豫最近比较忙,导致博客没有更新。今天上午终于_android sqlite 版本直接是2导致没有新增字段
文章浏览阅读1.1k次。ssh客户端使用的是Xshell,windows环境。第一种方式,用户名密码方式原理如下:客户端发起ssh请求之后,服务器把自己的公钥传给客户端客户端输入服务器密码通过公钥加密之后传给服务器服务器根据自己的私钥解密登录密码,如果正确那么就让客户端登录Xshell操作如下:1.2.3.第二种方式基于秘钥的登录方式首先在客户端生..._在进行ssh配置时,可以允许用户使用以下何种方式进行登入
文章浏览阅读6k次,点赞6次,收藏16次。文章目录子空间的交也是子空间子空间的和子空间的和也是子空间子空间的交与和的结论维数公式证明推论子空间的交也是子空间V1,V2V_1,V_2V1,V2是子空间VVV的子空间那么,V1∩V2V_1\cap V_2V1∩V2也是VVV的子空间子空间的和V1,V2V_1,V_2V1,V2是线性空间VVV的子空间V1+V2V_1+V_2V1+V2是指:所有能表示成α1+α2..._空间的和和交公式
文章浏览阅读4.3k次。UPDATE wallet_account_trade_record A SET A.shop_id =( SELECT c.shop_id FROM mob_checkout_counter.payment_data_info B,mob_checkout_counter.checkout_record c WHERE A.clie..._update set a=(select)
文章浏览阅读401次。wince6.0 开发流程Windows CE概述 从6.0版本开始,Windows CE的名字改为Windows Embedded CE,当然这也是为了结合Windows Embedded品牌作出的改变。CE经过了十年的风风雨雨之后,终于在CE 6.0这个版本上再次浴火重生了。CE 6.0经历了CE历史上第二次内核重写,使CE操作系统更加符合当今嵌入式开发的方向。 CE 6.0在_wince6.0编程
文章浏览阅读864次。前端开发使用vue脚手架快速构建前端项目一、使用步骤Vue 提供了一个官方的 CLI,为单页面应用 (SPA) 快速搭建繁杂的脚手架。1.配置node环境前往node官网下载并安装,地址https://nodejs.org/zh-cn/;& node -v 检测是否安装成功2.下载安装vue官方脚手架npm install -g @vue/cli& vue --version 检测是否安装成功3.通过cd命令进入你想要创建项目的文件夹&_? target directory exists. continue? (abc1)
文章浏览阅读523次。http://www.cnblogs.com/kernel_hcy/archive/2010/03/24/1694203.html前面讲了lighttpd的fdevent系统,从这一篇开始,我们将进入lighttpd的状态机。状态机可以说是lighttpd最核心的部分。lighttpd将一个连接在不同的时刻分成不同的状态,状态机则根据连接当前的状态,决定要对连接进行的处理以及下一步要进_lighttpd1.4.20源码分析
文章浏览阅读2.8k次。六. 绝对路径和相对路径 七. ls和常用参数八. cd和pwd命令九. rm命令十. cp命令实验操作//建立空的文件夹test[root@VM_0_15_centos home]# mkdir test[root@VM_0_15_centos home]# cd test[root@VM_0_15_centos test]# l..._linux编程基础黑马程序员课后习题
文章浏览阅读9.9k次,点赞4次,收藏14次。问题描述:这个笔试题来自今年的知名游戏公司,因为签了保密协定,为了避免麻烦,自行改编一下。 在一款游戏中,武器等级可以分为0-7级,武器每次升级需要一块宝石,每次升级可能出现三种情况:升一级、保持不变、降一级。 已知i->i+1升一级概率为Ai,保持不变概率为Bi,降一级概率为Ci。A0~A7,B0~B7,C0~C7均已知,其中从等级0到等级1必定成功,即A0=1,B0=0
文章浏览阅读260次。关键词STC89C51单片机,数字控制,温度计,DS18B20 前言 随着人们生活水平的不断提高,单片机控制无疑是人们追求的目标之一,它所给人带来的方便也 是不可否定的,其中数字温度计就是一个典型的例子,但人们对它的要求越来越高,要为现代人工作、科研、生活、提供更好的更方便的设施就需要从数单片机技术入手,一切向着数字化控制,智能化控制方向发展。为了满足对对象的控制要求,单片机的指令系统均有极丰富的条件:分支转移能力,I/O口的逻辑操作及位处理能力,非常适用于专门的控制功能。的核心部分,品种繁多。_单片机温度传感器创新点分析
文章浏览阅读197次。better-scroll 滚动插件什么是 better-scrollbetter-scroll 是一个移动端滚动的解决方案,它是基于 iscroll 的重写,它和 iscroll 的主要区别在这里。better-scroll 也很强大,不仅可以做普通的滚动列表,还可以做轮播图、picker 等等。better-scroll的滚动原理浏览器的滚动条大家都会遇到,当页面内容的高度超过视口高..._betterscroll 是啥
文章浏览阅读462次,点赞10次,收藏11次。MLU370 跑sd_mlu370-m8部署stable-diffusion部署手册