工作日志:centos6.5下配置Nginx以轮询方式HTTP+TCP负载均衡

时间:2021-01-24 10:14:52

一.Centos下安装Nginx

注:Nginx1.9.0以后才支持TCP负载均衡,而且在编译时需要加入--with stream参数才会安装此功能。


(1)在/usr/local下创建nginx目录:

[root@wlwddc usr]#mkdir /usr/local/nginx

安装依赖软件pcre-devellibevent

[ root@wlwddc nginx]# yum install pcre-devel  libevent  openssl


(2)安装配置nginx

[ root@wlwddc nginx]# tar -zxvf nginx-1.6.3.tar.gz -C /usr/local/src/

[ root@wlwddc nginx]# cd /usr/local/src/nginx-1.6.3/

[ root@wlwddc nginx-1.6.3]# ./configure  --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx/nginx.pid  --lock-path=/var/lock/nginx.lock --user=nginx  --group=nginx  --with-http_ssl_module --with-http_flv_module  --with-http_stub_status_module --with-http_gzip_static_module --http-client-body-temp-path=/var/tmp/nginx/client/  --http-proxy-temp-path=/var/tmp/nginx/proxy/ --http-fastcgi-temp-path=/var/tmp/nginx/fcgi/  --with-pcre

[ root@wlwddc nginx-1.6.3]# make && make install


(3)为了能够启动服务因此要把控制脚本放到搜索路径去,因此要编辑/etc/profile文件

[ root@wlwddcnginx]# vim /etc/profile

加上PATH=$PATH:/usr/local/nginx/sbin

使配置生效:

[ root@wlwddc nginx]# ./etc/profile


(4)解决一些错误

//检验语法错误

[ root@wlwddc~]# nginx -t

nginx: the configuration file/etc/nginx/nginx.conf syntax is ok

nginx: [emerg] getpwnam("nginx")failed

nginx: configurationfile /etc/nginx/nginx.conf test failed

上面错误表明没有创建用户合组

//创建用户和组

[ root@wlwddc~]# groupadd -r nginx

[ root@wlwddc ~]# useradd -r -g nginx nginx

//由于编译过程中指明了/var/tmp/nginx/client/目录和/var/tmp/nginx/proxy/目录,因此要创建这两个目录。

[ root@wlwddc~]# mkdir -pv /var/tmp/nginx/client

[ root@wlwddc ~]# mkdir -pv /var/tmp/nginx/proxy


(5)启动nginx服务,并查看端口,

//进入目录

root@wlwddc ~]# cd /usr/local/nginx/sbin/

[ root@wlwddc sbin]# ./nginx

//出现错误,显示80口被占用:

[root@wlwddc sbin]# netstat -tupln |grep 80

tcp       0      0 :::80                       :::*                        LISTEN      1907/httpd

//将端口修改为82

[root@wlwddc sbin]# cd  /etc/nginx/

[root@wlwddc nginx]# vim nginx.conf

   server {

       listen       80;(-------此处修改为82)

       server_name  localhost;

 

       #charset koi8-r;

 

        #access_log  logs/host.access.log  main;


(6) 重新执行测试是否正确

[root@wlwddc nginx]# cd /usr/local/nginx/sbin/

[root@wlwddcsbin]# ./nginx

[root@wlwddc sbin]# netstat -tupln |grep nginx

tcp        0     0 0.0.0.0:82                 0.0.0.0:*                   LISTEN      22427/nginx


(7) 最后还应该修改防火墙

[root@wlwddc sbin]# vi/etc/sysconfig/iptables

加入:

-A INPUT -m state --state NEW -m tcp -p tcp --dport 82 -j ACCEPT

//重启防火墙

[root@wlwddc sbin]#service iptables restart

//然后在浏览器端访问

http://localhost:82 出现nginx成功页面


二.Centos下安装Tomcat

见:http://blog.csdn.net/fred_yang2013/article/details/45394801

其他:

1. Centos设置Tomcat开机启动

(1)进入编辑

vi/etc/rc.d/rc.local

(2)打开后在最底部复制下面 

export JDK_HOME=/usr/java/jdk1.6.0_45

export JAVA_HOME=/usr/java/jdk1.6.0_45

/usr/local/apache-tomcat/bin/startup.sh

(3)重启服务器,试试能不能访问。

Tips:如果JDK和Tomcat安装的目录不跟上面的一样,请修改相应路径

2. CentOS Tomcat修改默认端口

(1) 熟悉tomcat的配置文件

#/usr/local/apache-tomcat/conf/server.xml/编辑Tomcat配置文件

(假设我是安装在/usr/local/apache-tomcat/ 实际情况参考你服务器安装的路径为准)

打开配置文件里找到下面这一段

<Connector port="8080" protocol="HTTP/1.1"connection Timeout="20000" redirect Port="8443" />


(2) 修改端口

1、打开tomcat配置文件

 #vi/usr/local/apache-tomcat/conf/server.xml

2、打开Tomcat配置文件之后按 /Connector port  快速检索可以修改端口号

3、修改端口,按 i 进行,将8080 修改为 8180

4、按:wq 保存并退出


(3) 重启Tomcat 并检测

    启动Tomcat服务 

  在根目录下执行

  [root@primary /]# find -name apache-tomcat

   显示的就是安装路径

  ./usr/local/apache-tomcat

   然后执行启动:

  [root@primary /]# cd /usr/local/apache-tomcat/bin

  [root@primary bin]# bash catalina.sh start

  1、重启Tomcat服务

  停用#/var/apache-tomcat/bin/shutdown.sh

  (如果不行,#cd /var/apache-tomcat/bin/ 再执行#shutdown.sh)

  启用 #bashcatalina.sh start /要先进入#/usr/local/apache-tomcat/bin/ 再操作

   2、尝试访问

  服务器IP 如http://192.168.100.110:8180 如果访问不了,检查防火墙或者有没有启动成功

        若远程登录不了,进入server.xml文件,将如下的注释去掉:

 <Connector port="8180" protocol="HTTP/1.1"

              connectionTimeout="20000"

               redirectPort="8443"/>

   <!-- A "Connector" using the shared thread pool-->

 

    <Connector executor="tomcatThreadPool"

               port="8180"protocol="HTTP/1.1"

              connectionTimeout="20000"

               redirectPort="8443"/>

 

   <!-- Define a SSL HTTP/1.1 Connector on port 8443

        This connector uses the JSSE configuration, when using APR, the

        connector should be using the OpenSSL style configuration

        described in the APR documentation -->

   <!--

 

tomcat登录密码在tomcat-users.xml文件如下设置:

 <role rolename="tomcat"/>

  <rolerolename="manager-gui"/>

  <role rolename="admin-gui"/>

  <user username="wlwddc"password="111111" roles="manager-gui,admin-gui"/>

<!--

  <user username="both"password="tomcat" roles="tomcat,role1"/>

  <user username="role1"password="tomcat" roles="role1"/>

-->

 

</tomcat-users>



三.轮询方式负载均衡配置

1. http负载均衡配置

[root@wlwddc nginx]# cd /etc/nginx/

[root@wlwddc nginx]# ls

fastcgi.conf           koi-win             scgi_params

fastcgi.conf.default   mime.types         scgi_params.default

fastcgi_params         mime.types.default  uwsgi_params

fastcgi_params.default nginx.conf         uwsgi_params.default

koi-utf                 nginx.conf.default  win-utf


修改nginx配置文件:

红色部分是比较重要的修改部分:

[root@wlwddcnginx]# vim nginx.conf

user  root;
worker_processes 10;
worker_rlimit_nofile 100000;

error_log /var/log/nginx/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;


events {
worker_connections 1024;
use epoll;
}

http {
include 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"';

access_log /var/log/nginx/access.log main;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
server_tokens off;
#keepalive_timeout 0;

gzip on;
gzip_static on;
gzip_comp_level 5;
gzip_min_length 1024;
keepalive_timeout 65;
limit_conn_zone $binary_remote_addr zone=addr:10m;
upstream tomcat-host{
server 192.168.100.164:8081 weight=10;
server 192.168.100.110:8180 weight=10;
}
server {
listen 82;
server_name 192.168.100.224;
#charset koi8-r;

#access_log logs/host.access.log main;
location /{
root html;
index index.html index.htm;

proxy_pass http://tomcat-host;
# 获取真实IP
proxy_set_header X-Real-IP $remote_addr;
# 获取代理者的真实IP
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# nginx非80端口处理
proxy_set_header Host $host:$server_port;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
location ~ \.php$ {
root html;
fastcgi_pass 192.168.100.224:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
include fastcgi_params;
}
location ~ /\.ht {
deny all;
}
}
}

重启nginx

[root@wlwddc sbin]# ./nginx -s reload

打开Tomcat服务后在浏览器输入:http://192.168.100.224:82/  就会跳到对应tomcat服务


2. TCP负载均衡设置

TCP负载均衡主要针对quickserver

首先将quickserver文件夹拷贝到目标主机,使用ssh复制命令:

scp -r /root/file_name 192.168.100.120://root

拷贝至目标主机后执行:

[root@localhost wlwddc_car]# ./wlwddc_car.sh 


Loading QuickServer v2.1.0 [PID:7085]... Done
log4j:WARN No appenders could be found for logger (org.apache.commons.digester3.Digester.sax).
log4j:WARN Please initialize the log4j system properly.

-------------------------------
 Name : WlwddcServer v 1.0
 Port : 4455
-------------------------------


可以查看端口监听情况:

[root@localhost ~]# netstat -tulpn | grep :4455
tcp        0      0 0.0.0.0:4455                0.0.0.0:*                   LISTEN      7085/java

TCP负载均衡在nginx.conf中加入如下模块:


#TCP模块
stream {
upstream backend {
#hash $remote_addr consistent;//根据IP地址hash值分配服务器,往往一个IP只能访问固定的服务器
server 192.168.100.163:4455;
server 192.168.100.160:4455;
#server 127.0.0.1:12345 max_fails=3 fail_timeout=30s;
#server unix:/tmp/backend3;
}

server {
listen 4455;
proxy_connect_timeout 1s;
proxy_timeout 60s; #原始参数是3秒,测试时每隔30秒发一次消息挂掉了,改成60s后就好了
proxy_pass backend;
}

# server {
# listen [::1]:12345;
# proxy_pass unix:/tmp/stream.socket;
# }
}


防火墙开放4455端口

重启nginx:

[root@wlwddc sbin]# ./nginx -s reload

使用测试工具往服务器224发送TCP数据包,然后使用命令截取数据包,使用Wireshark分析是否有数据包传送:

tcpdump tcp port 4455 and host192.168.100.224 -w /home/224.cap

tcpdump tcp port 4455 and host192.168.100.160 -w /home/160.cap

tcpdump tcp port 4455 and host192.168.100.163 -w /home/163.cap



nginx可如下启动、重启和关闭

[root@wlwddc /]#cd /usr/local/nginx/sbin

[root@wlwddc sbin]# ./nginx

[root@wlwddc sbin]# ./nginx -s reload

[root@wlwddc sbin]# nginx -s stop

最后设置下nginx自启动,

vi/etc/rc.local

添加

/usr/local/nginx/sbin/nginx


可能出现的问题:

1. 当nginx端口不是默认的80端口时,访问会重定向至默认80端口导致错误

解决方法:http://shitouququ.blog.51cto.com/24569/1551221,我是使用该文中的第三种方法解决的,前两种方法没有效果,全文如下:

Tomcat前端配置一个HTTP服务器应该是大部分应用的标配了,基本思路就是所有动态请求都反向代理给后端的Tomcat,HTTP服务器来处理静态请求,包括图片、js、css、html以及xml等。这样可以让你的应用的负载能力提高很多,前端这个HTTP服务器主流用的最多的当属Apache HTTP Server和nginx。今天这篇文章主要讲解的是这种组合的方式的前提下,后端的Tomcat中的app在301跳转的时候遇到的一个问题。

问题

先把问题说清楚,前端nginx占用81端口,因为80干了别的,暂时懒得停80的应用,暂时修改为81端口而已。然后Tomcat占用8080端口,具体配置如下(只是截取了server中的一段):

location /app1/ {
    index index.jsp index.html index.html index.shtml;
    proxy_pass http://localhost:8080/app1/;

    proxy_set_header   Host             $host;
     proxy_set_header   X-Real-IP        $remote_addr;
    proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;}location ~* ^.+\.(png|jpg|jpeg|gif|ico|css|js|xml)$ {
    root /home/gap/app/apache-tomcat-5.5.14/webapps;}
上面的代码只是简单举例,其中处理静态内容的部分也可以用目录alias或者root的方式去处理,效果应该一样的,但是具体区别我也没深入了解,不过这不是今天的重点。在这个配置下出现的问题就是当访问http://host:81/app1/Login.do的时候,登录成功需要301跳转到用户中心页面,然后跳转的地址本应该是http://host:81/app1/userindex.do,但是结果不太尽如人意,浏览器实际出现的地址http://host/app1/userindex.do。这里面的问题就是81端口没了,跑80端口去了,自然就404了。扯了一大段,这就是今天想说的问题。

问题出现了,自然得分析原因,由于我们这个项目中需要支持ssl,使用了Struts1.2的Framework,于是采用了SecurePlugIn(想了解的可以参照SSLExt Command 2.3节)的插件来处理。那么我首先怀疑是不是这个东西在作怪,看了下配置文件这个插件的enable都直接为false。看来不是这个插件作怪了,那么在不是应用本身逻辑在作怪的话那么可能是服务器配置有问题了,这个时候就应该直接从http请求开始分析了。

首先我打开chrome,然后来分析这次request发生了什么(打开开发者工具中的Network面板),能发现的基本就是请求Login.do是没问题的,但是Login.do之后发生的301重定向是错误的,一个重要的线索就是Login.do的请求中response中的Location的值是http://host/usercenter.do,这里丢掉了端口号。这个地方的具体原因后边会提到,先说下解决思路。

解决思路可以有两个,第一个就是nginx是可以利用proxy_redirect来修改response的Location和Refresh的值,Location自然可以被重新修改为81端口的地址,第二个就是找到是谁把Location搞错了,修改这个地方别搞错Location就行了。

解决思路1:利用nginx的proxy_redirect

这个思路其实有点偏重解决问题型,就是我看到这里错了,原因不纠结,我让你好使就可以了。可能好多人都是这个思路,毕竟解决问题是首要目的。

很多人在配置nginx的时候,习惯参考官方wiki的Full Example (taken from Nginx site),来做一些配置,参考这个肯定比参考baidu搜索出来的文档要靠谱很多,建议不了解每个属性的可以来参照下这个官方示例。这个配置里面proxy_redirect的属性为off,很多人应该没有问过为什么就直接根据人家来做了,之所以这样下结论是因为我看到太多国内人的集成例子中都是这样设置的了。我这里也是这样设置的,以前也倒是没想起来问下为啥,的确不太符合我的风格。反正服务器是这样配置的,现在是出来问题了,我们先来看下这个属性能做什么。

首先看官方文档Reference:proxy_redirect的说明:

Sets a text that should be changed in the header fields “Location” and “Refresh” of a response from the proxied server. Suppose a proxied server returned the header field “Location: http://localhost:8000/two/some/uri/”.

基本意思就是修改代理服务器(也就是此时的nginx)的response的头信息里面的LocationRefresh的值,按照这个解释的话我们的问题肯定就迎刃而解了,因为现在遇到的问题就是这个能够修改的两个中的一个Location出了问题,那么下面的代码就可以解决问题

proxy_redirect     http://host http://host:81;

这样重启sudo nginx -s reload然后再访问应该就ok了。其实你google搜索nginx proxy_redirect 重定向有好多这样的例子和这个解决方式是一样的,就不细说了,如果有人想了解的可以自己参照nginx官方文档和结合例子来操作下试试就可以理解了。

解决思路2:找到问题原因,修改出错的地方解决

根据上个思路解决了问题以后,一点都没如释重负的感觉,反而各个地方都觉得很空的感觉,因为有好几个疑问没解决,其中包括为啥是80而不是81或者8080没道理?这个Location是不是应该nginx来重写,修改掉那个跳转错的地方是不是比这个思路会更好?

那就先来分析下问题的原因:既然response的Locaiton不对,那么首先想到的就是这个Location是谁构造出来的,了解HTTP协议的人应该都知道,request中的header都是client(浏览器等)构造好发送给服务器的,服务器收到请求以后构造response信息返回给client。那么这样Location这个值肯定就是nginx或者Tomcat给搞出的问题了,这个地方nginx只是一个proxy server,那么response肯定是Tomcat发给nginx的,也就是说我们应该从Tomcat下手来分析这个问题。

首先我就看了下Tomcat的官方文档 Proxy Support,这里面对这个介绍如下:

The proxyName and proxyPort attributes can be used when Tomcat is run behind a proxy server. These attributes modify the values returned to web applications that call the request.getServerName() and request.getServerPort() methods, which are often used to construct absolute URLs for redirects. Without configuring these attributes, the values returned would reflect the server name and port on which the connection from the proxy server was received, rather than the server name and port to whom the client directed the original request.

意思就是proxyPort的属性就是用来我这种nginx做前端代理服务器Tomcat在后端处理动态请求的情况的。修改属性的值可以作用于应用的两个方法,主要用于绝对路径和重定向之用。如果不配置的话,可能会不对头。那么既然是这里不对头,我就先把server.xml中我这个http的connector的配置加入了proxyPort="81",重启Tomcat,然后把nginx上步骤的修改注释掉,重启测试。结果基本如所料,完全正常跳转了。

事情到了这个时候,其实问题基本明了了,不过我还是对这个Tomcat为啥默认解析了80端口很是疑惑。我下载了Tomcat的source来看下问题究竟,看了以后用通俗的语言来表述的话就是这样:如果默认不配置proxyPort默认为0,然后在构造response的时候判断如果proxyPort为0那么就不添加端口,不添加端口当然就默认走了80端口,源代码如下:

// FIXME: the code below doesnt belongs to here, // this is only have sense // in Http11, not in ajp13..// At this point the Host header has been processed.// Override if the proxyPort/proxyHost are set String proxyName = connector.getProxyName();int proxyPort = connector.getProxyPort();if (proxyPort != 0) {
    req.setServerPort(proxyPort);}if (proxyName != null) {
    req.serverName().setString(proxyName);}

到了这里就真相大白了,心里也没结了,一块石头终于落地了。

解决思路3:如果是程序自动获取URl

Nginx通过80端口反向代理到Tomcat实现很简单,通过Jsp的request.getServerPort()获取到的端口号依然是80,而如果Nginx使用非80端口做反响代理时request.getServerPort()获取到的端口号返回依然会是80,这样边无法正确response.sendRedirect

String path = request.getContextPath(); 
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";

这样response.sendRedirect会跳转到80端口去

解决办法:

修改proxy.conf获取你把代理的配置写到了nginx内,也可以在其内部修改

proxy_redirect          off;

# nginx非80端口处理 
proxy_set_header        Host $host:$server_port
# 获取真实IP 
proxy_set_header        X-Real-IP $remote_addr; 
# 获取代理者的真实ip 
proxy_set_header       X-Forwarded-For   $proxy_add_x_forwarded_for; 
client_max_body_size    10m; 
client_body_buffer_size 128k; 
proxy_connect_timeout   90; 
proxy_send_timeout      90; 
proxy_read_timeout      90; 
proxy_buffer_size       4k; 
proxy_buffers           4 32k; 
proxy_busy_buffers_size 64k; 
proxy_temp_file_write_size 64k;


总结

也就是说Tomcat在设计的时候是对这种代理服务器和Tomcat集成的情况做了考虑,80端口之所以没问题是因为port为空,浏览器会默认走80端口,如果nginx这代理服务器不是80这个端口应该需要配置proxyPort的属性的,这样就不会遇到这个问题。

那么基于这个来总结的话,两种解决方式都可以,不过修改Tomcat配置文件的方式是我最推荐的,因为这个思路看起来是又合理、又易于理解。我的感觉就是谁的事情谁来解决比较好,nginx作为proxy server 你就只需要做你的静态文件的解析,和把动态请求方向代理的服务器就可以了,既然Tomcat把这个信息构造错了,人家也有提供了解决方案,就根据你的情况合理配置就可以了。

一直以来自己是个特别较真的人,各种事情都是,希望每个人在解决问题的时候不要仅限于解决了问题就ok吧,更多的去了解问题的真相才会进步更快,例如这个问题其实有一个必要前提是需要了解一些HTTP的协议的基础知识,如果不了解的话可能你不会很快判断出Location出了问题,你可能也不会很快知道response是谁构造错的。建议大家都读下《HTTP权威指南》,每个做web开发的工程师都应该拥有这本书,可以大概先看一遍了解,后续需要就拿出来作为工具书查阅资料。如果作为工具书的话,那就强烈推荐大家购买图灵推出的《HTTP权威指南》电子版,我都把我的纸质书卖了换了电子版了,买了都说好啊。不过顺带说句图灵购买也需要输入个兑换码才能送银子,这体验不好,因为总是忘记,着急买书的都会忘记,建议改进下啊

2. nginx: [emerg] getpwnam("nginx--group=nginx") failed

解决方法:

1. 在nginx.conf中 把#user nobdy改为user nginx

2. 在编译前修改下install文件或make文件,将新建用户,新建一些自定义目录都添加下,再编译生成rpm包就OK了。

3. 在nginx.conf中 把user nobody的注释去掉



其他:

        Nginx配置参数说明

             proxy_set_header设置Host为$proxy_host,$host与$local_host的区别

            自动跳转到80端口的问题
           Nginx官方网站

            Nginx官网文档