负载均衡和Nginx

2020-01-19  本文已影响0人  攻城狮0902

在经典的框架和组件里,nginx无疑占有一席之地。作为高性能轻量级的反向代理web服务器,其单机并发量可达3万QPS
使用nginx的初衷,为了解决内部网需要访问外网,但防火墙限制导致只能访问指定ip,但外网比如头条等为了安全使用域名+动态ip的方式,无法开放所有ip的访问权限。所以需要在外网部署服务对内网的请求进行转发。
有2种方式:一、部署web服务进行接收并访问外网服务;二、部署nginx应用进行代理转发,使用nginx的反向代理功能。无疑使用nginx是最佳的尝试。
本文介绍自己使用过程的接触到的概念和配置,以及对Nginx真实部署时需要考虑问题的探究。

基本概念

应用场景

静态文件服务器

实现动静分离

反向代理服务器

面向内部服务器的代理,对外接收请求,转到内部服务器

负载均衡

内置策略:

  1. 轮询Round-Ribon/RR
  2. 加权轮询 各节点硬件性能不一样,可设置对应的权重
  3. ip hash 基于ip hash算法,对客户端请求的ip进行hash计算,然后根据hash结果将同一个客户端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配置文件

文件结构:

  1. 全局块 允许生成worker processes数目等
  2. events块 配置与用户的网络连接
  3. http块 嵌套多个server
#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 =) > (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)一起工作来达到集群的高可用。

image.png

部署分布式集群

  1. 每台nginx都有公网地址,利用DNS的负载均衡【在域名处设置同个域名多个指向,只能是最简单轮询算法】。但故障切换会慢,且增加网络开销。

  2. 一台公网nginx通过upstream功能,轮询、ip、url多方式分发到内网多台nginx。但公网的nginx如果down机的话,内网全断

  3. 两个公网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;

缺点:

  1. DNS是多级解析,且每级缓存A记录。当A调整时,DNS未感知刷新完成,导致访问A的请求失效
  2. DNS采用最简单的RR负载均衡算法,不能满足内部服务动态调整
  3. 造成额外的网络交互,为了在A调整时及时刷新各级DNS的缓存,设置DNS刷新时间小

大型网站总是部分使用DNS域名解析,利用域名解析作为第一级负载均衡手段,找到同样提供负载均衡服务器的内部服务器,这组内部负载均衡服务器再进行负载均衡,请请求发到真实的服务器上,最终完成请求

虚拟IP

VIP,是一种不与特定计算机或者特定计算机网卡相对应的IP地址。所有发往这个IP地址的数据包最后都会经过真实的网卡到达目的主机的目的进程
用来网络地址转换,提升网络容错和可移动性
虚拟IP常用于系统高可用性的场景,能够自由漂浮

原理:当虚拟IP漂浮后,刷新所有其他主机的arp缓存

CDN服务

...


高级配置

底层原理

惊群现象

上一篇下一篇

猜你喜欢

热点阅读