文章

为了安装NGINX,拼了

[TOC]

前言 {#}

客户给我们了几台vps,主要是为了给我们的应用使用,目前我们的应用程序运行在A机和B机两台VPS上,使用了weblogic的集群,但是,有一个proxy应用安装在A机上,专门负责分发应用,这样的话,无形中增加了A机的负载,年初就因为这个事情,A机每天高峰期就宕机,我又拿了一台闲置的vps专门跑应用的计划任务,目前一共A,B,C三台vps在跑应用,最近开始关注这个事情,为什么不能使用nginx去做负载呢?我还有一台闲置的vps啊,我可以安装nginx专门做负载,转发流量给其他三台,这样A机就不会有负载问题了。

规划 {#}

一共四台VPS,A,B,C,D。

设计原则

  • 利用现有网络规划;
  • 不调整现有主机和应用结构,减小生产环境的影响;
  • 因为没有公网,所以必须使用源码编译安装;

A机和B机主要负责正常的负载均衡,C机做备用,D机跑NGINX做流量转发。客户端向D机发送请求,D机根据NGINX的轮询机制,转发给A机或者B机,C机可以设为backup,若A机和B机出现问题,负责所有请求。很简单的设计。

APR

为什么要安装apr?

因为D机只跑了nginx,也可以再运行一个tomcat作为backup,基于这种考虑,我想把apr安装好,使得tomcat以apr的运行模式工作。

安装步骤 {#}

1. 下载源码包 {#1}

官网下载apr和apr-utils源码包,上传至D服务器。

1
2
apr-1.5.2.tar.gz  
apr-util-1.5.4.tar.gz  

2. 安装APR {#2apr}

远程至D机,以root身份安装,在编译之前,需要修改一下configure文件,否则编译会报错rm: cannot remove 'libtoolT': No such file or directory

解压文件,进入apr目录

1
2
tar -xvf apr-1.5.2.tar.gz  
cd apr-1.5.2  

vi编辑configure文件,查找$RM “$cfgfile” ,注释该句,我没数行数,但是那行就这么一句代码。

vi configure  
# $RM "$cfgfile"

然后开始编码和安装

./configure
make && make install  

3. 安装APR-UTIL {#3aprutil}

apr-util安装没有难度,按照标准程序执行。

tar -zxvf apr-util-1.5.4.tar.gz  
cd apr-util-1.5.4  
./configure --with-apr=/usr/local/apr
make && make install  

ld.so.conf.d增加库文件查找路径

1
echo '/usr/local/apr/lib' > /etc/ld.so.conf.d/apr  

openssl

我将openssl编译为了PIC[^1]的动态库。

1
2
3
4
tar xvf openssl-1.0.2l.tar.gz  
cd openssl-1.0.2l  
./config --prefix=/usr/local/openssl -fPIC
make && make install  

编译完成之后,还需要将动态库路径增加到ld.so.conf配置文件

1
echo '/usr/local/openssl/lib' > /etc/ld.so.conf.d/openssl  

openssh

1. 为什么还要编译openssh? {#1openssh}

这是因为我们编译安装了openssl,会影响到openssh,所以需要重新编译安装openssh。

2. 安装之前 {#2}

强烈建议打开telnet服务,一旦openssh启动失败,如果你没有启用telnet,你就哭去吧。

建议提前下载系统镜像到目录,方便yum安装xinetd软件包。

mount -o loop -t iso9660 /home/rhel-server-6.4-x86_64-dvd.iso /mnt  

修改yum.repos.d目录下的cd.repo文件

[CDROM]
name=isofile  
baseurl=file:///mnt  
enabled=1  
gpgcheck=0  
gpgkey=file:///mnt/RPM-GPG-KEY-redhat-release  

之后yum安装所需软件包

yum install telnet-server xinetd  

配置xinetd服务,使得telnet启动,编辑/etc/xinetd.d/telnet

# default: on 
# description: The telnet server serves telnet sessions; it uses \ 
# unencrypted username/password pairs for authentication. 
service telnet {  
        flags = REUSE 
        socket_type = stream 
        wait = no 
        user = root 
        server = /usr/sbin/in.telnetd 
        log_on_failure += USERID 
        disable = no ##修改为no
}

启动服务

chkconfig xinetd on  
service xinetd start  

提示: 如果使用了iptables,请一并关闭。

3. 安装openssh {#3openssh}

因我之前已经编译安装了openssh7.3p1,所以仍然使用这个软件包。

1
2
cd openssh-7.3p1  
make clean   #清除之前编译产生的文件  

编译参数

./configure \
 --prefix=/usr \
 --sysconfdir=/etc/ssh \
 --with-ssl-dir=/usr/include/openssl \
 --with-md5-passwords \
 --with-pam \
 --with-mantype=man \
 --with-tcp-wrappers

安装

make && make install  

4. 验证服务 {#4}

重启openssh验证是否可以启动服务

1
service sshd restart  

5. Trouble shooting {#5troubleshooting}

服务无法启动,原则先看日志,检查启动的报错信息,根据报错信息处理。

一般来说,可能都是因为配置文件的问题导致的。

配置文件路径:/etc/ssh/sshd_config

zlib

zlib目前版本1.2.11,可以直接从官方网站下载即可。

1
2
3
4
tar xvf zlib-1.2.11.tar.gz  
cd zlib-1.2.11  
./configure --shared
make && make install  

nginx

1. 安装 {#1}

安装nginx之前需要准备好pcre和zlib

1
2
3
tar xvf pcre-8.40.tar.gz  
tar xvf zlib-1.2.11.tar.gz  
tar xvf nginx-1.12.0.tar.gz  

进入nginx目录,开始编译安装

1
2
3
4
5
6
7
8
9
10
11
cd nginx-1.12.0  
./configure --build=nginx --with-poll_module --with-select_module --prefix=/usr/local/nginx \
 --pid-path=/var/run/nginx.pid --lock-path=/var/lock/nginx.lock --with-http_ssl_module \
 --with-http_dav_module --with-http_flv_module --with-http_realip_module \
 --with-http_gzip_static_module --with-http_stub_status_module --with-mail \
 --with-mail_ssl_module --with-pcre=../pcre-8.40 --with-zlib=../zlib-1.2.11 \
 --with-debug --http-client-body-temp-path=/var/tmp/nginx/client \
 --http-proxy-temp-path=/var/tmp/nginx/proxy \
 --http-fastcgi-temp-path=/var/tmp/nginx/fastcgi --http-uwsgi-temp-path=/var/tmp/nginx/uwsgi \
 --http-scgi-temp-path=/var/tmp/nginx/scgi --conf-path=/etc/nginx/nginx.conf --sbin-path=/usr/sbin
make && make install  

nginx的配置文件路径在 /etc/nginx目录,执行脚本在/usr/sbin/目录,其他文件都在/usr/local/nginx。

2. 配置 {#2}

创建一个进程用户

1
useradd -M -s /sbin/nologin web  

创建日志目录

1
2
3
mkdir /var/log/nginx  
chown -R web.web /var/log/nginx  
ln -s /var/log/nginx /etc/nginx/logs  

修改配置文件

1
vi /etc/nginx/nginx.conf  

配置参数参见此文

3. 开机服务 {#3}

在/etc/init.d目录新建nginx文件,内容如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
#!/bin/bash
# nginx     This shell script takes care of starting and stopping
#           nginx
#
# chkconfig: - 13 68
# description: nginx is a web server
### BEGIN INIT INFO
# Provides: $named
# Short-Description: start|stop|status|restart|configtest 
### END INIT INFO
#variables
NGINX_BIN="/usr/sbin/nginx"  
NGINX_CONF="/etc/nginx/nginx.conf"  
NGINX_PID="/var/run/nginx.pid"  
NETSTAT="/bin/netstat"  
alter=$1  
prog=nginx  
#load system function
. /etc/rc.d/init.d/functions
#function:echo ok or error
function if_no {  
if [ $2 == 0 ]; then  
echo -n $"$1 ${prog}:" && success && echo  
else  
echo -n $"$1 ${prog}:" && failure && echo  
fi  
}
#start nginx
function start {  
if [ -s ${NGINX_PID} ]; then  
echo "nginx already running"  
else  
if [ `${NETSTAT} -tnpl | grep nginx | wc -l` -eq 0 ]; then  
rm -f ${NGINX_PID} 2>/dev/null  
${NGINX_BIN} -c ${NGINX_CONF} 
if_no start $?  
        else
${NETSTAT} -tnpl | grep nginx | awk '{ print $7}' | cut -d '/' -f 1 > ${NGINX_PID}
if_no start $?  
fi  
fi  
}
#stp nginx
function stop {  
if [ -s ${NGINX_PID} ]; then  
cat ${NGINX_PID} | xargs kill -QUIT  
if_no stop $?  
else  
        if [ `${NETSTAT} -tnpl | grep nginx | wc -l` -eq 0 ]; then
rm -f ${NGINX_PID} 2>/dev/null  
if_no stop 0  
else  
rm -f ${NGINX_PID} 2>/dev/null  
kill `${NETSTAT} -tnpl | grep nginx | awk '{ print $7}' | cut -d '/' -f 1`  
if_no stop $?  
fi  
fi  
}
function restart {  
if [ -s ${NGINX_PID} ]; then  
cat ${NGINX_PID} | xargs kill -HUP  
if_no restart $?  
else  
stop  
sleep 1  
start  
fi  
}
function status {  
${NETSTAT} -tnpl | grep nginx | grep LISTEN
[ $? == 0 ] && echo "nginx is running" || echo "nginx is not running"
}
function configtest {  
${NGINX_BIN} -t
}
case $alter in  
start)  
start  
;;
stop)  
stop  
;;
restart)  
restart  
;;
status)  
status  
;;
configtest)  
configtest  
;;
*)
echo "use:${NGINX} {start|stop|restart|status|configtest}"  
;;
esac  

给于权限和开机执行

1
2
3
4
chmod a+x /etc/init.d/nginx  
chkconfig --add nginx  
chkconfig nginx on  
service nginx start  

4. 验证服务 {#4}

访问IP,应该显示nginx的欢迎页面

alt

5. 配置负载 {#5}

5.1 内置负载策略 {#51}

Nginx负载均衡是通过upstream模块来实现的,内置实现了三种负载策略,配置还是比较简单的。官网负载均衡配置说明:http://nginx.org/en/docs/http/load_balancing.html

  • 轮循(默认)

    Nginx根据请求次数,将每个请求均匀分配到每台服务器

  • 最少连接

    将请求分配给连接数最少的服务器。Nginx会统计哪些服务器的连接数最少。

  • IP Hash

    绑定处理请求的服务器。第一次请求时,根据该客户端的IP算出一个HASH值,将请求分配到集群中的某一台服务器上。后面该客户端的所有请求,都将通过HASH算法,找到之前处理这台客户端请求的服务器,然后将请求交给它来处理。

5.2 配置 {#52}

参考了别人的配置文件[^2],配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
http {  
    # ... 省略其它配置
    upstream tomcats {
        server A机IP:7010;
        server B机IP:7010;
        server C机IP:8080 backup;
    }

    server {
        listen 80;

        location / {
            proxy_pass http://tomcats;
        }
    }
    # ... 省略其它配置
}

补充后续事宜 {#}

周一上班后,我测试了一下,发现在会话的保存上存在问题,而且不能存在混合状态的主机。比如我的A机和B机是WEBLOGIC集群,C机又是tomcat,无法做负载。后来我修改了一下配置文件,

1
2
3
4
5
    upstream tomcats {
        iphash;
        server A机IP:7010;
        server B机IP:7010;
    }

是可以做负载了,但是我登录系统以后,我发现我的应用的各种报表和功能菜单,点击后要么还是无故返回未登录状态,要么就是一直持续加载中。看来nginx负载均衡weblogic集群的方案还是不可行。

于是,我又求助于oracle官方站点,发现一篇文章是将apache作为前端web服务器负载均衡weblogic,弄了半天weblogic给Apache做了module,只要有那个module,Apache也可以作为负载均衡的前端。我这边安装的welogic版本是10.3.6.0,于是我在weblogic的安装目录找了半天,也没发现这个组件,我就又去google找,终于找到了。

下载地址在这里:ORACLE Webtier

根据我的weblogic的版本号,我需要下载Oracle WebLogic Server Proxy Plugins 11gR1 (11.1.1.9)这个版本。

下载以后解压出来,然后从apache的配置文件中load这个模块。

1
2
[root@tasdb2 conf.d]# cat /etc/httpd/conf.d/mod_wl.conf
LoadModule weblogic_module /u01/wlsplugin/lib/mod_wl.so  

然后新建一个虚拟主机,可以使用下面的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<VirtualHost 135.149.80.36:80>  
#WLSRequest On
SetHandler weblogic-handler  
WebLogicCluster 135.149.80.33:7010,135.149.80.34:7010  
MatchExpression *.jsp  
#WLLogFile /var/log/httpd/wlproxy.log
<ifmodule mod_deflate.c>  
    DeflateCompressionLevel 9
    SetOutputFilter DEFLATE
    AddOutputFilterByType DEFLATE text/html text/plain text/xml
    AddOutputFilterByType DEFLATE application/javscript
    AddOutputFilterByType DEFLATE text/css
</ifmodule>  
</VirtualHost>  

注意一下配置文件里面的WebLogicCluster ,我用的是weblogic集群,所以这里这样配置,然后为了性能,我还打开了gzip压缩模块。

重启apache,然后我又测试了一次所有的菜单和报表,OK,全部都可以正常使用。终于,搞定了。

  1. 位置无关代码(Position Independent Code,PIC)

  2. http://blog.csdn.net/xyang81/article/details/51702900

本文由作者按照 CC BY 4.0 进行授权