我眼中的nginx:深入nginx/openresty服务里的dns解析

upyun upyun     2022-12-02     549

关键词:

张超:又拍云系统开发高级工程师,负责又拍云 CDN 平台相关组件的更新及维护。Github ID: tokers,活跃于 OpenResty 社区和 Nginx 邮件列表等开源社区,专注于服务端技术的研究;曾为 ngx_lua 贡献源码,在 Nginx、ngx_lua、CDN 性能优化、日志优化方面有较为深入的研究。

DNS 解析在 Nginx/OpenResty 的服务里是不可分割的一个功能,本文主要来介绍下 Nginx 和 OpenResty 服务里的一些不同的 DNS 解析方式以及它们之间的优缺点。

配置解析阶段

很多时候我们会在 Nginx 配置文件里配置上一些域名,比如配置我们的上游服务器。

  • upstream example.com
  • server foo.example.com;

对于这类域名,Nginx 会在配置解析阶段就将其解析出来,接下来(请求处理过程)使用的都是当时解析得到的 IP。Nginx 核心有一个函数 ngx_parse_url,负责对 url 格式进行分析,包括解析出主机名,端口号以及 URL path 等。针对 IPv4 的情况,它会调用 ngx_parse_inet_url进行具体的解析任务,如果必要,最终它会调用到 ngx_inet_resolve_host进行域名解析,ngx_inet_resolve_host 大多情况下会使用 getaddrinfo 进行解析,最终向 /etc/resolv.conf 下所配置的 DNS server 发起解析请求。

归纳来说这个解析过程有两个特点,一是使用了系统配置的 DNS server;二是解析过程是同步且阻塞的,因此这种解析方式仅在 Nginx 配置解析阶段会被使用。另外这种解析方式的缺点就是只解析一次,所以如果在 Nginx 运行过程中域名解析发生了改变也是无法感知到的,除非手动重启 Nginx 服务。

运行时 DNS resolver

Nginx 核心提供了一套供运行时使用的 DNS 解析机制,它充分契合 Nginx 的事件模型,同样是异步非阻塞的,并且提供了缓存机制。http、stream 和 mail 模块分别提供了配置指令(比如 http 模块提供的 resolver),供我们配置相关 DNS server 地址等信息。

下面这个简单的反向代理配置,就会在进行代理前解析 http://www.upyun.com 这个域名。

  • location /
  • set $myupstream www.upyun.com;
  • proxy_http_version 1.1;
  • proxy_set_header Connection "";
  • proxy_pass http://$myupstream/index.html;

注意如果直接在 proxy_pass 指令里写明需要代理的域名(即不使用变量的方式),那么域名解析就会发生在配置解析阶段了,即上面所讲的过程。这其实也是一种实现动态 upstream 的方式。

这套运行时 DNS resolver 其实是一个 DNS client 的角色,由它自己组织查询报文并发送给目标 DNS 服务器,同时支持解析 IPv6 地址(从 1.5.8 开始),支持反向地址解析和 SRV 解析。它把对每个域名的解析抽象为一棵红黑树的节点,包括任何必要的信息。同时这棵红黑树也充当着缓存,查询时会以域名作为 key,如果对应缓存是新鲜的,即会复用缓存,并且会对解析得到的地址顺序进行一定的回转后再提供给上层使用。如果没有缓存或者缓存过期,新的 DNS 请求会被构建并且发送。

当然,很多时候这套运行时的 DNS resolver 也不能完全满足需求:

  1. 无法配置主备 DNS 服务器地址,我们在 resolver 指令里配置的地址都会按顺序被轮询到。
  2. 无法在 DNS 服务器故障或者网络质量不佳的情况下复用陈旧的缓存,这可能导致上层服务不可用。
  3. 每个 Nginx worker 进程独享解析缓存。

Cosocket

Cosocket 是 lua-nginx-module 提供的最强有力的接口(个人来看没有之一)。它的 connect方法同样支持传入域名,之后会调用上面介绍的 Nginx 运行时 resolver 来解析对应域名,然后随机挑选一个 IP 作为本次连接的目标 IP 地址。由于是使用的 Nginx 运行时 resolver ,如果 DNS resolver 无法正常进行解析,则利用 Cosocket 构建的服务也都会受到影响。

lua-resty-dns

OpenResty 官方开源的 lua-resty-dns 是利用 Cosocket 实现的一套百分百非阻塞的 DNS resolver,它仅仅充当了一个 DNS 解析器,没有任何其他的附加功能,包括缓存。

前面介绍过 Nginx 运行时 DNS resolver 在很多时候是有诸多的不便的,而 lua-resty-dns 则给我们留了很多的扩展空间:

  1. 提供主备 DNS 服务器地址 —— 结合像 lua-resty-checkups 这样的工具可以很容易的维护主备 DNS 服务器地址,包括进行心跳检测。
  2. 进程间共享缓存 —— 结合使用 lua-nginx-module 提供的共享内存字典,可以非常容易地管理缓存。
  3. 故障时使用陈旧缓存 —— 在 lua-resty-dns 报告异常时再次使用缓存即可(只要缓存拷贝没有被强行淘汰)。

目前 OpenResty 生态圈已经有一些基于lua-resty-dns 实现的加强版实现,比如 Kong 的 lua-resty-dns-client。

总的来说,每一种 DNS 解析方式都有它适用的场景,也有它自己的不足,没有最好的,只有最合适的。在程序设计的时候,需要找到最合适自己业务场景的方式,才能最大程度地保障服务的可用性和可靠性,避免带来一些灾难。

 

推荐阅读:

我眼中的 Nginx(五):Nginx - 子请求设计之道?
我眼中的 Nginx(四):是什么让你的 Nginx 服务退出这么慢??
我眼中的 Nginx(三):Nginx 变量和变量插值
我眼中的 Nginx(二):HTTP/2 dynamic table size update?
我眼中的 Nginx(一):Nginx 和位运算?

我眼中的项目经理

  在项目组待的时间久了,渐渐地跟微软的项目经理Michael熟悉起来了,跟他有过很多次深入的聊天,向他请教过很多关于人生,理想,技术上的问题,不得不说,项目经理是我神往的角色。虽然我没有亲身经历过,但是我认... 查看详情

我眼中的webviewjavascriptbridge(图解)

   工作中涉及到一段时间iOS开发,在开发中有个小小的框架让我非常深刻,就是WebViewJavascriptBridge,用于原生控件与前端交互通信。我觉得WebViewJavascriptBridge的工作让我们的交互通信有了工程性,虽然感觉上增加了耦... 查看详情

我眼中的算法

算法一个既熟悉又陌生的词。我曾经很躁动的时候,想去各家应聘或者面试,然后人家问算法你会么?当时听到了,我就蒙蔽了,只能摇头。天啊,作为接受过本科计算机专业学习的大学生来讲,竟然不知道什么是算法。我好脸... 查看详情

jerry眼中的sap客户数据模型

本文Jerry将介绍八款SAP产品中的客户模型。希望您在阅读完本文之后,能对SAP客户模型设计的思路有一个最最粗浅的了解。由于Jerry水平和精力所限,本文不会详细阐述这些产品里的客户模型设计细节,而是介绍了一种方法,如... 查看详情

jerry眼中的sap客户数据模型

本文Jerry将介绍八款SAP产品中的客户模型。希望您在阅读完本文之后,能对SAP客户模型设计的思路有一个最最粗浅的了解。由于Jerry水平和精力所限,本文不会详细阐述这些产品里的客户模型设计细节,而是介绍了一种方法,如... 查看详情

我眼中的机器学习

在上一篇文章(我眼中的机器学习(一))中,我们通过三个非常简单的数学例子了解了机器学习的基本流程(训练,预测). 有的同学可能会觉的机器学习好像也没有什么神奇的,什么一元一次方程,三元一次方程, 二元二次方程等,... 查看详情

我眼中的架构设计

我眼中的架构设计1.架构与设计2.没有最好,只有最适合3.架构设计!=设计模式4.设计思维的养成5.事例实践5.1.需求分析5.2.规范与约束5.3.细化与评估5.4.技术选型5.5.框架搭建5.6.推进与支持6.架构设计对我的影响1.架构与设计... 查看详情

我眼中的计算机网络

...么,为什么,怎么用。利用空闲的时间要总结一下,在我眼中的计算机网络。参考书目《计算机网络》第6版 谢希仁 编著主要从10个大章节来说说计算机网络。一、概述二、物理层三、数据链路层四、网络层五、运输层六... 查看详情

我眼中的javascript闭包

一、变量的作用域  要理解闭包,首先必须理解Javascript特殊的变量作用域。  变量的作用域无非就是两种:全局变量和局部变量。  JavaScript语言在函数内部可以访问外部的变量,但是在函数外部不可以使用函数内部的变... 查看详情

读架构漫谈&我眼中的架构师

   本周是开学的第二周,读了由资深架构师王概凯Kevin执笔的系列专栏架构漫谈。初识这门课,懂得也不是很多,读了架构漫谈,有了一些理解。首先作者讲述了缘起,由早期人独立自主生活到后来的集群,作者由这... 查看详情

我眼中的面向对象分析

面向对象似乎我也没学过其他的编程思维方式了,面向对象是我编程时常用的思维方式,因为我觉得它更加贴近于我们的生活,更加容易地去理解和定义程序想要表达的内容。正是因为如此,每当项目要开启的时候,我都会使用... 查看详情

我眼中的“阿里月饼事件”

近日网上大家都在热议阿里开除了利用js脚本抢内部月饼的5位员工。 新闻详见:http://business.sohu.com/20160913/n468382014.shtml 新闻后续跟进:http://toutiao.com/i6330260731623113217/其实我从技术的角度上来分析那几位员工只是用浏览器... 查看详情

我眼中的java大牛之孤尽老师

...自己心目中的大牛,希望可以借着这个机会写一下我眼中的大牛:孤尽老师。写孤尽老师的主要原因是我认为孤尽老师影响和帮助了很多人。本文将讲述自己和孤尽老师的一些“接触”,我眼中的孤尽老师是什么样的... 查看详情

我眼中的adaboost(代码片段)

步骤:defbuildStump(dataArr,classLabels,D):1。循环取出数据集中的一个特征(一列)输入(for:)  2。循环调整阀值threshVal (for:)    3,。分成两个子树    左边:特征值xi<=threshVal为-1,否则为1      获得预... 查看详情

我眼中的dockerimage(代码片段)

Docker安装如何安装docker详见官网: installation 或者 中文指南. 不过linux上我推荐用curl安装,因为apt-get中源要么没有docker,要么版本较低。$sudoapt-getinstallcurl$sudocurl-sSLhttps://get.docker.com/|sh$sudodockerrunhello-worl 查看详情

我眼中的devops(转)

 过去一年以来,一批来自欧美的、不墨守陈规的系统管理员和开发人员一直在谈论一个新概念:DevOps。DevOps就是开发(Development)和运维(Operations)这两个领域的合并。(如果没错的话,DevOps还包括产品管理、QA、*winces*甚... 查看详情

我眼中的技术地图

一晃研究生毕业参加工作也已经8、9年,这些年搞过嵌入式、web开发、移动应用、IT咨询、项目集成,零零种种到如今也不知是好事还是坏事。今天几个项目进度不错,上线的版本问题居然还没有问题反馈,真是XX都笑歪了。抽下... 查看详情

我眼中的计算机专业

     我之所以选择计算机专业,是因为我没得选哈哈,调剂就在这专业。个人对于计算机专业其实不感兴趣,在我看来这是一个专业性很强的专业,对于我这一个很随性的人吸引力非常的低。我比较喜欢音乐,... 查看详情