• 在应用内维护域名缓存时遇到的问题


    近期参与的项目中,依赖DNS服务器来解析外部的业务集群,遇到了一连串的问题。
    远端的业务集群基于HTTP/HTTPS协议,提供业务服务,集群中包含了多个业务节点,当前方案中在DNS服务器上配置域名,指向业务集群中的多个业务节点。
    DNS服务器由客户提供。
    产品的特性代码中使用libcurl来访问业务集群提供的HTTP/HTTPS的服务。
    在本地开发、验证过程中,上述组网方式没有什么问题,一切都很美好。
    结果进入大规模测试阶段时,暴露了一个严重的问题:由于产品的并发度比较高,特性开启后,在短时间内会触发大量的业务请求。这导致如下后果:

    1. libcurl代码发起了大量的域名解析请求,DNS服务器的并发能力不足,只能选择性回复部分报文。
    2. 大量请求由于建立链接时因域名解析失败而失败。
    3. 由于产品内建了重试逻辑,于是引发了更多的请求。
    4. 于是DNS不堪重负,拒绝了更多的域名解析请求。
    5. 结果其它依赖DNS解析域名的业务,同样受到了波及。

    测试团队反馈了上述问题之后,开发团队做如下几件事情:

    1. 在现有的重试逻辑中,增加了休眠时间,使用指数退减的方式,逐次增加重试之间的间隔时间,避免大量请求扎堆。经过实测,本策略缓解了问题,但并没有解决问题。
    2. 修改libcurl的使用方法,启用了DNS缓存特性,并增大了缓存的失效时间。经过实测,本策略的效果不明确。
    3. 修改产品的业务代码,降低并发度。本策略实施后有明显的效果,失败的请求次数明显下降,考虑到产品的代码中,存在多个特性使用libcurl访问远端集群的服务,本问题依然存在。

    上述策略都是小打小闹,并没有从根本上解决问题。
    开发团队内部组织讨论,重新讨论,得出如下结论:

    • 降低并发度不可行。
      一方面可能导致当前特性的性能规格不达标。另外前期多个特性均在使用libcurl,各个业务都按照相同的策略去降低并发度,修改、验证的工作量巨大,管理团队无法接受,开发、测试团队同样觉得疲惫,难以为继。
    • DNS服务器的并发能力不可预期。
      交付场景下,DNS服务器由客户提供,其并发能力不可预期,短时间内也不可能提升性能,假如由于本产品的原因占满了客户DNS服务器的处理能力,可能会阻塞客户的其它业务,因此仍然需要直面问题。

    开发团队经过讨论,有如下决策:

    • 收编现有业务代码中libcurl的使用,对各特性提供统一的HTTP协议客户端。
    • 在上述客户端的代码中增加域名解析结果的缓存。

    这个方案工作量不大,很快通过了测试团队组织的功能验证、性能验证。
    本来觉得未来一片光明,但测试团队在执行故障注入的用例时,发现了新的问题,域名解析操作执行时间过久,单次调用居然要20+秒才能返回。

    这个新问题和前述方案中域名解析的实现相关,换句话说,这是域名解析的C函数的坑。
    目前已知的用于完成域名解析的C函数,如下:

    • gethostbyname线程不安全,排除。
    • gethostbyname_rgethostbyname的线程安全版本,当前在用。

    从实际测试的结果来看,发现gethostbyname_r存在一个严重的问题,函数的参数中不能指定超时值,导致耗时不可控。
    查阅了大量资料之后,发现耗时的问题其实和DNS域名解析的过程相关,不能怪设计API的前辈不用心。
    虽然不能在调用gethostbyname_r时传入超时值,但无意中发现了/etc/resolv.conf。通过修改options attempts:5 timeout:6中的attemptstimeout,发现在一定程度上可以缓解在DNS故障场景下调用gethostbyname_r函数耗时过长的现象。

    经过一系列折腾,目前的解决方案虽不完美,但至少获得了产品团队的认可,因此优化工作暂告一段落。

    如下是处理前述问题过程中,使用到的配置文件或者工具。

    /etc/resolv.conf文件的内容样例,如下:

    $ cat /etc/resolv.conf
    # Dynamic resolv.conf(5) file for glibc resolver(3) generated by resolvconf(8)
    #     DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTEN
    # 127.0.0.53 is the systemd-resolved stub resolver.
    # run "systemd-resolve --status" to see details about the actual nameservers.
    
    nameserver 127.0.0.53
    search DHCP HOST
    options attempts:5 timeout:6
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    /etc/hosts文件的样例,如下:

    $ cat /etc/hosts
    127.0.0.1	localhost
    127.0.1.1	jackie-ubuntu
    
    # The following lines are desirable for IPv6 capable hosts
    ::1     ip6-localhost ip6-loopback
    fe00::0 ip6-localnet
    ff00::0 ip6-mcastprefix
    ff02::1 ip6-allnodes
    ff02::2 ip6-allrouters
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    dig命令的执行输出,样例如下:

    $ dig www.baidu.com
    
    ; <<>> DiG 9.16.1-Ubuntu <<>> www.baidu.com
    ;; global options: +cmd
    ;; Got answer:
    ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 56073
    ;; flags: qr rd ra; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 1
    
    ;; OPT PSEUDOSECTION:
    ; EDNS: version: 0, flags:; udp: 65494
    ;; QUESTION SECTION:
    ;www.baidu.com.			IN	A
    
    ;; ANSWER SECTION:
    www.baidu.com.		1105	IN	CNAME	www.a.shifen.com.
    www.a.shifen.com.	29	IN	A	36.152.44.96
    www.a.shifen.com.	29	IN	A	36.152.44.95
    
    ;; Query time: 4 msec
    ;; SERVER: 127.0.0.53#53(127.0.0.53)
    ;; WHEN: 日 1112 11:15:58 CST 2023
    ;; MSG SIZE  rcvd: 101
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    dig+trace的选项,执行输出,样例如下:

    $ dig +trace www.baidu.com
    
    ; <<>> DiG 9.16.1-Ubuntu <<>> +trace www.baidu.com
    ;; global options: +cmd
    .			2687	IN	NS	f.root-servers.net.
    .			2687	IN	NS	m.root-servers.net.
    .			2687	IN	NS	e.root-servers.net.
    .			2687	IN	NS	l.root-servers.net.
    .			2687	IN	NS	c.root-servers.net.
    .			2687	IN	NS	h.root-servers.net.
    .			2687	IN	NS	j.root-servers.net.
    .			2687	IN	NS	a.root-servers.net.
    .			2687	IN	NS	k.root-servers.net.
    .			2687	IN	NS	g.root-servers.net.
    .			2687	IN	NS	i.root-servers.net.
    .			2687	IN	NS	d.root-servers.net.
    .			2687	IN	NS	b.root-servers.net.
    ;; Received 262 bytes from 127.0.0.53#53(127.0.0.53) in 12 ms
    
    com.			172800	IN	NS	a.gtld-servers.net.
    com.			172800	IN	NS	b.gtld-servers.net.
    com.			172800	IN	NS	c.gtld-servers.net.
    com.			172800	IN	NS	d.gtld-servers.net.
    com.			172800	IN	NS	e.gtld-servers.net.
    com.			172800	IN	NS	f.gtld-servers.net.
    com.			172800	IN	NS	g.gtld-servers.net.
    com.			172800	IN	NS	h.gtld-servers.net.
    com.			172800	IN	NS	i.gtld-servers.net.
    com.			172800	IN	NS	j.gtld-servers.net.
    com.			172800	IN	NS	k.gtld-servers.net.
    com.			172800	IN	NS	l.gtld-servers.net.
    com.			172800	IN	NS	m.gtld-servers.net.
    com.			86400	IN	DS	30909 8 2 E2D3C916F6DEEAC73294E8268FB5885044A833FC5459588F4A9184CF C41A5766
    com.			86400	IN	RRSIG	DS 8 1 86400 20231124170000 20231111160000 46780 . rTOgKkj9DMvMzyk+rKDz7dsie4Xx1jwuBlZdH9ntLEikavNoZMRN7SxE iweiVanZo1q9hhrSxAn8O1ScKkRwwHTSCiSvQnZ8bzy4ToM3I832VIiR Oir+C+K7GtufMaxNCOmD14s7Zg24qLf9CmQT+id3eIBMP4Sjuq4MSIsu tgSXJS6EI1OumSojANeO9mq1khc5cxLaeOqJfRb10Vvujl73jZpaXxE9 J4/GehjpG6YR04/37geOwOSaVwx6c3PndgT0L33O/maN/Tjng2UUhHtW lOh8gIVxFYRipqdDZ1XJQK+x5o4o8Oh3YN3Vd1I5rrKJhEfwecej7nyI fe5BKA==
    ;; Received 1173 bytes from 199.7.83.42#53(l.root-servers.net) in 20 ms
    
    baidu.com.		172800	IN	NS	ns2.baidu.com.
    baidu.com.		172800	IN	NS	ns3.baidu.com.
    baidu.com.		172800	IN	NS	ns4.baidu.com.
    baidu.com.		172800	IN	NS	ns1.baidu.com.
    baidu.com.		172800	IN	NS	ns7.baidu.com.
    CK0POJMG874LJREF7EFN8430QVIT8BSM.com. 86400 IN NSEC3 1 1 0 - CK0Q2D6NI4I7EQH8NA30NS61O48UL8G5 NS SOA RRSIG DNSKEY NSEC3PARAM
    CK0POJMG874LJREF7EFN8430QVIT8BSM.com. 86400 IN RRSIG NSEC3 8 2 86400 20231118052525 20231111041525 63246 com. HHilTlIgM2bBSkNCrfIYydeweb7FpcSd/HCPjoMq9cDoI45LnU1trxYf GtncYfSgPxd01lt7BuBdTBRjFX2kHEWQNAjqKR+wj9ohk9mqvk3naenD eWVPwSEZjYdV+LPjL7rXvMWq6GRZXFG2OC0oR37mS4PCPT/pWYTARo7m 66PiR/ixIP8UPkUbxjZTHFuDsR+lywg8Od0OsTopTj5+rw==
    HPVV1UNKTCF9TD77I2AUR73709T975GH.com. 86400 IN NSEC3 1 1 0 - HPVVAN8CFKHHHMEIDVJHFNQEOI5G6C89 NS DS RRSIG
    HPVV1UNKTCF9TD77I2AUR73709T975GH.com. 86400 IN RRSIG NSEC3 8 2 86400 20231115212015 20231108201015 63246 com. jtcfLKFI33jWF+yVS/iT/x73j+JM7gult+JQD6xHY0yl4ZWp2ktqwCrA wk8ybADERvnpDU/u9LKgBVGkT7rIDnheKGcXzKe5Lgjilu9aHWjIiyny J/kwYkBe+XCqXofFrkq5QS/El4Esu4Hp7FCUAm5lRMNlGL8H9QrdqESl G4NIUZFsyhqj3Ulz0/u1QjPRm13QmKOuUh/DvWhj63Ru5g==
    ;; Received 849 bytes from 192.48.79.30#53(j.gtld-servers.net) in 284 ms
    
    www.baidu.com.		1200	IN	CNAME	www.a.shifen.com.
    ;; Received 100 bytes from 36.155.132.78#53(ns3.baidu.com) in 8 ms
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    nslookup命令的执行输出,样例如下:

    $ nslookup www.baidu.com
    Server:		127.0.0.53
    Address:	127.0.0.53#53
    
    Non-authoritative answer:
    www.baidu.com	canonical name = www.a.shifen.com.
    Name:	www.a.shifen.com
    Address: 36.152.44.96
    Name:	www.a.shifen.com
    Address: 36.152.44.95
    Name:	www.a.shifen.com
    Address: 2409:8c20:6:1d55:0:ff:b09c:7d77
    Name:	www.a.shifen.com
    Address: 2409:8c20:6:1135:0:ff:b027:210c
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    相关资料

  • 相关阅读:
    JS 找到字符串中所有的数字部分
    Lua 基础 04 模块
    完全彻底的卸载MySQL5.7.35
    网关、网桥、路由器和交换机之【李逵与李鬼】
    PMP(Project Management Professional)证在哪个行业比较有用?
    矩阵的QR分解
    Nginx的核心配置文件
    nginx关闭重启和配置检查
    LabVIEW开发基于图像处理的车牌检测系统
    Python绘制各种图形(模板)
  • 原文地址:https://blog.csdn.net/babyblue_963/article/details/134361677