使用DNS通过NGINX和NGINX Plus实现服务发现

NGINX | 2016年4月27日

[编者注:本文已更新,现改为介绍NGINX Plus API。该API取代了原文中提到的独立动态配置模块,后者现已弃用。]

One of the great advantages of a 微服务架构的一大优势是可以快速、轻松地扩展服务实例。使用多个服务实例时,需要通过负载均衡器分配流量,并以某种方式及时向其告知可用服务实例集合的变化。这称为服务发现。NGINX Plus提供两种与服务发现系统集成的方式:NGINX Plus API和域名系统(DNS)重新解析。本文重点介绍后者。

通过添加或移除虚拟机(VM)或容器来扩缩服务实例(本文将其称为“后端”)时,必须相应更改负载均衡器的配置,以反映后端集合的每次变化。根据应用的不同,扩缩操作可能每天、每小时甚至每分钟发生多次。由于配置变更频繁,需要实现自动化,而通过DNS进行服务发现就是其中一种方式。

目前,许多用于运行应用的平台(例如Kubernetes)都支持使用DNS进行服务发现。本博文末尾提供了相关文章的链接,介绍如何将NGINX Plus与常用平台及使用DNS的服务发现工具集成。

DNS关键功能速览

在介绍如何通过DNS配置服务发现之前,我们先快速了解一下DNS协议中与此密切相关或特别实用的一些功能。

生存时间

为防止DNS客户端使用过时信息,DNS记录包含生存时间(TTL)字段,用于定义客户端可将记录视为有效的时长。为遵循DNS标准,记录超过TTL后,客户端必须查询DNS服务器以获取更新。NGINX Plus默认遵循TTL,同时还支持更精细地控制记录的“有效期”:您可以将NGINX Plus配置为忽略TTL,改为按指定频率更新记录。(本文稍后将介绍NGINX Open Source如何处理TTL。)

基于TCP的DNS

默认情况下,DNS客户端和服务器通过UDP进行通信。但是,如果一个域名解析出大量后端IP地址,完整响应可能无法容纳在单个UDP数据报中,因为其大小上限为512字节。使用TCP代替UDP可以解决此问题:当完整的记录集无法容纳在一个数据报中时,服务器会在响应中设置截断标志,通知客户端切换到TCP以获取所有记录。NGINX 1.9.11及更高版本以及NGINX Plus R9及更高版本支持DNS over TCP。有关更多详细信息,请参阅我们博客中的《使用NGINX和NGINX Plus对DNS流量进行负载均衡》。

SRV记录

DNS可将主机名解析为IP地址,但端口号该如何处理?在某些情况下,例如对Docker容器进行负载均衡时,无法依赖众所周知的端口号,因为端口号是动态分配的。DNS提供了一种特殊的记录类型,即服务(SRV)记录,其中包含端口号和其他一些参数。从R9开始,NGINX Plus支持SRV记录,因此可以从中提取端口信息。

编者注:如需了解NGINX Plus R9所有新功能的概述,请参阅NGINX Plus R9发布公告博客文章。

使用DNS为NGINX和NGINX Plus进行服务发现的方法

下面将按复杂程度由低到高,介绍在NGINX和NGINX Plus中使用DNS进行服务发现的5种方法。前3种方法同时适用于NGINX和NGINX Plus,后2种仅适用于NGINX Plus。

在本次服务发现方法概述中,假设我们为区域example.com配置了一台权威名称服务器,其IP地址为10.0.0.2。域名backends.example.com对应三台后端服务器,如以下nslookup实用工具的输出所示。在接下来介绍的前四种方法中,NGINX和NGINX Plus会向DNS请求标准A记录;在最后一种方法中,NGINX Plus则会请求SRV记录。

$ nslookup backends.example.com 10.0.0.2Server:		10.0.0.2
Address:	10.0.0.2#53

Name:	backends.example.com
Address: 10.0.0.11
Name:	backends.example.com
Address: 10.0.0.10
Name:	backends.example.com
Address: 10.0.0.12

使用DNS通过NGINX进行服务发现

首先介绍将DNS与NGINX Open Source结合使用的3种方式(如上所述,这些方式也适用于NGINX Plus)。

在proxy_pass指令中使用域名

定义上游服务器组(后端)最简单的方法,是将域名指定为proxy_pass指令的参数:

server {    location / {
        proxy_pass http://backends.example.com:8080;
    }
}

NGINX启动或重新加载配置时,会查询DNS服务器以解析backends.example.com。DNS服务器返回上述3个后端的列表,NGINX使用默认的轮询算法在这些后端之间对请求进行负载均衡。NGINX根据操作系统配置文件/etc/resolv.conf选择DNS服务器。

这种服务发现方法的灵活性较低,并且还有以下缺点:

  • 如果无法解析域名,NGINX将无法启动或重新加载配置。
  • NGINX会缓存DNS记录,直至下次重启或重新加载配置,并忽略记录的TTL值。
  • 无法指定其他负载均衡算法,也无法配置被动健康检查或由server指令参数定义的其他功能。下一节将介绍这些功能。

在上游服务器组中使用域名

要使用NGINX提供的负载均衡选项,可以在upstream配置块中定义上游服务器组。但不要使用IP地址标识各个服务器,而应将域名用作server指令的参数。

与第一种方法一样,backends.example.com会在NGINX启动或重新加载配置时解析为3台后端服务器。但现在可以定义更复杂的负载均衡算法,即最少连接,并使用max_fails参数启用被动健康检查,指定当连续3个请求失败时,NGINX将服务器标记为不可用。

upstream backends {    least_conn;

    server backends.example.com:8080 max_fails=3;
}

server {
    location / {
        proxy_pass http://backends;
    }
}

虽然此方法允许选择负载均衡算法并配置健康检查,但在启动、重新加载和TTL方面,它仍与上一种方法存在相同的缺点。

在变量中设置域名

此方法是第一种方法的变体,但可以控制NGINX重新解析域名的频率:

resolver 10.0.0.2 valid=10s;
server {
    location / {
        set $backend_servers backends.example.com;
        proxy_pass http://$backend_servers:8080;
    }
}

使用变量在proxy_pass指令中指定域名时,NGINX会在该域名的TTL到期后重新解析域名。必须包含resolver指令以明确指定名称服务器(与前两种方法不同,NGINX不会读取/etc/resolv.conf)。在resolver指令中添加valid参数,可以让NGINX忽略TTL,改为按指定频率重新解析域名。此处将NGINX设置为每10秒重新解析一次域名。

注意:对于TCP/UDP负载均衡,在proxy_pass指令中使用变量的这种方法受NGINX 1.11.3及更高版本和NGINX Plus R10及更高版本支持。

此方法消除了第一种方法的两个缺点:域名无法解析时,NGINX启动或重新加载操作不会失败;还可以控制NGINX重新解析该名称的频率。但是,由于此方法不使用上游组,因此无法在server指令中指定负载均衡算法或其他参数(与第二种方法中的做法不同)。

使用DNS通过NGINX Plus进行服务发现

下面介绍NGINX Plus特有的两种DNS服务发现方法。

将A记录与NGINX Plus结合使用

借助NGINX Plus,我们可以按所需频率重新解析 DNS名称,同时避免上述前三种方法的缺点。要使用此功能,需要:

  • 与上一种方法一样,添加resolver指令以指定名称服务器。
  • 在zone配置块中添加upstream指令,以分配共享内存区。
  • 在使用域名的resolve指令中添加server参数。

请参考以下示例:

resolver 10.0.0.2 valid=10s;
upstream backends {
    zone backends 64k;
    server backends.example.com:8080 resolve;
}

server {
    location / {
        proxy_pass http://backends;
    }
}

默认情况下,NGINX Plus 遵循 TTL,并在记录过期时重新解析名称。要让 NGINX Plus 改为按指定频率重新解析名称,请在 valid 参数中添加 resolver 指令。

在该代码片段中,NGINX Plus每隔10秒查询位于10.0.0.2的名称服务器,以解析backends.example.com。如果无法解析该名称,NGINX Plus在启动、重新加载配置或运行期间都不会失败。客户端会看到标准的502错误页面。

在NGINX Plus中使用SRV记录

NGINX Plus R9及更高版本支持DNS SRV记录。因此,NGINX Plus不仅可以从名称服务器获取IP地址,还可以获取端口号、权重和优先级。这对于服务端口号通常动态分配的微服务环境至关重要。

编者注:如需了解NGINX Plus R9所有新功能的概述,请参阅我们博客上的《NGINX Plus R9发布公告》。

SRV记录由服务名称、与服务通信所用的协议和域名这三个要素定义。查询名称服务器时,必须提供这三个要素。我们的10.0.0.2名称服务器中有3条SRV记录,其服务名称为http,协议为tcp,域名为backends.example.com,如下方nslookup实用工具的输出所示:

$ nslookup -query=SRV _http._tcp.backends.example.com 10.0.0.2Server:		10.0.0.2
Address:	10.0.0.2#53

_http._tcp.backends.example.com	service = 0 2 8090 backend-0.example.com.
_http._tcp.backends.example.com	service = 0 1 8091 backend-1.example.com.
_http._tcp.backends.example.com	service = 10 1 8092 backend-2.example.com.

查询每条SRV记录中的主机名时,会得到其IP地址:

$ nslookup backend-0.example.com 10.0.0.2...
Name:	backend-0.example.com
Address: 10.0.0.10

$ nslookup backend-1.example.com 10.0.0.2
...
Name:	backend-1.example.com
Address: 10.0.0.11

$ nslookup backend-2.example.com 10.0.0.2
...
Name:	backend-2.example.com
Address: 10.0.0.12

下面详细了解第一个SRV记录中的信息,该记录由第一条nslookup命令返回:

_http._tcp.backends.example.com	service = 0 2 8090 backend-0.example.com.
  • _http._tcp.:SRV记录的名称和协议。我们会将其指定为NGINX Plus配置文件中server指令的service参数值(见下文)。
  • 0,优先级。值越低,优先级越高。NGINX Plus 将优先级最高的服务器指定为主服务器,其余服务器指定为备份服务器。此记录的值在所有记录中最低(优先级最高),因此 NGINX Plus 将对应的后端指定为主服务器。
  • 2:权重。NGINX Plus 将后端添加到上游组时,会将后端的权重设置为此值(相当于 weight 参数,该参数位于 server 指令中)。
  • 8090,端口号。NGINX Plus 将后端添加到上游组时,会将后端端口设置为此值。
  • backend‑0.example.com:后端服务器的主机名。NGINX Plus解析此名称,并将对应的后端添加到上游组。如果此名称解析为多条记录,NGINX Plus会添加多台服务器。

下面介绍如何配置NGINX Plus以使用SRV记录。以下是示例配置文件:

resolver 10.0.0.2 valid=10s;

upstream backends {
    zone backends 64k;
    server backends.example.com service=_http._tcp resolve;
}

server {
    location / {
        proxy_pass http://backends;
    }
}

通过service参数为server指令指定要解析的SRV记录的名称和协议。在本例中,名称和协议分别为_http和_tcp。除使用service参数且未指定端口外,此配置与上一节中的配置示例相同。

根据本节第一个nslookup命令返回的值,NGINX Plus 配置了3台后端服务器:

  • 10.0.0.10,主服务器,端口为8090,权重为2。
  • 10.0.0.11,主服务器,端口为 8091,权重为 1。
  • 10.0.0.12,备用服务器,端口为8092,权重为1。

如果为NGINX Plus配置实时活动监控,就可以在内置仪表板上看到这些后端:

实时活动监控仪表板显示NGINX Plus如何根据DNS SRV记录中为上游服务器分配的权重来分发请求。该仪表板可用于监控微服务架构中作为负载均衡器的NGINX。

请注意,请求会按照指定的权重进行分配。10.0.0.11:8091服务器(权重为1)接收三分之一的请求,而10.0.0.10:8090服务器(权重为2)接收三分之二的请求。10.0.0.12:8092是备用服务器,只有另外两台服务器停机时才会接收请求。

注意事项

使用DNS通过NGINX Plus进行服务发现时,需要注意以下几点:

  • DNS服务器需要具备高可用性或配有备用服务器。如果DNS服务器不可用,NGINX Plus将停止获取更新。它会保留配置中现有的后端(除非重启NGINX Plus或重新加载配置),并忽略相应记录的TTL值。
  • 可以使用resolver指令指定多个名称服务器。这样,如果其中一个服务器不可用,NGINX Plus会尝试其他服务器。
  • 如引言所述,使用NGINX Plus进行服务发现时,除DNS外,还可以选择NGINX Plus API。通过该API,可以发送简单的HTTP请求,在上游组中添加或移除服务器。

示例

如需深入了解完整示例,请参阅以下博客文章,了解如何将NGINX和NGINX Plus与使用DNS的服务发现平台集成:

今后,随着我们发布更多有关新集成选项的内容,将持续更新此列表。

结论

NGINX Plus全面支持通过DNS进行服务发现,为更新微服务环境中的负载均衡器配置提供了一种简单的方法。SRVNGINX Plus Release 9及更高版本支持SRV记录,功能更加强大,不仅可以获取后端的IP地址,还可以获取端口号。

准备好体验NGINX Plus的DNS服务发现及其他增强功能了吗?立即开始30天免费试用,或联系我们,探讨您的使用场景。


分享
标签: DevOps, F5 NGINX, Tech, 2016

相关博客文章

NGINX Plus R26 正式发布
NGINX | 2022/02/15

NGINX Plus R26 正式发布

NGINX Plus R26通过缓存JSON Web密钥集加快JWT验证,并强化TLS握手,从而提升安全性。NGINX JavaScript的新功能包括增强对异步函数的支持,以及实现WebCrypto API。

使用NGINX App Protect DoS保护gRPC应用,抵御严重的DoS攻击
NGINX | 2022/02/10

使用NGINX App Protect DoS保护gRPC应用,抵御严重的DoS攻击

gRPC具备开发人员设计和部署现代应用所需的速度与灵活性,但其开放性也使其极易受到第7层DoS攻击。NGINX App Protect DoS可保护gRPC应用免受此类破坏性攻击。

Ingress Controller 选型指南(第 2 部分):风险与面向未来的规划
NGINX | 2021/09/13

Ingress Controller 选型指南(第 2 部分):风险与面向未来的规划

了解选择错误的Ingress控制器可能带来的风险,以及如何从关键方面着手,让您的选择更好地适应未来需求。

NGINX Plus R19 正式发布
NGINX | 2019/09/03

NGINX Plus R19 正式发布

NGINX Plus R19扩展了监控功能,不仅提供更多指标,还新增了指标分析方式;增加试运行模式,用于测试限速效果;增强键值存储,以支持IP地址范围;并使限速更加动态。

NGINX现已正式加入F5
NGINX | 2019/05/09

NGINX现已正式加入F5

NGINX现已正式成为F5的一部分。Gus Robertson现任F5 NGINX业务部门负责人。他阐述了两家公司在人才、文化和愿景方面融合的价值,以及双方将如何携手增强NGINX的开源产品和商业产品。

使用NGINX和NGINX Plus实现高性能缓存
NGINX | 2016/08/24

使用NGINX和NGINX Plus实现高性能缓存

我将介绍NGINX在内容缓存和性能方面的工作原理,并分享一些控制NGINX内容缓存方式的技巧。