Nginx 学习 —— 负载均衡

拥抱心中的梦想 芋道源码 3天前
点击上方“芋道源码”,选择“置顶公众号”

技术文章第一时间送达!

源码精品专栏

精尽 Dubbo 原理与源码 69 篇

精尽 Netty 原理与源码 61 篇

中文详细注释的开源项目

Java 并发源码合集

RocketMQ 源码合集

Sharding-JDBC 源码解析合集

Spring MVC 和 Security 源码合集

MyCAT 源码解析合集

来源:http://t.cn/RDXvzld

说到负载均衡,我想说它天生就是不公平的。为什么这么说呢?请你想象这么一个场景,一块蛋糕切成5份,现在要将它分给A、B、C3个人,基于公平原则,我们说每个人正常可以分到5/3份,但是,5/3份很明显不好进行划分,诶碰巧这个时候A中午没有吃饭,能多吃几份,B、C肚子偏饱,1份即可,基于不公平原则,我们分给A3份蛋糕,B、C个一份,这样按照一定策略将资源进行划分的方式,是一种均衡的策略。

在web应用中,一个web应用(或者说某个服务)在生产环境中一般是集群部署,然后采用负载均衡硬件(F5)或者软件(nginx)将请求分发到不同的服务主机中进行处理,很明显,这里的蛋糕就相当于我们的web request,假设有5个request进来,基于一定的均衡策略,我们可能会将其中的3个request交给A服务器去处理,B、C服务器各处理1个request。下面我画张图片简单说明这个模型:

Nginx 学习 —— 负载均衡

那么使用负载均衡有什么好处呢?首先优化资源利用率,最大化吞吐量,减少延迟,再者系统的伸缩性和可靠性也得到了相应的保障。

一、Nginx 负载均衡及相关策略介绍
负载均衡技术少不了相关的均衡策略,Nginx 中提供了 4 种均衡策略,我们可以根据具体的业务场景选择合适的均衡策略。下面分别介绍这 4 中均衡策略:

1、基于轮询的均衡策略:

轮询嘛,就是说对进到nginx的request按照遍历的方式进行分发,如果request 1 分发到 Server A,那么request 2将被分发到 Server B,…以此循环类推

2、基于最少连接数的均衡策略:

最少连接,也就是说nginx会判断后端集群服务器中哪个Server当前的 Active Connection 数是最少的,那么对于每个新进来的request,nginx将该request分发给对应的Server.

3、基于ip-hash的均衡策略:

我们都知道,每个请求的客户端都有相应的ip地址,该均衡策略中,nginx将会根据相应的hash函数,对每个请求的ip作为关键字,得到的hash值将会决定将请求分发给相应Server进行处理

4、基于加权轮询的均衡策略:

加权轮询,很显然这个策略跟我们开题引入的场景是一样的,nginx会给Server配置相应的权重,权重越大,接收的request数将会越多

上面的均衡策略其实都非常很好理解,但是如果想了解其实现原理,可以看源代码,但是小编就算了,我是看不懂C、C++的。

二、Nginx 不同均衡策略的配置介绍
1、基于轮询的均衡策略:

这个是Nginx默认的均衡算法,如果你不进行相关的配置,默认会执行该策略,配置如下:


http {
   upstream myapp1 {
       server srv1.example.com;
       server srv2.example.com;
       server srv3.example.com;
   }
   server {
       listen 80;

       location / {
           proxy_pass http://myapp1;
       }
   }
}

可以看出,nginx负载均衡使用到的指令不多,其中比较重要的两个是upstream和proxy_pass,upstream块定义一个后端小集群,里边配置相关的Server组成这个集群,同时upstream为这个集群起个相应的名字,本实例叫myapp1.proxy_pass处于location块中,表示对于所有符合/的request,将会交给哪个集群进行处理,本实例为http://myapp1。

但又一点我们需要注意,上面http://myapp1中myapp1必须是upstream起的名字,对于协议是使用http还是https,都无所谓,如果你的协议使用https,则将http直接改成https即可。另外,如果你在upstream中的server指令中指定了协议名,那么在proxy_pass指令中就不需要加上协议名称了。

nginx负载均衡使用反向代理实现,也就是我们上面使用到的proxy_pass指令,支持的协议不止是http和https,同时还支持FastCGI、uwsgi、SCGI、memcached、gRPC,如果你需要使用除了http、https外的其他协议,我们不能使用proxy_pass指令了,应该转而使用相应的指令,如fastcgi_pass、uwsgi_pass、scgi_pass、memcached_pass、grpc_pass。

该策略处理负载,小编认为还是有缺陷的,不能防止某台Server出现负载过高的情况。因为如果有些请求执行时间过长,而系统的并发量却非常大,那么就可能导致某台Server出现request堆积,负载过高,snowslide is possible~

2、基于最少连接数的均衡策略:

该策略主要使用了least_conn指令,具体配置如下:

upstream myapp1 {
least_conn;
server srv1.example.com;
server srv2.example.com;
server srv3.example.com;
}
该策略还是比较人性化的,可以按照机器的实际情况进行刚需分配。

3、基于ip-hash的均衡策略:

当然了,如果我们想实现这样一个功能,我们想让对于相同客户端的请求每次都被分发到同一个Server进行处理,上面两种策略都是不做到。此策略可确保来自同一客户端的请求始终定向到同一服务器,但此服务器不可用时除外。相关配置如下:

upstream myapp1 {
ip_hash;
server srv1.example.com;
server srv2.example.com;
server srv3.example.com;
}
既然相同客户端的请求能被同一台Server进行处理,那么相同客户端的会话Session就可以实现持久化了。

4、基于加权轮询的均衡策略:

基于加权轮询的策略就不需要过多讲解了,就是在轮询的基础上加上个权重信息

upstream myapp1 {
server srv1.example.com weight=3;
server srv2.example.com;
server srv3.example.com;
}
这种策略适合Server机器处理能力有区别的情况。

三、nginx 负载均衡更多高级特性及配置
1、健康检查

不仅人需要体检,机器也是需要体检的,那么就当nginx就是那位体检医生吧!nginx健康检查是什么呢?当我们一个request进来被分发到相应的Server进行处理后,nginx会检查该request执行是否超时,是否执行失败了等情况,然后做出相应的处理—比如说当nginx检查出Server A执行某request时报出502错误了,那么下次nginx负载均衡时就会在upstream块中将Server A排除掉,不分发请求给到Server A了。

对于健康检查的功能,nginx提供了基本两个指令,即max_fails和fail_timeout,也就是说当nginx检查到某Server发生错误的request数达到max_fails或者执行某request执行时间超过fail_timeout了,如果发生超时了,nginx将开始使用实时请求优雅地探测Server,如果有响应,则认为对应的Server还是活着的,没有毛病的。

2、更多配置

针对上面upstream块中的server指令,其格式为:server address [parameters];,里边的parameters可以有很多的参数类型,比如说指定某台Server不参与负载均衡等。具体配置详见官网链接,点击此处传送门。

如果你对 Dubbo / Netty 等等源码与原理感兴趣,欢迎加入我的知识星球一起交流。长按下方二维码噢:

目前在知识星球更新了《Dubbo 源码解析》目录如下:

  1. 调试环境搭建

  2. 项目结构一览

  3. 配置 Configuration

  4. 核心流程一览

  5. 拓展机制 SPI

  6. 线程池

  7. 服务暴露 Export

  8. 服务引用 Refer

  9. 注册中心 Registry

  10. 动态编译 Compile

  11. 动态代理 Proxy

  12. 服务调用 Invoke

  13. 调用特性

  14. 过滤器 Filter

  15. NIO 服务器

  16. P2P 服务器

  17. HTTP 服务器

  18. 序列化 Serialization

  19. 集群容错 Cluster

  20. 优雅停机

  21. 日志适配

  22. 状态检查

  23. 监控中心 Monitor

  24. 管理中心 Admin

  25. 运维命令 QOS

  26. 链路追踪 Tracing

… 一共 69+ 篇

目前在知识星球更新了《Netty 源码解析》目录如下:

  1. 调试环境搭建

  2. NIO 基础

  3. Netty 简介

  4. 启动 Bootstrap

  5. 事件轮询 EventLoop

  6. 通道管道 ChannelPipeline

  7. 通道 Channel

  8. 字节缓冲区 ByteBuf

  9. 通道处理器 ChannelHandler

  10. 编解码 Codec

  11. 工具类 Util

… 一共 61+ 篇

目前在知识星球更新了《数据库实体设计》目录如下:

  1. 商品模块
  2. 交易模块
  3. 营销模块
  4. 公用模块

… 一共 17+ 篇