一般情况下,客户端发送多个请求到服务器,服务器处理请求,其中一部分可能要操作一些资源比如数据库、静态资源等,服务器处理完毕后,再将结果返回给客户端。
这种模式对于早期的系统来说,功能要求不复杂,且并发请求相对较少的情况下还能胜任,成本也低。随着信息数量不断增长,访问量和数据量飞速增长,以及系统业务复杂度持续增加,这种做法已无法满足要求,并发量特别大时,服务器容易崩。
很明显这是由于服务器性能的瓶颈造成的问题,除了堆机器之外,最重要的做法就是负载均衡。
请求爆发式增长的情况下,单个机器性能再强劲也无法满足要求了,这个时候集群的概念产生了,单个服务器解决不了的问题,可以使用多个服务器,然后将请求分发到各个服务器上,将负载分发到不同的服务器,这就是负载均衡,核心是「分摊压力」。Nginx 实现负载均衡,一般来说指的是将请求转发给服务器集群。
比如晚高峰乘坐地铁的时候,入站口经常会有地铁工作人员大喇叭“请走 B 口,B 口人少车空....”,这个工作人员的作用就是负载均衡。
负载均衡
负载均衡(Load Balance),是一种计算机技术,意思是将负载(工作任务,访问请求)进行平衡、分摊到多个操作单元(服务器,组件)上进行执行。是解决高性能,单点故障(高可用),扩展性(水平伸缩)的终极解决方案。负载平衡服务通常可以由专用软件(nginx、Lvs等)和硬件(F5负载均衡器)来完成。
负载均衡的作用:
- 解决并发压力,提高应用处理性能(增加吞吐量,加强网络处理能力);
- 提供故障转移,实现高可用;
- 通过添加或减少服务器数量,提供网站伸缩性(扩展性);
- 安全防护,做一些过滤,黑白名单等处理。
常用算法
轮询法-随机法
将请求按照顺序轮流的分配到服务器上,它均衡的对待每一台后端的服务器,不关心服务器的的连接数和负载情况.
适用于每台服务器处理的事情和处理能力都差不多的情况。
加权轮询法
以轮询的方式依次请求调度不同的服务器;实现时,一般为服务器带上权重;
这样有两个好处:
- 针对服务器的性能差异可分配不同的负载;
- 当需要将某个结点剔除时,只需要将其权重设置为0即可;
最小连接-最快响应
通过连接数和响应时间来分配,也就是根据服务器当前剩余的能力来分配任务。也是最靠谱的方案。
实现
2层:对外IP转发不同的mac地址。
3层:对外IP转发对内IP。
4层:建立在传输层,将数据包(流量)转发到指定的IP+端口。
7层:建立在引用层,基于URL等应用层信息做转发。
通常我们都用的nginx做7层负载均衡,实现:
nginx的反向代理有几种实现方式:
- 仅使用模块ngx_http_proxy_module实现简单的反向代理。指令为proxy_pass。
- 使用fastcgi模块提供的功能,反向代理动态内容。指令为fastcgi_pass。
- 使用ngx_http_memcached_module模块提供的功能,反向代理memcached缓存内容,指令为memcached_pass。
- 结合upstream模块实现更人性化的分组反向代理。
使用模块ngx_http_proxy_module实现简单的反向代理
//反向代理服务器nginx-proxy(192.168.100.29)的配置
server {
listen 80;
server_name www.test.com;
location ~ \.(png|jpg|jpeg|bmp|gif)$ {
proxy_pass http://192.168.100.28:80;
}
location / {
proxy_pass http://192.168.100.30:80/;
}
location ~ \.(php|php5)$ {
proxy_pass http://192.168.100.25:80;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
//提供动态服务的nginx服务器(192.168.100.25)的配置
server {
listen 80;
server_name www.test.com;
location / {
root /www/test/;
index index.php index.html index.htm;
}
location ~ \.php$ {
root /php/;
fastcgi_pass 192.168.100.27:9000;
fastcgi_index test.php;
include fastcgi.conf;
}
}
//php-fpm服务器(192.168.100.27)上的/www/test/index.php
<h1>page from php-fpm</h1>
<?php
phpinfo();
?>
详细语法:
- proxy_buffer_zize
- proxy_set_header:在将客户端请求发送给后端服务器之前,更改来自客户端的请求头信息;
- proxy_hide_header:隐藏头
- proxy_connect_timeout:配置 Nginx 与后端代理服务器尝试建立连接的超时时间;
- proxy_read_timeout:配置 Nginx 向后端服务器组发出 read 请求后,等待相应的超时时间;
- proxy_send_timeout:配置 Nginx 向后端服务器组发出 write 请求后,等待相应的超时时间;
- proxy_redirect:用于修改后端服务器返回的响应头中的 Location 和 Refresh。
使用upstream模块实现分组反向代理
借助ngx_http_upstream_module模块,该模块用于定义后端服务器池,后端服务器也称为上游服务器(upstream),可以为每一种类型的后端服务器分一个组。然后在结合proxy_pass或其他代理指令将相应的请求转发到池内。
服务器池可以有多台服务器,多台服务器如何实现负载均衡和算法有关,默认是指定权重的加权均衡算法。
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
# define server pool
upstream dynamic_pool {
server IP1:80;
}
upstream pic_pool {
server IP3:80 weight=2;
server IP4:80 weight=1;
}
upstream static_pool {
server IP5:80 weight=1;
server IP6:80 weight=1;
}
server {
listen 80;
server_name www.test.com;
# define how to proxy
location ~ \.(php|php5)$ {
proxy_pass http://dynamic_pool;
}
location ~ \.(png|jpeg|jpg|bmp|gif)$ {
proxy_pass http://pic_pool;
}
location / {
proxy_pass http://static_pool;
}
}
}
后端服务器在负载均衡调度中的状态:
down:当前的server暂时不参与负载均衡
- backup:预留的备份服务器
- max fails:允许请求失败的次数
- fail timeout:经过max,fails失败后,服务暂停的时间
- max conns:限制最大的接收的连接数
调度算法:
- 轮询:按时间顺序逐一分配到不同的后端服务器
- 加权轮询:weight值越大,分配到的访问几率越高。
- ip_hash:每个请求按访问IP的hash结果分配,这样来自同一个IP的固定访问一个后端服务器。
- least conn:最少链接数,那个机器连接数少就分发。
- url hash:按照访问的URL的hash结果来分配请求,是每个URL定向到同一个后端服务器。
- hash关键数值:hash自定义的key,比如用户ID。