Nginx负载均衡、页面缓存、读写分离等详解(转)

大纲

一、前言

二、环境准备

三、安装与配置Nginx

四、Nginx之反向代理

五、Nginx之负载均衡

六、Nginx之页面缓存

七、Nginx之URL重写

八、Nginx之读写分离

注,操作系统为 CentOS 6.4 x86_64 , Nginx 是版本是最新版的1.4.2,所以实验用到的软件请点击这里下载: http://yunpan.cn/QXIgqMmVmuZrm

 

一、前言

       在前面的几篇博文中我们主要讲解了Nginx作为Web服务器知识点,主要的知识点有nginx的理论详解、nginx作为web服务器的操作讲解、nginx作为LNMP架构的讲解,不清楚的博友可以回头看看,在这一篇博客中我们主要讲解, nginx的反向代理、负载均衡、缓存、URL重写以及读写分离详解。好了,下面我们来具体说一说。

二、环境准备

1. 操作系统

  • CentOS 6.4 x86_64

2.软件版本

  • Nginx 1.4.2

3.实验拓扑

注,实验拓扑见下文。

4.安装yum源

1
2
3
[[email protected] ~] # rpm -ivh http://download.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm
[[email protected] ~] # rpm -ivh http://download.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm
[[email protected] ~] # rpm -ivh http://download.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm

5.各节点时间同步

1
2
3
[[email protected] ~] # ntpdate 202.120.2.101
[[email protected] ~] # ntpdate 202.120.2.101
[[email protected] ~] # ntpdate 202.120.2.101

6.关闭防火墙与SELinux

1
2
3
4
5
6
7
8
9
10
11
12
[[email protected] ~] # service iptables stop
[[email protected] ~] # chkconfig iptables off 
[[email protected] ~] # getenforce 
Disabled
[[email protected] ~] # service iptables stop
[[email protected] ~] # chkconfig iptables off 
[[email protected] ~] # getenforce 
Disabled
[[email protected] ~] # service iptables stop
[[email protected] ~] # chkconfig iptables off 
[[email protected] ~] # getenforce 
Disabled

三、安装Nginx

1.解压

1
[[email protected] src] # tar xf nginx-1.4.2.tar.gz

2.新建nginx用户与组

1
2
3
4
[[email protected] src] # groupadd -g 108  -r nginx
[[email protected] src] # useradd -u 108 -r -g 108 nginx 
[[email protected] src] # id nginx 
uid=108(nginx) gid=108(nginx) 组=108(nginx)

3.准备编译配置文件

1
2
[[email protected] src] # yum install -y pcre-devel openssl-devel
[[email protected] nginx-1.4.2] # ./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

4.编译并安装

1
[[email protected] nginx-1.4.2] # make && make install

5.为nginx提供SysV init脚本

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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
[[email protected] ~] # cat /etc/init.d/nginx
#!/bin/sh 
# 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 function library. 
/etc/rc .d /init .d /functions 
# Source networking configuration. 
/etc/sysconfig/network 
# Check that networking is up. 
"$NETWORKING"  "no"  ] &&  exit 
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 
     [ -f $NGINX_CONF_FILE ] ||  exit 
     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 
     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() { 
     status $prog 
rh_status_q() { 
     rh_status > /dev/null  2>&1 
case  "$1"  in 
     start) 
         rh_status_q &&  exit 
         $1 
         ;; 
     stop) 
         rh_status_q ||  exit 
         $1 
         ;; 
     restart|configtest) 
         $1 
         ;; 
     reload) 
         rh_status_q ||  exit 
         $1 
         ;; 
     force-reload) 
         force_reload 
         ;; 
     status) 
         rh_status 
         ;; 
     condrestart|try-restart) 
         rh_status_q ||  exit 
             ;; 
     *) 
         echo  $ "Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload|configtest}" 
         exit 
esac

6.为此脚本赋予执行权限

1
[[email protected] ~] # chmod +x /etc/init.d/nginx

7.添加至服务管理列表,并让其开机自动启动

1
2
3
4
[[email protected] ~] # chkconfig --add nginx
[[email protected] ~] # chkconfig nginx on 
[[email protected] ~] # chkconfig nginx --list 
nginx              0:关闭    1:关闭    2:启用    3:启用    4:启用    5:启用    6:关闭

8.启动nginx

1
2
[[email protected] ~] # service nginx start
正在启动 nginx:                                           [确定]

9.查看一下端口

1
2
[[email protected] ~] # netstat -ntlp | grep :80
tcp        0      0 0.0.0.0:80                  0.0.0.0:*                   LISTEN      3889 /nginx

10.测试一下

Nginx负载均衡、页面缓存、读写分离等详解(转)_第1张图片

好了,Nginx安装与配置就到这里,下面我们来说一说Nginx的反向代理。

四、Nginx之反向代理

在配置nginx反向代理之间我们得先准备两台测试服务器,Web1与Web2。

1.安装httpd

1
2
[[email protected] ~] # yum install -y httpd
[[email protected] ~] # yum install -y httpd

2.提供测试页面

1
2
[[email protected] ~] # echo "

web1.test.com

" > /var/www/html/index.html
[[email protected] ~] # echo "

web2.test.com

" > /var/www/html/index.html

3.启动httpd服务

1
2
3
4
[[email protected] ~] # service httpd start
正在启动 httpd:                                           [确定]
[[email protected] ~] # service httpd start
正在启动 httpd:                                           [确定]

4.测试一下

Nginx负载均衡、页面缓存、读写分离等详解(转)_第2张图片

Nginx负载均衡、页面缓存、读写分离等详解(转)_第3张图片

5.简单说一下,正向代理与反向代理

(1).正向代理的概念

       正向代理,也就是传说中的代理,他的工作原理就像一个跳板,简单的说,我是一个用户,我访问不了某网站,但是我能访问一个代理服务器,这个代理服务器呢,他能访问那个我不能访问的网站,于是我先连上代理服务器,告诉他我需要那个无法访问网站的内容,代理服务器去取回来,然后返回给我。从网站的角度,只在代理服务器来取内容的时候有一次记录,有时候并不知道是用户的请求,也隐藏了用户的资料,这取决于代理告不告诉网站。

       结论就是,正向代理 是一个位于客户端和原始服务器(origin server)之间的服务器,为了从原始服务器取得内容,客户端向代理发送一个请求并指定目标(原始服务器),然后代理向原始服务器转交请求并将获得的内容返回给客户端。客户端必须要进行一些特别的设置才能使用正向代理。

(2).反向代理的概念

继续举例:    
       例用户访问  http://www.test.com/readme,但 www.test.com上并不存在readme页面,他是偷偷从另外一台服务器上取回来,然后作为自己的内容返回用户,但用户并不知情。这里所提到的  www.test.com 这个域名对应的服务器就设置了反向代理功能。

       结论就是,反向代理正好相反,对于客户端而言它就像是原始服务器,并且客户端不需要进行任何特别的设置。客户端向反向代理的命名空间(name-space)中的内容发送普通请求,接着反向代理将判断向何处(原始服务器)转交请求,并将获得的内容返回给客户端,就像这些内容原本就是它自己的一样。

(3).两者区别

用途上来讲:

       正向代理的典型用途是为在防火墙内的局域网客户端提供访问Internet的途径。正向代理还可以使用缓冲特性减少网络使用率。反向代理的典型用途是将防火墙后面的服务器提供给Internet用户访问。反向代理还可以为后端的多台服务器提供负载平衡,或为后端较慢的服务器提供缓冲服务。另外,反向代理还可以启用高级URL策略和管理技术,从而使处于不同web服务器系统的web页面同时存在于同一个URL空间下。

安全性来讲:

       正向代理允许客户端通过它访问任意网站并且隐藏客户端自身,因此你必须采取安全措施以确保仅为经过授权的客户端提供服务。反向代理对外都是透明的,访问者并不知道自己访问的是一个代理。

6.nginx 代理模块

http 代理官方中文文档: http://www.howtocn.org/nginx:nginx%E6%A8%A1% E5%9D%97%E5%8F%82%E8%80%83%E6%89%8B%E5%86%8C%E4%B8%AD%E6%96%87%E7%89%88:standardhttpmodules:httpproxy

说明:代理模块的指令有很多我这里只讲解重要的proxy_pass,想了解更多代理指令请参考官方中文文档。

这个模块可以转发请求到其他的服务器。 HTTP/1.0无法使用keepalive(后端服务器将为每个请求创建并且删除连接)。nginx为浏览器发送HTTP/1.1并为后端服务器发送HTTP/1.0,这样浏览器就可以为浏览器处理keepalive。     
如下例:

1
2
3
4
location / {
   proxy_pass        http: //localhost :8000;
   proxy_set_header  X-Real-IP  $remote_addr;
}

注意,当使用http proxy模块(甚至FastCGI),所有的连接请求在发送到后端服务器之前nginx将缓存它们,因此,在测量从后端传送的数据时,它的进度显示可能不正确。

实验拓扑:

Nginx负载均衡、页面缓存、读写分离等详解(转)_第4张图片

7.配置http反向代理

1
2
3
4
5
6
[[email protected] ~] # cd /etc/nginx/
[[email protected] nginx] # cp nginx.conf nginx.conf.bak #备份一个原配置文件
[[email protected] nginx] # vim nginx.conf
location / {
                proxy_pass      http: //192 .168.18.201;
        }

指令说明: proxy_pass

语法:proxy_pass  URL
默认值:no       
使用字段:location, location中的if字段       
这个指令设置被代理服务器的地址和被映射的URI,地址可以使用主机名或IP加端口号的形式,例如:proxy_pass  http://localhost:8000/uri/;

8.重新加载一下配置文件

1
2
3
4
[[email protected] ~] # service nginx reload
nginx: the configuration  file  /etc/nginx/nginx .conf syntax is ok
nginx: configuration  file  /etc/nginx/nginx .conf  test  is successful
重新载入 nginx:                                           [确定]

9.测试一下

Nginx负载均衡、页面缓存、读写分离等详解(转)_第5张图片

注,大家可以看到,当我们访问192.168.18.208时,被代理重新定向到Web1上。

10.查看一下Web服务器日志

1
2
3
4
5
6
7
8
9
10
11
[[email protected] ~] # tail /var/log/httpd/access_log
192.168.18.208 - - [04 /Sep/2013 :00:14:20 +0800]  "GET /favicon.ico HTTP/1.0"  404 289  "-"  "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.95 Safari/537.36"
192.168.18.208 - - [04 /Sep/2013 :00:14:20 +0800]  "GET / HTTP/1.0"  200 23  "-"  "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.95 Safari/537.36"
192.168.18.208 - - [04 /Sep/2013 :00:14:20 +0800]  "GET /favicon.ico HTTP/1.0"  404 289  "-"  "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.95 Safari/537.36"
192.168.18.138 - - [04 /Sep/2013 :00:14:45 +0800]  "GET / HTTP/1.1"  200 23  "-"  "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.95 Safari/537.36"
192.168.18.138 - - [04 /Sep/2013 :00:14:48 +0800]  "GET /favicon.ico HTTP/1.1"  404 289  "-"  "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.95 Safari/537.36"
192.168.18.208 - - [04 /Sep/2013 :00:14:55 +0800]  "GET /favicon.ico HTTP/1.0"  404 289  "-"  "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.95 Safari/537.36"
192.168.18.208 - - [04 /Sep/2013 :00:15:05 +0800]  "GET /favicon.ico HTTP/1.0"  404 289  "-"  "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.95 Safari/537.36"
192.168.18.208 - - [04 /Sep/2013 :00:15:13 +0800]  "GET /favicon.ico HTTP/1.0"  404 289  "-"  "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.95 Safari/537.36"
192.168.18.208 - - [04 /Sep/2013 :00:15:16 +0800]  "GET / HTTP/1.0"  200 23  "-"  "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.95 Safari/537.36"
192.168.18.208 - - [04 /Sep/2013 :00:15:16 +0800]  "GET /favicon.ico HTTP/1.0"  404 289  "-"  "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.95 Safari/537.36"

注,大家可以看到我们这里的客户的IP全是,nginx代理服务器的IP,并不是真实客户端的IP。下面我们修改一下,让日志的IP显示真实的客户端的IP。

11.修改nginx配置文件

 

1
2
3
4
location / {
         proxy_pass      http: //192 .168.18.201;
         proxy_set_header  X-Real-IP  $remote_addr;  #加上这一行
}

指令说明: proxy_set_header

语法:proxy_set_header header value 
默认值: Host and Connection 
使用字段:http, server, location 
这个指令允许将发送到被代理服务器的请求头重新定义或者增加一些字段。这个值可以是一个文本,变量或者它们的组合。proxy_set_header在指定的字段中没有定义时会从它的上级字段继承。

12.重新加载一下配置文件

1
2
3
4
[[email protected] ~] # service nginx reload
nginx: the configuration  file  /etc/nginx/nginx .conf syntax is ok
nginx: configuration  file  /etc/nginx/nginx .conf  test  is successful
重新载入 nginx:                                           [确定]

13.测试并查看日志

1
2
3
4
5
6
7
8
9
10
11
[[email protected] ~] # tail /var/log/httpd/access_log
192.168.18.208 - - [03 /Sep/2013 :16:26:18 +0800]  "GET / HTTP/1.0"  200 23  "-"  "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"
192.168.18.208 - - [03 /Sep/2013 :16:26:18 +0800]  "GET / HTTP/1.0"  200 23  "-"  "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"
192.168.18.208 - - [03 /Sep/2013 :16:26:18 +0800]  "GET / HTTP/1.0"  200 23  "-"  "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"
192.168.18.208 - - [03 /Sep/2013 :16:26:18 +0800]  "GET / HTTP/1.0"  200 23  "-"  "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"
192.168.18.208 - - [03 /Sep/2013 :16:26:18 +0800]  "GET / HTTP/1.0"  200 23  "-"  "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"
192.168.18.208 - - [03 /Sep/2013 :16:26:18 +0800]  "GET / HTTP/1.0"  200 23  "-"  "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"
192.168.18.208 - - [03 /Sep/2013 :16:26:18 +0800]  "GET / HTTP/1.0"  200 23  "-"  "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"
192.168.18.208 - - [03 /Sep/2013 :16:26:18 +0800]  "GET / HTTP/1.0"  200 23  "-"  "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"
192.168.18.208 - - [03 /Sep/2013 :16:26:18 +0800]  "GET / HTTP/1.0"  200 23  "-"  "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"
192.168.18.208 - - [03 /Sep/2013 :16:26:18 +0800]  "GET / HTTP/1.0"  200 23  "-"  "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"

注,大家可以看到日志记录的还是代理的IP,没有显示真实客户端的IP,为什么呢?我们来看一下httpd的配置文件。

14.查看并修改httpd配置文件

[[email protected] ~]# vim /etc/httpd/conf/httpd.conf

t5

注,大家可以这里记录日志的参数还是%h,下面我们修改一下参数。

t6

注,这是修改后的参数,将h%修改为%{X-Real-IP}i,好的下面我们再来测试一下。

15.重启并测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[[email protected] ~] # service httpd restart
停止 httpd:                                               [确定]
正在启动 httpd:                                           [确定]
[[email protected] ~] # tail /var/log/httpd/access_log
192.168.18.138 - - [03 /Sep/2013 :17:09:14 +0800]  "GET / HTTP/1.0"  200 23  "-"  "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"
192.168.18.138 - - [03 /Sep/2013 :17:09:14 +0800]  "GET / HTTP/1.0"  200 23  "-"  "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"
192.168.18.138 - - [03 /Sep/2013 :17:09:15 +0800]  "GET / HTTP/1.0"  200 23  "-"  "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"
192.168.18.138 - - [03 /Sep/2013 :17:09:15 +0800]  "GET / HTTP/1.0"  200 23  "-"  "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"
192.168.18.138 - - [03 /Sep/2013 :17:09:15 +0800]  "GET / HTTP/1.0"  200 23  "-"  "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"
192.168.18.138 - - [03 /Sep/2013 :17:09:15 +0800]  "GET / HTTP/1.0"  200 23  "-"  "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"
192.168.18.138 - - [03 /Sep/2013 :17:09:15 +0800]  "GET / HTTP/1.0"  200 23  "-"  "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"
192.168.18.138 - - [03 /Sep/2013 :17:09:15 +0800]  "GET / HTTP/1.0"  200 23  "-"  "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"
192.168.18.138 - - [03 /Sep/2013 :17:09:15 +0800]  "GET / HTTP/1.0"  200 23  "-"  "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"
192.168.18.138 - - [03 /Sep/2013 :17:09:15 +0800]  "GET / HTTP/1.0"  200 23  "-"  "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"

注,大家可以看到现在的日志里记录的IP地址就是真实的客户端地址了。好了,到这里Nginx代理后端一台服务器就演示到这里,下面我们继续说。

五、Nginx之负载均衡

注,大家可以看到,由于我们网站是发展初期,nginx只代理了后端一台服务器,但由于我们网站名气大涨访问的人越来越多一台服务器实在是顶不住,于是我们加了多台服务器,那么多台服务器又怎么配置代理呢,我们这里以两台服务器为案例,为大家做演示。

1.upstream 负载均衡模块说明

案例:

下面设定负载均衡的服务器列表。

1
2
3
4
5
6
7
8
9
10
11
12
upstream  test .net{
ip_hash;
server 192.168.10.13:80;
server 192.168.10.14:80  down;
server 192.168.10.15:8009  max_fails=3  fail_timeout=20s;
server 192.168.10.16:8080;
}
server {
   location / {
     proxy_pass  http: //test .net;
   }
}

       upstream是Nginx的HTTP Upstream模块,这个模块通过一个简单的调度算法来实现客户端IP到后端服务器的负载均衡。在上面的设定中,通过upstream指令指定了一个负载均衡器的名称test.net。这个名称可以任意指定,在后面需要用到的地方直接调用即可。

2.upstream 支持的负载均衡算法

Nginx的负载均衡模块目前支持4种调度算法,下面进行分别介绍,其中后两项属于第三方调度算法。  

  • 轮询(默认)。每个请求按时间顺序逐一分配到不同的后端服务器,如果后端某台服务器宕机,故障系统被自动剔除,使用户访问不受影响。Weight 指定轮询权值,Weight值越大,分配到的访问机率越高,主要用于后端每个服务器性能不均的情况下。

  • ip_hash。每个请求按访问IP的hash结果分配,这样来自同一个IP的访客固定访问一个后端服务器,有效解决了动态网页存在的session共享问题。

  • fair。这是比上面两个更加智能的负载均衡算法。此种算法可以依据页面大小和加载时间长短智能地进行负载均衡,也就是根据后端服务器的响应时间来分配请求,响应时间短的优先分配。Nginx本身是不支持fair的,如果需要使用这种调度算法,必须下载Nginx的upstream_fair模块。

  • url_hash。此方法按访问url的hash结果来分配请求,使每个url定向到同一个后端服务器,可以进一步提高后端缓存服务器的效率。Nginx本身是不支持url_hash的,如果需要使用这种调度算法,必须安装Nginx 的hash软件包。

3.upstream 支持的状态参数

在HTTP Upstream模块中,可以通过server指令指定后端服务器的IP地址和端口,同时还可以设定每个后端服务器在负载均衡调度中的状态。常用的状态有:      

  • down,表示当前的server暂时不参与负载均衡。

  • backup,预留的备份机器。当其他所有的非backup机器出现故障或者忙的时候,才会请求backup机器,因此这台机器的压力最轻。

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

  • fail_timeout,在经历了max_fails次失败后,暂停服务的时间。max_fails可以和fail_timeout一起使用。

注,当负载调度算法为ip_hash时,后端服务器在负载均衡调度中的状态不能是weight和backup。

4.实验拓扑

Nginx负载均衡、页面缓存、读写分离等详解(转)_第6张图片

5.配置nginx负载均衡

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[[email protected] ~] # vim /etc/nginx/nginx.conf
upstream webservers {
       server 192.168.18.201 weight=1;
       server 192.168.18.202 weight=1;
   }
   server {
       listen       80;
       server_name  localhost;
       #charset koi8-r;
       #access_log  logs/host.access.log  main;
       location / {
               proxy_pass      http: //webservers ;
               proxy_set_header  X-Real-IP  $remote_addr;
       }
}

注,upstream是定义在server{ }之外的,不能定义在server{ }内部。定义好upstream之后,用proxy_pass引用一下即可。

6.重新加载一下配置文件

1
2
3
4
[[email protected] ~] # service nginx reload
nginx: the configuration  file  /etc/nginx/nginx .conf syntax is ok
nginx: configuration  file  /etc/nginx/nginx .conf  test  is successful
重新载入 nginx:                                           [确定]

7.测试一下

Nginx负载均衡、页面缓存、读写分离等详解(转)_第7张图片

Nginx负载均衡、页面缓存、读写分离等详解(转)_第8张图片

注,大家可以不断的刷新浏览的内容,可以发现web1与web2是交替出现的,达到了负载均衡的效果。

8.查看一下Web访问服务器日志

Web1:

1
2
3
4
5
6
7
8
9
10
11
[[email protected] ~] # tail /var/log/httpd/access_log
192.168.18.138 - - [04 /Sep/2013 :09:41:58 +0800]  "GET / HTTP/1.0"  200 23  "-"  "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"
192.168.18.138 - - [04 /Sep/2013 :09:41:58 +0800]  "GET / HTTP/1.0"  200 23  "-"  "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"
192.168.18.138 - - [04 /Sep/2013 :09:41:59 +0800]  "GET / HTTP/1.0"  200 23  "-"  "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"
192.168.18.138 - - [04 /Sep/2013 :09:41:59 +0800]  "GET / HTTP/1.0"  200 23  "-"  "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"
192.168.18.138 - - [04 /Sep/2013 :09:42:00 +0800]  "GET / HTTP/1.0"  200 23  "-"  "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"
192.168.18.138 - - [04 /Sep/2013 :09:42:00 +0800]  "GET / HTTP/1.0"  200 23  "-"  "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"
192.168.18.138 - - [04 /Sep/2013 :09:42:00 +0800]  "GET / HTTP/1.0"  200 23  "-"  "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"
192.168.18.138 - - [04 /Sep/2013 :09:44:21 +0800]  "GET / HTTP/1.0"  200 23  "-"  "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"
192.168.18.138 - - [04 /Sep/2013 :09:44:22 +0800]  "GET / HTTP/1.0"  200 23  "-"  "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"
192.168.18.138 - - [04 /Sep/2013 :09:44:22 +0800]  "GET / HTTP/1.0"  200 23  "-"  "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"

Web2:

先修改一下,Web服务器记录日志的格式。

1
2
3
4
5
[[email protected] ~] # vim /etc/httpd/conf/httpd.conf
LogFormat  "%{X-Real-IP}i %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\""  combined
[[email protected] ~] # service httpd restart
停止 httpd:                                               [确定]
正在启动 httpd:                                           [确定]

接着,再访问多次,继续查看日志。

1
2
3
4
5
6
7
8
9
10
11
[[email protected] ~] # tail /var/log/httpd/access_log
192.168.18.138 - - [04 /Sep/2013 :09:50:28 +0800]  "GET / HTTP/1.0"  200 23  "-"  "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"
192.168.18.138 - - [04 /Sep/2013 :09:50:28 +0800]  "GET / HTTP/1.0"  200 23  "-"  "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"
192.168.18.138 - - [04 /Sep/2013 :09:50:28 +0800]  "GET / HTTP/1.0"  200 23  "-"  "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"
192.168.18.138 - - [04 /Sep/2013 :09:50:28 +0800]  "GET / HTTP/1.0"  200 23  "-"  "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"
192.168.18.138 - - [04 /Sep/2013 :09:50:28 +0800]  "GET / HTTP/1.0"  200 23  "-"  "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"
192.168.18.138 - - [04 /Sep/2013 :09:50:28 +0800]  "GET / HTTP/1.0"  200 23  "-"  "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"
192.168.18.138 - - [04 /Sep/2013 :09:50:28 +0800]  "GET / HTTP/1.0"  200 23  "-"  "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"
192.168.18.138 - - [04 /Sep/2013 :09:50:28 +0800]  "GET / HTTP/1.0"  200 23  "-"  "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"
192.168.18.138 - - [04 /Sep/2013 :09:50:29 +0800]  "GET / HTTP/1.0"  200 23  "-"  "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"
192.168.18.138 - - [04 /Sep/2013 :09:50:29 +0800]  "GET / HTTP/1.0"  200 23  "-"  "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"

注,大家可以看到,两台服务器日志都记录是192.168.18.138访问的日志,也说明了负载均衡配置成功。

9.配置nginx进行健康状态检查

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

  • fail_timeout,在经历了max_fails次失败后,暂停服务的时间。max_fails可以和fail_timeout一起使用,进行健康状态检查。

1
2
3
4
5
[[email protected] ~] # vim /etc/nginx/nginx.conf
upstream webservers {
         server 192.168.18.201 weight=1 max_fails=2 fail_timeout=2;
         server 192.168.18.202 weight=1 max_fails=2 fail_timeout=2;
     }

10.重新加载一下配置文件

1
2
3
4
[[email protected] ~] # service nginx reload
nginx: the configuration  file  /etc/nginx/nginx .conf syntax is ok
nginx: configuration  file  /etc/nginx/nginx .conf  test  is successful
重新载入 nginx:                                           [确定]

11.停止服务器并测试

1
2
3
先停止Web1,进行测试。
[[email protected] ~] # service httpd stop
停止 httpd:                                               [确定]

Nginx负载均衡、页面缓存、读写分离等详解(转)_第9张图片

注,大家可以看到,现在只能访问Web2,再重新启动Web1,再次访问一下。

1
2
[[email protected] ~] # service httpd start
正在启动 httpd:                                           [确定]

Nginx负载均衡、页面缓存、读写分离等详解(转)_第10张图片

Nginx负载均衡、页面缓存、读写分离等详解(转)_第11张图片

注,大家可以看到,现在又可以重新访问,说明nginx的健康状态查检配置成功。但大家想一下,如果不幸的是所有服务器都不能提供服务了怎么办,用户打开页面就会出现出错页面,那么会带来用户体验的降低,所以我们能不能像配置LVS是配置sorry_server呢,答案是可以的,但这里不是配置sorry_server而是配置backup。

12.配置backup服务器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[[email protected] ~] # vim /etc/nginx/nginx.conf
server {
                 listen 8080;
                 server_name localhost;
                 root  /data/www/errorpage ;
                 index index.html;
         }
upstream webservers {
         server 192.168.18.201 weight=1 max_fails=2 fail_timeout=2;
         server 192.168.18.202 weight=1 max_fails=2 fail_timeout=2;
         server 127.0.0.1:8080 backup;
     }
[[email protected] ~] # mkdir -pv /data/www/errorpage
[[email protected] errorpage] # cat index.html

Sorry......< /h1 >

13.重新加载配置文件

1
2
3
4
[[email protected] errorpage] # service nginx reload
nginx: the configuration  file  /etc/nginx/nginx .conf syntax is ok
nginx: configuration  file  /etc/nginx/nginx .conf  test  is successful
重新载入 nginx:                                           [确定]

14.关闭Web服务器并进行测试

1
2
3
4
[[email protected] ~] # service httpd stop
停止 httpd:                                               [确定]
[[email protected] ~] # service httpd stop
停止 httpd:                                               [确定]

Nginx负载均衡、页面缓存、读写分离等详解(转)_第12张图片

注,大家可以看到,当所有服务器都不能工作时,就会启动备份服务器。好了,backup服务器就配置到这里,下面我们来配置ip_hash负载均衡。

15.配置ip_hash负载均衡

  • ip_hash,每个请求按访问IP的hash结果分配,这样来自同一个IP的访客固定访问一个后端服务器,有效解决了动态网页存在的session共享问题。(一般电子商务网站用的比较多)

1
2
3
4
5
6
7
[[email protected] ~] # vim /etc/nginx/nginx.conf
upstream webservers {
         ip_hash;
         server 192.168.18.201 weight=1 max_fails=2 fail_timeout=2;
         server 192.168.18.202 weight=1 max_fails=2 fail_timeout=2;
         #server 127.0.0.1:8080 backup;
     }

注,当负载调度算法为ip_hash时,后端服务器在负载均衡调度中的状态不能有backup。(有人可能会问,为什么呢?大家想啊,如果负载均衡把你分配到backup服务器上,你能访问到页面吗?不能,所以了不能配置backup服务器)

16.重新加载一下服务器

1
2
3
4
[[email protected] ~] # service nginx reload
nginx: the configuration  file  /etc/nginx/nginx .conf syntax is ok
nginx: configuration  file  /etc/nginx/nginx .conf  test  is successful
重新载入 nginx:                                           [确定]

17.测试一下

Nginx负载均衡、页面缓存、读写分离等详解(转)_第13张图片

注,大家可以看到,你不断的刷新页面一直会显示的民Web2,说明ip_hash负载均衡配置成功。下面我们来统计一下Web2的访问连接数。

18.统计Web2的访问连接数

1
2
[[email protected] ~] # netstat -an | grep :80 | wc -l
304

注,你不断的刷新,连接数会越来越多。好了,nginx的负载均衡就全部演示到这里下面我们来说一说,页面缓存。

六、Nginx之页面缓存

1.指令说明

proxy_cache_path

语法:proxy_cache_path path [levels=number] keys_zone=zone_name:zone_size [inactive=time] [max_size=size];  
默认值:None  
使用字段:http  
指令指定缓存的路径和一些其他参数,缓存的数据存储在文件中,并且使用代理url的哈希值作为关键字与文件名。levels参数指定缓存的子目录数,例如:

1
proxy_cache_path   /data/nginx/cache   levels=1:2   keys_zone=one:10m;

文件名类似于:

1
/data/nginx/cache/c/29/b7f54b2df7773722d382f4809d65029c

levels指定目录结构,可以使用任意的1位或2位数字作为目录结构,如 X, X:X,或X:X:X 例如: “2”, “2:2”, “1:1:2“,但是最多只能是三级目录。  
所有活动的key和元数据存储在共享的内存池中,这个区域用keys_zone参数指定。one指的是共享池的名称,10m指的是共享池的大小。  
注意每一个定义的内存池必须是不重复的路径,例如:

1
2
3
proxy_cache_path   /data/nginx/cache/one     levels=1      keys_zone=one:10m;
proxy_cache_path   /data/nginx/cache/two     levels=2:2    keys_zone=two:100m;
proxy_cache_path   /data/nginx/cache/three   levels=1:1:2  keys_zone=three:1000m;

如果在inactive参数指定的时间内缓存的数据没有被请求则被删除,默认inactive为10分钟。一个名为cache manager的进程控制磁盘的缓存大小,它被用来删除不活动的缓存和控制缓存大小,这些都在max_size参数中定义,当目前缓存的值超出max_size指定的值之后,超过其大小后最少使用数据(LRU替换算法)将被删除。内存池的大小按照缓存页面数的比例进行设置,一个页面(文件)的元数据大小按照操作系统来定,如FreeBSD/i386下为64字节,FreeBSD/amd64下为128字节。

proxy_cache

语法:proxy_cache zone_name;  
默认值:None  
使用字段:http, server, location  
设置一个缓存区域的名称,一个相同的区域可以在不同的地方使用。  
在0.7.48后,缓存遵循后端的”Expires”, “Cache-Control: no-cache”, “Cache-Control: max-age=XXX”头部字段,0.7.66版本以后,”Cache-Control:“private”和”no-store”头同样被遵循。nginx在缓存过程中不会处理”Vary”头,为了确保一些私有数据不被所有的用户看到,后端必须设置 “no-cache”或者”max-age=0”头,或者proxy_cache_key包含用户指定的数据如$cookie_xxx,使用cookie的值作为proxy_cache_key的一部分可以防止缓存私有数据,所以可以在不同的location中分别指定proxy_cache_key的值以便分开私有数据和公有数据。  
缓存指令依赖代理缓冲区(buffers),如果proxy_buffers设置为off,缓存不会生效。

proxy_cache_valid

语法:proxy_cache_valid reply_code [reply_code …] time;  
默认值:None  
使用字段:http, server, location  
为不同的应答设置不同的缓存时间,例如:

1
2
proxy_cache_valid  200 302  10m;
proxy_cache_valid  404      1m;

为应答代码为200和302的设置缓存时间为10分钟,404代码缓存1分钟。  
如果只定义时间:

1
proxy_cache_valid 5m;

那么只对代码为200, 301和302的应答进行缓存。  
同样可以使用any参数任何应答。

1
2
3
proxy_cache_valid  200 302 10m;
proxy_cache_valid  301 1h;
proxy_cache_valid  any 1m;

2.定义一个简单nginx缓存服务器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[[email protected] ~] # vim /etc/nginx/nginx.conf
proxy_cache_path  /data/nginx/cache/webserver  levels=1:2 keys_zone=webserver:20m max_size=1g;
    server {
        listen       80;
        server_name  localhost;
        #charset koi8-r;
        #access_log  logs/host.access.log  main;
        location / {
                proxy_pass      http: //webservers ;
                proxy_set_header  X-Real-IP  $remote_addr;
                proxy_cache webserver;
                proxy_cache_valid 200 10m;
        }
}

3.新建缓存目录

1
[[email protected] ~] # mkdir -pv /data/nginx/cache/webserver

4.重新加载一下配置文件

1
2
3
4
[[email protected] webserver] # service nginx reload
nginx: the configuration  file  /etc/nginx/nginx .conf syntax is ok
nginx: configuration  file  /etc/nginx/nginx .conf  test  is successful
重新载入 nginx:                                           [确定]

5.下面我们来测试一下(谷歌浏览器)

Nginx负载均衡、页面缓存、读写分离等详解(转)_第14张图片

注,大家用谷歌浏览器测试的时候,可以按F12调用开发工具,选择Network选项,我们可以看到,Response Headers,在这里我们可以看到,我们请求的是否是缓存,但现在还看不到,下面我们来配置一下,再来测试。

6. 缓存变量说明

$server_addr

服务器地址,在完成一次系统调用后可以确定这个值,如果要绕开系统调用,则必须在listen中指定地址并且使用bind参数。

$upstream_cache_status

0.8.3版本中其值可能为:

  • MISS 未命中

  • EXPIRED - expired。请求被传送到后端。

  • UPDATING - expired。由于proxy/fastcgi_cache_use_stale正在更新,将使用旧的应答。

  • STALE - expired。由于proxy/fastcgi_cache_use_stale,后端将得到过期的应答。

  • HIT 命中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[[email protected] ~] # vim /etc/nginx/nginx.conf
proxy_cache_path  /data/nginx/cache/webserver  levels=1:2 keys_zone=webserver:20m max_size=1g;
     server {
         listen       80;
         server_name  localhost;
         #charset koi8-r;
         #access_log  logs/host.access.log  main;
        #增加两头部
         add_header X-Via $server_addr;
         add_header X-Cache $upstream_cache_status;
         location / {
                 proxy_pass      http: //webservers ;
                 proxy_set_header  X-Real-IP  $remote_addr;
                 proxy_cache webserver;
                 proxy_cache_valid 200 10m;
         }
}

7.重新加载一下配置文件

1
2
3
4
[[email protected] ~] # service nginx reload
nginx: the configuration  file  /etc/nginx/nginx .conf syntax is ok
nginx: configuration  file  /etc/nginx/nginx .conf  test  is successful
重新载入 nginx:                                           [确定]

8.测试一下

Nginx负载均衡、页面缓存、读写分离等详解(转)_第15张图片

注,从图中我们可以看到,我们访问的服务器是192.168.18.208,缓存命中。大家可以看到是不是很直观啊。下面我们看一下缓存目录。

9.查看一下缓存目录

1
2
3
[[email protected] ~] # cd /data/nginx/cache/webserver/f/63/
[[email protected] 63] # ls
681ad4c77694b65d61c9985553a2763f

注,缓存目录里确实有缓存文件。好了,nginx缓存配置就到这边了,更多配置请根据需要看配置文档。下面我们来说一下,URL重写。

七、Nginx之URL重写

1. URL重写模块(Rewrite)

摘要

这个模块允许使用正则表达式重写URI(需PCRE库),并且可以根据相关变量重定向和选择不同的配置。如果这个指令在server字段中指定,那么将在被请求的location确定之前执行,如果在指令执行后所选择的location中有其他的重写规则,那么它们也被执行。如果在location中执行这个指令产生了新的URI,那么location又一次确定了新的URI。这样的循环可以最多执行10次,超过以后nginx将返回500错误。

指令

break

语法:break  
默认值:none  
使用字段:server, location, if  
完成当前设置的规则,停止执行其他的重写指令。  
示例:

1
2
3
4
if  ($slow) {
   limit_rate  10k;
   break ;
}
if

语法:if (condition) { … }  
默认值:none  
使用字段:server, location  
注意:在使用if指令之前请查看 if is evil page并且尽量考虑用 try_files代替。  
判断一个条件,如果条件成立,则后面的大括号内的语句将执行,相关配置从上级继承。  
可以在判断语句中指定下列值:

  • 一个变量的名称;不成立的值为:空字符传”“或者一些用“0”开始的字符串。

  • 一个使用=或者!=运算符的比较语句。

  • 使用符号~*和~模式匹配的正则表达式:

  • ~为区分大小写的匹配。

  • ~*不区分大小写的匹配(firefox匹配FireFox)。

  • !~和!~*意为“不匹配的”。

  • 使用-f和!-f检查一个文件是否存在。

  • 使用-d和!-d检查一个目录是否存在。

  • 使用-e和!-e检查一个文件,目录或者软链接是否存在。

  • 使用-x和!-x检查一个文件是否为可执行文件。

正则表达式的一部分可以用圆括号,方便之后按照顺序用$1-$9来引用。  
示例配置:

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
if  ($http_user_agent ~ MSIE) {
   rewrite  ^(.*)$   /msie/ $1   break ;
}
                                                                                                                                                        
if  ($http_cookie ~*  "id=([^;] +)(?:;|$)"  ) {
   set   $ id   $1;
}
                                                                                                                                                        
if  ($request_method = POST ) {
   return  405;
}
                                                                                                                                                        
if  (!-f $request_filename) {
   break ;
   proxy_pass  http: //127 .0.0.1;
}
                                                                                                                                                        
if  ($slow) {
   limit_rate  10k;
}
                                                                                                                                                        
if  ($invalid_referer) {
   return    403;
}
                                                                                                                                                        
if  ($args ~ post=140){
   rewrite ^ http: //example .com/ permanent;
}

内置变量$invalid_referer用指令valid_referers指定。

return

语法:return code  
默认值:none  
使用字段:server, location, if  
这个指令结束执行配置语句并为客户端返回状态代码,可以使用下列的值:204,400,402-406,408,410, 411, 413, 416与500-504。此外,非标准代码444将关闭连接并且不发送任何的头部。

rewrite

语法:rewrite regex replacement flag  
默认值:none  
使用字段:server, location, if  
按照相关的正则表达式与字符串修改URI,指令按照在配置文件中出现的顺序执行。  
可以在重写指令后面添加标记。  
如果替换的字符串以http://开头,请求将被重定向,并且不再执行多余的rewrite指令。  
尾部的标记(flag)可以是以下的值:

  • last - 完成重写指令,之后搜索相应的URI或location。

  • break - 完成重写指令。

  • redirect - 返回302临时重定向,如果替换字段用http://开头则被使用。

  • permanent - 返回301永久重定向。

注意如果一个重定向是相对的(没有主机名部分),nginx将在重定向的过程中使用匹配server_name指令的“Host”头或者server_name指令指定的第一个名称,如果头不匹配或不存在,如果没有设置server_name,将使用本地主机名,如果你总是想让nginx使用“Host”头,可以在server_name使用“*”通配符(查看http核心模块中的 server_name)。例如:

1
2
3
rewrite  ^( /download/ .*) /media/ (.*)\..*$  $1 /mp3/ $2.mp3  last;
rewrite  ^( /download/ .*) /audio/ (.*)\..*$  $1 /mp3/ $2.ra   last;
return    403;

但是如果我们将其放入一个名为/download/的location中,则需要将last标记改为break,否则nginx将执行10次循环并返回500错误。

1
2
3
4
5
location  /download/  {
   rewrite  ^( /download/ .*) /media/ (.*)\..*$  $1 /mp3/ $2.mp3   break ;
   rewrite  ^( /download/ .*) /audio/ (.*)\..*$  $1 /mp3/ $2.ra    break ;
   return    403;
}

如果替换字段中包含参数,那么其余的请求参数将附加到后面,为了防止附加,可以在最后一个字符后面跟一个问号:

1
rewrite  ^ /users/ (.*)$   /show ?user=$1?  last;

注意:大括号({和}),可以同时用在正则表达式和配置块中,为了防止冲突,正则表达式使用大括号需要用双引号(或者单引号)。例如要重写以下的URL:

1
/photos/123456

为:

1
/path/to/photos/12/1234/123456 .png

则使用以下正则表达式(注意引号):

1
rewrite   "/photos/([0-9] {2})([0-9] {2})([0-9] {2})"  /path/to/photos/ $1/$1$2/$1$2$3.png;

如果指定一个“?”在重写的结尾,Nginx将丢弃请求中的参数,即变量 $args,当使用 $request_uri或 $uri& $args时可以在rewrite结尾使用“?”以避免nginx处理两次参数串。  
在rewrite中使用$request_uri将www.example.com重写到example.com:

1
2
3
4
server {
    server_name www.example.com;
    rewrite ^ http: //example .com$request_uri? permanent;
}

同样,重写只对路径进行操作,而不是参数,如果要重写一个带参数的URL,可以使用以下代替:

1
2
3
if  ($args ^~ post=100){
   rewrite ^ http: //example .com /new-address .html? permanent;
}

注意$args变量不会被编译,与location过程中的URI不同(参考http核心模块中的 location)。

rewrite_log

语法:rewrite_log on | off  
默认值:rewrite_log off  
使用字段:server, location, if  
变量:无  
启用时将在error log中记录notice 标记的重写日志。

set

语法:set variable value  
默认值:none  
使用字段:server, location, if  
指令设置一个变量并为其赋值,其值可以是文本,变量和它们的组合。  
你可以使用set定义一个新的变量,但是不能使用set设置$http_xxx头部变量的值。

uninitialized_variable_warn

语法:uninitialized_variable_warn on|off  
默认值:uninitialized_variable_warn on  
使用字段:http, server, location, if  
开启或关闭在未初始化变量中记录警告日志。  
事实上,rewrite指令在配置文件加载时已经编译到内部代码中,在解释器产生请求时使用。  
这个解释器是一个简单的堆栈虚拟机,如下列指令:

1
2
3
4
5
6
7
8
location  /download/  {
   if  ($forbidden) {
     return    403;
   }
   if  ($slow) {
     limit_rate  10k;
   }
   rewrite  ^/(download/.*) /media/ (.*)\..*$  /$1 /mp3/ $2.mp3   break ;

将被编译成以下顺序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
variable $forbidden
checking to zero
recovery 403
completion of entire code
variable $slow
checking to zero
checkings of regular excodession
copying  "/"
copying $1
copying  "/mp3/"
copying $2
copying  ".mp3"
completion of regular excodession
completion of entire sequence

注意并没有关于limit_rate的代码,因为它没有提及ngx_http_rewrite_module模块,“if”块可以类似”location”指令在配置文件的相同部分同时存在。  
如果$slow为真,对应的if块将生效,在这个配置中limit_rate的值为10k。  
指令:

1
rewrite  ^/(download/.*) /media/ (.*)\..*$  /$1 /mp3/ $2.mp3   break ;

如果我们将第一个斜杠括入圆括号,则可以减少执行顺序:

1
rewrite  ^( /download/ .*) /media/ (.*)\..*$  $1 /mp3/ $2.mp3   break ;

之后的顺序类似如下:

1
2
3
4
5
6
7
checking regular excodession
copying $1
copying  "/mp3/"
copying $2
copying  ".mp3"
completion of regular excodession
completion of entire code
2.简单案例
注,由于配置文件内容较多,为了让大家看着方便,我们备份一下配置文件,打开一个新的配置文件。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[[email protected] ~] # cd /etc/nginx/
[[email protected] nginx] # mv nginx.conf nginx.conf.proxy
[[email protected] nginx] # cp nginx.conf.bak nginx.conf
[[email protected] nginx] # vim /etc/nginx/nginx.conf
server {
       listen       80;
       server_name  localhost;
       #charset koi8-r;
       #access_log  logs/host.access.log  main;
       location / {
           root   html;
           index  index.html index.htm;
           rewrite ^ /bbs/ (.*)$ http: //192 .168.18.201 /forum/ $1;
       }
}
准备forum目录与测试文件
1
2
3
4
5
6
7
[[email protected] ~] # cd /var/www/html/
[[email protected] html] # ls
index.html
[[email protected] html] # mkdir forum
[[email protected] html] # cd forum/
[[email protected] forum] # vim index.html

forum page!< /h1 >

测试一下

Nginx负载均衡、页面缓存、读写分离等详解(转)_第16张图片

好了,下面我们来测试一下rewrite重写。

3.重新加载一下配置文件
1
2
3
4
[[email protected] 63] # service nginx reload
nginx: the configuration  file  /etc/nginx/nginx .conf syntax is ok
nginx: configuration  file  /etc/nginx/nginx .conf  test  is successful
重新载入 nginx:                                           [确定]

4.测试一下

Nginx负载均衡、页面缓存、读写分离等详解(转)_第17张图片

注,大家可以从图中看出,status code 302指的是临时重定向,那就说明我们rewrite重写配置成功。大家知道302是临时重定向而301是永久重定向,那么怎么实现永久重定向呢。一般服务器与服务器之间是临时重定向,服务器内部是永久重定向。下面我们来演示一下永久重定向。

5.配置永久重定向

1
2
3
4
5
6
7
8
9
10
11
12
[[email protected] nginx] # vim /etc/nginx/nginx.conf
server {
         listen       80;
         server_name  localhost;
         #charset koi8-r;
         #access_log  logs/host.access.log  main;
         location / {
             root   html;
             index  index.html index.htm;
             rewrite ^ /bbs/ (.*)$  /forum/ $1;
         }
}
准备forum目录与测试文件
1
2
3
4
5
6
7
[[email protected] ~] # cd /usr/html/
[[email protected] html] # ls
50x.html  index.html
[[email protected] html] # mkdir forum
[[email protected] html] # cd forum/
[[email protected] forum] # vim index.html

192.168.18.208 forum page< /h1 >

6.重新加载一下配置文件

1
2
3
4
[[email protected] ~] # service nginx reload
nginx: the configuration  file  /etc/nginx/nginx .conf syntax is ok
nginx: configuration  file  /etc/nginx/nginx .conf  test  is successful
重新载入 nginx:                                           [确定]

7.测试一下

Nginx负载均衡、页面缓存、读写分离等详解(转)_第18张图片

注,大家从图中可以看到,我们访问bbs/是直接帮我们跳转到forum/下,这种本机的跳转就是永久重定向也叫隐式重定向。好了,rewrite重定向我们就说到这里了,想要查询更多关于重定向的指令请参考官方文档。最后,我们来说一下读写分离。

八、Nginx之读写分离

1.实验拓扑

Nginx负载均衡、页面缓存、读写分离等详解(转)_第19张图片

       需求分析,前端一台nginx做负载均衡反向代理,后面两台httpd服务器。整个架构是提供BBS(论坛)服务,有一需求得实现读写分离,就是上传附件的功能,我们上传的附件只能上传到Web1,然后在Web1上利用rsync+inotify实现附件同步,大家都知道rsync+inotify只能是主向从同步,不能双向同步。所以Web1可进行写操作,而Web2只能进行读操作,这就带来读写分离的需求,下面我们就来说一下,读写分离怎么实现。

2.WebDAV功能说明

       WebDAV (Web-based Distributed Authoring and Versioning) 一种基于 HTTP 1.1协议的通信协议。它扩展了HTTP 1.1,在GET、POST、HEAD等几个HTTP标准方法以外添加了一些新的方法,使应用程序可直接对Web Server直接读写,并支持写文件锁定(Locking)及解锁(Unlock),还可以支持文件的版本控制。这样我们就能配置读写分离功能了,下面我们来具体配置一下。

3.修改配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
[[email protected] nginx] # vim /etc/nginx/nginx.conf
server {
         listen       80;
         server_name  localhost;
         #charset koi8-r;
         #access_log  logs/host.access.log  main;
         location / {
                 proxy_pass http: //192 .168.18.202;
                 if  ($request_method =  "PUT" ){
                         proxy_pass http: //192 .168.18.201;
                 }
         }
}

4.重新加载一下配置文件

1
2
3
4
[[email protected] ~] # service nginx reload
nginx: the configuration  file  /etc/nginx/nginx .conf syntax is ok
nginx: configuration  file  /etc/nginx/nginx .conf  test  is successful
重新载入 nginx:                                           [确定]

5.配置httpd的WebDAV功能

1
[[email protected] ~] # vim /etc/httpd/conf/httpd.conf

t17

注,在下启用就行。

6.重新启动一下httpd

1
2
3
[[email protected] ~] # service httpd restart
停止 httpd:                                               [确定]
正在启动 httpd:                                           [确定]

7.测试一下

1
2
3
4
[[email protected] ~] # curl http://192.168.18.201

web1. test .com< /h1 >

[[email protected] ~] # curl http://192.168.18.202

web2. test .com< /h1 >

注,web1与web2访问都没问题。

1
2
3
4
5
6
7
8
9
10
[[email protected] ~] # curl -T /etc/issue  http://192.168.18.202
"-//IETF//DTD HTML 2.0//EN" >
< head >
405 Method Not Allowed<</code> <code>/title</code> <code>></code> </div> <div> <code><</code> <code>/head</code> <code>><body></code> </div> <div> <code><h1>Method Not Allowed<</code> <code>/h1</code> <code>></code> </div> <div> <code>The requested method PUT is not allowed </code> <code>for</code>  <code>the URL </code> <code>/issue</code> <code>.</code> </div> <div> <code><hr></code> </div> <div> <code><address>Apache</code> <code>/2</code> <code>.2.15 (CentOS) Server at 192.168.18.202 Port 80<</code> <code>/address</code> <code>></code> </div> <div> <code><</code> <code>/body</code> <code>><</code> <code>/html</code> <code>></code> </div> </div> </td> </tr> </tbody> </table> </div> </div> <p>注,我们上传文件到,web2上时,因为web2只人读功能,所以没有开户WebDAV功能,所以显示是405 Method Not Allowed。   <br></p> <div> <div> <table border="0"> <tbody> <tr> <td> <div> 1 </div> <div> 2 </div> <div> 3 </div> <div> 4 </div> <div> 5 </div> <div> 6 </div> <div> 7 </div> <div> 8 </div> <div> 9 </div> <div> 10 </div> <div> 11 </div> </td> <td> <div> <div> <code>[[email protected] ~]</code> <code># curl -T /etc/issue  http://192.168.18.201</code> </div> <div> <code><!DOCTYPE HTML PUBLIC </code> <code>"-//IETF//DTD HTML 2.0//EN"</code> <code>></code> </div> <div> <code><html><</code> <code>head</code> <code>></code> </div> <div> <code><title>403 Forbidden<</code> <code>/title</code> <code>></code> </div> <div> <code><</code> <code>/head</code> <code>><body></code> </div> <div> <code><h1>Forbidden<</code> <code>/h1</code> <code>></code> </div> <div> <code>You don't have permission to access </code> <code>/issue</code> </div> <div> <code>on this server.</code> </div> <div> <code><hr></code> </div> <div> <code><address>Apache</code> <code>/2</code> <code>.2.15 (CentOS) Server at 192.168.18.201 Port 80<</code> <code>/address</code> <code>></code> </div> <div> <code><</code> <code>/body</code> <code>><</code> <code>/html</code> <code>></code> </div> </div> </td> </tr> </tbody> </table> </div> </div> <p>注,我们在Web1开启了WebDAV功能,但我们目录是root目录是不允许apache用户上传的,所以显示的是403 Forbidden。下面我们给apache授权,允许上传。</p> <div> <div> <table border="0"> <tbody> <tr> <td> <div> 1 </div> </td> <td> <div> <div> <code>[[email protected] ~]</code> <code># setfacl -m u:apache:rwx /var/www/html/</code> </div> </div> </td> </tr> </tbody> </table> </div> </div> <p>下面我们再来测试一下,</p> <div> <div> <table border="0"> <tbody> <tr> <td> <div> 1 </div> <div> 2 </div> <div> 3 </div> <div> 4 </div> <div> 5 </div> <div> 6 </div> <div> 7 </div> <div> 8 </div> <div> 9 </div> <div> 10 </div> </td> <td> <div> <div> <code>[[email protected] ~]</code> <code># curl -T /etc/issue  http://192.168.18.201</code> </div> <div> <code><!DOCTYPE HTML PUBLIC </code> <code>"-//IETF//DTD HTML 2.0//EN"</code> <code>></code> </div> <div> <code><html><</code> <code>head</code> <code>></code> </div> <div> <code><title>201 Created<</code> <code>/title</code> <code>></code> </div> <div> <code><</code> <code>/head</code> <code>><body></code> </div> <div> <code><h1>Created<</code> <code>/h1</code> <code>></code> </div> <div> <code>Resource </code> <code>/issue</code>  <code>has been created.</code> </div> <div> <code><hr /></code> </div> <div> <code><address>Apache</code> <code>/2</code> <code>.2.15 (CentOS) Server at 192.168.18.201 Port 80<</code> <code>/address</code> <code>></code> </div> <div> <code><</code> <code>/body</code> <code>><</code> <code>/html</code> <code>></code> </div> </div> </td> </tr> </tbody> </table> </div> </div> <p>注,大家可以看到我们成功的上传了文件,说明nginx读写分离功能配置完成。最后,我们来查看一下上传的文件。</p> <div> <div> <table border="0"> <tbody> <tr> <td> <div> 1 </div> <div> 2 </div> <div> 3 </div> <div> 4 </div> <div> 5 </div> <div> 6 </div> </td> <td> <div> <div> <code>[[email protected] ~]</code> <code># cd /var/www/html/</code> </div> <div> <code>[[email protected] html]</code> <code># ll</code> </div> <div> <code>总用量 12</code> </div> <div> <code>drwxr-xr-x 2 root   root   4096 9月   4 13:16 forum</code> </div> <div> <code>-rw-r--r-- 1 root   root     23 9月   3 23:37 index.html</code> </div> <div> <code>-rw-r--r-- 1 apache apache   47 9月   4 14:06 issue</code> </div> </div> </td> </tr> </tbody> </table> </div> </div> <p>好了,到这里nginx的反向代理、负载均衡、页面缓存、URL重写及读写分离就全部讲解完成。希望大家有所收获,^_^……</p> <p> </p> <p>本文出自 “ Share your knowledge …” 博客,请务必保留此出处 http://freeloda.blog.51cto.com/2033581/1288553</p> </div> <br> <br> 已有 <strong>0</strong> 人发表留言,猛击->> <strong>这里</strong><<-参与讨论 <br> <br> <br> ITeye推荐 <br> <ul> <li> —软件人才免语言低担保 赴美带薪读研!— </li> </ul> <br> <br> <br> </div> </div> </div> </div> <!--PC和WAP自适应版--> <div id="SOHUCS" sid="1489602655650078720"></div> <script type="text/javascript" src="/views/front/js/chanyan.js"></script> <!-- 文章页-底部 动态广告位 --> <div class="youdao-fixed-ad" id="detail_ad_bottom"></div> </div> <div class="col-md-3"> <div class="row" id="ad"> <!-- 文章页-右侧1 动态广告位 --> <div id="right-1" class="col-lg-12 col-md-12 col-sm-4 col-xs-4 ad"> <div class="youdao-fixed-ad" id="detail_ad_1"> </div> </div> <!-- 文章页-右侧2 动态广告位 --> <div id="right-2" class="col-lg-12 col-md-12 col-sm-4 col-xs-4 ad"> <div class="youdao-fixed-ad" id="detail_ad_2"></div> </div> <!-- 文章页-右侧3 动态广告位 --> <div id="right-3" class="col-lg-12 col-md-12 col-sm-4 col-xs-4 ad"> <div class="youdao-fixed-ad" id="detail_ad_3"></div> </div> </div> </div> </div> </div> </div> <div class="container"> <h4 class="pt20 mb15 mt0 border-top">你可能感兴趣的:(nginx,负载均衡,页面)</h4> <div id="paradigm-article-related"> <div class="recommend-post mb30"> <ul class="widget-links"> <li><a href="/article/1943992018111885312.htm" title="发票合并工具" target="_blank">发票合并工具</a> <span class="text-muted">小朋的软件园</span> <a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/html/1.htm">html</a><a class="tag" taget="_blank" href="/search/%E6%9C%8D%E5%8A%A1%E5%99%A8/1.htm">服务器</a> <div>"发票合并工具"是一款专为高效整理票据设计的实用工具,支持将来自不同渠道的发票文件(如PDF文档、各类图片格式)快速整合为排版规范的PDF文件,尤其适用于财务报销场景下的批量票据处理需求。核心功能亮点多格式兼容:无缝导入PDF文件及常见图片格式(.png/.jpg/.jpeg/.bmp),适配多来源发票整合需求。智能布局配置:提供灵活的页面布局选项(每页2/3/4张发票),其中"2合1"模式针对报</div> </li> <li><a href="/article/1943985462716723200.htm" title="docker-compose方式搭建lnmp环境——筑梦之路" target="_blank">docker-compose方式搭建lnmp环境——筑梦之路</a> <span class="text-muted">筑梦之路</span> <a class="tag" taget="_blank" href="/search/linux%E7%B3%BB%E7%BB%9F%E8%BF%90%E7%BB%B4/1.htm">linux系统运维</a><a class="tag" taget="_blank" href="/search/%E5%9B%BD%E4%BA%A7%E5%8C%96/1.htm">国产化</a><a class="tag" taget="_blank" href="/search/docker/1.htm">docker</a><a class="tag" taget="_blank" href="/search/android/1.htm">android</a><a class="tag" taget="_blank" href="/search/adb/1.htm">adb</a> <div>docker-compose.yml文件#生成docker-compose.ymlcat>docker-compose.ymlnginx/conf.d/default.conf">www/index.phpecho"开始启动服务..."docker-composeup-d#获取本机ipip_addr=$(hostname-I|awk'{print$1}')echo"部署完成!"echo"访问测试页</div> </li> <li><a href="/article/1943983064719880192.htm" title="分布式学习笔记_04_复制模型" target="_blank">分布式学习笔记_04_复制模型</a> <span class="text-muted">NzuCRAS</span> <a class="tag" taget="_blank" href="/search/%E5%88%86%E5%B8%83%E5%BC%8F/1.htm">分布式</a><a class="tag" taget="_blank" href="/search/%E5%AD%A6%E4%B9%A0/1.htm">学习</a><a class="tag" taget="_blank" href="/search/%E7%AC%94%E8%AE%B0/1.htm">笔记</a><a class="tag" taget="_blank" href="/search/%E6%9E%B6%E6%9E%84/1.htm">架构</a><a class="tag" taget="_blank" href="/search/%E5%90%8E%E7%AB%AF/1.htm">后端</a> <div>常见复制模型使用复制的目的在分布式系统中,数据通常需要被分布在多台机器上,主要为了达到:拓展性:数据量因读写负载巨大,一台机器无法承载,数据分散在多台机器上仍然可以有效地进行负载均衡,达到灵活的横向拓展高容错&高可用:在分布式系统中单机故障是常态,在单机故障的情况下希望整体系统仍然能够正常工作,这时候就需要数据在多台机器上做冗余,在遇到单机故障时能够让其他机器接管统一的用户体验:如果系统客户端分布</div> </li> <li><a href="/article/1943975880120397824.htm" title="php SPOF" target="_blank">php SPOF</a> <span class="text-muted">贵哥的编程之路(热爱分享 为后来者)</span> <a class="tag" taget="_blank" href="/search/PHP%E8%AF%AD%E8%A8%80%E7%BB%8F%E5%85%B8%E7%A8%8B%E5%BA%8F100%E9%A2%98/1.htm">PHP语言经典程序100题</a><a class="tag" taget="_blank" href="/search/php/1.htm">php</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a> <div>1.什么是单点故障(SPOF)?单点故障指的是系统中某个组件一旦失效,整个系统或服务就会不可用。常见的单点有:数据库、缓存、Web服务器、负载均衡、网络设备等。2.常见单点故障场景只有一台数据库服务器,宕机后所有业务不可用只有一台Redis缓存,挂掉后缓存全部失效只有一台Web服务器,挂掉后网站无法访问只有一个负载均衡节点,挂掉后流量无法分发只有一条网络链路,断开后所有服务失联3.消除单点故障的主</div> </li> <li><a href="/article/1943974492640440320.htm" title="Anaconda 详细下载与安装教程" target="_blank">Anaconda 详细下载与安装教程</a> <span class="text-muted"></span> <div>Anaconda详细下载与安装教程1.简介Anaconda是一个用于科学计算的开源发行版,包含了Python和R的众多常用库。它还包括了conda包管理器,可以方便地安装、更新和管理各种软件包。2.下载Anaconda2.1访问官方网站首先,打开浏览器,访问Anaconda官方网站。2.2选择适合的版本在页面中,你会看到两个主要的下载选项:AnacondaIndividualEdition:适用于</div> </li> <li><a href="/article/1943950289824444416.htm" title="实时预览功能问题" target="_blank">实时预览功能问题</a> <span class="text-muted">GISer_Jinger</span> <a class="tag" taget="_blank" href="/search/%E9%A1%B9%E7%9B%AE/1.htm">项目</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a><a class="tag" taget="_blank" href="/search/ecmascript/1.htm">ecmascript</a> <div>你遇到的问题是:“B端修改配置后无法实时出现在previewiframe中,而必须点击刷新才能生效”。主要原因与以下几方面有关:❗为什么需要手动刷新:iFrame与主页面之间缺少实时通信机制:原本仅靠刷新重新加载iframe,而没有通过postMessage等方式同步状态;Valtio的proxy状态不能跨文件热刷新持久保存:当你修改包含proxy定义的文件,热重载会导致object被替换,监听丢</div> </li> <li><a href="/article/1943950037142794240.htm" title="Windows平台下Android Studio搭建Flutter开发环境的正确姿势(202506)" target="_blank">Windows平台下Android Studio搭建Flutter开发环境的正确姿势(202506)</a> <span class="text-muted"></span> <div>Flutter作为Google推出的跨平台移动应用开发框架,近年来获得了广泛关注。它允许开发者使用单一代码库构建iOS和Android应用,大大提高了开发效率。本文将带你一步步在Windows系统上搭建完整的Flutter开发环境。第一步:下载并安装FlutterSDK首先,我们需要获取FlutterSDK:访问Flutter官方中文文档的安装页面:https://docs.flutter.cn/</div> </li> <li><a href="/article/1943932016164663296.htm" title="Vue3组件库实战: 打造高复用UI系统" target="_blank">Vue3组件库实战: 打造高复用UI系统</a> <span class="text-muted">武昌库里写JAVA</span> <a class="tag" taget="_blank" href="/search/%E9%9D%A2%E8%AF%95%E9%A2%98%E6%B1%87%E6%80%BB%E4%B8%8E%E8%A7%A3%E6%9E%90/1.htm">面试题汇总与解析</a><a class="tag" taget="_blank" href="/search/%E8%AF%BE%E7%A8%8B%E8%AE%BE%E8%AE%A1/1.htm">课程设计</a><a class="tag" taget="_blank" href="/search/spring/1.htm">spring</a><a class="tag" taget="_blank" href="/search/boot/1.htm">boot</a><a class="tag" taget="_blank" href="/search/vue.js/1.htm">vue.js</a><a class="tag" taget="_blank" href="/search/layui/1.htm">layui</a><a class="tag" taget="_blank" href="/search/%E6%AF%95%E4%B8%9A%E8%AE%BE%E8%AE%A1/1.htm">毕业设计</a> <div>Vue3组件库实战:打造高复用UI系统介绍什么是Vue3组件库在前端开发中,UI组件库是非常重要的一部分。Vue3组件库是基于Vue.js3.x版本开发的一套可用于构建Web应用的UI组件集合,可以帮助开发者快速搭建页面并保证页面的一致性和美观性。目标关键词:Vue3组件库设计与构建设计原则组件库的设计需要遵循一定的原则,比如易用性、可维护性、扩展性等。在设计阶段需要考虑到不同场景的使用,并且保证</div> </li> <li><a href="/article/1943930755528847360.htm" title="在 Windows 上安装 Docker Desktop" target="_blank">在 Windows 上安装 Docker Desktop</a> <span class="text-muted">不老刘</span> <a class="tag" taget="_blank" href="/search/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/1.htm">人工智能</a><a class="tag" taget="_blank" href="/search/windows/1.htm">windows</a><a class="tag" taget="_blank" href="/search/docker/1.htm">docker</a><a class="tag" taget="_blank" href="/search/%E5%AE%B9%E5%99%A8/1.htm">容器</a> <div>还是简单说一下,如何在Windows上安装DockerDesktop,具体步骤如下:系统要求Windows10/1164-bit(专业版、企业版或教育版,版本21H2或更高)启用WSL2(WindowsSubsystemforLinux2)或Hyper-V至少4GB内存BIOS中启用虚拟化(VT-x/AMD-V)安装步骤1.下载DockerDesktop访问Docker官网下载页面。下载Docke</div> </li> <li><a href="/article/1943924322171154432.htm" title="数据分析常用指标名词解释及计算公式" target="_blank">数据分析常用指标名词解释及计算公式</a> <span class="text-muted">走过冬季</span> <a class="tag" taget="_blank" href="/search/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/1.htm">学习笔记</a><a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/1.htm">数据分析</a><a class="tag" taget="_blank" href="/search/%E5%A4%A7%E6%95%B0%E6%8D%AE/1.htm">大数据</a> <div>数据分析中有大量常用指标,它们帮助我们量化业务表现、用户行为、产品健康度等。下面是一些核心指标的名词解释及计算方式,按常见类别分类:一、流量与用户规模指标页面浏览量名词解释:用户访问网站或应用时,每次加载或刷新一个页面就算一次PV。它衡量的是页面被打开的总次数。计算方式:PV=∑(所有页面被加载的次数)(通常由埋点或日志直接统计)独立访客数名词解释:在特定时间范围内(如一天、一周、一月),访问网站</div> </li> <li><a href="/article/1943919026744913920.htm" title="JavaScript之DOM操作与事件处理详解" target="_blank">JavaScript之DOM操作与事件处理详解</a> <span class="text-muted">AA-代码批发V哥</span> <a class="tag" taget="_blank" href="/search/JavaScript/1.htm">JavaScript</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a> <div>JavaScript之DOM操作与事件处理详解一、DOM基础:理解文档对象模型二、DOM元素的获取与访问2.1基础获取方法2.2集合的区别与注意事项三、DOM元素的创建与修改3.1创建与插入元素3.2修改元素属性与样式3.2.1属性操作3.2.2样式操作3.3元素内容的修改四、DOM元素的删除与替换4.1删除元素4.2替换元素五、事件处理:实现页面交互5.1事件绑定的三种方式5.1.1HTML属性</div> </li> <li><a href="/article/1943913603195269120.htm" title="【个人笔记】负载均衡" target="_blank">【个人笔记】负载均衡</a> <span class="text-muted">撰卢</span> <a class="tag" taget="_blank" href="/search/%E7%AC%94%E8%AE%B0/1.htm">笔记</a><a class="tag" taget="_blank" href="/search/%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1/1.htm">负载均衡</a><a class="tag" taget="_blank" href="/search/%E8%BF%90%E7%BB%B4/1.htm">运维</a> <div>文章目录nginx反向代理的好处负载均衡负载均很的配置方式均衡负载的方式nginx反向代理的好处提高访问速度进行负载均衡保证后端服务安全负载均衡负载均衡,就是把大量的请求按照我们指定的方式均衡的分配给集群中的每台服务器负载均很的配置方式upstreamwebservers{server192.168.100.128:8080server192.168.100.129:8080}server{lis</div> </li> <li><a href="/article/1943910581287317504.htm" title="redis管道 -redis pipeline -redis pipelining" target="_blank">redis管道 -redis pipeline -redis pipelining</a> <span class="text-muted">shuair</span> <a class="tag" taget="_blank" href="/search/redis/1.htm">redis</a><a class="tag" taget="_blank" href="/search/redis/1.htm">redis</a><a class="tag" taget="_blank" href="/search/bootstrap/1.htm">bootstrap</a><a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E5%BA%93/1.htm">数据库</a> <div>redis管道文档redis单机安装redis常用的五种数据类型redis数据类型-位图bitmapredis数据类型-基数统计HyperLogLogredis数据类型-地理空间GEOredis数据类型-流Streamredis数据类型-位域bitfieldredis持久化-RDBredis持久化-AOFredis持久化-RDB+AOF混合模式redis事务官方文档官网操作命令指南页面:https</div> </li> <li><a href="/article/1943907050870337536.htm" title="深入解析 “void(0);” 的用法与作用_void(0);" target="_blank">深入解析 “void(0);” 的用法与作用_void(0);</a> <span class="text-muted"></span> <div>关键要点void(0);是JavaScript中的一个表达式,研究表明它通常用于超链接中,防止页面跳转。它通过void运算符计算表达式并返回undefined,常用于创建“死链接”。证据显示,这种用法简单易用,但现代开发更推荐使用事件监听器。基本概念void(0);的作用void(0);是JavaScript的void运算符的一个实例,void运算符会计算一个表达式但不返回任何值,而是始终返回un</div> </li> <li><a href="/article/1943891045188169728.htm" title="项目开发日记" target="_blank">项目开发日记</a> <span class="text-muted"></span> <div>框架整理学习UIMgr:一、数据结构与算法1.1关键数据结构成员变量类型说明m_CtrlsList当前正在显示的所有UI页面m_CachesList已打开过、但现在不显示的页面(缓存池)1.2算法逻辑查找缓存页面:从m_Caches中倒序查找是否已有对应ePageType页面,找到则重用。页面加载:从资源管理器ResMgr加载prefab并绑定控制器/视图组件。页面关闭:从m_Ctrls移除,添加</div> </li> <li><a href="/article/1943885877600120832.htm" title="浏览器的事件循环中的任务队列(消息队列)" target="_blank">浏览器的事件循环中的任务队列(消息队列)</a> <span class="text-muted">小吴在摸渝</span> <a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a> <div>在浏览器的事件循环中,任务队列是有优先级的。这些优先级决定了在一次事件循环中,哪些任务会被优先执行。以下是一些主要的任务队列及其优先级:微任务队列(优先级最高):这个队列用于存放需要最快执行的任务。添加任务到微任务队列的主要方式是使用Promise和MutationObserver1。交互队列(优先级高):这个队列用于存放用户操作后产生的事件处理任务,例如鼠标点击、页面滚动等。延时队列(优先级中)</div> </li> <li><a href="/article/1943875785089675264.htm" title="Webpack5 多页面实践" target="_blank">Webpack5 多页面实践</a> <span class="text-muted"></span> <div>特性维度单页面应用-SPA多页面统一目录-MPA多页面单独部署-MPA入口数量单个,只有一个HTML文件多个,多个HTML文件多个,多个HTML文件,分别打包输出资源输出结构所有资源输出到统一目录(如js/,css/)所有页面的资源共用js/,css/等目录每页资源放在各自目录(如index/js/,index/css/)公共资源复用高:依赖打入主包或懒加载chunk,资源完全共享中:可通过spl</div> </li> <li><a href="/article/1943871502210363392.htm" title="C#常见面试题" target="_blank">C#常见面试题</a> <span class="text-muted">rapLiu</span> <a class="tag" taget="_blank" href="/search/c%23/1.htm">c#</a><a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E5%BA%93/1.htm">数据库</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a> <div>1.http和https的区别1.HTTP明文传输,数据都是未加密的,安全性较差,HTTPS(SSL+HTTP)数据传输过程是加密的,安全性较好。2.使用HTTPS协议需要到CA(CertificateAuthority,数字证书认证机构)申请证书,一般免费证书较少,因而需要一定费用。证书颁发机构如:Symantec、Comodo、GoDaddy和GlobalSign等。3.HTTP页面响应速度比</div> </li> <li><a href="/article/1943862672797790208.htm" title="家庭网络中的服务器怎么对外提供服务?" target="_blank">家庭网络中的服务器怎么对外提供服务?</a> <span class="text-muted">行而不知</span> <a class="tag" taget="_blank" href="/search/%E6%9C%8D%E5%8A%A1%E5%99%A8/1.htm">服务器</a><a class="tag" taget="_blank" href="/search/%E8%BF%90%E7%BB%B4/1.htm">运维</a><a class="tag" taget="_blank" href="/search/%E5%86%85%E7%BD%91%E7%A9%BF%E9%80%8F/1.htm">内网穿透</a><a class="tag" taget="_blank" href="/search/DDNS/1.htm">DDNS</a> <div>家庭网络中的服务器怎么对外提供服务?方案1DDNS(家庭网络需要有公网ip)方案2内网穿透(需要有一台公网ip的服务器)方案1DDNS(家庭网络需要有公网ip)  怎么判断是否有公网ip?大致的流程就是光猫改桥接,由光猫拨号改为路由器拨号,在路由器管理页面查看拨号获取的ip,用这个ip去ip查询网站验证,具体的操作可自行搜索,这里不进行赘述了。  我们都知道,ip有两种,ipv4和ipv6  网络</div> </li> <li><a href="/article/1943845649707495424.htm" title="RidgeUI页面脚本开发系列:反应速度测试页面" target="_blank">RidgeUI页面脚本开发系列:反应速度测试页面</a> <span class="text-muted"></span> <div>简介大家好,欢迎学习ridgeui页面脚本开发系列:反应速度测试页面脚本开发反应速度测试是个很简单的应用,开始时显示红色屏幕内容,当变为绿色时,用户以最快速度点击页面,进而测算出反应时间。应用的分析虽然应用简单,但是从界面角度看,应用有5个不同的页面。分别是启动说明页、红色等待、绿色点击、反应结果页、提前点击结果页。页面脚本除了要进行反应时间的计时,还需要调度安排何时显示哪个页面。为此我们首先创建</div> </li> <li><a href="/article/1943844765225250816.htm" title="前端面试题——5.AjAX的缺点?" target="_blank">前端面试题——5.AjAX的缺点?</a> <span class="text-muted">浅端</span> <a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF%E9%9D%A2%E8%AF%95%E9%A2%98/1.htm">前端面试题</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF%E9%9D%A2%E8%AF%95%E9%A2%98/1.htm">前端面试题</a> <div>①传统的web交互是:用户一个网页动作,就会发送一个http请求到服务器,服务器处理完该请求再返回一个完整的HTML页面,客户端再重新加载,这样极大地浪费了带宽。②AJAX的出现解决了这个问题,它只会向服务器请求用户所需要的数据,并在客户端采用JavaScript处理返回的数据,操作DOM更新页面。③AJXA优点:无刷新更新页面异步服务器通信前端后端负载均衡④AJAX缺点:干掉了Back和Hist</div> </li> <li><a href="/article/1943842998383079424.htm" title="2023高薪前端面试题(二、前端核心——Ajax)" target="_blank">2023高薪前端面试题(二、前端核心——Ajax)</a> <span class="text-muted"></span> <div>原生AjaxAjax简介Ajax全程为AsynchronousJavaScript+XML,就是异步的JS和XML通过AJAX可以在浏览器中向服务器发送异步请求,最大的优势是:无刷新获取数据,实现局部刷新Ajax是一种用于创建快速动态网页的技术AJAX不是新的编程语言,而是一种将现有的标准组合在一起使用的新方式Ajax的应用场景页面上拉加载更多数据列表数据无刷新分页表单项离开焦点数据验证搜索框提示</div> </li> <li><a href="/article/1943841736426057728.htm" title="前端面试题——手写实现 ajax" target="_blank">前端面试题——手写实现 ajax</a> <span class="text-muted">阿水爱踢中锋</span> <a class="tag" taget="_blank" href="/search/ajax/1.htm">ajax</a><a class="tag" taget="_blank" href="/search/js/1.htm">js</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a> <div>凡是和后台有过数据交互的小伙伴肯定都接触过ajax.我们可以通过ajax来实现页面的无刷新请求数据,这样就能在保证良好用户体验的同时,将更多的内容展示给用户ajax在我们的开发工作中已经司空见惯,几乎所有我们频繁使用的库和框架都提供了经过完善封装后的ajax方法,如jQuery、zepto、angular等等,这使得我们的数据请求变得异常简洁明了但是这也带来了很明显的缺陷,就是我们知道如何去使用封</div> </li> <li><a href="/article/1943833163788775424.htm" title="麒麟v10arm64自制nginx1.26.1的docker镜像包" target="_blank">麒麟v10arm64自制nginx1.26.1的docker镜像包</a> <span class="text-muted">睡不醒的双眼皮</span> <a class="tag" taget="_blank" href="/search/docker/1.htm">docker</a><a class="tag" taget="_blank" href="/search/nginx/1.htm">nginx</a> <div>#基础镜像openeuler2203arm64#1.宿主机下载nginx对应版本编译./configure--prefix=/usr/local/nginx--conf-path=/etc/nginx/nginx.conf&&make&&makeinstall2.#创建构建镜像目录mkdir/opt/dockerfilecp-r/usr/local/nginx/opt/dockerfile/ngi</div> </li> <li><a href="/article/1943832156052713472.htm" title="配置Nginx实现静态资源访问" target="_blank">配置Nginx实现静态资源访问</a> <span class="text-muted">Gappsong874</span> <a class="tag" taget="_blank" href="/search/nginx/1.htm">nginx</a><a class="tag" taget="_blank" href="/search/%E8%BF%90%E7%BB%B4/1.htm">运维</a><a class="tag" taget="_blank" href="/search/%E7%BD%91%E7%BB%9C%E5%AE%89%E5%85%A8/1.htm">网络安全</a><a class="tag" taget="_blank" href="/search/web%E5%AE%89%E5%85%A8/1.htm">web安全</a><a class="tag" taget="_blank" href="/search/%E5%AE%89%E5%85%A8%E6%9E%B6%E6%9E%84/1.htm">安全架构</a><a class="tag" taget="_blank" href="/search/%E8%BF%90%E7%BB%B4%E5%BC%80%E5%8F%91/1.htm">运维开发</a> <div>Nginx是一款高性能的HTTP和反向代理服务器,常用于处理静态资源请求。通过合理配置,可以显著提升静态资源的访问速度和服务器性能。以下内容将详细介绍如何配置Nginx以实现静态资源的高效访问。基本静态资源配置静态资源通常包括HTML文件、CSS样式表、JavaScript脚本、图片、视频等。Nginx通过简单的配置即可处理这些请求。在Nginx的配置文件中,通常位于/etc/nginx/ngin</div> </li> <li><a href="/article/1943826858080530432.htm" title="uniapp 如何封装实现任意页面都能使用的全局弹窗" target="_blank">uniapp 如何封装实现任意页面都能使用的全局弹窗</a> <span class="text-muted">代码简单说</span> <a class="tag" taget="_blank" href="/search/2025%E5%BC%80%E5%8F%91%E5%BF%85%E5%A4%87%28%E9%99%90%E6%97%B6%E7%89%B9%E6%83%A0%29/1.htm">2025开发必备(限时特惠)</a><a class="tag" taget="_blank" href="/search/uni-app/1.htm">uni-app</a><a class="tag" taget="_blank" href="/search/vue.js/1.htm">vue.js</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a><a class="tag" taget="_blank" href="/search/uniapp%E5%85%A8%E5%B1%80%E5%BC%B9%E7%AA%97/1.htm">uniapp全局弹窗</a><a class="tag" taget="_blank" href="/search/uniapp%E5%BC%B9%E7%AA%97%E7%BB%84%E4%BB%B6/1.htm">uniapp弹窗组件</a> <div>【实战干货】uniapp如何封装实现任意页面都能使用的全局弹窗标签:uniapp弹窗组件全局弹窗Vue动态渲染跨页面弹窗✨前端老司机亲授,uniapp无法在所有页面中直接用自定义弹窗?别急,一招动态挂载vue实例,优雅解决!背景故事:一个被“弹窗”搞崩溃的早晨作为一名前端开发工程师,有一天我在给uniapp项目加IM消息功能,需求是:不论当前用户在哪个页面,只要有消息来,就要立即弹出提示窗口。听起</div> </li> <li><a href="/article/1943825850080227328.htm" title="若依框架(路由跳转,如何动态修改tabs页的title )" target="_blank">若依框架(路由跳转,如何动态修改tabs页的title )</a> <span class="text-muted">5335ld</span> <a class="tag" taget="_blank" href="/search/vue.js/1.htm">vue.js</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a> <div>//store/modules/tagsView.js页面中添加constmutations={//动态改变tab页签EDIT_VISITED_VIEWS:(state,view)=>{for(varIndexinstate.visitedViews){console.log(state.visitedViews[Index].path)if(state.visitedViews[Index].p</div> </li> <li><a href="/article/1943824842390302720.htm" title="【前端】接口日志追踪" target="_blank">【前端】接口日志追踪</a> <span class="text-muted">毕业茄</span> <a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a> <div>1.问题描述场景:前端提交数据后,接口回调再次添加参数,但页面跳转/刷新导致之前的console.log数据丢失。影响:无法追踪完整的请求流程,调试困难。2.环境信息项目说明浏览器GoogleChrome120+开发者工具ChromeDevTools技术栈前端:Vue/React/其他接口类型RESTfulAPI/GraphQL3.解决方案3.1保留控制台日志(推荐)步骤:打开Chrome开发者工</div> </li> <li><a href="/article/1943823833769242624.htm" title="uniApp实战五:自定义组件实现便捷选择" target="_blank">uniApp实战五:自定义组件实现便捷选择</a> <span class="text-muted">博主逸尘</span> <a class="tag" taget="_blank" href="/search/uniApp%E5%AE%9E%E6%88%98/1.htm">uniApp实战</a><a class="tag" taget="_blank" href="/search/uniApp/1.htm">uniApp</a><a class="tag" taget="_blank" href="/search/vue3/1.htm">vue3</a><a class="tag" taget="_blank" href="/search/%E5%BF%AB%E9%80%9F%E9%80%89%E6%8B%A9/1.htm">快速选择</a> <div>文章目录1.最终效果预览2.快速选择组件封装3.弹框组件封装4.组件逻辑实现5.组件样式6.页面引入1.最终效果预览2.快速选择组件封装{{title}}{{content}}基于uv-ui的行组件实现的快速选择,默认展示前三个值3.弹框组件封装请选择{{item.name}}确定取消这两个放一个页面了,没必要再单独封装一个弹框组件了4.组件逻辑实现import{defineProps,defin</div> </li> <li><a href="/article/1943823074403086336.htm" title="uniapp自定义全局弹窗组件" target="_blank">uniapp自定义全局弹窗组件</a> <span class="text-muted">LuWiHa</span> <a class="tag" taget="_blank" href="/search/uni-app/1.htm">uni-app</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a> <div>可以参考一下方法,如果大家有更好的全局弹窗方法欢迎留言//使用方法//在main.js里全局注册importglobalModalfrom'./components/global-popup.vue'Vue.component('global-popup',globalModal)//在需要的页面引用组件this.$refs.globalModal.openPopup({title:'标题',co</div> </li> <li><a href="/article/81.htm" title="java短路运算符和逻辑运算符的区别" target="_blank">java短路运算符和逻辑运算符的区别</a> <span class="text-muted">3213213333332132</span> <a class="tag" taget="_blank" href="/search/java%E5%9F%BA%E7%A1%80/1.htm">java基础</a> <div> /* * 逻辑运算符——不论是什么条件都要执行左右两边代码 * 短路运算符——我认为在底层就是利用物理电路的“并联”和“串联”实现的 * 原理很简单,并联电路代表短路或(||),串联电路代表短路与(&&)。 * * 并联电路两个开关只要有一个开关闭合,电路就会通。 * 类似于短路或(||),只要有其中一个为true(开关闭合)是</div> </li> <li><a href="/article/208.htm" title="Java异常那些不得不说的事" target="_blank">Java异常那些不得不说的事</a> <span class="text-muted">白糖_</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/exception/1.htm">exception</a> <div>一、在finally块中做数据回收操作 比如数据库连接都是很宝贵的,所以最好在finally中关闭连接。 JDBCAgent jdbc = new JDBCAgent(); try{ jdbc.excute("select * from ctp_log"); }catch(SQLException e){ ... }finally{ jdbc.close(); </div> </li> <li><a href="/article/335.htm" title="utf-8与utf-8(无BOM)的区别" target="_blank">utf-8与utf-8(无BOM)的区别</a> <span class="text-muted">dcj3sjt126com</span> <a class="tag" taget="_blank" href="/search/PHP/1.htm">PHP</a> <div>BOM——Byte Order Mark,就是字节序标记   在UCS 编码中有一个叫做"ZERO WIDTH NO-BREAK SPACE"的字符,它的编码是FEFF。而FFFE在UCS中是不存在的字符,所以不应该出现在实际传输中。UCS规范建议我们在传输字节流前,先传输 字符"ZERO WIDTH NO-BREAK SPACE"。这样如</div> </li> <li><a href="/article/462.htm" title="JAVA Annotation之定义篇" target="_blank">JAVA Annotation之定义篇</a> <span class="text-muted">周凡杨</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E6%B3%A8%E8%A7%A3/1.htm">注解</a><a class="tag" taget="_blank" href="/search/annotation/1.htm">annotation</a><a class="tag" taget="_blank" href="/search/%E5%85%A5%E9%97%A8/1.htm">入门</a><a class="tag" taget="_blank" href="/search/%E6%B3%A8%E9%87%8A/1.htm">注释</a> <div>    Annotation: 译为注释或注解 An annotation, in the Java computer programming language, is a form of syntactic metadata that can be added to Java source code. Classes, methods, variables, pa</div> </li> <li><a href="/article/589.htm" title="tomcat的多域名、虚拟主机配置" target="_blank">tomcat的多域名、虚拟主机配置</a> <span class="text-muted">g21121</span> <a class="tag" taget="_blank" href="/search/tomcat/1.htm">tomcat</a> <div>众所周知apache可以配置多域名和虚拟主机,而且配置起来比较简单,但是项目用到的是tomcat,配来配去总是不成功。查了些资料才总算可以,下面就跟大家分享下经验。 很多朋友搜索的内容基本是告诉我们这么配置: 在Engine标签下增面积Host标签,如下: <Host name="www.site1.com" appBase="webapps"</div> </li> <li><a href="/article/716.htm" title="Linux SSH 错误解析(Capistrano 的cap 访问错误 Permission )" target="_blank">Linux SSH 错误解析(Capistrano 的cap 访问错误 Permission )</a> <span class="text-muted">510888780</span> <a class="tag" taget="_blank" href="/search/linux/1.htm">linux</a><a class="tag" taget="_blank" href="/search/capistrano/1.htm">capistrano</a> <div> 1.ssh -v hdfs@192.168.18.133 出现 Permission denied (publickey,gssapi-keyex,gssapi-with-mic,password). 错误 运行状况如下: OpenSSH_5.3p1, OpenSSL 1.0.1e-fips 11 Feb 2013 debug1: Reading configuratio</div> </li> <li><a href="/article/843.htm" title="log4j的用法" target="_blank">log4j的用法</a> <span class="text-muted">Harry642</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/log4j/1.htm">log4j</a> <div>一、前言:     log4j 是一个开放源码项目,是广泛使用的以Java编写的日志记录包。由于log4j出色的表现,     当时在log4j完成时,log4j开发组织曾建议sun在jdk1.4中用log4j取代jdk1.4 的日志工具类,但当时jdk1.4已接近完成,所以sun拒绝使用log4j,当在java开发中</div> </li> <li><a href="/article/970.htm" title="mysql、sqlserver、oracle分页,java分页统一接口实现" target="_blank">mysql、sqlserver、oracle分页,java分页统一接口实现</a> <span class="text-muted">aijuans</span> <a class="tag" taget="_blank" href="/search/oracle/1.htm">oracle</a><a class="tag" taget="_blank" href="/search/jave/1.htm">jave</a> <div> 定义:pageStart 起始页,pageEnd 终止页,pageSize页面容量 oracle分页:     select * from ( select mytable.*,rownum num from (实际传的SQL) where rownum<=pageEnd) where num>=pageStart sqlServer分页:  </div> </li> <li><a href="/article/1097.htm" title="Hessian 简单例子" target="_blank">Hessian 简单例子</a> <span class="text-muted">antlove</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/Web/1.htm">Web</a><a class="tag" taget="_blank" href="/search/service/1.htm">service</a><a class="tag" taget="_blank" href="/search/hessian/1.htm">hessian</a> <div>hello.hessian.MyCar.java package hessian.pojo; import java.io.Serializable; public class MyCar implements Serializable { private static final long serialVersionUID = 473690540190845543</div> </li> <li><a href="/article/1224.htm" title="数据库对象的同义词和序列" target="_blank">数据库对象的同义词和序列</a> <span class="text-muted">百合不是茶</span> <a class="tag" taget="_blank" href="/search/sql/1.htm">sql</a><a class="tag" taget="_blank" href="/search/%E5%BA%8F%E5%88%97/1.htm">序列</a><a class="tag" taget="_blank" href="/search/%E5%90%8C%E4%B9%89%E8%AF%8D/1.htm">同义词</a><a class="tag" taget="_blank" href="/search/ORACLE%E6%9D%83%E9%99%90/1.htm">ORACLE权限</a> <div>回顾简单的数据库权限等命令; 解锁用户和锁定用户 alter user scott account lock/unlock; //system下查看系统中的用户 select * dba_users; //创建用户名和密码 create user wj identified by wj; identified by //授予连接权和建表权 grant connect to </div> </li> <li><a href="/article/1351.htm" title="使用Powermock和mockito测试静态方法" target="_blank">使用Powermock和mockito测试静态方法</a> <span class="text-muted">bijian1013</span> <a class="tag" taget="_blank" href="/search/%E6%8C%81%E7%BB%AD%E9%9B%86%E6%88%90/1.htm">持续集成</a><a class="tag" taget="_blank" href="/search/%E5%8D%95%E5%85%83%E6%B5%8B%E8%AF%95/1.htm">单元测试</a><a class="tag" taget="_blank" href="/search/mockito/1.htm">mockito</a><a class="tag" taget="_blank" href="/search/Powermock/1.htm">Powermock</a> <div>        实例: package com.bijian.study; import static org.junit.Assert.assertEquals; import java.io.IOException; import org.junit.Before; import org.junit.Test; import or</div> </li> <li><a href="/article/1478.htm" title="精通Oracle10编程SQL(6)访问ORACLE" target="_blank">精通Oracle10编程SQL(6)访问ORACLE</a> <span class="text-muted">bijian1013</span> <a class="tag" taget="_blank" href="/search/oracle/1.htm">oracle</a><a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E5%BA%93/1.htm">数据库</a><a class="tag" taget="_blank" href="/search/plsql/1.htm">plsql</a> <div>/* *访问ORACLE */ --检索单行数据 --使用标量变量接收数据 DECLARE v_ename emp.ename%TYPE; v_sal emp.sal%TYPE; BEGIN select ename,sal into v_ename,v_sal from emp where empno=&no; dbms_output.pu</div> </li> <li><a href="/article/1605.htm" title="【Nginx四】Nginx作为HTTP负载均衡服务器" target="_blank">【Nginx四】Nginx作为HTTP负载均衡服务器</a> <span class="text-muted">bit1129</span> <a class="tag" taget="_blank" href="/search/nginx/1.htm">nginx</a> <div> Nginx的另一个常用的功能是作为负载均衡服务器。一个典型的web应用系统,通过负载均衡服务器,可以使得应用有多台后端服务器来响应客户端的请求。一个应用配置多台后端服务器,可以带来很多好处:   负载均衡的好处 增加可用资源 增加吞吐量 加快响应速度,降低延时 出错的重试验机制 Nginx主要支持三种均衡算法: round-robin l</div> </li> <li><a href="/article/1732.htm" title="jquery-validation备忘" target="_blank">jquery-validation备忘</a> <span class="text-muted">白糖_</span> <a class="tag" taget="_blank" href="/search/jquery/1.htm">jquery</a><a class="tag" taget="_blank" href="/search/css/1.htm">css</a><a class="tag" taget="_blank" href="/search/F%23/1.htm">F#</a><a class="tag" taget="_blank" href="/search/Firebug/1.htm">Firebug</a> <div>留点学习jquery validation总结的代码:   function checkForm(){ validator = $("#commentForm").validate({// #formId为需要进行验证的表单ID errorElement :"span",// 使用"div"标签标记错误, 默认:&</div> </li> <li><a href="/article/1859.htm" title="solr限制admin界面访问(端口限制和http授权限制)" target="_blank">solr限制admin界面访问(端口限制和http授权限制)</a> <span class="text-muted">ronin47</span> <a class="tag" taget="_blank" href="/search/%E9%99%90%E5%AE%9AIp%E8%AE%BF%E9%97%AE/1.htm">限定Ip访问</a> <div>solr的管理界面可以帮助我们做很多事情,但是把solr程序放到公网之后就要限制对admin的访问了。 可以通过tomcat的http基本授权来做限制,也可以通过iptables防火墙来限制。 我们先看如何通过tomcat配置http授权限制。 第一步: 在tomcat的conf/tomcat-users.xml文件中添加管理用户,比如: <userusername="ad</div> </li> <li><a href="/article/1986.htm" title="多线程-用JAVA写一个多线程程序,写四个线程,其中二个对一个变量加1,另外二个对一个变量减1" target="_blank">多线程-用JAVA写一个多线程程序,写四个线程,其中二个对一个变量加1,另外二个对一个变量减1</a> <span class="text-muted">bylijinnan</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E5%A4%9A%E7%BA%BF%E7%A8%8B/1.htm">多线程</a> <div> public class IncDecThread { private int j=10; /* * 题目:用JAVA写一个多线程程序,写四个线程,其中二个对一个变量加1,另外二个对一个变量减1 * 两个问题: * 1、线程同步--synchronized * 2、线程之间如何共享同一个j变量--内部类 */ public static </div> </li> <li><a href="/article/2113.htm" title="买房历程" target="_blank">买房历程</a> <span class="text-muted">cfyme</span> <div>    2015-06-21: 万科未来城,看房子   2015-06-26: 办理贷款手续,贷款73万,贷款利率5.65=5.3675   2015-06-27: 房子首付,签完合同   2015-06-28,央行宣布降息 0.25,就2天的时间差啊,没赶上。   首付,老婆找他的小姐妹接了5万,另外几个朋友借了1-</div> </li> <li><a href="/article/2240.htm" title="[军事与科技]制造大型太空战舰的前奏" target="_blank">[军事与科技]制造大型太空战舰的前奏</a> <span class="text-muted">comsci</span> <a class="tag" taget="_blank" href="/search/%E5%88%B6%E9%80%A0/1.htm">制造</a> <div>        天气热了........空调和电扇要准备好..........        最近,世界形势日趋复杂化,战争的阴影开始覆盖全世界..........        所以,我们不得不关</div> </li> <li><a href="/article/2367.htm" title="dateformat" target="_blank">dateformat</a> <span class="text-muted">dai_lm</span> <a class="tag" taget="_blank" href="/search/DateFormat/1.htm">DateFormat</a> <div> "Symbol Meaning Presentation Ex." "------ ------- ------------ ----" "G era designator (Text) AD" "y year</div> </li> <li><a href="/article/2494.htm" title="Hadoop如何实现关联计算" target="_blank">Hadoop如何实现关联计算</a> <span class="text-muted">datamachine</span> <a class="tag" taget="_blank" href="/search/mapreduce/1.htm">mapreduce</a><a class="tag" taget="_blank" href="/search/hadoop/1.htm">hadoop</a><a class="tag" taget="_blank" href="/search/%E5%85%B3%E8%81%94%E8%AE%A1%E7%AE%97/1.htm">关联计算</a> <div>    选择Hadoop,低成本和高扩展性是主要原因,但但它的开发效率实在无法让人满意。     以关联计算为例。     假设:HDFS上有2个文件,分别是客户信息和订单信息,customerID是它们之间的关联字段。如何进行关联计算,以便将客户名称添加到订单列表中?   &nbs</div> </li> <li><a href="/article/2621.htm" title="用户模型中修改用户信息时,密码是如何处理的" target="_blank">用户模型中修改用户信息时,密码是如何处理的</a> <span class="text-muted">dcj3sjt126com</span> <a class="tag" taget="_blank" href="/search/yii/1.htm">yii</a> <div>当我添加或修改用户记录的时候对于处理确认密码我遇到了一些麻烦,所有我想分享一下我是怎么处理的。 场景是使用的基本的那些(系统自带),你需要有一个数据表(user)并且表中有一个密码字段(password),它使用 sha1、md5或其他加密方式加密用户密码。 面是它的工作流程: 当创建用户的时候密码需要加密并且保存,但当修改用户记录时如果使用同样的场景我们最终就会把用户加密过的密码再次加密,这</div> </li> <li><a href="/article/2748.htm" title="中文 iOS/Mac 开发博客列表" target="_blank">中文 iOS/Mac 开发博客列表</a> <span class="text-muted">dcj3sjt126com</span> <a class="tag" taget="_blank" href="/search/Blog/1.htm">Blog</a> <div>  本博客列表会不断更新维护,如果有推荐的博客,请到此处提交博客信息。 本博客列表涉及的文章内容支持 定制化Google搜索,特别感谢 JeOam 提供并帮助更新。 本博客列表也提供同步更新的OPML文件(下载OPML文件),可供导入到例如feedly等第三方定阅工具中,特别感谢 lcepy 提供自动转换脚本。这里有导入教程。 </div> </li> <li><a href="/article/2875.htm" title="js去除空格,去除左右两端的空格" target="_blank">js去除空格,去除左右两端的空格</a> <span class="text-muted">蕃薯耀</span> <a class="tag" taget="_blank" href="/search/%E5%8E%BB%E9%99%A4%E5%B7%A6%E5%8F%B3%E4%B8%A4%E7%AB%AF%E7%9A%84%E7%A9%BA%E6%A0%BC/1.htm">去除左右两端的空格</a><a class="tag" taget="_blank" href="/search/js%E5%8E%BB%E6%8E%89%E6%89%80%E6%9C%89%E7%A9%BA%E6%A0%BC/1.htm">js去掉所有空格</a><a class="tag" taget="_blank" href="/search/js%E5%8E%BB%E9%99%A4%E7%A9%BA%E6%A0%BC/1.htm">js去除空格</a> <div>js去除空格,去除左右两端的空格 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>&g</div> </li> <li><a href="/article/3002.htm" title="SpringMVC4零配置--web.xml" target="_blank">SpringMVC4零配置--web.xml</a> <span class="text-muted">hanqunfeng</span> <a class="tag" taget="_blank" href="/search/springmvc4/1.htm">springmvc4</a> <div>servlet3.0+规范后,允许servlet,filter,listener不必声明在web.xml中,而是以硬编码的方式存在,实现容器的零配置。 ServletContainerInitializer:启动容器时负责加载相关配置 package javax.servlet; import java.util.Set; public interface ServletContainer</div> </li> <li><a href="/article/3129.htm" title="《开源框架那些事儿21》:巧借力与借巧力" target="_blank">《开源框架那些事儿21》:巧借力与借巧力</a> <span class="text-muted">j2eetop</span> <a class="tag" taget="_blank" href="/search/%E6%A1%86%E6%9E%B6/1.htm">框架</a><a class="tag" taget="_blank" href="/search/UI/1.htm">UI</a> <div>同样做前端UI,为什么有人花了一点力气,就可以做好?而有的人费尽全力,仍然错误百出?我们可以先看看几个故事。 故事1:巧借力,乌鸦也可以吃核桃 有一个盛产核桃的村子,每年秋末冬初,成群的乌鸦总会来到这里,到果园里捡拾那些被果农们遗落的核桃。 核桃仁虽然美味,但是外壳那么坚硬,乌鸦怎么才能吃到呢?原来乌鸦先把核桃叼起,然后飞到高高的树枝上,再将核桃摔下去,核桃落到坚硬的地面上,被撞破了,于是,</div> </li> <li><a href="/article/3256.htm" title="JQuery EasyUI 验证扩展" target="_blank">JQuery EasyUI 验证扩展</a> <span class="text-muted">可怜的猫</span> <a class="tag" taget="_blank" href="/search/jquery/1.htm">jquery</a><a class="tag" taget="_blank" href="/search/easyui/1.htm">easyui</a><a class="tag" taget="_blank" href="/search/%E9%AA%8C%E8%AF%81/1.htm">验证</a> <div>  最近项目中用到了前端框架-- EasyUI,在做校验的时候会涉及到很多需要自定义的内容,现把常用的验证方式总结出来,留待后用。   以下内容只需要在公用js中添加即可。   使用类似于如下: <input class="easyui-textbox" name="mobile" id="mobile&</div> </li> <li><a href="/article/3383.htm" title="架构师之httpurlconnection----------读取和发送(流读取效率通用类)" target="_blank">架构师之httpurlconnection----------读取和发送(流读取效率通用类)</a> <span class="text-muted">nannan408</span> <div>1.前言.    如题. 2.代码. /* * Copyright (c) 2015, S.F. Express Inc. All rights reserved. */ package com.test.test.test.send; import java.io.IOException; import java.io.InputStream</div> </li> <li><a href="/article/3510.htm" title="Jquery性能优化" target="_blank">Jquery性能优化</a> <span class="text-muted">r361251</span> <a class="tag" taget="_blank" href="/search/JavaScript/1.htm">JavaScript</a><a class="tag" taget="_blank" href="/search/jquery/1.htm">jquery</a> <div>一、注意定义jQuery变量的时候添加var关键字 这个不仅仅是jQuery,所有javascript开发过程中,都需要注意,请一定不要定义成如下: $loading = $('#loading'); //这个是全局定义,不知道哪里位置倒霉引用了相同的变量名,就会郁闷至死的 二、请使用一个var来定义变量 如果你使用多个变量的话,请如下方式定义: . 代码如下: var page </div> </li> <li><a href="/article/3637.htm" title="在eclipse项目中使用maven管理依赖" target="_blank">在eclipse项目中使用maven管理依赖</a> <span class="text-muted">tjj006</span> <a class="tag" taget="_blank" href="/search/eclipse/1.htm">eclipse</a><a class="tag" taget="_blank" href="/search/maven/1.htm">maven</a> <div>概览: 如何导入maven项目至eclipse中 建立自有Maven  Java类库服务器 建立符合maven代码库标准的自定义类库 Maven在管理Java类库方面有巨大的优势,像白衣所说就是非常“环保”。 我们平时用IDE开发都是把所需要的类库一股脑的全丢到项目目录下,然后全部添加到ide的构建路径中,如果用了SVN/CVS,这样会很容易就 把</div> </li> <li><a href="/article/3764.htm" title="中国天气网省市级联页面" target="_blank">中国天气网省市级联页面</a> <span class="text-muted">x125858805</span> <a class="tag" taget="_blank" href="/search/%E7%BA%A7%E8%81%94/1.htm">级联</a> <div>1、页面及级联js <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> &l</div> </li> </ul> </div> </div> </div> <div> <div class="container"> <div class="indexes"> <strong>按字母分类:</strong> <a href="/tags/A/1.htm" target="_blank">A</a><a href="/tags/B/1.htm" target="_blank">B</a><a href="/tags/C/1.htm" target="_blank">C</a><a href="/tags/D/1.htm" target="_blank">D</a><a href="/tags/E/1.htm" target="_blank">E</a><a href="/tags/F/1.htm" target="_blank">F</a><a href="/tags/G/1.htm" target="_blank">G</a><a href="/tags/H/1.htm" target="_blank">H</a><a href="/tags/I/1.htm" target="_blank">I</a><a href="/tags/J/1.htm" target="_blank">J</a><a href="/tags/K/1.htm" target="_blank">K</a><a href="/tags/L/1.htm" target="_blank">L</a><a href="/tags/M/1.htm" target="_blank">M</a><a href="/tags/N/1.htm" target="_blank">N</a><a href="/tags/O/1.htm" target="_blank">O</a><a href="/tags/P/1.htm" target="_blank">P</a><a href="/tags/Q/1.htm" target="_blank">Q</a><a href="/tags/R/1.htm" target="_blank">R</a><a href="/tags/S/1.htm" target="_blank">S</a><a href="/tags/T/1.htm" target="_blank">T</a><a href="/tags/U/1.htm" target="_blank">U</a><a href="/tags/V/1.htm" target="_blank">V</a><a href="/tags/W/1.htm" target="_blank">W</a><a href="/tags/X/1.htm" target="_blank">X</a><a href="/tags/Y/1.htm" target="_blank">Y</a><a href="/tags/Z/1.htm" target="_blank">Z</a><a href="/tags/0/1.htm" target="_blank">其他</a> </div> </div> </div> <footer id="footer" class="mb30 mt30"> <div class="container"> <div class="footBglm"> <a target="_blank" href="/">首页</a> - <a target="_blank" href="/custom/about.htm">关于我们</a> - <a target="_blank" href="/search/Java/1.htm">站内搜索</a> - <a target="_blank" href="/sitemap.txt">Sitemap</a> - <a target="_blank" href="/custom/delete.htm">侵权投诉</a> </div> <div class="copyright">版权所有 IT知识库 CopyRight © 2000-2050 E-COM-NET.COM , All Rights Reserved. <!-- <a href="https://beian.miit.gov.cn/" rel="nofollow" target="_blank">京ICP备09083238号</a><br>--> </div> </div> </footer> <!-- 代码高亮 --> <script type="text/javascript" src="/static/syntaxhighlighter/scripts/shCore.js"></script> <script type="text/javascript" src="/static/syntaxhighlighter/scripts/shLegacy.js"></script> <script type="text/javascript" src="/static/syntaxhighlighter/scripts/shAutoloader.js"></script> <link type="text/css" rel="stylesheet" href="/static/syntaxhighlighter/styles/shCoreDefault.css"/> <script type="text/javascript" src="/static/syntaxhighlighter/src/my_start_1.js"></script> </body> </html>