nginx安装、编译和参数讲解
传统上基于进程或线程模型架构的web服务通过每个进程或每个线程处理并发连接请求,这势必会在网络I/O操作时产生阻塞,其另一个必然结果则是对内存或CPU的利用率低下。生成一个新的进程/线程需要实现备好其运行时环境,这包括为其分配堆内存和栈内存,以及为其创建新的执行上下文等。这些操作都需要占用CPU,而且过多的进程/线程还会带来线程抖动或频繁的上下文切换,系统性能也会由此进一步下降。
在设计的最初阶段,nginx的主要着眼点就是其高性能以及对物理计算资源的高密度利用,因此其采用了不同的架构模型,受启发于多中操作系统设计中基于“事件”的高级处理机制,nginx采用了模块化、时间驱动、异步、单线程及非阻塞设计的架构,并大量采用了多路复用及时间通知机制。在nginx中,连接请求由为数不多的几个仅包含一个线程的进程worker以高效的回环(run-loop)机制进行处理,而每个worker可以并行处理数千个的并发连接及请求。
如果负载以CPU密集型应用为主,如SSL或压缩应用,则worker数应与CPU数相同;如果负载以IO密集型为主,如相应大量内容给客户端,则worker数应该为CPU个数的1.5或2倍。
nginx会按需同时运行多个进程;一个主进程(master)和几个工作进程(worker),配置了缓存时还会有缓存加载器进程(cache loader)和缓存管理器进程(cache manager)等,所有进程均是仅含有一个进程,并主要通过“共享内存”的机制实现进程间通信,主进程以root用户身份运行,而worker、cache loader 和cache manager 均应以非特权用户身份运行。
主进程主要完成如下工作:
1.读取并验证配置信息;
2.创建、绑定及关闭套接字;
3.启动、终止及维护worker进程的个数;
4.无须终止服务而重新配置工作特性;
5.控制非中断式程序升级,启用新的二进制程序并在需要时回滚至老版本;
6.重新打开日志文件;
7.编译嵌入式perl脚本;
worker进程主要完成的任务包括:
1.接收、传入并处理来自客户端的连接;
2.提供反向代理及过滤功能;
3.nginx任何能完成的其他任务;
cache loader进程主要完成的任务包括:
1.检查缓存存储中的缓存对象;
2.使用缓存元数据建立内存数据库;
cache manager 进程的主要任务:
1.缓存的失效及过期检验;
Nginx的配置有着几个不同的上下文:main、http、server、upstream和location(还有实现邮件伴服务反向代理的mail)。配置语法的格式和定义方式遵循所谓的C风格,因此支持嵌套,还有着逻辑清晰并已于创建、阅读和维护等优势。
Nginx的代码是由一个核心和一系列的模块组成,核心主要用于提供web server的基本功能,以及web和mail反向代理的功能:还用于启用网络协议,创建必要的运行时环境以及确保不同的模块之间平滑地进行交互。不过,大多跟协议相关的功能和某引用特有的功能都是由nginx的模块实现的。这些功能模块大致可以分为事件模块、阶段性处理器、输出过滤器、变量处理器、协议、upstream和负载均衡几个类别,这些共同组成了nginx的http功能。事件模块主要用于提供OS独立的(不同操作系统 的事件机制有所不同)
事件通知机制如kqueue或epoll等,协议模块则负责实现nginx通过http、tls/ssl、smtp、pop3以及imap与对应的客户端建立会话。
用户请求过来了,先到达网卡,网卡将请求交给内核,内核将请求交给监听在80端口(套接字)上的应用程序(worker进程),worker进程发现请求通过连接建立,接入请求,分析发现用户请求是一个静态文件,然后进行系统调用(I/O),内核给用户进程准备缓冲空间,内核通过磁盘加载这个文件到缓冲当中。然后再将这个文件复制到进程自己的地址空间,然后这个程序就能封装一个小的报文(http响应首部),然后再将报文交给内核,由内核封装TCP首部,IP首部,最终响应给客户端。而sendfile机制就是省去了将静态文件交给用户空间这一步,直接再内核完成所有封装并响应给客户端,尽可能避免了数据拷贝操作。
user
group
worker
http {
server {
location {
}
}
}
mail {
}
1. 安装nginx
# 1.解决依赖关系
编译安装nginx需要实现需要安装开发包组“Development Tools”和“Development Libraries”.同时,还需要专门安装pcre-devel包:
yum -y install pcre-devel
# 2.安装
首先添加用户nginx,实现以运行ngnix服务进程:
# groupadd -r nginx
# useradd -r -g nginx nginx
接着开始编译和安装:
# ./configure --prefix=/usr \
--sbin-path=/usr/sbin/nginx \
--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/ \
--http-uwsgi-temp-path=/var/tmp/nginx/uwsgi/ \
--http-scgi-temp-path=/var/tmp/nginx/scgi \
--with-pcre \
--with-file-aio \
解释参数:
'''
./configure --prefix=/usr # 默认安装路径
--sbin-path=/usr/sbin/nginx #nginx自身的可执行路径
--conf-path=/etc/nginx/nginx.conf # 主配置文件路径,如果不存在,会自动创建,该路径下还有其他几个nginx相关的配置文件
--error-log-path=/var/log/nginx/error.log # 错误日志
--http-log-path=/var/log/nginx/access.log # 访问日志
--pid-path=/var/run/nginx/nginx.pid # 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 # 支持gzip压缩
--http-proxy-client-body-temp-path=/var/tmp/nginx/client/ # 请求报文的主体,除了http首部
--http-proxy-temp-path=/var/tmp/nginx/proxy/ # 代理目录
--http-fastcgi-temp-path=/var/tmp/nginx/fcgi/
--http-uwsgi-temp-path=/var/tmp/nginx/uwsgi/ # 如果不使用python框架,这个参数可以不启用
--http-scgi-temp-path=/var/tmp/nginx/scgi
--with-pcre=/usr
--with-file-aio
--with-http_image_filter_module # 实现图片过滤
使用 ./configure --help |less 查看具体都有哪些参数
'''
# make && make install
说明:如果想使用nginx的perl模块,可以通过为configure脚本添加 --with-http_perl_module选项来实现,但目前此模块仍处于实验性使用阶段,可能会再运行中出现以外,因此,其实现方式这里不再介绍。如果想使用基于nginx的cgi功能,也可以基于FCGI来实现,具体实现方法请参照网上的文档。
3.为nginx提供SysV init 脚本:
新建文件/etc/rc.d/init.d/nginx,内容如下:
#!/bin/bash
#
# nginx - this script starts and stops the nginx daemon
#
# chkconfig: - 85 15
# description: Nginx is an HTTP(S) server,HTTP(S) reverse \
# proxy and IMAP/POP3 proxy server
# processname: nginx
# config: /etc/nginx/nginx.conf
# config: /etc/sysconfig/nginx
# pidfile: /var/run/nginx.pid
# Source networking configuration.
. /etc/sysconfig/network
# Check that networking is up.
[ "$NETWORKING" = "no" ] && exit 0
nginx="/usr/sbin/nginx"
prog=$(basename $nginx)
NGINX_CONF_FILE="/etc/nginx/nginx.conf"
[ -f /etc/sysconfig/nginx ] && . /etc/sysconfig/nginx
lockfile=/var/lock/subsys/nginx
make_dirs() {
# make required directories
user=`$nginx -V 2>&1 | grep "configure arguments:" | sed 's/[^*]*--user=\([^ ]*\).*/\1/g' -`
options=`$nginx -v 2>&1 | grep 'configure arguments:'`
for opt in $options;do
if [ `echo $opt | grep '.*-temp-path'` ];then
value=`echo $opt | cut -d "=" -f 2`
if [ ! -d "$value" ];then
# echo "creating $value"
mkdir -p $value && chown -R $user $value
fi
fi
done
}
start() {
[ -x $nginx ] || exit 5
[ -f $NGINX_CONF_FILE ] || exit 6
make_dirs
echo -n $"Starting $prog:"
daemon $nginx -c $NGINX_CONF_FILE
retval=$?
echo
[ $retval -eq 0 ] && touch $lockfile
return $retval
}
stop() {
echo -n $"Stopping $prog:"
killproc $prog -QUIT
retval=$?
echo
[ $retval -eq 0 ] && rm -f $lockfile
return $retval
}
restart() {
configtest || return $?
stop
sleep 1
start
}
reload() {
configtest || return $?
echo -n $"Reloading $prog:"
killproc $nginx -hUP
RETVAL=$?
echo
}
force_reload() {
restart
}
configtest() {
$nginx -t -c $NGINX_CONF_FILE
}
rh_status() {
rh_status >/dev/null 2>&1
}
rh_status_q() {
rh_status >/dev/null 2>&1
}
case "$1" in
start)
rh_status_q && exit 0
$1
;;
stop)
rh_status_q || exit 0
$1
;;
restart|configtest)
$1
;;
reload)
rh_status_q || exit 7
$1
;;
force-reload)
force_reload
;;
status)
rh_status
;;
condrestart|try-restart)
rh_status_q || exit 0
;;
*)
echo $"Usage: $0 {start|stop|status|restart|condrestart|reload|force-reload|configtest}"
exit 2
esac
而后为此脚本赋予执行权限:
# chmod +x /etc/rc.d/init.d/nginx
添加至服务管理列表,并让其开机自动启动:
# chkconfig --add nginx
# chkconfig nginx on
而后就可以启动服务并测试了:
# service nginx start
二、安装mysql-5.5.28
1.准备一个逻辑卷,并将其挂载至特定目录即可,这里不再给出过程。
这里假设其逻辑卷的挂载目录为/mydata,而后需要创建/mydata/data目录作为mysql数据的存放目录。
2.新建用户以安全方式运行进程:
URI 路径:
http://www.baidu.com
location [ = | ~ | ~* | ^~ ] uri {...}
location URI {};
对当前路径及子路径下的所有对象都生效;
location = URI {};
精确匹配指定路径,不包括子路径,因此,只对当前资源生效;
location ~ URI {};
location ~* URI {};
模式匹配URI,此处的URI可使用正则表达式,~区分字符大小写,~*不区分字符大小写;
location ^~ URI {};
不使用正则表达式
location /bbs/ {
root /web;
index index.html index.htm;
auth_basic "Restricted Area.."; # 需要用户通过认证才能访问
auth_basic_user_file /etc/nginx/.users;
}
需要创建需要认证的账户名和密码
htpasswd -c -m /etc/nginx/.users tom # 第一次需要指定-c 创建.users文件,接下来的创建用户就不需要指定-c了
htpasswd -m /etc/nginx/.users jerry
nginx -s reload
Paxos算法
再网络拥塞控制领域,我们知道有个非常有名的算法叫做Nagle算法(Nagle algorithm),这是使用它的发明人John Nagle的名字来命名的,John Nagle 在1984年首次用这个算法来尝试解决福特汽车公司的网络拥塞问题(RFC 896),该问题的具体描述是:如果我们的应用程序一次产生1个字节的数据,而这个1个字节数据又以网络数据包的形式发送到远端服务器,那么就很容易导致网络由于太多的数据包而过载。比如,当用户使用Telnet连接到远程服务器时,每一次击键操作就会产生1个字节数据,进而发送出去一个数据包,所以,在典型情况下,传送一个只拥有1个字节有效数据的数据包,却要花费40个字节长包头(即IP头20字节+tcp头20字节)的额外开销,这种有效荷载(payload)利用率极其低下的情况被统称之为愚蠢窗口症候群(Silly Window Syndrome)。可以看到,这种情况对于轻负载的网络来说,可能还可以接受,但是对于重负载的网络而言,就极有可能承载不了而轻易的发生拥塞雍痪。针对上面提到的这个状况,Nagle算法的改进在于:如果发送端欲多次发送包含少量字符的数据包(一般情况下,后面同意称长度小于MSS的数据包为小包,与此相对,称长度等于MSS的数据包为大包,为了某些对比说明,还有中包,即长度比小包长,但又不是一个MSS的包),则发送端会先将第一个小包发送出去,而将后面到达的少量字符数据都缓存起来而不立即发送,直到收到接收端对前一个数据包报文段的ACK确认、或当前字符数据紧急数据,或者积攒到了一定数量的数据(比如缓存的字符数据已经到达数据包报文段的最大长度)等多种情况才将其组成一个较大的数据包发送出去。
TCP中的Nagle算法默认是启用的,但是它并不是适合任何情况,对于telnet或rlogin这样的远程登录应用的确比较合适(原本就是为此而设计),但是在某些应用场景下我们却又需要关闭它。
Nagle算法是指发送方发送的数据不会立即发出,而是先放在缓冲区,等缓存区满了再发出,发送完一批数据后,会等待接收方对这批数据的回应,然后再发送下一批数据。Nagle算法适用于发送方需要发送大批量数据,并且接收方会即使做出回应的场合,这种算法通过减少传输数据的次数来提高通信效率,如果发送方持续地发送小批量的数据,并且接受方不一定会立即发送响应数据,那么Nagle算法会使发送方运行很慢,对于GUI程序,如网络游戏程序(服务器需要实时跟踪客户端鼠标的移动),这个问题尤其突出,客户端鼠标位置改动的信息需要实时发送到服务器上,由于Nagle算法采用缓冲,大大减低了实时响应速度,导致客户程序运行很慢,这个时候就需要使用TCP_MODELAY选项。