负载均衡和Nginx
在经典的框架和组件里,nginx无疑占有一席之地。作为高性能轻量级的反向代理web服务器,其单机并发量可达3万QPS
使用nginx的初衷,为了解决内部网需要访问外网,但防火墙限制导致只能访问指定ip,但外网比如头条等为了安全使用域名+动态ip的方式,无法开放所有ip的访问权限。所以需要在外网部署服务对内网的请求进行转发。
有2种方式:一、部署web服务进行接收并访问外网服务;二、部署nginx应用进行代理转发,使用nginx的反向代理功能。无疑使用nginx是最佳的尝试。
本文介绍自己使用过程的接触到的概念和配置,以及对Nginx真实部署时需要考虑问题的探究。
基本概念
应用场景
静态文件服务器
实现动静分离
反向代理服务器
面向内部服务器的代理,对外接收请求,转到内部服务器
负载均衡
内置策略:
- 轮询Round-Ribon/RR
- 加权轮询 各节点硬件性能不一样,可设置对应的权重
- ip hash 基于ip hash算法,对客户端请求的ip进行hash计算,然后根据hash结果将同一个客户端ip的请求分发给同一台服务器进行处理;
- 能够一定保持用户的session,但免不了节点切换时的session失效【节点失效/超时重试机制】
- 但前提是nginx作为内部服务器的直接转发者
- hash算法的影响因素:机器权重、是否存活、负载上限。对象:目标散列调度(利用目标IP)和源地址散列调度(利用源IP)
n = ServerNode[hashkey(dest_ip)];
if ( (n is dead) OR (W(n) == 0) OR (C(n) > 2*W(n))) then
return NULL;
return n; // 如果一切OK
注:S(n)是ServerNode列表中第n个服务器,c(n)是负载上限;w(n)是该服务器的权重;hashkey()为散列函数。在实现时,一般采用素数乘法Hash函数,通过乘以素数使得散列键值尽可能地达到较均匀的分布。
web缓存
对不同的文件作不同的缓存处理
正向代理服务器
适用resolver关键字代理客户端的请求,但不能代理https的
nginx.conf配置文件
文件结构:
- 全局块 允许生成worker processes数目等
- events块 配置与用户的网络连接
- http块 嵌套多个server
- upstream块
- server块
- location块 配置请求的路由,及各页面的处理情况
#worker_processes auto; #工作进程数:如果有SSL、gzip这些比较消耗CPU的工作可以设为和CPU的数量一样;要处理很多很多的小文件,充分利用IO带宽
#worker_cpu_affinity auto;
#worker_rlimit_nofile 200000; #更改worker进程的最大打开文件数限制,不受ulimit-a的限制
error_log logs/error.log;
error_log logs/error.log notice;
error_log logs/error.log info;
events {
worker_connections 1024; #单个工作进程可以允许同时建立外部连接的数量
use epoll; #设置用于复用客户端线程的轮询方法
multi_accept on; #告诉nginx收到一个新连接通知后接受尽可能多的连接
}
http {
include /etc/nginx/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"'
'$request_time - $upstream_cache_status' ;
access_log logs/access.log main;
sendfile on; 可以在磁盘和TCP socket之间互相拷贝数据(或任意两个文件描述符)
tcp_nopush on; 告诉nginx在一个数据包里发送所有头文件,而不一个接一个的发送
tcp_nodelay on; 告诉nginx不要缓存数据,而是一段一段的发送--当需要及时发送数据时,就应该给应用设置这个属性
keepalive_timeout 30;
keepalive_requests 100;
reset_timedout_connection on;
client_body_timeout 40;
send_timeout 2;
#负载均衡列表及算法配置
upstream mysvr {
#ip_hash; #可以解决session不能跨服务器的问题
server 10.189.96.92:8002 weight=100;
server 10.189.96.92:8003 weight=10 max_fails=3 fail_timeout=30s;
server 10.189.96.92:8004 down; #down表示当前的server暂时不参与负载
server 10.189.96.92:8005 backup; #backup其它所有的非backup机器down或者忙的时候,请求backup机器
#server 172.17.0.2:8124 ;
}
server {
keepalive_requests 120; #单连接请求上限次数。
listen 8767; #监听端口
server_name 127.0.0.1; #监听地址
location ~*^.+$ { #请求的url过滤,正则匹配,~为区分大小写,~*为不区分大小写。
#root path; #根目录
#index vv.txt; #设置默认页
#proxy_pass http://mysvr; #请求转向mysvr 定义的服务器列表
# deny 127.0.0.1; #拒绝的ip
#allow 172.18.5.54; #允许的ip
}
location ~ ^~ /zhjrsl {
# proxy_pass http://10.189.96.92:8002; #代理,访问http://10.189.110.30:8764/zhjrsl/时会转向http://10.189.96.92:8002/zhjrsl/
proxy_pass http://mysvr;
}
location /zipkin/ { #有没有/都一样
proxy_pass http://10.189.96.92:9411;
}
location /kibana {
#proxy_pass http://10.187.114.10:9202/app/kibana/; #有/时,则将kibana后面的路径放到代理路径后面
proxy_pass http://10.187.114.10:9202/app; #无/时,则将kibana后面的路径+kibana放到代理路径后面
}
location ~ ^\/zhjrsl\/* {
return 301 http://10.189.96.92:8002/zhjrsl/; #重定向
}
#兜底的
location / {
}
location /monitor{
check_status;
access_log off;
allow 10.189.110.30;
deny all;
}
}
include /etc/nginx/conf.d/*.conf;
}
ngnix中location与proxy_pass配置规则:
代理转发主要用到的配置
- location配置用于匹配请求的URL,即ngnix中的$request_uri变量
- proxy_pass配置用于转发URL
(location =) > (location 完整路径) > (location ^~ 路径) > (location ,* 正则顺序) > (location 部分起始路径) > (/)
location = /uri =开头表示精确匹配,只有完全匹配上才能生效。
location ^~ /uri ^~ 开头对URL路径进行前缀匹配,并且在正则之前。
location ~ pattern ~开头表示区分大小写的正则匹配。
location ~* pattern ~*开头表示不区分大小写的正则匹配。
location /uri 不带任何修饰符,也表示前缀匹配,但是在正则匹配之后,如果没有正则命中,命中最长的规则。
location / 通用匹配,任何未匹配到其它location的请求都会匹配到,相当于switch中的default
实际部署
Nginx的高可用性
高可用借助于主备节点和监控切换
主流方案是Keepalived+Nginx实现双机热备
Keepalived是一个基于VRRP协议来实现的服务高可用方案,可以利用其来避免IP单点故障,类似的工具还有heartbeat、corosync、pacemaker。但是它一般不会单独出现,而是与其它负载均衡技术(如lvs、haproxy、nginx)一起工作来达到集群的高可用。
部署分布式集群
-
每台nginx都有公网地址,利用DNS的负载均衡【在域名处设置同个域名多个指向,只能是最简单轮询算法】。但故障切换会慢,且增加网络开销。
-
一台公网nginx通过upstream功能,轮询、ip、url多方式分发到内网多台nginx。但公网的nginx如果down机的话,内网全断
-
两个公网nginx服务+三个公网ip【2个nginx的实际ip和1个虚拟ip/VIP】,通过keepalive+lvs实现高可用,再upstream到内网
如果并发量真的巨大的话,一般就要借助硬件F5等设备做负载均衡,跟DNS、CDN等服务商合作做域名解析转发、缓存配置,这也是目前大多数大厂的架构配置
DNS做负载均衡
DNS(Domain Name System)是因特网的一项服务,它作为域名和IP地址相互映射的一个分布式数据库,能够使人更方便的访问互联网
同时许多DNS还支持基于地理位置的域名解析,即会将域名解析成距离用户地理最近的一个服务器地址,这样就可以加速用户访问,改善性能
域名解析请求都会根据对应的负载均衡算法计算出一个不同的IP地址并返回,这样A记录中配置多个服务器就可以构成一个集群,并可以实现负载均衡
www.apusapp.com IN A 114.100.20.201;
www.apusapp.com IN A 114.100.20.202;
www.apusapp.com IN A 114.100.20.203;
缺点:
- DNS是多级解析,且每级缓存A记录。当A调整时,DNS未感知刷新完成,导致访问A的请求失效
- DNS采用最简单的RR负载均衡算法,不能满足内部服务动态调整
- 造成额外的网络交互,为了在A调整时及时刷新各级DNS的缓存,设置DNS刷新时间小
大型网站总是部分使用DNS域名解析,利用域名解析作为第一级负载均衡手段,找到同样提供负载均衡服务器的内部服务器,这组内部负载均衡服务器再进行负载均衡,请请求发到真实的服务器上,最终完成请求
虚拟IP
VIP,是一种不与特定计算机或者特定计算机网卡相对应的IP地址。所有发往这个IP地址的数据包最后都会经过真实的网卡到达目的主机的目的进程
用来网络地址转换,提升网络容错和可移动性
虚拟IP常用于系统高可用性的场景,能够自由漂浮
原理:当虚拟IP漂浮后,刷新所有其他主机的arp缓存
CDN服务
...