-- nginx 反向代理 client 10.1.1.x nginx(虚拟机1) 10.1.1.7 web1(宿主机) web2(虚拟机2) 10.1.1.35:8000 10.1.1.9 第一步,安装nginx,过程可以和装lnmp时一模一样 # useradd nginx --我这里建立一个用户来跑nginx,不做也可以,它默认是用daemon用户来跑 # id nginx --nginx的uid,gid无所谓是多少 uid=517(nginx) gid=518(nginx) groups=518(nginx) # tar xf nginx-1.8.0.tar.gz -C /usr/src/ # cd /usr/src/nginx-1.8.0/ # ./configure --prefix=/usr/local/nginx --user=nginx --group=nginx --with-http_gzip_static_module --with-http_stub_status_module # make ;make install ----------------------------------------------------------- 如果在configure时报下面的错,表示默认使用了rewrite模块,需要用到pcre的库 ./configure: error: the HTTP rewrite module requires the PCRE library. You can either disable the module by using --without-http_rewrite_module option, or install the PCRE library into the system, or build the PCRE library statically from the source with nginx by using --with-pcre= option. 解决方法: 第一种: yum install pcre* --安装系统自带的pcre库文件就可以了 # ./configure --prefix=/usr/local/nginx --user=nginx --group=nginx --with-http_gzip_static_module --with-http_stub_status_module # make ;make install 第二种: 自己下载pcre的源码先编,再编译nginx用--with-pcre来指定pcre的源码路径就可以了 # ./configure --prefix=/usr/local/nginx --user=nginx --group=nginx --with-http_gzip_static_module --with-http_stub_status_module --with-pcre=/usr/src/pcre-7.9/ # make ;make install ----------------------------------------------------------------- --注意:下面这五个例子,是以静态页面来做测试,如果现在讨论动态页面(比如登录相关),下面的配置并不完整;并且这五个例子都是同网段做,如果换成双网段(后台web在内网)则会出现问题,需要使用后面综合例子里的proxy_set_header等指令来辅助 例一:使用前端nginx代理后面一台web client 10.1.1.x nginx 10.1.1.7 web1 10.1.1.35:8000 [root@li nginx]# cat /usr/local/nginx/conf/nginx.conf user nginx nginx; worker_processes 5; error_log logs/error.log info; pid logs/nginx.pid; events { use epoll; worker_connections 65535; } http { server { listen 80; server_name 10.1.1.7; root /nginxroot/; location /web1/ { proxy_pass http://10.1.1.35:8000/; } } } # mkdir /nginxroot/ # echo "nginx main page" > /nginxroot/index.html --启动 # ulimit -SHn 65535 # /usr/local/nginx/sbin/nginx --验证 找另一台客户端机器验证 # elinks 10.1.1.7 --得到10.1.1.7上nginx的主页 # elinks 10.1.1.7/web1/ --得到10.1.1.35上8000端口的web1主页 例二:使用前端nginx代理后端两台web,一个代理后台10的8000端口的web1,一个代理后台12的80端口的web2 client 10.1.1.x nginx 10.1.1.7:80 web1 web2 10.1.1.35:8000 10.1.1.9:80 # cat /usr/local/nginx/conf/nginx.conf user nginx nginx; worker_processes 5; error_log logs/error.log info; pid logs/nginx.pid; events { worker_connections 65535; use epoll; } http { server { listen 80; server_name 10.1.1.7; root /nginxroot/; location /web1/ { proxy_pass http://10.1.1.35:8000/; } location /web2/ { proxy_pass http://10.1.1.9/; } } } 重启 [root@li nginx]# /usr/local/nginx/sbin/nginx -s stop [root@li nginx]# /usr/local/nginx/sbin/nginx 验证 # elinks 10.1.1.7 # elinks 10.1.1.7/web1/ # elinks 10.1.1.7/web2/ 例三:基于文件类型的反向代理(可用于做动静分离) [root@li nginx]# cat conf/nginx.conf user nginx nginx; worker_processes 5; error_log logs/error.log info; pid logs/nginx.pid; events { use epoll; worker_connections 65535; } http { server { listen 80; server_name 10.1.1.7; root /nginxroot/; location /images/ { proxy_pass http://10.1.1.9/; --这里后面得加/ } location ~ \.(txt|php)$ { proxy_pass http://10.1.1.35:8000; --这里后面不能加/ } } } --这里是做的七层代理,上面的配置表示访问10.1.1.7/images/时会调给后面的10.1.1.9的80端口;访问任何以.txt或.php结尾的文件时会调给10.1.1.35的8000端口;其它的由10.1.1.7的nginx自己解析 重启 (省略) 验证 (省略) 例四:代理后端时使用负载均衡 # cat /usr/local/nginx/conf/nginx.conf user nginx nginx; worker_processes 5; error_log logs/error.log info; pid logs/nginx.pid; events { worker_connections 65535; use epoll; } http { upstream backendweb { server 10.1.1.35:8000 weight=1 max_fails=2 fail_timeout=1s; server 10.1.1.9:80 weight=1 max_fails=2 fail_timeout=1s; } server { listen 80; server_name 10.1.1.7; root /nginxroot/; location ~ \.(txt|php)$ { proxy_pass http://backendweb; } } } --上面配置的意思是:.txt或.php结尾的文件都去均衡的调度给35的8000端口和12的80端口;其它的由11的nginx自己解析 --upstream指令不要加到http {} 外面,也不要加到server{}里面 重启 (省略) 验证 (省略) --验证时,会发现客户端针对同一个URL的访问也会一次web1一次web2,这说明nginx默认并没有squid或varnish那样的缓存功能 例五:使用ip_hash,实现同一IP客户端一旦调到一台,就一直调那一台 # cat /usr/local/nginx/conf/nginx.conf user nginx nginx; worker_processes 8; error_log logs/error.log info; pid logs/nginx.pid; events { worker_connections 65535; use epoll; } http { upstream backendweb { ip_hash; --加上这句 server 10.1.1.35:8000 weight=1 max_fails=2 fail_timeout=1s; server 10.1.1.9:80 weight=1 max_fails=2 fail_timeout=1s; } server { listen 80; server_name 10.1.1.7; root /nginxroot/; location ~ \.(txt|php)$ { proxy_pass http://backendweb; } } } --nginx的ip_hash的意思是,如果一个客户端的访问被调度到其中一台后台服务器,那么同一个IP来的访问都只会被调到这个后台服务器;这里测试时,如果都用同一个网段的内网IP来做客户端测试,可能会都只转到一个后台(因为nginx的hash算法是按网段来算的,如果是公网不同网段的客户端IP就不一样了) 重启 (省略) 验证 (省略) 对于nginx的upstrem算法总结: 1,round-robin 轮循(平均分配) 2,weight 权重(人为地分配权重,用于后台服务器性能不均的情况) 3,fair 响应时间(按后台的响应时间来分配,需要第三模块,但如果后台服务器都在内网,就没太大必要使用这种算法了) 4,url_hash 按访问url的hash结果来分配请求,使每个url定向到同一个后端服务器,后端服务器为多台缓存时比较有效,提高缓存命中率 5,ip_hash =================================================================== client 1.1.1.129 | | 1.1.1.128 nginx 反向代理 | 10.1.1.7 | ----------- | | 命中 hit 直接返回 动态程序文件.php | | | squid或varnish(web加速,缓存静态文件或图片) 直接找web | | ---- | 没命中 miss 找后端web去取 | | 10.1.1.9 lnmp <---- | 10.1.1.35:8000 li.cluster.com 实验前准备: 1,互相都在/etc/hosts里加主机名和IP的对应(三步) 下面我以squid机器的主机名配置为例 # hostname squid.cluster.com --马上生效,临时修改 # vim /etc/sysconfig/network NETWORKING=yes HOSTNAME=squid.cluster.com --改在这里,重启仍然生效 # vim /etc/hosts --在这个文件,绑定架构里所有的机器的IP和主机名的对应,但不要修改默认的最前面的两行 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 10.1.1.35 li.cluster.com 10.1.1.9 squid.cluster.com 10.1.1.7 nginx.cluster.com 2,时间同步 在宿主机上搭建简单的内网时间同步服务器 # yum install xinetd -y # vim /etc/xinetd.d/time-stream disable = no --yes改为no # vim /etc/xinetd.d/time-dgram disable = no --yes改为no # /etc/init.d/xinetd restart # chkconfig xinetd on # netstat -ntlup |grep :37 --端口为37 tcp 0 0 :::37 :::* LISTEN 28330/xinetd udp 0 0 :::37 :::* 28330/xinetd 所有的需要同步时间的机器都使用下面的命令同步宿主机 (还可以放到crontab时间任务里周期性同步) rdate -s 10.1.1.35 3,关闭iptables和selinux # iptable -F # iptables -t nat -F # iptables -t mangle -F # /etc/init.d/iptables save # chkconfig iptables on # setenforce 0 --让selinux由enforcing强制模式改为Permissive警告模式,临时生效 # vim /etc/sysconfig/selinux SELINUX=disabled --由enforcing改为disabled,那么重启机器后,selinux就会被永久关闭 4, 配置好yum 省略 第一大步:在上图中的lnmp上安装并配置后面的网站 把上次课的lnmp启动 (过程省略) 第二大步:在上图中的squid服务器上安装并配置squid 1,安装squid # yum install squid* -y 2,配置squid主配置文件 # vim /etc/squid/squid.conf http_access allow all --修改成允许所有 http_port 3128 accel vhost vport --修改成支持反向代理模式,端口不一定要改为80,因为我这个web架构,最前端的是nginx cache_dir ufs /var/spool/squid 256 16 256 --打开缓存目录的定义这一句 cache_peer 10.1.1.35 parent 8000 0 no-query originserver name=web cache_peer_domain web web.cluster.com --web.cluster.com就是我现在模拟的整个网站架构的域名 cache_peer_domain web 1.1.1.128 --加上这三句,表示代理后台的lnmp的8000端口;web.cluster.com为网站的域名,1.1.1.128为我这个架构最前端的nginx的IP 3,启动squid # /etc/init.d/squid restart 第三大步:在上图中的nginx服务器上安装并配置nginx 1,安装nginx 省略 2,配置nginx [root@nginx ~]# vim /usr/local/nginx/conf/nginx.conf user nginx nginx; worker_processes 8; error_log logs/error.log info; pid logs/nginx.pid; events { worker_connections 65535; 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"'; sendfile on; tcp_nopush on; keepalive_timeout 65; gzip on; upstream squid { server 10.1.1.9:3128 weight=1 max_fails=2 fail_timeout=3s; } upstream web { server 10.1.1.35:8000 weight=1 max_fails=2 fail_timeout=3s; } server { listen 80; server_name 1.1.1.128; access_log logs/access.log main; location ~ .*\.php$ { proxy_pass http://web; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $remote_addr; } location ~ .*\.(html|htm|gif|jpeg|jpg|css|js|png|swf)$ { proxy_pass http://squid; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $remote_addr; } location / { proxy_pass http://web; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $remote_addr; } } } --说明:下面这两句是做外网转内网双网段架构必需要加的 proxy_set_header Host $host; proxy_set_header X-Forwarded-For $remote_addr; 3,启动nginx # ulimit -SHn 65535 # /usr/local/nginx/sbin/nginx -s stop # /usr/local/nginx/sbin/nginx 第四大步:验证 在客户端机器1.1.1.129上首先绑定静态DNS --用于模拟DNS,如果不绑定,也可以直接使用公网IP1.1.1.128来访问,因为在squid里配置了(cache_peer_domain web web.cluster.com 和 cache_peer_domain web 1.1.1.128 两句) cat /etc/hosts 1.1.1.128 web.cluster.com --IP要为前端nginx的IP,名字为这个网站的域名要和squid里的cache_peer_domain web web.cluster.com要对应 1,在客户端用firefox访问http://web.cluster.com/或http://1.1.1.128/是可以正常看到我的lnmp的8000端口安装的discuz论坛 2,在客户端使用下面的命令验证discuz论坛的一个logo,可以看到在squid上命中的信息 # curl -I http://web.cluster.com/static/image/common/logo.png HTTP/1.1 200 OK Server: nginx/1.8.0 Date: Mon, 23 Nov 2015 08:10:09 GMT Content-Type: image/png Content-Length: 4425 Connection: keep-alive Last-Modified: Tue, 09 Jun 2015 02:21:12 GMT ETag: "55764d98-1149" Accept-Ranges: bytes Age: 3227 X-Cache: HIT from squid.cluster.com X-Cache-Lookup: HIT from squid.cluster.com:3128 Via: 1.0 squid.cluster.com (squid/3.1.10) 3,关闭squid,在客户端用firefox访问,会发现整个网站都没有图片(静态的元素) 用curl -I http://web.cluster.com/static/image/common/logo.png来验证也会报错 因为我的架构里只有一台squid,再次启动squid后,一切又恢复正常 4,在squid配置文件里加上 # vim /etc/squid/squid.conf maximum_object_size 600 KB --表示限制能缓存的文件最大大小为600k # /etc/init.d/squid stop # rm /var/spool/squid/* -rf --手动这样删除缓存 # squid -zX /var/spool/squid/ --再次创建缓存目录;当然这样清缓存肯定不是好方法 # /etc/init.d/squid start 先在lnmp服务器上dd创建两个文件一个大于600k,一个小于600k # dd if=/dev/zero of=test1.html bs=1k count=500 # dd if=/dev/zero of=test2.html bs=1k count=700 在客户端curl -I 接这两个文件的路径来测试,结果为大于600k的一直都是MISS(表示不缓存),小于600K的第一次MISS,之后都是HIT(表示缓存) 5,关于squid清缓存 # vim /etc/squid/squid.conf --可以加上下面这四句;要注意的是这四句不能随便乱放,要放到acl的最后一个默认定义的下面;在rhel6.5的rpm版里就是大概在28行后面 acl purge_admin src 127.0.0.1 10.1.1.9 acl purge method PURGE http_access allow purge_admin purge http_access deny all purge # /etc/init.d/squid restart 最基本的清除一条缓存的操作,必须要在10.1.1.9这台机器上执行 # squidclient -m PURGE -h 10.1.1.9 -p 3128 http://1.1.1.128/static/image/common/logo.png -- -h参数后只能接127.0.0.1或10.1.1.9;-p 3128是squid的监听端口;最后的路径就是客户端访问的路径 如果要批量清除squid,可以使用下面的脚本(你需要修改成自己对应的路径) vim /tmp/purge_squid.sh #!/bin/sh squidcache_path="/var/spool/squid/" squidclient_path="/usr/bin/squidclient" grep -a -r $1 $squidcache_path/* | strings | grep "http" | while read url do $squidclient_path -h 127.0.0.1 -m PURGE -p 3128 $url > /dev/null 2>&1 done --注意:脚本的squidcache_path修改成你对应的缓存目录,squidclient_path修改成squidclient命令的路径;-h 127.0.0.1是因为我做了acl限制的,所以只能在squid本机上清除 批量清除的方法: sh /tmp/purge_squid.sh .txt --表示清除所有的.txt结尾的缓存 sh /tmp/purge_squid.sh . --表示清除所有缓存 sh /tmp/purge_squid.sh /aaa/ --表示url里有/aaa/路径就清掉缓存 6,关于后台web日志的里的客户端访问IP都是前端代理的IP的解决 建议直接使用前端nginx的日志 DNS轮循 nginx代理1 nginx代理2 nginx nginx nginx nginx php(fastcgi) php(fastcgi) memcache memcache mysql mysql ====================================================================== 把上面架构图中的squid换成varnish client | | |------------| | | | varnish | | |------------| | | lnmp 1,停掉squid /etc/init.d/squid stop 2,安装varnish,这次使用rpm版 软件包路径如下(下载地址为http://repo.varnish-cache.org/redhat/varnish-4.0/el6/x86_64/varnish/和http://dl.fedoraproject.org/pub/epel/6Server/x86_64/) 软件包路径为笔记目录下/varnish_soft/ jemalloc-3.6.0-1.el6.x86_64.rpm varnish-4.0.3-1.el6.x86_64.rpm varnish-libs-4.0.3-1.el6.x86_64.rpm varnish-docs-4.0.3-1.el6.x86_64.rpm 安装顺序 # rpm -ivh jemalloc-3.6.0-1.el6.x86_64.rpm # rpm -ivh varnish-4.0.3-1.el6.x86_64.rpm varnish-libs-4.0.3-1.el6.x86_64.rpm varnish-docs-4.0.3-1.el6.x86_64.rpm 3,配置rpm版varnish # vim /etc/sysconfig/varnish 66 VARNISH_LISTEN_PORT=3128 --这是listen的端口,默认为6081,我这里改为3128,为了和前面的nginx调度的端口对应 # vim /etc/varnish/default.vcl --配置主配置文件如下 vcl 4.0; backend lnmp { .host = "10.1.1.35"; .port = "8000"; } acl purgers { "127.0.0.1"; "10.1.1.0"/24; } sub vcl_recv { if (req.method == "PURGE") { if (!client.ip ~ purgers) { return(synth(405,"Method not allowed")); } return(hash); } if (req.http.host ~ "web.cluster.com") { set req.backend_hint = lnmp ; } else { return(synth(404,"error domain name")); } } sub vcl_miss { return(fetch); } sub vcl_hit { if (req.method == "PURGE") { unset req.http.cookie; return(synth(200,"Purged")); } } sub vcl_backend_response { if (bereq.url ~ "\.(jpg|jpeg|gif|png)$") { set beresp.ttl = 1d; } if (bereq.url ~ "\.(html|css|js)$") { set beresp.ttl = 6h; } if (beresp.http.Set-Cookie) { return(deliver); } } sub vcl_deliver { if (obj.hits > 0) { set resp.http.X-Cache = "@_@ HIT from " + server.ip; } else { set resp.http.X-Cache = "@_@ oh,god,MISS"; } } 4,启动varnish服务 # /etc/init.d/varnish restart # lsof -i:3128 # lsof -i:6082 5,测试,客户端使用web.cluster.com这个域名来访问(不能使用IP,见varnish配置) ===================================================================== 在上面的架构中,把squid或varnish去掉,由nginx又做反向代理,又做缓存 nginx做缓存需要一个另外一个软件(ngx_cache_purge) 下载的网址为:http://labs.frickle.com/files/ngx_cache_purge-2.3.tar.gz 架构图,在上面做的基础上把squid或varnish去掉 client 1.1.1.129 | | 1.1.1.128 nginx 反向代理加缓存 | 10.1.1.7 | lnmp 10.1.1.35:8000 第一步: 先把squid或varnish停掉 再把刚做过的nginx给删除(因为需要重新编译) rm /usr/local/nginx/ -rf rm /usr/src/nginx-1.8.0/ -rf 重新解压,重新编译 软件包在笔记目录下/lnmp_soft/ nginx-1.8.0.tar.gz ngx_cache_purge-2.3.tar.gz tar xf nginx-1.8.0.tar.gz -C /usr/src/ tar xf ngx_cache_purge-2.3.tar.gz -C /usr/src/ cd /usr/src/nginx-1.8.0/ ./configure --prefix=/usr/local/nginx --user=nginx --group=nginx --with-http_gzip_static_module --with-http_stub_status_module --add-module=../ngx_cache_purge-2.3/ make make install --编译和以前几乎一样,只是多了一个--add-module=../ngx_cache_purge-2.3/参数,两个目录是同级目录(从编译的路径可以看出来) 第二步: 修改nginx主配置文件 vim /usr/local/nginx/conf/nginx.conf user nginx nginx; worker_processes 8; error_log logs/error.log info; pid logs/nginx.pid; events { worker_connections 65535; 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" "$upstream_cache_status"'; sendfile on; tcp_nopush on; keepalive_timeout 65; gzip on; proxy_temp_path /usr/local/nginx/proxy_temp_dir 1 2; proxy_cache_path /usr/local/nginx/proxy_cache_dir/cache levels=1:2 keys_zone=cache:100m inactive=1d max_size=10g; upstream web { server 10.1.1.35:8000 weight=1 max_fails=2 fail_timeout=30s; } server { listen 80; server_name 1.1.1.128; access_log logs/host.access.log main; location / { proxy_pass http://web; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $remote_addr; proxy_cache cache; proxy_cache_key $host$uri$is_args$args; proxy_cache_valid 200 304 10m; add_header X-Cache '$upstream_cache_status from $host'; expires 1d; } location ~ .*\.(php|cgi)$ { proxy_pass http://web; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $remote_addr; } } } 上面的配置参数说明 1、http段设置。 proxy_temp_path /usr/local/nginx/proxy_temp_dir; --设置临时目录 proxy_cache_path /usr/local/nginx/proxy_cache_dir/cache levels=1:2 keys_zone=cache:100m inactive=1d max_size=10g; --keys_zone=cache1:100m 表示这个zone名称为cache1,分配的内存大小为100MB --/usr/local/nginx/proxy_cache_dir/cache1 表示cache1这个zone的文件要存放的目录 --levels=1:2 表示缓存目录的第一级目录是1个字符,第二级目录是2个字符,即/usr/local/nginx/proxy_cache_dir/cache/a/1b这种形式 --inactive=1d 表示这个zone中的缓存文件如果在1天内都没有被访问,那么文件会被cache manager进程删除掉 --max_size=10g 表示这个zone的硬盘容量为10GB 2、server段设置 proxy_cache cache; --设置缓存共享内存区块,也就是keys_zone名称 proxy_cache_key $host$uri$is_args$args; --设置缓存key proxy_cache_valid 200 304 10m; --设置http状态码为200,304缓存时间为10分钟 add_header X-Cache '$upstream_cache_status from $host'; --$upstream_cache_status表示资源缓存的状态,有HIT MISS EXPIRED三种状态 expires 1d; --设置失期时间,为1天 保存主配置文件后,建立对应的缓存目录 mkdir /usr/local/nginx/proxy_cache_dir/cache -p ls /usr/local/nginx/proxy_cache_dir/cache 启动nginx /usr/local/nginx/sbin/nginx 第三大步: 客户端测试 1,使用下面的命令访问 # curl -I http://1.1.1.128/static/image/common/logo.png HTTP/1.1 200 OK Server: nginx/1.8.0 Date: Mon, 25 Aug 2014 18:36:33 GMT Content-Type: image/png Content-Length: 2511 Connection: keep-alive Last-Modified: Wed, 20 Mar 2013 02:19:36 GMT ETag: "51491cb8-9cf" Accept-Ranges: bytes Expires: Tue, 26 Aug 2014 18:36:33 GMT Cache-Control: max-age=86400 X-Cache: MISS from 10.2.2.11 --第一次MISS # curl -I http://1.1.1.128/static/image/common/logo.png HTTP/1.1 200 OK Server: nginx/1.8.0 Date: Mon, 25 Aug 2014 18:36:44 GMT Content-Type: image/png Content-Length: 2511 Connection: keep-alive Last-Modified: Wed, 20 Mar 2013 02:19:36 GMT ETag: "51491cb8-9cf" Expires: Tue, 26 Aug 2014 18:36:44 GMT Cache-Control: max-age=86400 X-Cache: HIT from 10.2.2.11 Accept-Ranges: bytes --第二次HIT 2,在客户端用户firefox访问http://10.2.2.11/,可以访问整个discuz论坛 在nginx上查看缓存目录,会看到很多子目录(缓存都在这些目录里) ls /usr/local/nginx/proxy_cache_dir/cache 0 1 2 3 5 6 7 9 a b d e f 3,nginx的缓存清除 在nginx服务器写一个脚本,如下 vim /tmp/purge_nginx_cache.sh #!/bin/bash cachedir=/usr/local/nginx/proxy_cache_dir/cache grep -ra $1 $cachedir |grep $1 | awk -F':' '{print $1,$3}'|while read cacheurl url do rm -rf $cacheurl echo "$url" done echo "缓存清除成功" 清除方法为 sh /tmp/purge_nginx_cache.sh .png$ --清除所有的.png结尾的缓存