社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  NGINX

十万个why:Nginx 已经能做负载均衡,为什么还需要服务注册发现?

IT服务圈儿 • 3 周前 • 146 次点击  

来源丨经授权转自 程序员小富(ID:chengxy-nds)

作者丨小富

知乎上看到一个问题,说 Nginx 的 upstream 不就是负载均衡嘛,配几台后端机器,请求自动分发,和 Nacos、Eureka 这些注册中心干的事有什么本质区别?为什么还要额外引入一整套服务注册发现的东西?

这个问题热度挺高,其实这个问题问得挺好好,因为很多人对这个似是而非,感觉挺明白,面试问他他又不知道怎么组织语言。

Nginx和注册中心解决的他就不是一个问题啊!

Nginx 解决的是「请求该转发给谁」,属于转发规则;注册中心解决的是「后端服务实例的状态」,属于实时状态感知。

Nginx 负载均衡的不足

Nginx 负载均衡缺点很明显,实例列表是写死的,Nginx 做负载均衡的配置大家都见过,非常的简单

upstream order-service{
    server192.168.1.10 :8080;
    server192.168.1.11:8080;
    server192.168.1.12:8080;
}

server{
    location/api/orders{
        proxy_passhttp://order-service;
    }
}

三台机器轮询转发,服务数量少、实例基本不变动的情况下,这完全没问题。

问题是这个列表是静态的,写死在配置文件里了。

我每次后端实例变化,比如扩容加机器、缩容摘机器、某台挂了,就需要修改配置文件,然后执行 nginx -s reload,如果部署了多台 Nginx,每台都得改,比较麻烦。

机器少的时候这还能接受,微服务都几十个服务打底、每个服务多个实例、还要支持弹性扩缩容,靠手工改配置,上个线那肯定要通宵啊!

Nginx 感知不到实例挂了

Nginx 有被动健康检查机制,后端连续返回错误时,会把那台机器暂时摘掉。但这个机制有个前提:必须有真实请求打过去失败了,才能发现这台机器有问题。

举个具体场景:

图片

T1 和 T2 的请求是用真实用户的流量去试错的,在这段时间内所有打到 .11 的请求全部超时。

注册中心的机制不一样

服务实例启动后会持续向注册中心发送心跳,默认 5 秒一次。心跳超时没收到,注册中心直接把这个实例从注册表里摘掉。消费方下次拉取实例列表时,这个实例就已经不在了,整个过程不需要用真实流量去探路。

Nginx 开源版没有主动健康检查,商业版 Nginx Plus 有,你也可以装 nginx_upstream_check_module 来补,但那又引入了额外的运维负担,问题只是转移了,没有根本解决。

弹性扩缩容 Nginx 做不到

云环境下,实例数量随时在变,没法处理。

业务高峰期自动扩容,从 3 个实例扩到 20 个,低峰期缩回去,发版时滚动更新,旧实例下线、新实例上线。K8s 上的 Pod 被驱逐后在另一个节点重新调度,IP 直接变了,每一次变化,Nginx 的 upstream 列表都需要同步更新。

靠人工或脚本去改配置再 reload,这条路在自动化伸缩的场景下根本走不通,根本不知道什么时候扩了、扩到哪台机器、IP 是什么。

注册中心解决的就是这个问题,实例启动时自动向注册中心注册自己的 IP 和端口,实例下线时自动注销,心跳断了自动被摘除。

消费方持续订阅注册中心的变更,实例列表实时更新,整个过程不需要任何人工介入。

对比一下两种流程:

图片

一个是秒级自动完成,一个是分钟级人工操作,而且依赖人不出错。

服务间调用全走 Nginx?

Nginx 是中心化的反向代理,如果微服务之间的所有内部调用都经过 Nginx,调用链路是:

服务A → Nginx → 服务B

微服务架构下,服务间调用非常频繁,订单服务可能同时依赖库存服务、用户服务、优惠服务。如果所有内部流量都经 Nginx 中转,Nginx 的吞吐量就成了整个系统的天花板,而且多了一跳网络转发,延迟也上去了。

有了注册中心,服务间调用走的是客户端负载均衡:

图片

去掉 Nginx 这一跳之后,延迟减少,也消除了 Nginx 单点的风险。每个服务自己做负载均衡,负载分散到各个调用方。

Spring Cloud 里的 Spring Cloud LoadBalancer 就是干这个的。从 Nacos 或 Eureka 拉实例列表,在客户端本地做负载均衡,然后直接发请求过去。

这些 Nginx 很难做

注册中心不只是存 IP 和端口,每个实例注册时还可以带元数据:

{
    "serviceName""order-service",
    "ip""192.168.1.10",
    "port"8080,
    "metadata": {
        "version""v2",
        "region""shanghai",
        "env""gray",
        "weight"80
    }
}

基于这些元数据能做一些 Nginx 做不到,或者实现起来很麻烦的事。

灰度发布

v1 和 v2 同时在线,希望 95% 流量走 v1,5% 走 v2。在注册中心里给 v2 的实例打上  version=v2 的标签,消费方路由规则按标签分流,配置改一下就生效。Nginx 实现同样效果要写 split_clients 或者 Lua 脚本,每次版本变更还得改配置再 reload。

同机房优先调用

服务在上海和北京都有实例,希望上海的请求优先打上海的实例,减少跨机房网络延迟。注册中心里每个实例带 region 元数据,消费方按 region 就近路由,直接配置路由策略就行。

这个需求放在 Nginx 上要做额外的 geo 路由配置,实现起来繁琐。

动态权重调整

某个实例性能差一些,想降低它的流量权重。Nacos 控制台上直接改权重,秒级生效,不需要改任何配置文件。Nginx 改 weight 参数还得 reload。

这几个需求在微服务场景下都很常见,注册中心天然支持,Nginx 要实现得费很大力气。

Nginx 适合的场景

Nginx 是必须要有的,Nginx 和注册中心不是互相替代的关系,分工不同。

图片

外部用户请求进入系统,走 Nginx 或 API Gateway——统一入口、SSL 终止、限流、WAF,这是 Nginx 的主场,没有任何东西能替代它。

微服务内部互相调用,走注册中心加客户端负载均衡——动态发现实例、直连、去中心化。

两者各管一段,没有重叠,也不需要选择。

如果你的系统就三五个服务、实例基本不变动,Nginx 完全够用,不需要引入注册中心。注册中心是解决动态环境下实例管理问题的,规模上不去的时候引入反而增加复杂度。

说在最后

Nginx 负责把外部请求转进来,注册中心就是负责让内部服务知道彼此在哪、还活着没有。服务实例数量一多、变化频率一高,静态的 upstream 列表就跟不上了,需要一个能实时感知变化的动态机制。


1、一个 npm install,坑了前端 15 年!终被废!

2、微软开源的 Skill 进化神器,GitHub 上斩获 5000 多 Star 了。

3、全网爆火的Loop到底是什么?

4、明明 Spring 二级缓存就能解决循环依赖,为什么非弄个三级缓存?

5、腾讯面试官:“用过Codex吗?来聊聊”我懵了:“不是?都用AI写代码了?”面试官:“大部分是,另外想看你对于Transformer的理解!”

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/198024