第11章 nginx负载均衡

什么是负载均衡

负载均衡,其英文简称 Load Balancing,是一种计算机技术。用来在多个计算机(计算机集群)、网络连接、CPU、磁盘驱动器或其他资源中分配负载,以达到最优化资源使用、最大化吞吐率、最小化响应时间、同时避免过载的目的。宏观上的意思是将负载(工作任务,访问请求)进行平衡、分摊到多个操作单元(服务器,组件)上进行执行以解决高性能,单点故障(高可用),扩展性(水平伸缩)等高流量下常见的问题

负载均衡分类

由于载均衡技术是要对网络传输中的报文控制,因此会涉及到网络七层模型,因此负载均衡分类可以按照网络层次进行分类,比如二层、三层、四层、七层负载均衡。其中最常见的是四层和七层负载均衡。此外,还有其他方面进行分类的,有软件负载均衡、硬件负载均衡等。

二层负载均衡

负载均衡服务器对外依然提供一个VIP,集群中不同的机器采用相同的ip地址,但是机器mac地址不一样,当负载均衡服务器接收到了请求之后,通过改写报文的目标mac地址的方式将请求转发到目标机器实现负载均衡。

三层负载均衡

与二层负载均衡类似,负载均衡服务器对外依然提供一个vip ,集群中不同的机器采用不同的ip地址,当负载均衡服务器接受到请求后,根据不同的负载均衡算法,通过ip 将请求转发至不同的真实服务器。

四层负载均衡

四层负载均衡在OSI 模型的传输层,由于在传输层,只有TCP/UDP协议,这两种协议中除了包含源ip、目标ip之外,还包含源端口号和目标端口号。四层负载均衡服务器在接受客户端请求之后,以后通过修改数据包的的地址信息(ip + prot)将流量转发到应用服务器

七层负载均衡

七层负载均衡在OSI模块下的应用层,应用层协议较多,常用的有http、dns等等。七层负载基于这些协议工作。这些应用层协议中包含很多有意义的内容,例如同一个web服务器的负载均衡,除了根据ip+port 负载之外,还可以根据七层的URL、浏览器类别、语言等来决定是否要进行负载均衡。
目前有很多开源的负载均衡工具,大部分是四层和七层,其中nginx、LVS、haproxy比较有名,LVS主要做四层负载均衡,nginx和haproxy主要做七层负载均衡,但是nginx和haporxy都支持四层负载,nginx中的stream模块除了支持四层反向代理还支持四层负载均衡。

负载均衡算法

大致可以分为两大类,一类是静态负载均衡算法,常见的有轮训、权重等; 另一类是动态负载均衡算法,常见的有最少链接、最快响应、服务类型、服务质量等,还有策略很多其他策略(hash等),不同的软件实现的不同的负载均衡算法

Nginx中的负载均衡配置

Nginx 的 stream 模块和 http 模块分别支持四层和七层模块的负载均衡。其用法和支持的负载均衡策略大致相同。首先使用 upstream 指令块 和 server 指令指定上游的服务,upstream 指令的用法如下:

Syntax: upstream name { ... }
Default:    —
Context:    http

官方示例:

upstream backend {
    server backend1.example.com weight=5;
    server 127.0.0.1:8080       max_fails=3 fail_timeout=30s;
    server unix:/tmp/backend3;

    server backup1.example.com  backup;
}

默认情况下,将服务器的权重设置为1,使用加权循环平衡方法在服务器之间分配请求。在上面的示例中,每个7个请求将按如下方式分发:5个请求发送到backend1.example.com (因为设置了weight=5),一个请求发送给第二和第三服务器。如果在与服务器通信期间发生错误,则请求将被传递到下一个服务器,以此类推,直到尝试所有正在运行的服务器。如果无法从任何服务器获得成功的响应,客户端将收到与最后一台服务器通信的结果
这里定义了三类服务器 , 分别是域名、iP+port、socket 形式指定地址,后面跟上若干配置参数。默认情况下,upstream 指令块中采用的是加权 Round-Robin负载均衡算法。该算法通过加权轮询的方式访问 upstream 中 server 指令指定的上游服务。此时,在 server 指令中我们可以添加一些关于服务的静态配置,比如指定服务的权重(weight)、server 的最大并发连接数(max_conns)、max_fails和 fail_timeout 等。
除了默认的 Round-Robin 算法外,Nginx 中常用的负载均衡策略还有基于客户端ip 地址的 Hash 算法。该算法以客户端的 ip 地址作为 hash 算法的关键字,映射到特定的上游服务器中,当然也可以根据客户段的其他 key 来进行 hash 算法。涉及的配置指令为 ip_hash 和 hash,用法如下:

Syntax: ip_hash;
Default:    —
Context:    upstream


Syntax: hash key [consistent];
Default:    —
Context:    upstream
This directive appeared in version 1.7.2.

最后 Nginx 中一种常用的动态负载均衡算法是最少连接数算法。该算法会从所有的上游服务器中找到并发连接数最少的一个,然后将请求转发给它,如果出现多个最少连接数的服务器,则会在这些最少连接数的服务器中继续应用Round-Robin 算法。配置该策略的指令为 least_conn,其指令格式如下

Syntax: least_conn;
Default:    —
Context:    upstream
This directive appeared in versions 1.3.1 and 1.2.2.
# 将请求传递给活动连接数最少的服务器,同时考虑服务器的权重。

实验

Nginx 四层负载均衡实验

nginx.conf 中添加如下 stream 指令

stream {
    server {
        listen 3000;
        return '3000 sever  get ip:$remote_addr!\n';
    }
    
    server {
        listen 3001;
        return '3001 server get ip:$remote_addr!\n';
    }
    
    upstream servers {
        server 127.0.0.1:3000 weight=2;
        server 127.0.0.1:3001;
    }
    
    server {
        listen 3002;
        proxy_connect_timeout 3s;
        proxy_timeout 3s;
        proxy_pass servers;
    }
}

测试:上述配置用端口 3000 和 3001 模拟两个上游服务器,然后在 upstream 指令块中指定这两个上游服务器的地址,同时给第一个设置权重为 2。由于默认采用的是加权的 Round-Robin 算法,默认服务器的权重为 1。设置为 2,表明 3 次请求中,2 次会转发到 3000 端口,一次会转发到 3001 端口。

[root@centos-13 conf]# curl  127.0.0.1:3002
3000 sever  get ip:127.0.0.1!
[root@centos-13 conf]# curl  127.0.0.1:3002
3000 sever  get ip:127.0.0.1!
[root@centos-13 conf]# curl  127.0.0.1:3002
3001 server get ip:127.0.0.1!
[root@centos-13 conf]# curl  127.0.0.1:3002
3000 sever  get ip:127.0.0.1!
[root@centos-13 conf]# curl  127.0.0.1:3002
3000 sever  get ip:127.0.0.1!
[root@centos-13 conf]# curl  127.0.0.1:3002
3001 server get ip:127.0.0.1!

Nginx七层负载均衡实验

七层和四层配置类似。

简单七层负载均衡

Nginx配置如下http指令块

user  root;
worker_processes  1;

#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

#pid        logs/nginx.pid;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  logs/access.log  main;

    sendfile        on;

    keepalive_timeout  65;

    gzip  on;

    server {
        listen       8000;
                return 200 '8000,server\n';
        }

        server {
                listen 8001;
                return 200 '8001 ,server \n';
        }


        server {
                listen 8002;
                return 200 '8002 , server\n';
        }

        upstream backends {
        # ip_hash
        # hash user_$arg_username;
                server 127.0.0.1:8000;
                server 127.0.0.1:8001;
                server 127.0.0.1:8002;
        }

    server {
        listen       80;
        location / {
                proxy_pass http://backends;
                proxy_http_version 1.1;
                proxy_set_header Connection "";
                }
        }
}

用 8000,8001 和 8002 三个端口模拟了 3 个服务器,默认使用轮询负载均衡算法,而且三个的权重均为 1。进行如下的 http 请求操作,可以看到 Nginx 转发 http 请求会均匀地分配到 3 个服务器上。

[root@centos-13 conf]# curl 192.168.232.13
8000,server
[root@centos-13 conf]# curl 192.168.232.13
8001 ,server 
[root@centos-13 conf]# curl 192.168.232.13
8002 , server
[root@centos-13 conf]# curl 192.168.232.13
8000,server
[root@centos-13 conf]# curl 192.168.232.13
8001 ,server 
[root@centos-13 conf]# curl 192.168.232.13
8002 , server
[root@centos-13 conf]# curl 192.168.232.13
8000,server

负载均衡hash算法

打开 ip_hash 指令的注释,这个时候默认是使用客户端的 ip 地址作为
hash 的 key,然后重启 Nginx 服务并进行如下的命令行操作

user  root;
worker_processes  1;

#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

#pid        logs/nginx.pid;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  logs/access.log  main;

    sendfile        on;

    keepalive_timeout  65;

    gzip  on;

    server {
        listen       8000;
                return 200 '8000,server\n';
        }

        server {
                listen 8001;
                return 200 '8001 ,server \n';
        }


        server {
                listen 8002;
                return 200 '8002 , server\n';
        }

        upstream backends {
        ip_hash;
        # hash user_$arg_username;
                server 127.0.0.1:8000;
                server 127.0.0.1:8001;
                server 127.0.0.1:8002;
        }

    server {
        listen       80;
        location / {
                proxy_pass http://backends;
                proxy_http_version 1.1;
                proxy_set_header Connection "";
                }
        }
}

测试本机curl

[root@centos-13 conf]# curl 192.168.232.13
8000,server
[root@centos-13 conf]# curl 192.168.232.13
8000,server
[root@centos-13 conf]# curl 192.168.232.13
8000,server
[root@centos-13 conf]# curl 192.168.232.13
8000,server
[root@centos-13 conf]# curl 192.168.232.13
8000,server

使用其他 key 做 hash

注释 ip_hash 指令,我们打开 hash user_$arg_username 这行配置的注释, hash 指令可以让我们根据我们设置的 key 进行 hash,然后根据 hash 值选择上游的服务器。具体测试参看下面的 Linux 命令

user  root;
worker_processes  1;

#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

#pid        logs/nginx.pid;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  logs/access.log  main;

    sendfile        on;

    keepalive_timeout  65;

    gzip  on;

    server {
        listen       8000;
                return 200 '8000,server\n';
        }

        server {
                listen 8001;
                return 200 '8001 ,server \n';
        }


        server {
                listen 8002;
                return 200 '8002 , server\n';
        }

        upstream backends {
        # ip_hash;
        hash user_$arg_username;
                server 127.0.0.1:8000;
                server 127.0.0.1:8001;
                server 127.0.0.1:8002;
        }

    server {
        listen       80;
        location / {
                proxy_pass http://backends;
                proxy_http_version 1.1;
                proxy_set_header Connection "";
                }
        }
}

在请求中带上 username 参数,Nginx 中配置的 hash 算法会根据请求中带的 username 参数作为 key 去进行 hash,然后在根据 hash 结果映射上游服务器。username 相同时,选择的上游服务器肯定是一样的,只有在 username 的值发生变化时,返回的响应才可能有变化

[root@centos-13 conf]# curl 192.168.232.13?username=1
8002 , server
[root@centos-13 conf]# curl 192.168.232.13?username=1
8002 , server
[root@centos-13 conf]# curl 192.168.232.13?username=1
8002 , server
[root@centos-13 conf]# curl 192.168.232.13?username=2
8001 ,server 
[root@centos-13 conf]# curl 192.168.232.13?username=3
8001 ,server 
[root@centos-13 conf]# curl 192.168.232.13?username=qwer
8002 , server
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,923评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,154评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,775评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,960评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,976评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,972评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,893评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,709评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,159评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,400评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,552评论 1 346
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,265评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,876评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,528评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,701评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,552评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,451评论 2 352

推荐阅读更多精彩内容