使用Nginx、Keepalived构建文艺负载均衡

时间:2021-09-23 10:36:29

面对网站服务器端负载增大的问题,是“拿15万¥买一台服务器”来解决,还是靠“加三倍服务器”来解决?还是用其它一些办法?

对于一个访问量日益增加的网站架构而言,从单机到集群、从集群到分布式,架构演化是必然的。

接手环境,分析瓶颈,扩展架构

笔者现在的环境在刚接手时算是单机LAMP环境。在单机LAMP环境时,由于访问量逐渐变大,网站会经常出现打不开的情况,为了解决这个问题在LAMP前端临时加了一台vanish来缓存一些静态文件,从而减轻了web服务器的负载。再到后来为了满足业务访问需求,将架构改为CDN+Nginx负载均衡(反向代理)+LNMP+代码层缓存+MySQL主从,从而将网站整体负载性能提升15倍,且访问速度也得到很大提升。

负载均衡为什么要选择使用Nginx呢?

普通负载均衡用LVS,文艺负载均衡用Nginx/F5/HAproxy,XX负载均衡用NLB

LVS:四层负载均衡的典型代表,目前已经被添加到linux发行版的内核。LVS用于较为成熟,因此不再做类述,在此推荐一篇不错的LVS文章:《互联网运营智慧》第六章负载均衡及服务器集群(LVS)

Nginx/F5/HAproxy:均为七层负载均衡,F5为商业设备,功能强大,但价格不菲,所以在此不做讨论;HAproxy为重量级的七层负载均衡/反向代理程序,一般应用于大中型站点;而Nginx虽然属于轻量级产品,但是功能毫不逊色与HAproxy,如可以对静态文件可以实现缓存、可以通过URL、目录结构、静动分离对网站实现分流,还可以实现对后端服务器状态码健康检测、对网络依赖较小、对虚拟主机支持友好等等,这也是笔者选择Nginx来做负载均衡的原因。

NLB:windows下的东东,性能、可操作性可想而知。在此也提醒一下各位同仁,针对HTTP类的应用千万不要选择使用windows,如同样的业务放linux上只需两台服务器,而放windows上可能会需要三台甚至更多,运维/硬件采购成本也会增加,同时license也是一笔不小的费用。国内较大的一些web站点后端架构为windows的分别有京东商城、当当网、凡客诚品、麦包包。

使用Nginx构建负载均衡时需要注意的几个问题

Session同步:由于笔者所维护的架构硬件预算受限,所以在整个架构中没有共享存储,针对于session处理,笔者使用ip_hash来解决后端服务器session问题。另外,关于存储session,推荐使用redis或memcached(感谢小卫、小灰狼 两位兄弟的建议)

网站代码存储:还是由于没有共享存储,所以笔者每台web服务器本地均存放一份代码,为了保证多台web服务器的代码数据一致性,使用rsync+inotify实现动态同步(具体实现方法会在后面的文章中介绍)。倘若硬件条件允许的情况下,推荐使用NFS来存储;若考虑到NFS无法满足性能需求,可以将NFS的硬盘换成SSD或者使用分布式文件系统来解决。

负载均衡模式选择:在不受session困扰的情况下,负载均衡模式可以使用weight,因为ip_hash会有导致后端服务器负载不均的情况出现。

开始部署Nginx和Keepalived

为了避免负载均衡出现单点故障,所以使用keepalived对Nginx负载均衡做了HA,也就是说当主负载均衡发生软硬件故障时,负载均衡服务将有备用负载均衡服务器自动接管服务,环境拓扑如下:

Vip:192.168.1.100

Nginx-proxy-master:192.168.1.101

Nginx-proxy-backup:192.168.1.102

安装Nginx与Keepalived

在Nginx-proxy-master和Nginx-proxy-backup上分别安装Nginx、Keepalived,两台主机安装步骤相同

安装Nginx

#yum -y install pcre pcre-devel
#useradd www -s /sbin/nologin
#tar zxvf nginx-0.7.62.tar.gz
#cd nginx-0.7.62
#./configure \
--prefix=/usr/local/nginx \
--user=www \
--group=www \
--with-http_stub_status_module \
--with-http_ssl_module
#make && make install

安装Keepalived

#tar zxvf keepalived-1.1.17.tar.gz
#cd cd keepalived-1.1.17
#./configure --prefix=/usr/local/keepalived
#make && make install
#rm -rf /usr/local/keepalived/etc/keepalived/keepalived.conf
#mkdir /etc/keepalived

配置Nginx

注:Nginx-proxy-master和Nginx-proxy-backup的Nginx配置相同
#more /usr/local/nginx/conf/nginx.conf
user  www www;
worker_processes 4;
error_log  logs/error.log  crit;
pid        logs/nginx.pid;
worker_rlimit_nofile 51200;
 
events {
       use epoll;
       worker_connections 51200;
       }
 
http  {
      include       mime.types;
      default_type  application/octet-stream;
      server_names_hash_bucket_size 256;
      client_header_buffer_size 256k;
      large_client_header_buffers 4 256k;
      keepalive_timeout  120;
      client_max_body_size  50m;
      client_body_buffer_size  256k;
      server_tokens      off;
     
      gzip               on;
      gzip_min_length    1k;
      gzip_buffers  4 1024k;
      gzip_http_version 1.1;
      gzip_comp_level     6;
      gzip_types        text/plain application/x-javascript text/css application/xml;
 
      #gzip_vary          on;
      proxy_hide_header Vary;
 
      proxy_connect_timeout    600;
      proxy_read_timeout       600;
      proxy_send_timeout       600;
      proxy_buffer_size        16k;
      proxy_buffers            4 64k;
      proxy_busy_buffers_size 128k;
      proxy_temp_file_write_size 128k;
 
      sendfile on;
      tcp_nodelay on;
    # add_header Cache-Control no-cache;
 
upstream blog.luwenju.com  {
 
                ip_hash;
                server   192.168.1.201:80;
                server   192.168.1.202:80;
                server   192.168.1.203:80;
                }
 
server  {
         listen  80;
         server_name  blog.luwenju.com;
         location / {
         index        index.php;
              proxy_pass         http://blog.luwenju.com;
              proxy_set_header   Host             $host;
              proxy_next_upstream error timeout invalid_header http_500 http_502 http_504;
 
              proxy_set_header   X-Forwarded-For        $remote_addr;
                     }
         location /NginxStatus {
                  stub_status    on;
                  allow 192.168.1.0/24;
                  }
              log_format  blog.luwenju.com  '$remote_addr - $remote_user [$time_local] $upstream_addr $upstream_status $request'
 
                                '"$status" $body_bytes_sent "$http_referer"'
 
                                '"$http_user_agent" "$http_x_forwarded_for"';
 
              access_log /usr/local/nginx/logs/blog.luwenju.com_access.log  blog.luwenju.com;
         }
}

说明:upstream为服务器池。以本配置文件为例,upstream*包含三台web服务器,负载均衡方式为ip_hash。server为主机,用于为upstream内的三台web服务器实现反向代理,从而到达负载均衡的目的。在本配置文件中只设置了一个主机(server),如果要实现虚拟主机,将一个server分别对应一个upstream即可。

另外,还有两个关于日志设置的问题:

负载均衡上是否需要开启access_log系统/程序刚上线时需要开启,用于Nginx调试,后期运行稳定后建议将日志打印关闭,因为对于访问量较大的网站来说大量日志写入磁盘也会导致磁盘性能下降。

如何设置日志格式可能使用Nginx部署过负载均衡的朋友都知道,当把Nginx反向代理服务器部署在web前端时,web服务器的access_log就无法获取用户的真实ip地址了,针对这个问题的解决办法会放到后面的文章中<Nginx日志设置及日志分析>

在Nginx-proxy-master服务器上配置Keepalived

#more /etc/keepalived/keepalived.conf
! Configuration File for keepalived
 
     global_defs {
     router_id nginx-proxy-ha
     }
 
vrrp_script check_nginx {
     script "/etc/keepalived/check_nginx.sh"
     interval 2
     weight 2
     }
 
vrrp_instance VI_1 {
     state MASTER
     interface eth0
     virtual_router_id 51
     priority 200
     advert_int 1
     authentication {
     auth_type PASS
     auth_pass 1234
     }
 
track_interface { 
     eth0  
 
     } 
 
 
track_script {
     check_nginx
     }
 
virtual_ipaddress {
     192.168.1.100
     }
}

有关check_nginx.sh的说明 如果Nginx-proxy-master上的nginx进程由于某种原因停止了,但是keepalived进程还正常运行着,这时候Nginx-proxy-backup上的keepalived会认为Nginx-proxy-master是正常的(因为master检测到backup的keepalived进程还存在),所以在这种情况下当Nginx进程死亡的时候Keepalived也不会发生故障转移。那么这个脚本的作用就是让keepalived实时监控Nginx进程,当发现Nginx进程不存在的时候自动将本机的keepalived进程杀死,从而实现故障转移,脚本内容如下(注:Nginx-proxy-master和Nginx-proxy-backup上此脚本内容均一样)

#more /etc/keepalived/check_nginx.sh
#!/bin/bash
if [ "$(ps -ef | grep "nginx: master process"| grep -v grep )" == "" ]
 
 then
  killall -9  keepalived
 
fi

在Nginx-proxy-backup服务器上配置Keepalived

注:Nginx-proxy-backup上keepalived的配置与Nnginx-proxy-master只有两处不同,state为BACKUP、优先级低于master

#more /etc/keepalived/keepalived.conf
! Configuration File for keepalived
 
     global_defs {
     router_id nginx-proxy-ha
     }
 
vrrp_script check_nginx {
     script "/etc/keepalived/check_nginx.sh"
 
     interval 2
     weight 2
     }
 
vrrp_instance VI_1 {
     state BACKUP
     interface eth0
     virtual_router_id 51
     priority 180
     advert_int 1
     authentication {
     auth_type PASS
     auth_pass 1234
     }
 
track_interface { 
     eth0  
 
     } 
 
 
track_script {
     check_nginx
     }
 
virtual_ipaddress {
     192.168.1.100
     }
}

启动Nginx和Keepalived

#/usr/local/nginx/sbin/nginx
#/usr/local/keepalived/sbin/keepalived –D
 
#echo “/usr/local/nginx/sbin/nginx”>>/etc/rc.local
#echo “/usr/local/keepalived/sbin/keepalived –D” >>/etc/rc.local

测试负载均衡是否正常工作

1、打开浏览器,分别访问Nginx-proxy-master、Nginx-proxy-backup、vip,如都能访问到后端web内容,则说明如上所有配置正确

2、杀死Nginx-proxy-master服务器上的Nginx进程,观察keepalived进程是否自动消失、观察vip是否已经转移到了Nginx-proxy-backup服务器上,如杀死Nginx进程后,keepalived进程也随之消失,且vip已经转移到Nginx-proxy-backup服务器,则说明Nginx-proxy-master可正常实现故障转移

3、依次启动 Nginx-proxy-master的Nginx、Keepalived(必须先启动Nginx后启动Keepalived。如果先启动Keepalived,Keepalived检测到Nginx没有启动还是会执行杀死自己进程的脚本),然后将Nginx-proxy-backup的Nginx进程杀死,看vip是否会自动转移到Nginx-proxy-master服务器上,如杀死Nginx进程后,keepalived进程也随之消失,且vip已经转移到Nginx-proxy-master服务器,则说明Nginx-proxy-backup可正常实现故障转移

至此,Nginx负载均衡配置完毕。另外,Nginx非常稳定,笔者的Nginx负载均衡运行在HP DL380服务器上(一颗至强E5620CPU,16G内存,万转SAS硬盘),运行四个月以来,从未出现过任何问题。在负载性能上,2000并发情况下load average:仅为0.02, 0.01, 0.00,CPU使用率仅为3%,内存使用为1G(算上linux系统本身使用,系统为64bit)。