Nginx根据查询字符串屏蔽访问

发现有人在刷网站的注册,IP比较分散,网站注册环节是有验证码,但刷注册的这个验证码一直就没变过

36.251.148.6 - - [12/Oct/2015:13:50:38 +0800] "GET /member/reg.html?step=1&mobile=13872972880&checkcode=v5bb HTTP/1.1" 200 
101.71.32.12 - - [12/Oct/2015:13:50:38 +0800] "GET /member/reg.html?step=1&mobile=13971050735&checkcode=v5bb HTTP/1.1" 200
171.88.126.51 - - [12/Oct/2015:13:50:38 +0800] "GET /member/reg.html?step=1&mobile=15588291414&checkcode=v5bb HTTP/1.1" 200
222.216.31.24 - - [12/Oct/2015:13:50:38 +0800] "GET /member/reg.html?step=1&mobile=13977125525&checkcode=v5bb HTTP/1.1" 200
115.212.189.106 - - [12/Oct/2015:13:50:38 +0800] "GET /member/reg.html?step=1&mobile=13625885599&checkcode=v5bb HTTP/1.1" 200
115.212.189.106 - - [12/Oct/2015:13:50:38 +0800] "GET /member/reg.html?step=1&mobile=13625885599&checkcode=v5bb HTTP/1.1" 200
222.216.31.24 - - [12/Oct/2015:13:50:38 +0800] "GET /member/reg.html?step=1&mobile=15607818598&checkcode=v5bb HTTP/1.1" 200

虽说这样刷是注册不了的,但却增加了后端服务器的压力,干脆封掉,在nginx的server中添加如下内容,$query_string是nginx的内建变量,类似的还有$request_uri和$uri

if  ($query_string  ~* "step=1&mobile=(\d){11}&checkcode=v5bb") {
            return 403;
}

这样配置之后,nginx便直接给恶意访问者返回403,不用经过后端服务器处理了

 

 

 

fastcgi_temp目录权限不当导致页面加载不完全的问题

这个博客用的wordpress,这两天发现后台里的样式乱掉了,前台的标签及按月分类等也看不到了,第一反应是css没有加载上,但通过页面源码里的链接是可以直接打开css文件的,到vps上看了下nginx的error.log,发现如下错误

2015/07/07 14:31:27 [crit] 20844#0: *8686 open() "/usr/local/nginx/fastcgi_temp/4/28/0000000284" failed (13: Permission denied) while reading upstream, client: 121.79.18.36, server: gunner.me, request: "GET / HTTP/1.1", upstream: "fastcgi://127.0.0.1:9000", host: "gunner.me"

错误很明显,fastcgi_temp目录的权限不够,导致了php输出内容不全,chown改成与nginx运行用户一致后问题解决了。 OK,顺便了解下这个目录的作用,从nginx的buffer机制说起,对于来自 fastcgi server 的 response,nginx 先将其缓冲到内存中,然后依次发送到客户端浏览器。缓冲区的大小由 fastcgi_buffers 和 fastcgi_buffer_size 两个值控制。

fastcgi_buffer_size
语法:fastcgi_buffer_size the_size ;
使用字段:http, server, location 
这个参数指定将用多大的缓冲区来读取从FastCGI进程到来应答头。 默认的缓冲区大小为fastcgi_buffers指令中的每块大小,可以将这个值设置更小。 fastcgi_buffers 语法:fastcgi_buffers the_number is_size; 使用字段:http, server, location 这个参数指定了从FastCGI进程到来的应答,本地将用多少和多大的缓冲区读取。

如果是如下配置

fastcgi_buffers      8 4K;
fastcgi_buffer_size  4K;

fastcgi_buffers 控制 nginx 最多创建 8 个大小为 4K 的缓冲区,而 fastcgi_buffer_size 则是处理 Response 时第一个缓冲区的大小,不包含在前者中。所以总计能创建的最大内存缓冲区大小是 8*4K+4K = 36k。而这些缓冲区是根据实际的 Response 大小动态生成的,并不是一次性创建的。比如一个 8K 的页面,Nginx 会创建 2*4K 共 2 个 buffers。当 Response 小于等于 36k 时,所有数据当然全部在内存中处理。如果 Response 大于 36k 呢?fastcgi_temp 的作用就在于此。多出来的数据会被临时写入到文件中,放在这个目录下面。 我遇到的情况是前台和后台页面大于默认的内存缓冲区,而运行nginx的用户并没有fastcgi_temp目录的写权限,于是剩下的数据就丢失掉了,所以页面显示不完整。 参考:http://www.phpvim.net/os/ubuntu/fastcgi_temp_error_and_nginx_buffer.html

Nginx的编译参数说明

–prefix= 指向安装目录
–sbin-path 指向(执行)程序文件(nginx)
–conf-path= 指向配置文件(nginx.conf)
–error-log-path= 指向错误日志目录
–pid-path= 指向pid文件(nginx.pid)
–lock-path= 指向lock文件(nginx.lock)(安装文件锁定,防止安装文件被别人利用,或自己误操作。)
–user= 指定程序运行时的非特权用户
–group= 指定程序运行时的非特权用户组
–builddir= 指向编译目录
–with-rtsig_module 启用rtsig模块支持(实时信号)
–with-select_module 启用select模块支持(一种轮询模式,不推荐在高载环境下使用)禁用:–without-select_module
–with-poll_module 启用poll模块支持(功能与select相同,与select特性相同,为一种轮询模式,不推荐在高载环境下使用)
–with-file-aio 启用file aio支持(一种APL文件传输格式)
–with-ipv6 启用ipv6支持
–with-http_ssl_module 启用ngx_http_ssl_module支持(使支持https请求,需已安装openssl)
–with-http_realip_module 启用ngx_http_realip_module支持(这个模块允许从请求标头更改客户端的IP地址值,默认为关)
–with-http_addition_module 启用ngx_http_addition_module支持(作为一个输出过滤器,支持不完全缓冲,分部分响应请求)
–with-http_xslt_module 启用ngx_http_xslt_module支持(过滤转换XML请求)
–with-http_image_filter_module 启用ngx_http_image_filter_module支持(传输JPEG/GIF/PNG 图片的一个过滤器)(默认为不启用。gd库要用到)
–with-http_geoip_module 启用ngx_http_geoip_module支持(该模块创建基于与MaxMind GeoIP二进制文件相配的客户端IP地址的ngx_http_geoip_module变量)
–with-http_sub_module 启用ngx_http_sub_module支持(允许用一些其他文本替换nginx响应中的一些文本)
–with-http_dav_module 启用ngx_http_dav_module支持(增加PUT,DELETE,MKCOL:创建集合,COPY和MOVE方法)默认情况下为关闭,需编译开启
–with-http_flv_module 启用ngx_http_flv_module支持(提供寻求内存使用基于时间的偏移量文件)
–with-http_gzip_static_module 启用ngx_http_gzip_static_module支持(在线实时压缩输出数据流)
–with-http_random_index_module 启用ngx_http_random_index_module支持(从目录中随机挑选一个目录索引)
–with-http_secure_link_module 启用ngx_http_secure_link_module支持(计算和检查要求所需的安全链接网址)
–with-http_degradation_module 启用ngx_http_degradation_module支持(允许在内存不足的情况下返回204或444码)
–with-http_stub_status_module 启用ngx_http_stub_status_module支持(获取nginx自上次启动以来的工作状态)
–without-http_charset_module 禁用ngx_http_charset_module支持(重新编码web页面,但只能是一个方向–服务器端到客户端,并且只有一个字节的编码可以被重新编码)
–without-http_gzip_module 禁用ngx_http_gzip_module支持(该模块同-with-http_gzip_static_module功能一样)
–without-http_ssi_module 禁用ngx_http_ssi_module支持(该模块提供了一个在输入端处理处理服务器包含文件(SSI)的过滤器,目前支持SSI命令的列表是不完整的)
–without-http_userid_module 禁用ngx_http_userid_module支持(该模块用来处理用来确定客户端后续请求的cookies)
–without-http_access_module 禁用ngx_http_access_module支持(该模块提供了一个简单的基于主机的访问控制。允许/拒绝基于ip地址)
–without-http_auth_basic_module禁用ngx_http_auth_basic_module(该模块是可以使用用户名和密码基于http基本认证方法来保护你的站点或其部分内容)
–without-http_autoindex_module 禁用disable ngx_http_autoindex_module支持(该模块用于自动生成目录列表,只在ngx_http_index_module模块未找到索引文件时发出请求。)
–without-http_geo_module 禁用ngx_http_geo_module支持(创建一些变量,其值依赖于客户端的IP地址)
–without-http_map_module 禁用ngx_http_map_module支持(使用任意的键/值对设置配置变量)
–without-http_split_clients_module 禁用ngx_http_split_clients_module支持(该模块用来基于某些条件划分用户。条件如:ip地址、报头、cookies等等)
–without-http_referer_module 禁用disable ngx_http_referer_module支持(该模块用来过滤请求,拒绝报头中Referer值不正确的请求)
–without-http_rewrite_module 禁用ngx_http_rewrite_module支持(该模块允许使用正则表达式改变URI,并且根据变量来转向以及选择配置。如果在server级别设置该选项,那么他们将在 location之前生效。如果在location还有更进一步的重写规则,location部分的规则依然会被执行。如果这个URI重写是因为location部分的规则造成的,那么 location部分会再次被执行作为新的URI。 这个循环会执行10次,然后Nginx会返回一个500错误。)
–without-http_proxy_module 禁用ngx_http_proxy_module支持(有关代理服务器)
–without-http_fastcgi_module 禁用ngx_http_fastcgi_module支持(该模块允许Nginx 与FastCGI 进程交互,并通过传递参数来控制FastCGI 进程工作。 )FastCGI一个常驻型的公共网关接口。
–without-http_uwsgi_module 禁用ngx_http_uwsgi_module支持(该模块用来医用uwsgi协议,uWSGI服务器相关)
–without-http_scgi_module 禁用ngx_http_scgi_module支持(该模块用来启用SCGI协议支持,SCGI协议是CGI协议的替代。它是一种应用程序与HTTP服务接口标准。它有些像FastCGI但他的设计 更容易实现。)
–without-http_memcached_module 禁用ngx_http_memcached_module支持(该模块用来提供简单的缓存,以提高系统效率)
-without-http_limit_zone_module 禁用ngx_http_limit_zone_module支持(该模块可以针对条件,进行会话的并发连接数控制)
–without-http_limit_req_module 禁用ngx_http_limit_req_module支持(该模块允许你对于一个地址进行请求数量的限制用一个给定的session或一个特定的事件)
–without-http_empty_gif_module 禁用ngx_http_empty_gif_module支持(该模块在内存中常驻了一个1*1的透明GIF图像,可以被非常快速的调用)
–without-http_browser_module 禁用ngx_http_browser_module支持(该模块用来创建依赖于请求报头的值。如果浏览器为modern ,则$modern_browser等于modern_browser_value指令分配的值;如 果浏览器为old,则$ancient_browser等于 ancient_browser_value指令分配的值;如果浏览器为 MSIE中的任意版本,则 $msie等于1)
–without-http_upstream_ip_hash_module 禁用ngx_http_upstream_ip_hash_module支持(该模块用于简单的负载均衡)
–with-http_perl_module 启用ngx_http_perl_module支持(该模块使nginx可以直接使用perl或通过ssi调用perl)
–with-perl_modules_path= 设定perl模块路径
–with-perl= 设定perl库文件路径
–http-log-path= 设定access log路径
–http-client-body-temp-path= 设定http客户端请求临时文件路径
–http-proxy-temp-path= 设定http代理临时文件路径
–http-fastcgi-temp-path= 设定http fastcgi临时文件路径
–http-uwsgi-temp-path= 设定http uwsgi临时文件路径
–http-scgi-temp-path= 设定http scgi临时文件路径
-without-http 禁用http server功能
–without-http-cache 禁用http cache功能
–with-mail 启用POP3/IMAP4/SMTP代理模块支持
–with-mail_ssl_module 启用ngx_mail_ssl_module支持
–without-mail_pop3_module 禁用pop3协议(POP3即邮局协议的第3个版本,它是规定个人计算机如何连接到互联网上的邮件服务器进行收发邮件的协议。是因特网电子邮件的第一个离线协议标 准,POP3协议允许用户从服务器上把邮件存储到本地主机上,同时根据客户端的操作删除或保存在邮件服务器上的邮件。POP3协议是TCP/IP协议族中的一员,主要用于 支持使用客户端远程管理在服务器上的电子邮件)
–without-mail_imap_module 禁用imap协议(一种邮件获取协议。它的主要作用是邮件客户端可以通过这种协议从邮件服务器上获取邮件的信息,下载邮件等。IMAP协议运行在TCP/IP协议之上, 使用的端口是143。它与POP3协议的主要区别是用户可以不用把所有的邮件全部下载,可以通过客户端直接对服务器上的邮件进行操作。)
–without-mail_smtp_module 禁用smtp协议(SMTP即简单邮件传输协议,它是一组用于由源地址到目的地址传送邮件的规则,由它来控制信件的中转方式。SMTP协议属于TCP/IP协议族,它帮助每台计算机在发送或中转信件时找到下一个目的地。)
–with-google_perftools_module 启用ngx_google_perftools_module支持(调试用,剖析程序性能瓶颈)
–with-cpp_test_module 启用ngx_cpp_test_module支持
–add-module= 启用外部模块支持
–with-cc= 指向C编译器路径
–with-cpp= 指向C预处理路径
–with-cc-opt= 设置C编译器参数(PCRE库,需要指定–with-cc-opt=”-I /usr/local/include”,如果使用select()函数则需要同时增加文件描述符数量,可以通过–with-cc- opt=”-D FD_SETSIZE=2048”指定。)
–with-ld-opt= 设置连接文件参数。(PCRE库,需要指定–with-ld-opt=”-L /usr/local/lib”。)
–with-cpu-opt= 指定编译的CPU,可用的值为: pentium, pentiumpro, pentium3, pentium4, athlon, opteron, amd64, sparc32, sparc64, ppc64
–without-pcre 禁用pcre库
–with-pcre 启用pcre库
–with-pcre= 指向pcre库文件目录
–with-pcre-opt= 在编译时为pcre库设置附加参数
–with-md5= 指向md5库文件目录(消息摘要算法第五版,用以提供消息的完整性保护)
–with-md5-opt= 在编译时为md5库设置附加参数
–with-md5-asm 使用md5汇编源
–with-sha1= 指向sha1库目录(数字签名算法,主要用于数字签名)
–with-sha1-opt= 在编译时为sha1库设置附加参数
–with-sha1-asm 使用sha1汇编源
–with-zlib= 指向zlib库目录
–with-zlib-opt= 在编译时为zlib设置附加参数
–with-zlib-asm= 为指定的CPU使用zlib汇编源进行优化,CPU类型为pentium, pentiumpro
–with-libatomic 为原子内存的更新操作的实现提供一个架构
–with-libatomic= 指向libatomic_ops安装目录
–with-openssl= 指向openssl安装目录
–with-openssl-opt 在编译时为openssl设置附加参数
–with-debug 启用debug日志

转自:http://www.ttlsa.com/nginx/nginx-configure-descriptions/

Nginx日志中的双引号解析问题

这个问题其实是在上一篇的问题解决之后出现的又一个问题,还好测试到了,问题是这样的:

在Nginx记录的日志中会把出现在日志行中的双引号解析为x22

apache里面的正常日志应该是下面这样:

18.14.6.19 [28/Aug/2014:16:20:04 +0800] GET /server/shop/game/118 pos=0&cnt=50 200 \"clientInfo\":{\"num\":\"1375\",\"op\":\"46000\",\"dev\":\"GN708W\",\"imei\":\"862795012135838\",\"pkg\":\"com.assistor\",\"vc\":420,\"imsi\":\"460009182585103\",\"sdk\":17,\"vn\":\"4.2.0\",\"ccid\":\"5\"} 0.046

但是同样的log_format参数配置,到了Nginx里面就成了下面这样:

18.14.6.19 [28/Aug/2014:16:20:04 +0800] GET /server/shop/game/118 pos=0&cnt=50 200 \x22clientInfo\x22:{\x22num\x22:\x221375\x22,\x22op\x22:\x2246000\x22,\x22dev\x22:\x22GN708W\x22,\x22imei\x22:\x22862795012135838\x22,\x22pkg\x22:\x22com.assistor\x22,\x22vc\x22:420,\x22imsi\x22:\x22460009182585103\x22,\x22sdk\x22:17,\x22vn\x22:\x224.2.0\x22,\x22ccid\x22:\x225\x22} 0.046

查了很多资料,其中这里提到了,但是按照这办法没有测试成功,后来看到Nginx的Changelog里面是这样写的

Changes with nginx 1.1.6 17 Oct 2011

*) Change: now the 0x7F-0x1F characters are escaped as \xXX in an
   access_log.
Changes with nginx 0.7.0 19 May 2008

*) Change: now the 0x00-0x1F, '"' and '\' characters are escaped as \xXX
   in an access_log.
   Thanks to Maxim Dounin.

貌似Nginx是有意为之,只能理解为Nginx默认的log_format使用双引号作为间隔符,为了避免日志分析时候出现混乱,所以将双引号解析为x22了。

后来想了个笨办法,在每天日志切割的时候,替换日志中的x22字符为双引号,也算是绕过这个烦人的问题了。

附Nginx日志切割脚本

#!/bin/bash

#setting log path
log_files_path="/usr/local/nginx/logs/"
log_files_dir=${log_files_path}$(date -d "yesterday" +"%Y")/$(date -d "yesterday" +"%m")

#setting nginx
nginx_sbin="/usr/local/nginx/sbin/nginx"

if [ ! -d $log_files_dir ]; then
    mkdir -p $log_files_dir
fi

cd $log_files_path

#setting log name
log_files_name=(www.abc.com)
log_files_num=${#log_files_name[@]}

for((i=0;i<$log_files_num;i++));do
mv ${log_files_path}${log_files_name[i]}.log ${log_files_dir}/${log_files_name[i]}.log
/bin/sed -e 's/x22/"/g' ${log_files_dir}/${log_files_name[i]}.log > ${log_files_dir}/${log_files_name[i]}_$(date -d "yesterday" +"%Y%m%d").log
/bin/rm ${log_files_dir}/${log_files_name[i]}.log
done

kill -USR1 `cat /usr/local/nginx/nginx.pid`

 

 

在Nginx中记录自定义Header

从Apache切到Nginx需要保持日志格式统一,以便兼容之前的数据统计脚本

现在Apache的日志格式为:

LogFormat "%h %t %m %U %q %>s %{HEAD}i %D"

说明:

%h:客户端IP地址

%t:时间(标准英语格式)

%m:请求的方法(GET,POST)

%U:请求的URL路径,不包含查询字符串

%q:查询字符串

%>s:请求的最终状态

%{HEAD}i:请求头信息

%D:服务器处理请求所用时间,微秒为单位

对应的Nginx日志格式为:

log_format  main  '$remote_addr [$time_local] $request_method $uri '
                  '$query_string $status '
                  '$http_head $request_time ';

其中Apache里的%{HEAD}i这个参数里的HEAD是在程序里自定义了一个header,在Nginx里面取这个HEAD用到的是$http_head参数,head就是自定义的header名称HEAD, Nginx里面需要小写,在这里走了不少弯路。

用firebug获取http header,如下图

Snip20140828_3

有两部分内容,一个是响应头,一个是请求头,请求头是客户端发送给服务器的,包括Requst Line及HTTP Header,响应头是服务器返回给客户端的,包括Status Line及HTTP Header。关于http header的说明,这里有一篇很好的文章可以参考。

在Nginx里面可以用$upstream_http_’header名称’来获取响应头信息,比如$upstream_http_content_type将会获取到类似text/html; charset=utf-8的内容,说明返回的文件类型及编码格式。在我的需求中是要获取自定义的请求头的内容,需要使用$sent_http_’自定义header名称’来获取,但我测试过程中没有取到,用$http_’自定义header名称’才取到,也许和Nginx版本有关,我的版本是1.4.2。

另外,测试过程中用的是firefox的poster插件,可以自定义请求头,截图如下:

Snip20140828_4

自定义一个header,然后输入URL,点GET即可发送带有自定义header的请求,在服务器端查看日志可以看到取到了‘AAAAAAAAAAAAAAAAAAAAAA’.

nginx.org里关于log_format参数的说明,英文不好,看着费劲。

The ngx_http_core_module module supports embedded variables with names matching the Apache Server variables. First of all, these are variables representing client request header fields, such as $http_user_agent, $http_cookie, and so on. Also there are other variables:

$arg_name
argument name in the request line

$args
arguments in the request line

$binary_remote_addr
client address in a binary form, value’s length is always 4 bytes

$body_bytes_sent
number of bytes sent to a client, not counting the response header; this variable is compatible with the “%B” parameter of the mod_log_config Apache module

$bytes_sent
number of bytes sent to a client (1.3.8, 1.2.5)

$connection
connection serial number (1.3.8, 1.2.5)

$connection_requests
current number of requests made through a connection (1.3.8, 1.2.5)

$content_length
“Content-Length” request header field

$content_type
“Content-Type” request header field

$cookie_name
the name cookie

$document_root
root or alias directive’s value for the current request

$document_uri
same as $uri

$host
in this order of precedence: host name from the request line, or host name from the “Host” request header field, or the server name matching a request

$hostname
host name

$http_name
arbitrary request header field; the last part of a variable name is the field name converted to lower case with dashes replaced by underscores

$https
“on” if connection operates in SSL mode, or an empty string otherwise

$is_args
“?” if a request line has arguments, or an empty string otherwise

$limit_rate
setting this variable enables response rate limiting; see limit_rate

$msec
current time in seconds with the milliseconds resolution (1.3.9, 1.2.6)

$nginx_version
nginx version

$pid
PID of the worker process

$pipe
“p” if request was pipelined, “.” otherwise (1.3.12, 1.2.7)

$proxy_protocol_addr
client address from the PROXY protocol header, or an empty string otherwise (1.5.12)
The PROXY protocol must be previously enabled by setting the proxy_protocol parameter in the listen directive.

$query_string
same as $args

$realpath_root
an absolute pathname corresponding to the root or alias directive’s value for the current request, with all symbolic links resolved to real paths

$remote_addr
client address

$remote_port
client port

$remote_user
user name supplied with the Basic authentication

$request
full original request line

$request_body
request body
The variable’s value is made available in locations processed by the proxy_pass, fastcgi_pass, uwsgi_pass, and scgi_pass directives.

$request_body_file
name of a temporary file with the request body
At the end of processing, the file needs to be removed. To always write the request body to a file, client_body_in_file_only needs to be enabled. When the name of a temporary file is passed in a proxied request or in a request to a FastCGI/uwsgi/SCGI server, passing the request body should be disabled by the proxy_pass_request_body off, fastcgi_pass_request_body off, uwsgi_pass_request_body off, or scgi_pass_request_body off directives, respectively.

$request_completion
“OK” if a request has completed, or an empty string otherwise

$request_filename
file path for the current request, based on the root or alias directives, and the request URI

$request_length
request length (including request line, header, and request body) (1.3.12, 1.2.7)

$request_method
request method, usually “GET” or “POST”

$request_time
request processing time in seconds with a milliseconds resolution (1.3.9, 1.2.6); time elapsed since the first bytes were read from the client

$request_uri
full original request URI (with arguments)

$scheme
request scheme, “http” or “https”

$sent_http_name
arbitrary response header field; the last part of a variable name is the field name converted to lower case with dashes replaced by underscores

$server_addr
an address of the server which accepted a request
Computing a value of this variable usually requires one system call. To avoid a system call, the listen directives must specify addresses and use the bind parameter.

$server_name
name of the server which accepted a request

$server_port
port of the server which accepted a request

$server_protocol
request protocol, usually “HTTP/1.0” or “HTTP/1.1”

$status
response status (1.3.2, 1.2.2)

$tcpinfo_rtt, $tcpinfo_rttvar, $tcpinfo_snd_cwnd, $tcpinfo_rcv_space
information about the client TCP connection; available on systems that support the TCP_INFO socket option

$time_iso8601local
time in the ISO 8601 standard format (1.3.12, 1.2.7)

$time_local

local time in the Common Log Format (1.3.12, 1.2.7)

$uri
current URI in request, normalized
The value of $uri may change during request processing, e.g. when doing internal redirects, or when using index files.

参考:http://blog.51yip.com/apachenginx/1277.html

用Zabbix监控nginx日志里的http状态码

方法很简单,用脚本取nginx上一个小时输出的日志,然后计算几种http状态码出现的次数即可,修改这里用到的那个脚本,再次感谢krish@toonheart.com


#!/bin/bash
# Script to fetch nginx statuses for tribily monitoring systems
 
HOST=m.xyz.com
#HOST=`/sbin/ifconfig eth0 | sed -n '/inet /{s/.*addr://;s/ .*//;p}'`
PORT="80"
#webstatus=nginx-status
# Functions to return nginx stats

function active {
        /usr/bin/curl "http://$HOST:$PORT/nginx-status" 2>/dev/null| grep 'Active' | awk '{print $NF}' 
        } 

function reading {
        /usr/bin/curl "http://$HOST:$PORT/nginx-status" 2>/dev/null| grep 'Reading' | awk '{print $2}' 
        } 

function writing {
        /usr/bin/curl "http://$HOST:$PORT/nginx-status" 2>/dev/null| grep 'Writing' | awk '{print $4}' 
        } 

function waiting {
        /usr/bin/curl "http://$HOST:$PORT/nginx-status" 2>/dev/null| grep 'Waiting' | awk '{print $6}' 
        } 

function accepts {
        /usr/bin/curl "http://$HOST:$PORT/nginx-status" 2>/dev/null| awk NR==3 | awk '{print $1}'
        } 

function handled {
        /usr/bin/curl "http://$HOST:$PORT/nginx-status" 2>/dev/null| awk NR==3 | awk '{print $2}'
        } 

function requests {
        /usr/bin/curl "http://$HOST:$PORT/nginx-status" 2>/dev/null| awk NR==3 | awk '{print $3}'
        }

# Get http code status

logname='/usr/local/nginx/logs/abc.com.log'

function code_404 {
        more $logname |grep `date -d '1 hour ago' "+%d/%b/%Y:%H"`|cut -d '"' -f3|cut -d ' ' -f2|sort|uniq -c|sort -r|grep 404$|awk '{print $1}'
        }

function code_503 {
        more $logname |grep `date -d '1 hour ago' "+%d/%b/%Y:%H"`|cut -d '"' -f3|cut -d ' ' -f2|sort|uniq -c|sort -r|grep 503$|awk '{print $1}'
        }

function code_499 {
        more $logname |grep `date -d '1 hour ago' "+%d/%b/%Y:%H"`|cut -d '"' -f3|cut -d ' ' -f2|sort|uniq -c|sort -r|grep 499$|awk '{print $1}'
        }

function code_500 {
        more $logname |grep `date -d '1 hour ago' "+%d/%b/%Y:%H"`|cut -d '"' -f3|cut -d ' ' -f2|sort|uniq -c|sort -r|grep 500$|awk '{print $1}'
        }

function code_400 {
        more $logname |grep `date -d '1 hour ago' "+%d/%b/%Y:%H"`|cut -d '"' -f3|cut -d ' ' -f2|sort|uniq -c|sort -r|grep 400$|awk '{print $1}'
        }

# Run the requested function
$1

 

再修改/usr/local/zabbix_agent/conf/zabbix_agentd/userparameter_nginx.conf 文件

UserParameter=nginx.accepts,/usr/local/zabbix_agent/bin/get_nginx_status.sh accepts
UserParameter=nginx.handled,/usr/local/zabbix_agent/bin/get_nginx_status.sh handled
UserParameter=nginx.requests,/usr/local/zabbix_agent/bin/get_nginx_status.sh requests
UserParameter=nginx.connections.active,/usr/local/zabbix_agent/bin/get_nginx_status.sh active
UserParameter=nginx.connections.reading,/usr/local/zabbix_agent/bin/get_nginx_status.sh reading
UserParameter=nginx.connections.writing,/usr/local/zabbix_agent/bin/get_nginx_status.sh writing
UserParameter=nginx.connections.waiting,/usr/local/zabbix_agent/bin/get_nginx_status.sh waiting

UserParameter=nginx.code_404,/usr/local/zabbix_agent/bin/get_nginx_status.sh code_404
UserParameter=nginx.code_499,/usr/local/zabbix_agent/bin/get_nginx_status.sh code_499
UserParameter=nginx.code_500,/usr/local/zabbix_agent/bin/get_nginx_status.sh code_500
UserParameter=nginx.code_503,/usr/local/zabbix_agent/bin/get_nginx_status.sh code_503
UserParameter=nginx.code_400,/usr/local/zabbix_agent/bin/get_nginx_status.sh code_400

 

重启zabbix客户端程序,然后在服务器端测试:

root@ABC:/usr/local/zabbix/bin# ./zabbix_get  -s 192.168.0.1 -p 10050 -k "nginx.code_404"
11

 

最后,在Zabbix的web前端修改Template Nginx Status,添加几个状态码的Items即可。

 

 

Nginx几种Upstream的配置方式

相比Apache,使用Nginx的一个很大的好处是可以做简单的负载均衡,下面是upstream的几种配置。

1:轮询,每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器down掉,能自动剔除。

upstream test{
   server 192.168.0.1:3000;
   server 192.168.0.1:3001;
}

2:权重,可分配后端服务器的权重,适用于后端服务器性能不均衡的情况。

upstream test{
   server 192.168.0.1 weight=2;
   server 192.168.0.2 weight=3;
}

3:ip_hash,按照客户端IP的hash结果来分配请求,适用于需要保留session的情况。

upstream test{
   ip_hash;
   server 192.168.0.1;
   server 192.168.0.2;
}

4:fair,需要安装Upstream Fair Balancer Module,按后端服务器的响应时间来分配请求,响应时间短的优先分配。

upstream test{
   server 192.168.0.1;
   server 192.168.0.2;
   fair;
}

5:自定义hash,需要安装Upstream Hash Module,可以根据给定的字符串进行Hash分配,没太明白。

upstream test{
   server 192.168.0.1;
   server 192.168.0.2;
   hash $request_uri;
}

具体应用:

upstream domain1_server_pool {
	ip_hash;
    server 192.168.0.1:7001;
    server 192.168.0.2:7001;
}

server {

        listen       80;
        server_name  back.abc.com;
        root         /usr/local/nginx/html;

        location ^~/csbackend {
            proxy_pass               http://domain1_server_pool;
            proxy_redirect           off;
            proxy_set_header         Host            $host;
            proxy_set_header         X-Real-IP       $remote_addr;
            proxy_set_header         X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header         access_token    $http_access_token;
            proxy_set_header         client_id       $http_client_id;
            proxy_set_header         client_secret   $http_client_secret;
            proxy_set_header         m_client_type   $http_m_client_type;
            proxy_set_header         m_os_version    $http_m_os_version;
            proxy_set_header         m_hd_type       $http_m_hd_type;
            proxy_set_header         m_serial        $http_m_serial;
            client_max_body_size     10m;
            client_body_buffer_size  256k;
            proxy_connect_timeout    300;
            proxy_send_timeout       300;
            proxy_read_timeout       300;
            proxy_buffer_size 64k;
            proxy_buffers   32 32k;
            proxy_busy_buffers_size 128k;
        }
        
        access_log logs/back.abc.com.log main;
}

 

upstream每个后端的可设置参数:

1.down: 表示此台server暂时不参与负载。

2.weight: 默认为1,weight越大,负载的权重就越大。

3.max_fails: 允许请求失败的次数默认为1.当超过最大次数时,返回proxy_next_upstream模块定义的错误。

4.fail_timeout: max_fails次失败后,暂停的时间。

5.backup: 其它所有的非backup机器down或者忙的时候,请求backup机器,应急措施。

用Zabbix监控Nginx

首先在需要监控的nginx虚拟主机中打开stub_status配置项,并允许zabbxi服务器访问

location /nginx-status {
    stub_status on;
    access_log off;
    allow 1.2.3.4;
    deny all;
}

 

访问nginx-status页面得到的结果如下

Active connections: 1121 
server accepts handled requests
 1189 1189 1191 
Reading: 0 Writing: 7 Waiting: 42

 

结果说明:

active connections – 活跃的连接数量
server accepts handled requests — 总共处理了1189个连接 , 成功创建1189次握手, 总共处理了1191个请求
reading — 读取客户端的连接数.
writing — 响应数据到客户端的数量
waiting — 开启 keep-alive 的情况下,这个值等于 active – (reading+writing), 意思就是 Nginx 已经处理完正在等候下一次请求指令的驻留连接.

 

添加get_nginx_status.sh脚本(感谢krish@toonheart.com,直接拿来用了),客户端服务器上需要有curl环境

#!/bin/bash#
# Script to fetch nginx statuses for tribily monitoring systems
# Author: [email]krish@toonheart.com[/email]
# License: GPLv2
 
HOST=www.abc.com
PORT="80"
#webstatus=nginx-status

# Functions to return nginx stats

function active {
        /usr/bin/curl "http://$HOST:$PORT/nginx-status" 2>/dev/null| grep 'Active' | awk '{print $NF}' 
        } 

function reading {
        /usr/bin/curl "http://$HOST:$PORT/nginx-status" 2>/dev/null| grep 'Reading' | awk '{print $2}' 
        } 

function writing {
        /usr/bin/curl "http://$HOST:$PORT/nginx-status" 2>/dev/null| grep 'Writing' | awk '{print $4}' 
        } 

function waiting {
        /usr/in/curl "http://$HOST:$PORT/nginx-status" 2>/dev/null| grep 'Waiting' | awk '{print $6}' 
        } 

function accepts {
        /usr/bin/curl "http://$HOST:$PORT/nginx-status" 2>/dev/null| awk NR==3 | awk '{print $1}'
        } 

function handled {
        /usr/bin/curl "http://$HOST:$PORT/nginx-status" 2>/dev/null| awk NR==3 | awk '{print $2}'
        } 

function requests {
        /usr/bin/curl "http://$HOST:$PORT/nginx-status" 2>/dev/null| awk NR==3 | awk '{print $3}'
        }

# Run the requested function
$1

 

在zabbix客户端配置文件中Include目录/usr/local/zabbix_agent/conf/zabbix_agentd,并设置UnsafeUserParameters=1
在zabbix_agentd文件夹中添加文件userparameter_nginx.conf,内容如下:

UserParameter=nginx.accepts,/usr/local/zabbix_agent/bin/get_nginx_status.sh accepts
UserParameter=nginx.handled,/usr/local/zabbix_agent/bin/get_nginx_status.sh handled
UserParameter=nginx.requests,/usr/local/zabbix_agent/bin/get_nginx_status.sh requests
UserParameter=nginx.connections.active,/usr/local/zabbix_agent/bin/get_nginx_status.sh active
UserParameter=nginx.connections.reading,/usr/local/zabbix_agent/bin/get_nginx_status.sh reading
UserParameter=nginx.connections.writing,/usr/local/zabbix_agent/bin/get_nginx_status.sh writing
UserParameter=nginx.connections.waiting,/usr/local/zabbix_agent/bin/get_nginx_status.sh waiting

 

在zabbix前端导入nginx模板,内容如下

<zabbix_export version="1.0" date="14.03.11" time="08.48">
  
    
      <proxy_hostid>0
      1
      
      127.0.0.1
      10050
      3
      0
      <ipmi_ip>127.0.0.1
      <ipmi_port>623
      <ipmi_authtype>0
      <ipmi_privilege>2
      <ipmi_username>
      <ipmi_password>
      
        cy2009
      
      
      
        
          Nginx Accepts
          <ipmi_sensor>
          30
          365
          365
          0
          <data_type>0
          
          0
          0
          0
          0
          
          <delay_flex>
          0
          
          
          
          
          
          <trapper_hosts>localhost
          <snmp_community>
          <snmp_oid>
          <snmp_port>161
          <snmpv3_securityname>
          <snmpv3_securitylevel>0
          <snmpv3_authpassphrase>
          <snmpv3_privpassphrase>
          
            Nginx
          
        
        
          Nginx Connections Active
          <ipmi_sensor>
          30
          365
          365
          0
          <data_type>0
          
          0
          0
          0
          0
          
          <delay_flex>
          0
          
          
          
          
          
          <trapper_hosts>localhost
          <snmp_community>
          <snmp_oid>
          <snmp_port>161
          <snmpv3_securityname>
          <snmpv3_securitylevel>0
          <snmpv3_authpassphrase>
          <snmpv3_privpassphrase>
          
            Nginx
          
        
        
          Nginx Connections Reading
          <ipmi_sensor>
          30
          365
          365
          0
          <data_type>0
          
          0
          0
          0
          0
          
          <delay_flex>
          0
          
          
          
          
          
          <trapper_hosts>localhost
          <snmp_community>
          <snmp_oid>
          <snmp_port>161
          <snmpv3_securityname>
          <snmpv3_securitylevel>0
          <snmpv3_authpassphrase>
          <snmpv3_privpassphrase>
          
            Nginx
          
        
        
          Nginx Connections Waiting
          <ipmi_sensor>
          30
          365
          365
          0
          <data_type>0
          
          0
          0
          0
          0
          
          <delay_flex>
          0
          
          
          
          
          
          <trapper_hosts>localhost
          <snmp_community>
          <snmp_oid>
          <snmp_port>161
          <snmpv3_securityname>
          <snmpv3_securitylevel>0
          <snmpv3_authpassphrase>
          <snmpv3_privpassphrase>
          
            Nginx
          
        
        
          Nginx Connections Writing
          <ipmi_sensor>
          30
          365
          365
          0
          <data_type>0
          
          0
          0
          0
          0
          
          <delay_flex>
          0
          
          
          
          
          
          <trapper_hosts>localhost
          <snmp_community>
          <snmp_oid>
          <snmp_port>161
          <snmpv3_securityname>
          <snmpv3_securitylevel>0
          <snmpv3_authpassphrase>
          <snmpv3_privpassphrase>
          
            Nginx
          
        
        
          Nginx Handled
          <ipmi_sensor>
          30
          365
          365
          0
          <data_type>0
          
          0
          0
          0
          0
          
          <delay_flex>
          0
          
          
          
          
          
          <trapper_hosts>localhost
          <snmp_community>
          <snmp_oid>
          <snmp_port>161
          <snmpv3_securityname>
          <snmpv3_securitylevel>0
          <snmpv3_authpassphrase>
          <snmpv3_privpassphrase>
          
            Nginx
          
        
        
          Nginx Requests
          <ipmi_sensor>
          30
          365
          365
          0
          <data_type>0
          
          0
          0
          0
          0
          
          <delay_flex>
          0
          
          
          
          
          
          <trapper_hosts>localhost
          <snmp_community>
          <snmp_oid>
          <snmp_port>161
          <snmpv3_securityname>
          <snmpv3_securitylevel>0
          <snmpv3_authpassphrase>
          <snmpv3_privpassphrase>
          
            Nginx
          
        
      
      
      
        
          <ymin_type>0
          <ymax_type>0
          <ymin_item_key>
          <ymax_item_key>
          <show_work_period>1
          <show_triggers>1
          0
          0.0000
          100.0000
          <show_legend>0
          <show_3d>0
          <percent_left>0.0000
          <percent_right>0.0000
          <graph_elements>
            <graph_element item="Nginx Status:nginx.accepts">
              0
              0
              00EE00
              0
              <calc_fnc>2
              0
              <periods_cnt>5
            
            <graph_element item="Nginx Status:nginx.handled">
              0
              0
              EE0000
              0
              <calc_fnc>2
              0
              <periods_cnt>5
            
            <graph_element item="Nginx Status:nginx.requests">
              0
              1
              EEEE00
              0
              <calc_fnc>2
              0
              <periods_cnt>5
            
          
        
        
          <ymin_type>0
          <ymax_type>0
          <ymin_item_key>
          <ymax_item_key>
          <show_work_period>1
          <show_triggers>1
          0
          0.0000
          100.0000
          <show_legend>0
          <show_3d>0
          <percent_left>0.0000
          <percent_right>0.0000
          <graph_elements>
            <graph_element item="Nginx Status:nginx.connections.active">
              0
              0
              0000EE
              0
              <calc_fnc>2
              0
              <periods_cnt>5
            
            <graph_element item="Nginx Status:nginx.connections.writing">
              0
              1
              EE0000
              0
              <calc_fnc>2
              0
              <periods_cnt>5
            
            <graph_element item="Nginx Status:nginx.connections.waiting">
              0
              2
              EEEE00
              0
              <calc_fnc>2
              0
              <periods_cnt>5
            
            <graph_element item="Nginx Status:nginx.connections.reading">
              0
              3
              00EE00
              0
              <calc_fnc>2
              0
              <periods_cnt>5

 

然后在zabbix前端为主机链接nginx status模板即可。

安装zabbix2.2.5+php5.5+mysql5.5.9+nginx1.5.1

先安装php,nginx和mysql
php编译参数:

./configure \
–prefix=/usr/local/php5 \
–with-bz2 \
–with-curl \
–enable-ftp \
–enable-sockets \
–enable-bcmath \
–disable-ipv6 \
–with-gd \
–with-jpeg-dir=/usr/local \
–with-png-dir=/usr/local \
–with-freetype-dir=/usr/local \
–enable-gd-native-ttf \
–with-iconv-dir=/usr/local \
–enable-mbstring \
–enable-calendar \
–with-gettext \
–with-libxml-dir=/usr/local \
–with-zlib \
–with-pdo-mysql=mysqlnd \
–with-mysqli=mysqlnd \
–with-mysql=mysqlnd \
–enable-dom \
–enable-xml \
–enable-fpm \
–with-libdir=lib64

 

php装好之后需要修改php.ini为以下值,以满足zabbix安装需要

max_execution_time = 300
memory_limit = 128M
post_max_size = 16M
upload_max_filesize = 2M
max_input_time = 300
date.timezone PRC

nginx编译参数

./configure –prefix=/usr/local/nginx –add-module=/usr/local/src/nginx_upstream_check_module-master –with-http_stub_status_module –with-http_ssl_module –with-http_realip_module –with-http_sub_module –with-http_gzip_static_module –with-http_flv_module –with-http_dav_module –with-http_spdy_module –with-pcre –with-debug

 
mysql安装略过 安装zabbix
注意:zabbix只使用普通用户运行,如果在root环境下运行zabbix,那么zabbix将会主动使用zabbix用户来运行。

groupadd zabbix&&useradd -g zabbix zabbix
cd /usr/local/src/
wget http://jaist.dl.sourceforge.net/project/zabbix/ZABBIX%20Latest%20Stable/2.2.5/zabbix-2.2.5.tar.gz
tar -zxvf zabbix-2.2.5.tar.gz
cd /usr/local/src/zabbix-2.2.5
./configure –prefix=/usr/local/zabbix/ –enable-server –enable-agent –with-mysql –with-net-snmp –with-libcurl –with-libxml2
make&&make install

 

复制前端文件到主目录

cp -r /usr/local/src/zabbix-2.2.5/frontends/php/* /usr/local/nginx/html/zabbix/

 

修改nginx虚拟主机配置

server {
        listen       80;
        server_name  zabbix.abc.com;
        access_log  /usr/local/nginx/logs/zabbix.abc.com.log  main;

        index         index.html index.htm index.php;
        root         /usr/local/nginx/html/zabbix;

        location / {
                try_files $uri $uri/ /index.php?$args;
        }
        location ~ ^(.+.php)(.*)$ {
                fastcgi_split_path_info ^(.+.php)(.*)$;
                include fastcgi.conf;
                fastcgi_pass  127.0.0.1:9000;
                fastcgi_index index.php;
                fastcgi_param  PATH_INFO          $fastcgi_path_info;
        }
}

 
访问http://zabbix.abc.com开始配置

安装zabbix客户端

groupadd zabbix&&useradd -g zabbix zabbix
cd /usr/loca/src/
wget http://www.zabbix.com/downloads/2.2.5/zabbix_agents_2.2.5.linux2_6.amd64.tar.gz
mkdir /usr/local/zabbix_agent
tar -zxvf zabbix_agents_2.2.5.linux2_6.amd64.tar.gz -C /usr/local/zabbix_agent/
cd /usr/local/zabbix_agent/&&mkdir logs
chown -R zabbix:zabbix/usr/local/zabbix_agent

 

修改客户端配置文件

# vi /usr/local/zabbix_agent/conf/zabbix_agentd.conf

LogFile=/usr/local/zabbix_agent/logs/zabbix_agentd.log
Server=192.168.0.1
ServerActive=192.168.0.1
Hostname=Zabbix server

 

注意:Server和ServerActive都是指定zabbixserver的IP地址,Server是用来允许192.168.0.1来客户端取数据。而serverActive的192.168.0.1的意思是,客户端主动提交数据给服务器端 启动客户端

/usr/local/zabbix_agent/sbin/zabbix_agentd -c /usr/local/zabbix_agent/conf/zabbix_agentd.conf

检查是否正常启动

netstat -nlp|grep 10050

 

写一个客户端启动脚本链接到/etc/init.d/目录下

# more /etc/init.d/zabbix_agentd_srv
 
#!/bin/bash
# chkconfig: 345 20 80
# description: zabbix_agentd auto start-stop script.

case "$1" in

start)
echo "Starting zabbix_agentd ... "
/usr/local/zabbix_agent/sbin/zabbix_agentd -c /usr/local/zabbix_agent/conf/zabbix_agentd.conf
;;

stop)
echo "Stopping zabbix_agentd ... " 
/usr/bin/killall zabbix_agentd 
;;

restart)
$0 stop
sleep 2
$0 start
;;

*)
echo "Usage: $0 {start|stop|restart}" 
exit 1
esac

 

Nginx/LVS/HAProxy负载均衡软件的优缺点详解

PS:Nginx/LVS/HAProxy是目前使用最广泛的三种负载均衡软件,本人都在多个项目中实施过,参考了一些资料,结合自己的一些使用经验,总结一下。

一般对负载均衡的使用是随着网站规模的提升根据不同的阶段来使用不同的技术。具体的应用需求还得具体分析,如果是中小型的Web应用,比如日PV小于1000万,用Nginx就完全可以了;如果机器不少,可以用DNS轮询,LVS所耗费的机器还是比较多的;大型网站或重要的服务,且服务器比较多时,可以考虑用LVS。

一种是通过硬件来进行进行,常见的硬件有比较昂贵的F5和Array等商用的负载均衡器,它的优点就是有专业的维护团队来对这些服务进行维护、缺点就是花销太大,所以对于规模较小的网络服务来说暂时还没有需要使用;另外一种就是类似于Nginx/LVS/HAProxy的基于Linux的开源免费的负载均衡软件,这些都是通过软件级别来实现,所以费用非常低廉。

目前关于网站架构一般比较合理流行的架构方案:Web前端采用Nginx/HAProxy+Keepalived作负载均衡器;后端采用MySQL数据库一主多从和读写分离,采用LVS+Keepalived的架构。当然要根据项目具体需求制定方案。
下面说说各自的特点和适用场合。

Nginx的优点是:

1、工作在网络的7层之上,可以针对http应用做一些分流的策略,比如针对域名、目录结构,它的正则规则比HAProxy更为强大和灵活,这也是它目前广泛流行的主要原因之一,Nginx单凭这点可利用的场合就远多于LVS了。
2、Nginx对网络稳定性的依赖非常小,理论上能ping通就就能进行负载功能,这个也是它的优势之一;相反LVS对网络稳定性依赖比较大,这点本人深有体会;
3、Nginx安装和配置比较简单,测试起来比较方便,它基本能把错误用日志打印出来。LVS的配置、测试就要花比较长的时间了,LVS对网络依赖比较大。
3、可以承担高负载压力且稳定,在硬件不差的情况下一般能支撑几万次的并发量,负载度比LVS相对小些。
4、Nginx可以通过端口检测到服务器内部的故障,比如根据服务器处理网页返回的状态码、超时等等,并且会把返回错误的请求重新提交到另一个节点,不过其中缺点就是不支持url来检测。比如用户正在上传一个文件,而处理该上传的节点刚好在上传过程中出现故障,Nginx会把上传切到另一台服务器重新处理,而LVS就直接断掉了,如果是上传一个很大的文件或者很重要的文件的话,用户可能会因此而不满。
5、Nginx不仅仅是一款优秀的负载均衡器/反向代理软件,它同时也是功能强大的Web应用服务器。LNMP也是近几年非常流行的web架构,在高流量的环境中稳定性也很好。
6、Nginx现在作为Web反向加速缓存越来越成熟了,速度比传统的Squid服务器更快,可以考虑用其作为反向代理加速器。
7、Nginx可作为中层反向代理使用,这一层面Nginx基本上无对手,唯一可以对比Nginx的就只有lighttpd了,不过lighttpd目前还没有做到Nginx完全的功能,配置也不那么清晰易读,社区资料也远远没Nginx活跃。
8、Nginx也可作为静态网页和图片服务器,这方面的性能也无对手。还有Nginx社区非常活跃,第三方模块也很多。

Nginx的缺点是:
1、Nginx仅能支持http、https和Email协议,这样就在适用范围上面小些,这个是它的缺点。
2、对后端服务器的健康检查,只支持通过端口来检测,不支持通过url来检测。不支持Session的直接保持,但能通过ip_hash来解决。

LVS:使用Linux内核集群实现一个高性能、高可用的负载均衡服务器,它具有很好的可伸缩性(Scalability)、可靠性(Reliability)和可管理性(Manageability)。

LVS的优点是:
1、抗负载能力强、是工作在网络4层之上仅作分发之用,没有流量的产生,这个特点也决定了它在负载均衡软件里的性能最强的,对内存和cpu资源消耗比较低。
2、配置性比较低,这是一个缺点也是一个优点,因为没有可太多配置的东西,所以并不需要太多接触,大大减少了人为出错的几率。
3、工作稳定,因为其本身抗负载能力很强,自身有完整的双机热备方案,如LVS+Keepalived,不过我们在项目实施中用得最多的还是LVS/DR+Keepalived。
4、无流量,LVS只分发请求,而流量并不从它本身出去,这点保证了均衡器IO的性能不会收到大流量的影响。
5、应用范围比较广,因为LVS工作在4层,所以它几乎可以对所有应用做负载均衡,包括http、数据库、在线聊天室等等。

LVS的缺点是:
1、软件本身不支持正则表达式处理,不能做动静分离;而现在许多网站在这方面都有较强的需求,这个是Nginx/HAProxy+Keepalived的优势所在。
2、如果是网站应用比较庞大的话,LVS/DR+Keepalived实施起来就比较复杂了,特别后面有Windows Server的机器的话,如果实施及配置还有维护过程就比较复杂了,相对而言,Nginx/HAProxy+Keepalived就简单多了。

HAProxy的特点是:
1、HAProxy也是支持虚拟主机的。
2、HAProxy的优点能够补充Nginx的一些缺点,比如支持Session的保持,Cookie的引导;同时支持通过获取指定的url来检测后端服务器的状态。
3、HAProxy跟LVS类似,本身就只是一款负载均衡软件;单纯从效率上来讲HAProxy会比Nginx有更出色的负载均衡速度,在并发处理上也是优于Nginx的。
4、HAProxy支持TCP协议的负载均衡转发,可以对MySQL读进行负载均衡,对后端的MySQL节点进行检测和负载均衡,大家可以用LVS+Keepalived对MySQL主从做负载均衡。
5、HAProxy负载均衡策略非常多,HAProxy的负载均衡算法现在具体有如下8种:
① roundrobin,表示简单的轮询,这个不多说,这个是负载均衡基本都具备的;
② static-rr,表示根据权重,建议关注;
③ leastconn,表示最少连接者先处理,建议关注;
④ source,表示根据请求源IP,这个跟Nginx的IP_hash机制类似,我们用其作为解决session问题的一种方法,建议关注;
⑤ ri,表示根据请求的URI;
⑥ rl_param,表示根据请求的URl参数’balance url_param’ requires an URL parameter name;
⑦ hdr(name),表示根据HTTP请求头来锁定每一次HTTP请求;
⑧ rdp-cookie(name),表示根据据cookie(name)来锁定并哈希每一次TCP请求。

Nginx和LVS对比的总结:
1、Nginx工作在网络的7层,所以它可以针对http应用本身来做分流策略,比如针对域名、目录结构等,相比之下LVS并不具备这样的功能,所以Nginx单凭这点可利用的场合就远多于LVS了;但Nginx有用的这些功能使其可调整度要高于LVS,所以经常要去触碰触碰,触碰多了,人为出问题的几率也就会大。
2、Nginx对网络稳定性的依赖较小,理论上只要ping得通,网页访问正常,Nginx就能连得通,这是Nginx的一大优势!Nginx同时还能区分内外网,如果是同时拥有内外网的节点,就相当于单机拥有了备份线路;LVS就比较依赖于网络环境,目前来看服务器在同一网段内并且LVS使用direct方式分流,效果较能得到保证。另外注意,LVS需要向托管商至少申请多一个ip来做Visual IP,貌似是不能用本身的IP来做VIP的。要做好LVS管理员,确实得跟进学习很多有关网络通信方面的知识,就不再是一个HTTP那么简单了。
3、Nginx安装和配置比较简单,测试起来也很方便,因为它基本能把错误用日志打印出来。LVS的安装和配置、测试就要花比较长的时间了;LVS对网络依赖比较大,很多时候不能配置成功都是因为网络问题而不是配置问题,出了问题要解决也相应的会麻烦得多。
4、Nginx也同样能承受很高负载且稳定,但负载度和稳定度差LVS还有几个等级:Nginx处理所有流量所以受限于机器IO和配置;本身的bug也还是难以避免的。
5、Nginx可以检测到服务器内部的故障,比如根据服务器处理网页返回的状态码、超时等等,并且会把返回错误的请求重新提交到另一个节点。目前LVS中 ldirectd也能支持针对服务器内部的情况来监控,但LVS的原理使其不能重发请求。比如用户正在上传一个文件,而处理该上传的节点刚好在上传过程中出现故障,Nginx会把上传切到另一台服务器重新处理,而LVS就直接断掉了,如果是上传一个很大的文件或者很重要的文件的话,用户可能会因此而恼火。
6、Nginx对请求的异步处理可以帮助节点服务器减轻负载,假如使用apache直接对外服务,那么出现很多的窄带链接时apache服务器将会占用大 量内存而不能释放,使用多一个Nginx做apache代理的话,这些窄带链接会被Nginx挡住,apache上就不会堆积过多的请求,这样就减少了相当多的资源占用。这点使用squid也有相同的作用,即使squid本身配置为不缓存,对apache还是有很大帮助的。
7、Nginx能支持http、https和email(email的功能比较少用),LVS所支持的应用在这点上会比Nginx更多。在使用上,一般最前端所采取的策略应是LVS,也就是DNS的指向应为LVS均衡器,LVS的优点令它非常适合做这个任务。重要的ip地址,最好交由LVS托管,比如数据库的 ip、webservice服务器的ip等等,这些ip地址随着时间推移,使用面会越来越大,如果更换ip则故障会接踵而至。所以将这些重要ip交给 LVS托管是最为稳妥的,这样做的唯一缺点是需要的VIP数量会比较多。Nginx可作为LVS节点机器使用,一是可以利用Nginx的功能,二是可以利用Nginx的性能。当然这一层面也可以直接使用squid,squid的功能方面就比Nginx弱不少了,性能上也有所逊色于Nginx。Nginx也可作为中层代理使用,这一层面Nginx基本上无对手,唯一可以撼动Nginx的就只有lighttpd了,不过lighttpd目前还没有能做到 Nginx完全的功能,配置也不那么清晰易读。另外,中层代理的IP也是重要的,所以中层代理也拥有一个VIP和LVS是最完美的方案了。具体的应用还得具体分析,如果是比较小的网站(日PV小于1000万),用Nginx就完全可以了,如果机器也不少,可以用DNS轮询,LVS所耗费的机器还是比较多的;大型网站或者重要的服务,机器不发愁的时候,要多多考虑利用LVS。

现在对网络负载均衡的使用是随着网站规模的提升根据不同的阶段来使用不同的技术:

第一阶段:利用Nginx或HAProxy进行单点的负载均衡,这一阶段服务器规模刚脱离开单服务器、单数据库的模式,需要一定的负载均衡,但是仍然规模较小没有专业的维护团队来进行维护,也没有需要进行大规模的网站部署。这样利用Nginx或HAproxy就是第一选择,此时这些东西上手快, 配置容易,在七层之上利用HTTP协议就可以。这时是第一选择。

第二阶段:随着网络服务进一步扩大,这时单点的Nginx已经不能满足,这时使用LVS或者商用Array就是首要选择,Nginx此时就作为LVS或者Array的节点来使用,具体LVS或Array的是选择是根据公司规模和预算来选择,Array的应用交付功能非常强大,本人在某项目中使用过,性价比也远高于F5,商用首选!但是一般来说这阶段相关人才跟不上业务的提升,所以购买商业负载均衡已经成为了必经之路。

第三阶段:这时网络服务已经成为主流产品,此时随着公司知名度也进一步扩展,相关人才的能力以及数量也随之提升,这时无论从开发适合自身产品的定制,以及降低成本来讲开源的LVS,已经成为首选,这时LVS会成为主流。
最终形成比较理想的基本架构为:Array/LVS — Nginx/Haproxy — Squid/Varnish — AppServer

转自http://www.ha97.com/5646.html