标签:
Nginx负载均衡,其实主要就是用upstream、server指令,再配以权重等等参数。如果为了让nginx支持session共享,还需要额外增加一个模块。
一、Nginx负载均衡
在http{...}中配置一个upstream{...},参考如下:
引用
upstream tomcat {
server 10.11.155.26:8080;
server 10.11.155.41:8080;
}
接着修改location节点,配置代理:
引用
location / {
...
proxy_pass http://tomcat;
...
}
当访问根路径时,会轮播路由到两台服务器上,至于后端服务器是tomcat还是jetty之类的,都无所谓,照葫芦画瓢就是了。
当然,有的机器性能好,或者负载低,可以承担高负荷访问量,可以通过权重(weight),提升访问频率。数值越高,被分配到的请求数越多。
server指令参数如下:
- weight——权重,数值越大,分得的请求数就越多,默认值为1。
- max_fails——对访问失败的后端服务器尝试访问的次数。默认值为1,当设置为0时将关闭检查。
- fail_timeout——失效超时时间,当多次访问失败后,对该节点暂停访问。
- down——标记服务器为永久离线状态,用于ip_hash指令。
- backup——仅当非backup服务器全部宕机或繁忙时启用。
例如,可以这样配置:
引用
upstream tomcat {
server 10.11.155.26:8080 weight=5;
server 10.11.155.41:8080 weight=10;
}
后者分得的请求数就会较高。
二、Nginx+Tomcat+Session共享
为了让Nginx支持Tomcat的Session共享,需要对其升级,增加jvmroute模块。
1.下载nginx-upstream-jvm-route组件、对nginx源码做补丁。
我把nginx-upstream-jvm-route下载到了/opt/software路径下。
先切换到nginx源码目录下,执行:
Shell代码
- patch -p0 < /opt/software/nginx_upstream_jvm_route/jvm_route.patch
引用
patching file src/http/ngx_http_upstream.c
Hunk #1 succeeded at 4095 (offset 358 lines).
Hunk #3 succeeded at 4227 (offset 358 lines).
Hunk #5 succeeded at 4326 (offset 358 lines).
patching file src/http/ngx_http_upstream.h
Hunk #1 succeeded at 90 (offset 5 lines).
Hunk #3 succeeded at 118 (offset 5 lines).
说明补丁做好了!
2.升级nginx
先别急着折腾nginx-upstream-jvm-route,先看看nginx当时安装时的参数:
Shell代码
- nginx -V
引用
nginx version: nginx/1.2.0
configure arguments: --prefix=/opt/servers/nginx --user=nginx --group=www --pid-path=/var/run/nginx.pid --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --with-pcre=/opt/software/pcre-8.10 --with-zlib=/opt/software/zlib-1.2.5 --with-http_stub_status_module --with-http_realip_module --with-http_gzip_static_module
记得先备份nginx.conf!
使用追加参数(--add-module),增设nginx-upstream-jvm-route模块,
--add-module=/opt/software/nginx_upstream_jvm_route
,编译安装。
Shell代码
- ./configure --prefix=/opt/servers/nginx --user=nginx --group=www --pid-path=/var/run/nginx.pid --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --with-pcre=/opt/software/pcre-8.10 --with-zlib=/opt/software/zlib-1.2.5 --with-http_stub_status_module --with-http_realip_module --with-http_gzip_static_module --add-module=/opt/software/nginx_upstream_jvm_route && make && make insatll
如果没有错误提示,nginx就成功升级了!
3.修改upstream配置
要让Nginx支持Tomcat的jvmRoute,并共享session,在upstream下作如下修改:
引用
upstream tomcat {
server 10.11.155.26:8080 srun_id=tomcat1;
server 10.11.155.41:8080 srun_id=tomcat2;
jvm_route $cookie_JSESSIONID|sessionid reverse;
}
srun_id
跟tomcat配置有关。
4.Tomcat集群配置(Tomcat6、7通用)
该配置参考
征服 Apache + Tomcat
,以下仅作简要说明。
a.修改server.xml
找到
Engine
节点,并设置
jvmRoute
,这里指定
tomcat1
。
Xml代码
- <Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat1">
可以直接粘贴以下代码,并对应修改
Receiver
节点中的
address
属性,指向本机:
Xml代码
- <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"
- channelSendOptions="8">
- <Manager className="org.apache.catalina.ha.session.DeltaManager"
- expireSessionsOnShutdown="false"
- notifyListenersOnReplication="true"/>
- <Channel className="org.apache.catalina.tribes.group.GroupChannel">
- <Membership className="org.apache.catalina.tribes.membership.McastService"
- address="224.0.0.0"
- port="45564"
- frequency="500"
- dropTime="3000"/>
- <Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver"
- address="10.11.155.26"
- port="4000"
- autoBind="100"
- selectorTimeout="5000"
- maxThreads="6"/>
- <Sender className="org.apache.catalina.tribes.transport.ReplicationTransmitter">
- <Transport className="org.apache.catalina.tribes.transport.nio.PooledParallelSender"/>
- </Sender>
- <Interceptor className="org.apache.catalina.tribes.group.interceptors.TcpFailureDetector"/>
- <Interceptor className="org.apache.catalina.tribes.group.interceptors.MessageDispatch15Interceptor"/>
- </Channel>
- <Valve className="org.apache.catalina.ha.tcp.ReplicationValve"
- filter=".*\.gif;.*\.js;.*\.jpg;.*\.png;.*\.htm;.*\.html;.*\.css;.*\.txt;"/>
- <Valve className="org.apache.catalina.ha.session.JvmRouteBinderValve"/>
- <ClusterListener className="org.apache.catalina.ha.session.JvmRouteSessionIDBinderListener"/>
- <ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener"/>
- </Cluster>
注:如果本机上有多个tomcat并存,Receiver节点中的port属性,使其绑定在不同的端口上。
Membership
节点
address
属性配置多播地址,可使用
route
命令将其打开,参考如下:
Shell代码
- route add -net 224.0.0.0/8 dev eth0
b.修改应用的
web.xml
在web.xml末尾增加
<distributable />
Xml代码
- <web-app>
- ...
- <distributable />
- </web-app>
至此,已完成所有配置,重启tomcat、nginx,访问服务测试页面(见附件),强行关闭其中一台tomcat,令请求转向另一个台tomcat,测试session是否同步:
session共享成功,非粘性实现
一、准备工作
下载如下组件:
pcre,有关正则表达式匹配;zlib,用于压缩。这些就不细说了,如果要安装最简版的nginx,记得准备好这两样东西就好了。
用root账户启动服务是比较危险的!
前段时间,测试服务器被黑掉了,终归到底是通过一个root启动的服务上传了木马,最后连ssh都屏蔽了,活生生成为一台肉鸡。。。
所以,惨痛的经验告诉我,一定要为服务建立对应的组和用户,限制访问权限,降低风险!
这里为nginx建立一个www组,并建立一个不登录的账户nginx:
Shell代码
- #追加一个www组
- groupadd -f www
- #追加一个nginx用户
- useradd -s /sbin/nologin -g www nginx
建立一个目录用于存放nginx日志文件,并赋予相应权限:
Shell代码
- #建立nginx日志目录
- mkdir /var/log/nginx
- #赋予访问权限
- chown nginx.www /var/log/nginx
二、编译安装
我把pcre、zlib、nginx的压缩包都放在了
/opt/software
路径下,服务要装在
/opt/servers
路径下。
先对pcre、zlib、nginx解压,然后编译安装:
Shell代码
- ./configure --prefix=/opt/servers/nginx \
- --user=nginx \
- --group=www \
- --pid-path=/var/run/nginx.pid \
- --error-log-path=/var/log/nginx/error.log \
- --http-log-path=/var/log/nginx/access.log \
- --with-pcre=/opt/software/pcre-8.10 \
- --with-zlib=/opt/software/zlib-1.2.5 \
- --with-http_stub_status_module \
- --with-http_realip_module \
- --with-http_gzip_static_module \
- --without-http_fastcgi_module \
- --without-http_memcached_module \
- --without-http_map_module \
- --without-http_geo_module \
- --without-http_autoindex_module \
- --with-poll_module
- && make && make install
三、系统配置
我希望nginx可以作为一个服务,通过service命令启动或停止。
这样做的好处是,不论我用什么用户调用这个service命令,都不会因为使用错误的账户带来安全问题。
建立一个系统文件:
Shell代码
- vim /etc/init.d/nginx
前人栽树,后人乘凉。已经有老鸟做好了启动配置文件:
Shell代码
- #!/bin/bash
- # v.0.0.1
- # create by jackbillow at 2007.10.15
- # nginx - This shell script takes care of starting and stopping nginx.
- #
- # chkconfig: - 60 50
- # description: nginx [engine x] is light http web/proxy server
- # that answers incoming ftp service requests.
- # processname: nginx
- # config: /etc/nginx.conf
- nginx_path="/opt/servers/nginx"
- nginx_pid="/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 0
- [ -x $nginx_path/sbin/nginx ] || exit 0
- RETVAL=0
- prog="nginx"
- start() {
- # Start daemons.
- if [ -e $nginx_pid -a ! -z $nginx_pid ];then
- echo "nginx already running...."
- exit 1
- fi
- if [ -e $nginx_path/conf/nginx.conf ];then
- echo -n $"Starting $prog: "
- $nginx_path/sbin/nginx -c $nginx_path/conf/nginx.conf &
- RETVAL=$?
- [ $RETVAL -eq 0 ] && {
- touch /var/lock/subsys/$prog
- success $"$prog"
- }
- echo
- else
- RETVAL=1
- fi
- return $RETVAL
- }
- # Stop daemons.
- stop() {
- echo -n $"Stopping $prog: "
- killproc -d 10 $nigx_path/sbin/nginx
- RETVAL=$?
- echo
- [ $RETVAL = 0 ] && rm -f $nginx_pid /var/lock/subsys/$prog
- }
- # See how we were called.
- case "$1" in
- start)
- start
- ;;
- stop)
- stop
- ;;
- restart)
- stop
- start
- ;;
- status)
- status $prog
- RETVAL=$?
- ;;
- *)
- echo $"Usage: $0 {start|stop|restart|status}"
- exit 1
- esac
- exit $RETVAL
注意,这里的路径:
引用
nginx_path="/opt/servers/nginx"
nginx_pid="/var/run/nginx.pid"
如果你的nginx安装路径在其它位置,请对应修改!
然后赋予这个文件执行权限:
Shell代码
- chmod +x /etc/init.d/nginx
追加为系统服务:
Shell代码
- chkconfig --add nginx
- chkconfig nginx on
现在就可以使用,如下命令控制nginx服务了!
引用
#启动nginx
service nginx start
#停止nginx
service nginx stop
#重启nginx
service nginx restart
#查看nginx状态
service nginx status
三、vim语法支持
vim对于nginx配置文件的支持不那么友好,无法对关键字高亮显示。
不过,没关系。我们可以通过修改
~/.vim
配置,增强vim功能。
参考
vim for nginx
配置VIM语法高亮及自动缩进
可能你的用户目录下并没有
.vim
这个目录,需要自行建立。
Shell代码
- mkdir ~/.vim
- mkdir ~/.vim/syntax
建立针对nginx的配置文件,这里的nginx配置文件的路径是
/opt/servers/nginx/conf
,注意对应修改:
Shell代码
- echo ‘au BufRead,BufNewFile /opt/servers/nginx/conf/* set ft=nginx‘ > ~/.vim/filetype.vim
最后,请出主角(下载的是本文的附件
):
Shell代码
- wget http://dl.iteye.com/topics/download/7979de38-1263-3b65-8f7a-e5f567d40fec
- unzip nginx.zip
- mv nginx.vim ~/.vim/syntax/
这样就ok了!
四、基本配置
完成上述工作后,nginx还不能急于投入使用,需要做一些基本配置与优化工作。
修改nginx配置文件:
Shell代码
- vim /opt/servers/nginx/conf/nginx.conf
微调
引用
#使用的用户和组,这里我们为nginx服务新建了nginx账户和www工作组
user nginx www;
#制定的工作衍生进程数(2倍于CPU内核数)
worker_processes 4;
#错误日志存放路径,日志级别由低到高[debug | info | notice | warn | error | crit]
error_log /var/log/nginx/error.log crit;
#指定文件描述符数量 与ulimit -n数值保持一致
work_rlimit_nofile 65535;
events {
#使用的网络I/O模型,Linux用epoll模型,Unix用kqueue模型
use epoll;
#允许的连接数
worker_connections 51200;
}
http{
include mime.types;
default_type application/octet-stream;
#追加 ‘"$sent_http_cache_control" "$sent_http_pl" "$request_time"‘获取请求细节信息
log_format main ‘$remote_addr - $remote_user [$time_local] "$request" ‘
‘$status $body_bytes_sent "$http_referer" ‘
‘"$http_user_agent" "$http_x_forwarded_for"‘
‘"$sent_http_cache_control""$sent_http_pl" "$request_time"‘;
access_log /var/log/nginx/access.log main;
...
server{
...
location / {
root html;
index index.html index.htm index.jsp index.do;
#在header中传递请求放host、ip等信息
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass_header Content-Type;
proxy_pass_header Content-Disposition;
proxy_pass_header Content-Length;
...
}
}
}
五、虚拟目录
nginx配置虚拟目录很简单,主要是运用root、alias两个指令。
以访问图片服务为例:
root,用于相对路径
引用
location /image/ {
root /data;
}
当我们访问“/image/”路径时,实际上访问的是“/data/image/”,注意“/data”后面不要有“/”
alias,用于绝对路径
引用
location /image/ {
alias /data/img/;
}
当我们访问“/image/”路径时,实际上访问的是“/data/img/”,注意“/data/img/”以“/”结尾。
六、重定向
有时候链接不加考虑就放出去了,突然哪天需要调整,又不能及时撤回已放出的链接地址。只好自己修改nginx配置。
譬如,放出去的链接:/activity.do?m=v 想让它指到/路径上:
引用
rewrite ^/activity(.*)$ / last;
想要把请求来的参数也带上:
引用
rewrite ^/activity(.*)$ /$1 last;
$1
指得是第一个参数,以此类推。
六、监控
引用
location /status {
stub_status on;
access_log off;
allow 10.10.0.0/16;
allow 10.1.0.0/16;
allow 10.11.0.0/16;
deny all;
}
引用
Active connections: 14
server accepts handled requests
62 62 302
Reading: 0 Writing: 3 Waiting: 11
七、日志分割
Shell代码
- #!/bin/bash
- # THis script run at 00:00
- # author dongliang at 2012-09-07
- # Nginx Log Path
- logs_path="/var/log/nginx/"
- # Nginx PID Path
- nginx_pid="/var/run/nginx.pid"
-
- mkdir -p ${logs_path}$(date -d "yesterday" +"%Y")/$(date -d "yesterday" +"%m")/
-
- mv ${logs_path}access.log ${logs_path}$(date -d "yesterday" +"%Y")/$(date -d "yesterday" +"%m")/access_$(date -d "yesterday" +"%Y%m%
- d").log
-
- mv ${logs_path}error.log ${logs_path}$(date -d "yesterday" +"%Y")/$(date -d "yesterday" +"%m")/error_$(date -d "yesterday" +"%Y%m%d"
- ).log
-
- kill -USR1 `cat $nginx_pid`
赋予执行权限
Shell代码
- chmod +x nginx_log.sh
凌晨执行
Shell代码
- crontab -e
- 0 0 * * * /opt/script/nginx_log.sh
步骤:
- 安装Apache基本模块
- 后台监控
- 负载均衡简单测试
- 配置Tomcat相关模块(AJP)
- 保持Session唯一,粘性会话
- Tomcat集群,Session复制
1.安装Apache相关模块
负载均衡需要的主要是代理模块!
经过几次Apache配置尝试,在Ubuntu下配置Apache实在是太容易了。加载什么模块、取消什么模块两个命令搞定。
Shell代码
- #启用模块
- sudo a2enmod <model>
- #禁用模块
- sudo a2dismod <model>
这里,我们需要让Apache提供代理服务,其中又包含基于http、ftp、ajp等等协议的代理功能,同时还需要负载均衡模块。我们可以通过命令逐个加载:
Shell代码
- #代理核心模块
- sudo a2enmod proxy
- #代理AJP模块
- sudo a2enmod proxy_ajp
- #代理负载均衡模块
- sudo a2enmod proxy_balancer
- #代理HTTP模块
- sudo a2enmod proxy_http
- #代理FTP模块
- sudo a2enmod proxy_ftp
完成上述操作后,系统会提示重启Apache!
先不着急重启,现学现卖,了解下Apache的目录结构。在Ubuntu下配置Apache主要是在
/etc/apache2
目录下:
分述:
- apache2.conf核心配置文件,一般不需要修改!
- conf.d目录,里面包含了一些字符集设置,文档等设置!
- dav_svn.authz和dav_svn.passwd是前面做SVN时,相关权限、密码文件。
- envvars定义了运行时的用户身份——www-data。
- httpd.conf是Apache留给我们自己折腾的配置文件,默认为空。apache2.conf会加载这个文件。
- ports.conf端口默认配置。apache2.conf会加载这个文件。
- magic为mod_mime_magic模块服务。
- mods-enabled和mods-available mods-enabled会被apache2.conf加载,里面包含*.load和*.conf文件。*.load文件中是加载相应的模块(位于/usr/lib/apache2/modules/中),而*.conf中是对应的基本配置。但这些文件其实都是链接到mods-available中相应的文件上。当我们通过a2enmod操作时,实际上正是操作了这些软链接。
- sites-available和sites-enabled 与 mods-enabled和mods-available的关系类似,只是其中包含的是站点内容。
罗嗦了一堆,下面配置负载均衡部分。
执行修改:
Shell代码
- sudo vi /etc/apache2/mods-available/proxy.conf
上图红框中的内容是原始内容,白框中的内容是我新加的部分。
注意红框中的配置:
Conf代码
- <Proxy *>
- AddDefaultCharset off
- Order deny,allow
- #Deny from all
- Allow from localhost ip6-localhost
- </Proxy>
在默认配置中,Deny from all处于可用状态。当我们配置其他代理节点时,将导致杜绝访问!
使用
Allow from localhost ip6-localhost
限制仅允许本机访问!
再说,白框中的内容:
Conf代码
- <Proxy balancer://zlex>
- BalancerMember http://localhost:8080/
- BalancerMember http://192.168.49.1:8080/
- </Proxy>
这里,我配置了一个负载均衡节点
balancer://zlex
,其中包含了两个服务
http://localhost:8080/
和
http://192.168.49.1:8080/
,一个是虚拟机上的Tomcat、一个是真机上的Tomcat。这里使用的Http的转发方式,当然,使用AJP未尝不可,稍后详述!
这里的节点次序会有一个先后关系,Apache会将请求按照FIFO的方式调度顺次分配到各个节点上!如果其中有一个节点挂掉,将跳过该节点顺次寻找可用节点。
再说代理和反向代理:
Conf代码
- ProxyPass /zlex balancer://zlex
- ProxyPassReverse /zlex balancer://zlex
这里配置,如果要访问
/zlex
路径时,将跳转到
balancer://zlex
上,也就是享受负载均衡!
2.后台监控
我们如何知道某个节点负载多少,响应时间多久,服务是否正常呢?Apache提供了负载均衡监控平台:
http://localhost/balancer-manager
。但是,这个服务默认是不存在。
除了用于负载均衡配置、监控的
balancer-manager
还有
http://localhost/server-status
和
http://localhost/server-info
我们需要添加info模块:
Shell代码
- #系统信息模块
- sudo a2enmod info
同时,为了能够使用
balancer-manager
,我们需要配置:
Conf代码
- <Location /balancer-manager>
- SetHandler balancer-manager
- Order Deny,Allow
- #Deny from all
- Allow from localhost ip6-localhost
- </Location>
把这段代码放到哪?由于它同属系统信息配置,我把它放到了
info.conf
中,说白了就是照猫画虎:
Shell代码
- sudo vi /etc/apache2/mods-available/info.conf
注意,这段代码放到了
<IfModule mod_info.c>
和
</IfModule>
之间!
现在,我们重启Apache:
Shell代码
- sudo /etc/init.d/apache2 restart
来看看管理界面
http://localhost/balancer-manager
:
我们再来看看服务器基本信息
http://localhost/server-info
:
上述两个服务需要加载info模块,而服务器状态(server-status)不需要
http://localhost/server-status
:
3.负载均衡简单测试
疯狂访问
http://localhost/zlex
,直到手酸眼烦!
我这里故意使用不同了Tomcat界面,来验证自己的配置是否生效。更疯狂的是,我甚至把节点指向了百度、搜狐,来测试负载均衡的效果。如果你细致观察,Apache是将请求顺次分配到各个节点上的。
如果其中一个节点发生问题(例如,强行关闭一个Tomcat,或配置一个错误节点)Apache将会经过几次尝试后,绕过这个问题节点,寻找可以成功访问的节点。如果这个节点恢复正常使用,Apache将在该Tomcat恢复正常工作后大约1分钟内将该节点标识为可用!
现在,再看看现在的后台(
http://localhost/balancer-manager
)啥样子:
如果我们控制一个节点的状态是否可用,该怎么做:
涉及到负载量,session同步等等,我们最后讨论!
4.配置Tomcat相关模块(AJP)
基于Http协议分发并不复杂,但AJP效果更好!一次诡异事件中,内网访问正常,外网访问多次失败,最后通过AJP方式完美解决了!
在Tomcat中配置AJP也很简单,修改
server.xml
开启AJP模块:
Shell代码
- sudo vi /etc/tomcat6/server.xml
开启AJP配置:
Xml代码
- <Connector port="8009" protocol="AJP/1.3"
- URIEncoding="UTF-8"
- redirectPort="8443" />
注意使用的端口port="8009",字符集URIEncoding="UTF-8",这是输入框、请求字符集乱码的入口!
接下里就可以通过AJP方式进行节点分发了。修改
/etc/apache2/mods-available/proxy.conf
:
Shell代码
- sudo vi /etc/apache2/mods-available/proxy.conf
将
http
改为
ajp
,将
8080
改为
8009
:
Conf代码
- <Proxy balancer://zlex>
- BalancerMember ajp://localhost:8009/
- BalancerMember ajp://192.168.49.1:8009/
- </Proxy>
重启Apache:
Shell代码
- sudo /etc/init.d/apache2 restart
再看看管理界面
http://localhost/balancer-manager
至此,我们完成了基本负载均衡的基本配置!
/etc/apache2/mods-available/proxy.conf
还有一些属性:
noFailOver
是否打开失败转移,
On
|
Off
,默认为Off,添加在
ProxyPass
后面,如:
Conf代码
- ProxyPass /zlex balancer://zlex stickySession=JSESSIONID noFailOver=On
如果这样配置,当提供给你服务的服务器发生异常,那么你将一直看着它返回给你503,直到系统恢复正常!
loadfactor
表示后台服务器负载到由Apache发送请求的权值,默认值为1添加在
BalancerMember
后面:
Conf代码
- <Proxy balancer://zlex>
- BalancerMember ajp://localhost:8009/
- BalancerMember ajp://192.168.49.1:8009/
- </Proxy>
可以实现三种策略:
- 轮询均衡策略的配置
- 按权重分配均衡策略的配置
- 权重请求响应负载均衡策略的配置
5.Session唯一,粘性会话
Apache已经可以轻松将内容处理的工作分配给各个Tomcat了!
当然,这还不够,Session还是个问题!
WHY?
我们来做一系列修改,来检测Session到底出现了什么问题!
先来改造Tomcat,修改
server.xml
:
Shell代码
- sudo vi /etc/tomcat6/server.xml
修改
<Engine />
节点,增加
jvmRoute
属性:
Xml代码
- <Engine
- name="Catalina"
- defaultHost="localhost"
- jvmRoute="tomcat1">
另一个Tomcat设置改为
Xml代码
- <Engine
- name="Catalina"
- defaultHost="localhost"
- jvmRoute="tomcat2">
通过
jvmRoute
,指定了Tomcat唯一标识!
然后修改
/etc/apache2/mods-available/proxy.conf
Shell代码
- sudo vi /etc/apache2/mods-available/proxy.conf
如下:
Java代码
- <Proxy balancer://zlex>
- BalancerMember ajp://localhost:8009/zlex route=tomcat1
- BalancerMember ajp://192.168.49.1:8009/zlex route=tomcat2
- </Proxy>
-
- ProxyPass /zlex balancer://zlex
- ProxyPassReverse /zlex balancer://zlex
这里需要通过修改
route
属性,将Apache与Tomcat关联起来!
注意,Tomcat中定义的jvmRoute需要与Apache定义的route相对应!
我们来看一下
http://localhost/balancer-manager
发生了什么变化:
我们注意到route字段有了新的标识,当然,我们也可以通过这个配置界面修改这些信息,但当前修改不会真的修改/etc/apache2/mods-available/proxy.conf文件,Apache重启后将丢失。
为了更细致的对比进过复杂均衡的结果,这里增加了zlex应用!主要是监控Session的变化!
只看核心代码:
Jsp代码
- <b>当前SessionID:</b>
- <br />
- <%
- String sessionID = session.getId();
- out.println(sessionID);
- System.err.println("sessionID = " + sessionID);
-
- // 如果有新的 Session 属性设置
- String dataName = request.getParameter("dataName");
- if (dataName != null && !dataName.isEmpty()) {
- String dataValue = request.getParameter("dataValue");
- session.setAttribute(dataName, dataValue);
- }
- %>
- <br />
- <br />
- <b>Session属性列表:</b>
-
- <br />
- <%
- Enumeration<String> e = (Enumeration<String>) session
- .getAttributeNames();
- while (e.hasMoreElements()) {
- String name = e.nextElement();
- String value = (String) session.getAttribute(name);
- out.println(name + " = " + value + "<br>");
- System.err.println(name + " = " + value);
- }
- %>
- <form method="POST">
- <ul style="list-style-type: none;">
- <li><label for="dataName">键:</label><input size="20" id="dataName"
- name="dataName"></li>
- <li><label for="dataValue">值:</label><input size="20"
- id="dataValue" name="dataValue"></li>
- <li><input type="submit" value="提交" /></li>
- </ul>
- </form>
将其做成一个名为zlex的web应用,分别部署到两个Tomcat上!
然后重启Apache:
Shell代码
- sudo /etc/init.d/apache2 restart
不断刷新
http://localhost/zlex
,看看真正的结果:
第1次:
第2次:
第3次:
第4次:
仔细观察,每次请求都按照负载均衡配置的节点次序依次请求到不同的Tomcat上。尤其是当我们通过
jvmRoute
和
route
做了绑定之后,信息更加准确。但是,
仔细观察,每次请求的SessionID都是不一样!
对于纯Web应用,尤其是依靠SessionID区分唯一用户的应用,这将是一场噩梦——解决了服务器压力均衡问题,却带来了SessionID不唯一问题!这就需要SessionID绑定,或者说叫做“会话复制”。
如果这时候你在页面上提交表单,将键值对保持在session中,在页面刷新后,将无法获得该信息,因为Seesion丢失了!
接着修改
/etc/apache2/mods-available/proxy.conf
,让SeesionID保持唯一:
Shell代码
- sudo vi /etc/apache2/mods-available/proxy.conf
增加
stickySession
属性:
Conf代码
- ProxyPass /zlex balancer://zlex stickySession=JSESSIONID
stickySession
粘性会话,根据这一属性,浏览器将通过cookie绑定SeesionID。如果这个时候再次访问
http://localhost/zlex
,你会发现,页面不会来回跳转了!
sticky是什么?
引用
sticky模式
利用负载均衡器的sticky模式的方式把所有同一session的请求都发送到相同的Tomcat节点。这样不同用户的请求就被平均分配到集群中各个tomcat节点上,实现负载均衡的能力。这样做的缺点是没有灾难恢复的能力。一旦一个节点发生故障,这个节点上所有的session信息全部丢失;
同一用户同一session只和一个webServer交互,一旦这个webserver发生故障,本次session将丢失,用户不能继续使用 !
提交一个Session设定看看
http://localhost/zlex
:
观察后台日志:
再看看返回页面,这相当于一次页面刷新,如果正常粘性会话,我们将获得当前SessionID对应的一切信息:
这说明粘性会话生效了!
我们得到了形如
引用
50DAF14C6CDF8ACFBDC1095A5EE8E2CF.tomcat1
的SessionID。这样,我们就能知道当前访问的是哪台服务器了!
如果,换一个浏览器打开该页面http://localhost/zlex,将会获得一个新的SessionID,并且,根据Apache中配置的负载均衡节点列表依次访问下一个节点!
如果这时候负载均衡节点列表中某一节点发生异常,那么Apache将按照惯例,跳转该节点,并在该节点恢复正常后约1分钟内重新将其纳入可用节点!
修改刚才的jsp页面,看看Http头中都有些什么:
Jsp代码
- <b>Cookie信息:</b>
- <br />
- ${header["cookie"]}
- <br />
- <b>Host信息:</b>
- <br />
- ${header["host"]}
- <br />
sticky模式的根本在于浏览器支持cookie,如果浏览器不支持cookie,则需要修改server.xml文件中的<Context />节点,将cookie置为false,关闭cookie功能,让jsessionid显式传递!
6.Tomcat集群,Session复制
经过两天反复研究,两只互不相认的Tomcat终于在网络上“资源共享”了——Session复制成功!
关于
Tomcat集群以及Session复制
,网上已经有很多很多,但是否真的能用?!为了确认这一问题,周末还跑到书店翻了翻《Apache Tomcat 高级编程》,参考
Clustering/Session Replication HOW-TO
(有点小错误),经过两天苦战,克服种种小问题,终于拿下!
整理概念:
引用
群集,是包含多个服务器实例的指定集合,这些服务器实例共享相同的应用程序、资源以及配置信息。您可以将不同计算机上的服务器实例分组到一个逻辑群集中并将其作为一个单元来管理。您可以使用 DAS 轻松控制多机群集的生命周期。
群集可以实现水平可伸缩性、负载平衡和故障转移保护。根据定义,群集中的所有实例都具有相同的资源和应用程序配置。当群集中的服务器实例或计算机出现故障时,负载平衡器检测到该故障,会将通信从出现故障的实例重定向至群集中的其他实例,并恢复用户会话状态。由于群集中所有实例上的应用程序和资源都相同,因此一个实例可以故障转移至群集中的任何其他实例。
引用
Session复制,主要是指集群环境下,多台应用服务器之间同步Session,确保Session保持一致,且Session中的内容保持一致,对外透明——看起来就像是一台应用服务器!
如果其中一台服务器发生故障,根据负载均衡的原理,Apache会遍历寻找可用节点,分发请求。与此同时,当前用户Session不能发生数据丢失,其余各节点服务器应保证用户Session数据同步。
Session复制核心内容主要是:
- Session内容序列化(serialize),会消耗系统性能。
- Session内容通过广播同步给成员,会造成网络流量瓶颈,即便是内网瓶颈。
因此,Session复制的这两个潜在问题,致使复杂均衡节点最多不会超过4个。因为,当节点数大于4时,整个集群的吞吐量将不再上升!
为了搭建Tomcat集群,我将两个Tomcat分别部署到两台虚拟机上,确保网段一致。(这一步很关键,我最初将
Tomcat1(192.168.49.132)
部署在虚拟机上,将
Tomcat2(192.168.49.128)
部署在本机上,结果,网络总有问题,耽误了很多时间。
)
由于变换了IP,我需要修改Apache的
/etc/apache2/mods-available/proxy.conf
文件:
Shell代码
- sudo vi /etc/apache2/mods-available/proxy.conf
修改负载均衡节点如下:
Conf代码
- <Proxy balancer://zlex>
- BalancerMember ajp://192.168.49.128:8009/zlex route=tomcat1
- BalancerMember ajp://192.168.49.132:8009/zlex route=tomcat2
- </Proxy>
对于windows系统,不需要考虑网络问题,广播地址(这里用到
224.0.0.0
和
240.0.0.0
)默认开放,对于linux则需要通过命令开放地址。
Ubuntu上开放广播地址(eth0网卡):
Shell代码
- sudo route add -net 224.0.0.0 netmask 240.0.0.0 dev eth0
然后通过
-v
参数查看当前开放的广播地址:
Shell代码
- route -v
注意,重启后,该路由设置将丢失!
在Ubuntu下,可以考虑修改
/etc/networks
文件!
如果有必要,Windows上开放广播地址(192.168.49.128本机地址):
Cmd代码
- route add 224.0.0.0 mask 240.0.0.0 192.168.49.128
然后通过
print
参数查看当前开放的广播地址:
Shell代码
- route print
然后,修改tomcat的server.xml文件:
Shell代码
- sudo vi /etc/tomcat6/server.xml
在
<Engine />
节点中加入如下内容:
Xml代码
- <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"
- channelSendOptions="8">
-
- <Manager className="org.apache.catalina.ha.session.DeltaManager"
- expireSessionsOnShutdown="false"
- notifyListenersOnReplication="true"/>
-
- <Channel className="org.apache.catalina.tribes.group.GroupChannel">
- <Membership className="org.apache.catalina.tribes.membership.McastService"
- address="224.0.0.0"
- port="45564"
- frequency="500"
- dropTime="3000"/>
- <Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver"
- address="192.168.49.1"
- port="4000"
- autoBind="100"
- selectorTimeout="5000"
- maxThreads="6"/>
-
- <Sender className="org.apache.catalina.tribes.transport.ReplicationTransmitter">
- <Transport className="org.apache.catalina.tribes.transport.nio.PooledParallelSender"/>
- </Sender>
- <Interceptor className="org.apache.catalina.tribes.group.interceptors.TcpFailureDetector"/>
- <Interceptor className="org.apache.catalina.tribes.group.interceptors.MessageDispatch15Interceptor"/>
- </Channel>
-
- <Valve className="org.apache.catalina.ha.tcp.ReplicationValve"
- filter=".*\.gif;.*\.js;.*\.jpg;.*\.png;.*\.htm;.*\.html;.*\.css;.*\.txt;"/>
- <Valve className="org.apache.catalina.ha.session.JvmRouteBinderValve"/>
-
- <ClusterListener className="org.apache.catalina.ha.session.JvmRouteSessionIDBinderListener"/>
- <ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener"/>
- </Cluster>
这里需要注意
<Membership />
和
Receiver
:
<Membership />
节点的
address
属性是广播地址;
Receiver
节点的
address
属性是本地绑定地址。当然,默认为
auto
。由于我在启动Tomcat时,Tomcat频频将地址指向
127.0.0.1
,无奈只好使用固定IP。
此外,为了降低Session复制的成本,Tomcat通过
<Valve />
节点,以过滤器的方式控制哪些请求可以忽略Session复制:
Xml代码
- <Valve className="org.apache.catalina.ha.tcp.ReplicationValve"
- filter=".*\.gif;.*\.js;.*\.jpg;.*\.png;.*\.htm;.*\.html;.*\.css;.*\.txt;"/>
同时,在<Host>节点中加入如下内容:
Xml代码
- <Deployer className="org.apache.catalina.ha.deploy.FarmWarDeployer"
- tempDir="/tmp/war-temp/"
- deployDir="/tmp/war-deploy/"
- watchDir="/tmp/war-listen/"
- watchEnabled="false"/>
在Tomcat的官方文档(Tomcat 6)中,对于<Deployer />节点的部署位置是错误的,通过观察Tomcat启动日志,确认该节点应当不属于<Host />节点中!
注意:Tomcat 6与Tomcat5在上述节点中使用的类包(包中名称由cluster变化为ha)有所不同,且结构有所调整。
先别急着重启,我们需要修改应用中的
web.xml
文件,将
<distributable />
节点部署到
<web-app />
节点中,开启分布式服务:
注意:如果没有设置该节点,SessionID将不能保持同步,不同的服务器将各自建立独立的SessionID!
监控Tomcat日志:
Shell代码
- tail -f /var/lib/tomcat6/logs/catalina.out
然后重启Tomcat1:
Shell代码
- sudo /etc/init.d/tomcat6 restart
观察日志:
注意两处红框:
第一处,Cluster启动,并绑定192.168.49.132:4000上,进行TCP通讯,并等待其它成员(Member)。
第二处,在管理器中注册/zlex,绑定JvmRouteBinderValve。
至此,说明集群设置已经生效,但不能说明集群配置成功!
接着我们启动Tomcat2,观察其日志:
Cluster启动,并绑定192.168.49.128:4000上并发现成员[b]192.168.49.132
![/b]
再看Tomcat1的日志:
Tomcat1发现其成员Tomcat2!这说明TCP通讯已建立,Tomcat成员可以进行Session同步!
同时,Tomcat成员直接会每隔一个时间段相互侦测/验证其他成员是否正常:
现在,开始访问
http://localhost/zlex
,并不断刷新当前页面:
除了两处标识主机来源的tomcatX不同外,session是完全一致的!
提交一次修改,并不断刷新当前页:
如果仔细观察,当前SessionID在不断交替变化,这说明负载均衡在起作用!
我们再来看看2个Tomcat后台日志都做了什么!
Tomcat1:
Tomcat2:
两只猫都打印了相同的内容(
a=1
)不同的细节在于,sessionID带有服务器标识!
如果我们强行关闭Tomcat2:
首先,Tomcat1会很快侦测到Tomcat2离线,因为这是TCP通讯,成员之间很容易检测到其他成员是否离线!Tomcat1后台日志如下:
其次,Apache会侦测到Tomcat2发生异常,将其余请求转交给其他节点,即交由Tomcat1处理!
继续刷新
http://localhost/zlex
当前页面,耐心等待几秒。你会发现,即便再次刷新页面,sessionID仍旧绑定在标识tomcat1服务器上。
然后,我们恢复Tomcat2服务,Tomcat1会马上侦测到Tomcat2已经恢复正常:
最后,我们再次刷新当前页,Apache已经将请求分发给Tomcat2了,从后台日志可以看到session信息会很快被同步了!
如果带有tomcatX标识的sessionID有很多不便之处,可以关闭粘性会话。简单的讲,就是取消Tomcat中[b]server.xml
中
<Engine/ >
节点的
jvmRoute
属性![/b]然后,重启tomcat、apache!
页面提交一个
b=3
!
左边为Tomcat1,右边为Tomcat2!SessionID一致!
除了上述几种方案外,还有
Terracotta
模式。一种第三方集群组件,2009年收购了缓存组件EhCache,可以结合Tomcat、JBoss等多种服务器,提供多种负载均衡、集群等功能实现,且当负载均衡节点超过8个时,仍然能够保持集群吞吐量的线性增长。
Eclipse插件地址:
http://download.terracotta.org/eclipse/update
下载地址:
http://www.terracotta.org/dl/oss-download-catalog
至此,Apache + Tomcat成功完成,征服Apache系列暂告一段落!
作为开博以来的第100帖,算是很成功了
Apache + SVN + LDAP
对于开发服务器,如果只有subersion,虽然也可以通过
svn://host/svn
方式访问svn;但是,这样的访问方式,终归不方便,尤其是外网访问,于是,我们整合Apache中的WebDAV,使之可以通过
http://host/svn
方式访问svn;可是,如果直接通过外网访问svn,于是,我们结合SSL,以
https://host/svn
方式访问svn;当然,如果有很多人要使用svn,svn帐号管理就成为一个麻烦事!如何解决?帐号分配,密码更迭等等,这些事情都很麻烦。LDAP,正好解决这个问题!
在搭建Apache+SVN+LDAP服务前,先使用ldapSearch命令检测下LDAP服务连接:
Shell代码
- ldapsearch -h ldap.zlex.org -p 389 -x -b "cn=users,dc=zlex,dc=org" -D "snowolf@zlex.org" -w 11111111
简要描述:
-h
主机地址
-p
端口号(默认389)
-x
简单授权
-b
BaseDN
-D
BindDN 这里就是邦定的用户帐号了
-w
显式输入密码
-W
隐式输入密码
这是基于绑定用户帐号方式访问LDAP服务,如果可以匿名访问LDAP,这事情就更简单了,也就更不安全了!
如果连接成功,可以获得一堆该账户下的所有LDAP信息。如果不成功,只能向LDAP服务提供者咨询了!
PS:这一个月,我被LDAP服务搞死了,公司负责LDAP服务维护的同事也不懂如何配置相关应用中的LDAP连接。我只能误打误撞,挨个参数测验了。
如果你的Ubuntu正好不能使用这个命令,那么就执行下面的命令安装好了!
Shell代码
- sudo apt-get install ldap-utils
在Ubuntu下,想要搭建Apache+SVN+LDAP,除了完成Apache+SVN服务搭建,只需要通过追加ldap模块的方式,就可以很快完成这套服务的搭建工作。
如果不知道哪些apache模块跟ldap有关,我们可以使用这个命令找到相关模块:
Shell代码
- sudo apt-cache search apache2 ldap
如下提示:
引用
libapache2-mod-ldap-userdir - Apache module that provides UserDir lookups via LDAP
libapache2-mod-vhost-ldap - Apache 2 module for Virtual Hosting from LDAP
这下,事情就简单了,直接安装相关模块:
Shell代码
- sudo apt-get install libapache2-mod-ldap-userdir libapache2-mod-vhost-ldap
接下来,修改我们上次的SVN配置文件:
Shell代码
- sudo vi /etc/apache2/mods-available/dav_svn.conf
找到
AuthType Basic
,追加
AuthBasicProvider ldap
,同时注释掉
AuthUserFile
。
以下是配置片段:
Conf代码
- AuthType Basic
- AuthName "Subversion Repository"
-
- #使用LDAP服务校验用户身份,废弃密码文本
- # AuthUserFile /etc/apache2/dav_svn.passwd
-
- AuthzSVNAccessFile /etc/apache2/dav_svn.authz
-
- #以下为LDAP服务配置
- AuthBasicProvider ldap
-
- AuthzLDAPAuthoritative off
-
- #LDAP连接
- AuthLDAPURL "ldap://ldap.zlex.org/dc=zlex,dc=org?sAMAccountName?sub?(objectClass=user)"
-
- #邦定用户
- AuthLDAPBindDN "snowolf@zlex.org"
-
- #邦定密码
- AuthLDAPBindPassword "11111111"
-
- Require valid-user
悲哀地是,LDAP服务现在还不知道如何构建。对于LDAP服务,我也知之甚少,更无法深入了解每一个参数的含义。构建LDAP服务,将是我下一个技术攻坚标杆
选用Ubuntu Server 10.04,Apache 2.2.14,Subversion 1.6.6。
步骤:
- 安装SVN相关模块
- 配置SVN版本库
- 配置APACHE
- 简单测试
1.安装SVN相关模块
这里主要用到的是Subversion 以及Apache与SVN相关的模块(DAV_SVN)!
执行命令,安装:
Shell代码
- sudo apt-get install subversion libapache2-svn
注意观察安装后的结果:
引用
Considering dependency dav for dav_svn:
Enabling module dav.
Enabling module dav_svn.
Run ‘/etc/init.d/apache2 restart‘ to activate new configuration!
如果看到这样的提示,那说明DAV_SVN模块已经成功安装,可以重启Apache看看是否正常启动:
Shell代码
- sudo /etc/init.d/apache2 restart
或者,使用
Shell代码
- sudo service apache2 restart
以我本机为例,正常启动了:
引用
zlex@localhost:~$ sudo /etc/init.d/apache2 restart
* Restarting web server apache2
apache2: Could not reliably determine the server‘s fully qualified domain name, using 127.0.0.1 for ServerName
... waiting .apache2: Could not reliably determine the server‘s fully qualified domain name, using 127.0.0.1 for ServerName
当然,稍后你可能需要修改
/etc/apache2/mods-available/dav_svn.conf
文件,配置SVN版本库等。
2.配置SVN版本库
完成上述操作,只是为Apache获知SVN给出了一种途径,最关键的还是要配置SVN相关部分!
首先,我们要创建subversion组并把www-data作为subversion中的一员。因为,apache是通过www-data账户启动的,我们需要让它能够访问subversion组的文件!
Shell代码
- sudo addgroup subversion
- sudo usermod -G subversion -a www-data
然后,我们要配置版本库:
我们可以在
/var/lib
目录下构建一个svn目录,作为SVN版本库根目录:
Shell代码
- cd /var/lib
- sudo mkdir svn
假设我们要创建版本库zlex:
Shell代码
- cd svn
- sudo svnadmin create zlex
更改版本库所属用户、组:
Shell代码
- sudo chown -R root:subversion zlex
赋予组成员对所有新加入文件仓库的文件拥有相应的权限:
Shell代码
- sudo chmod -R g+rws zlex
试试
Shell代码
- svn co file://localhost/var/lib/svn/zlex
,这时候应该可以访问了!
3.配置Apache
接下来,我们需要修改
/etc/apache2/mods-available/dav_svn.conf
文件,配置SVN版本库:
Shell代码
- sudo vi /etc/apache2/mods-available/dav_svn.conf
打开红框中的注释,
Conf代码
- # dav_svn.conf - Example Subversion/Apache configuration
- #
- # For details and further options see the Apache user manual and
- # the Subversion book.
- #
- # NOTE: for a setup with multiple vhosts, you will want to do this
- # configuration in /etc/apache2/sites-available/*, not here.
-
- # <Location URL> ... </Location>
- # URL controls how the repository appears to the outside world.
- # In this example clients access the repository as http://hostname/svn/
- # Note, a literal /svn should NOT exist in your document root.
- <Location /svn>
-
- # Uncomment this to enable the repository
- DAV svn
-
- # Set this to the path to your repository
- #SVNPath /var/lib/svn
- # Alternatively, use SVNParentPath if you have multiple repositories under
- # under a single directory (/var/lib/svn/repo1, /var/lib/svn/repo2, ...).
- # You need either SVNPath and SVNParentPath, but not both.
- SVNParentPath /var/lib/svn
-
- # Access control is done at 3 levels: (1) Apache authentication, via
- # any of several methods. A "Basic Auth" section is commented out
- # below. (2) Apache <Limit> and <LimitExcept>, also commented out
- # below. (3) mod_authz_svn is a svn-specific authorization module
- # which offers fine-grained read/write access control for paths
- # within a repository. (The first two layers are coarse-grained; you
- # can only enable/disable access to an entire repository.) Note that
- # mod_authz_svn is noticeably slower than the other two layers, so if
- # you don‘t need the fine-grained control, don‘t configure it.
-
- # Basic Authentication is repository-wide. It is not secure unless
- # you are using https. See the ‘htpasswd‘ command to create and
- # manage the password file - and the documentation for the
- # ‘auth_basic‘ and ‘authn_file‘ modules, which you will need for this
- # (enable them with ‘a2enmod‘).
- AuthType Basic
- AuthName "Subversion Repository"
- AuthUserFile /etc/apache2/dav_svn.passwd
-
- # To enable authorization via mod_authz_svn
- AuthzSVNAccessFile /etc/apache2/dav_svn.authz
-
- # The following three lines allow anonymous read, but make
- # committers authenticate themselves. It requires the ‘authz_user‘
- # module (enable it with ‘a2enmod‘).
- #<LimitExcept GET PROPFIND OPTIONS REPORT>
- Require valid-user
- #</LimitExcept>
-
- </Location>
分述:
<Location /svn>
与
</Location>
成对儿出现!
DAV svn
开启DAV模块支持!
SVNPath /var/lib/svn
与
SVNParentPath /var/lib/svn
选其一,
不可同时出现!
建议使用
SVNParentPath
,可以在SVN根目录下创建多个SVN版本库!
引用
AuthType Basic
AuthName "Subversion Repository"
AuthUserFile /etc/apache2/dav_svn.passwd
定义了授权类型、并指定了密码文件(
/etc/apache2/dav_svn.passwd
)。
AuthzSVNAccessFile /etc/apache2/dav_svn.authz
授权配置文件,规定了路径访问权限!
引用
#<LimitExcept GET PROPFIND OPTIONS REPORT>
Require valid-user
#</LimitExcept>
建议只使用Require valid-user,打开<LimitExcept />注释,将允许匿名访问!
现在通过命令设置SVN账户:
Shell代码
- sudo htpasswd -c /etc/apache2/dav_svn.passwd <username>
这里用到参数-c,是因为/etc/apache2/dav_svn.passwd文件不存在,如果文件存在,则无需该参数!否则,将覆盖掉原有密码文件!
形如:
引用
sudo htpasswd -c /etc/apache2/dav_svn.passwd snowolf
New password:
Re-type new password:
Updating password for user snowolf
可以追加多个账户!
引用
sudo htpasswd /etc/apache2/dav_svn.passwd zlex
New password:
Re-type new password:
Updating password for user zlex
现在,需要设置路径访问权限文件
AuthzSVNAccessFile /etc/apache2/dav_svn.authz
。
我们先做一个默认的配置,当前这个文件还不存在:
Shell代码
- sudo vi /etc/apache2/dav_svn.authz
然后追加:
引用
[zlex:/]
* = r
这样,所有授权用户就都能够看到zlex项目了!
然后访问
http://localhost/svn/zlex
:
试试检出:
Shell代码
- svn co http://localhost/svn/zlex --username snowolf
我们通过组方式管理项目,修改
/etc/apache2/dav_svn.authz
文件:
Shell代码
- sudo vi /etc/apache2/dav_svn.authz
我们定义一个超级用户组admin,组中成员为snowolf;开发组developer,组中成员为snowolf,zlex,多个用户用逗号分隔。
引用
[groups]
admin = snowolf
developer = snowolf, zlex
让admin和developer组成员有创建项目版本库的权限,其余用户只有查看权限:
引用
[zlex:/]
*=r
@admin = rw
@developer = rw
给出一个完整配置:
引用
[groups]
admin = snowolf
developer = zlex
[zlex:/]
@admin = rw
@developer = rw
* =
有关Subversion详细配置,参照
Subversion官方中文文档
!
修改这个配置文件时,不需要重启apache!
4.简单测试
我们之前构建了一个项目仓库——zlex,现在项目有了,我们需要构建相应的版本库管理,及trunk、tags以及branches!
用命令创建:
Shell代码
- svn mkdir "http://localhost/svn/zlex/branches" "http://localhost/svn/zlex/tags" "http://localhost/svn/zlex/trunk" -m "create a new project zlex" --username "snowolf"
这时,我们用zlex账号提交一个docs目录:
Shell代码
- svn mkdir "http://192.168.49.132/svn/zlex/docs" -m "文档目录" --username zlex
系统会提示输入密码:
192.168.49.132
是我本机的IP地址!
我们可以使用命令将项目签出:
Shell代码
- svn checkout "http://localhost/svn/zlex/trunk@HEAD" -r HEAD --depth infinity zlex-svn --username zlex
我们随便修改一个文件:
提交修改:
如果你参照
征服 Apache + SSL
完成了HTTPS平台搭建,这时候,也可以使用HTTPS方式访问了:
动手,在Ubuntu上做Apache+SSL!
步骤
- 安装Apache
- 安装SSL模块
- 生成证书
- 配置生效
1.安装Apache
这里系统选用Ubuntu Server 10.04版本,Apache选用2.2.14,OpenSSL选用0.98k。
安装Apache2
Shell代码
- sudo apt-get install apache2
这个就不用解释了,不明白可以查Ubuntu/Debian技术手册。
2.安装SSL模块
Ubuntu版Apache提供了两个命令用于配置SSL站点、模块:
Shell代码
- sudo a2ensite default-ssl
这个命令建立了基本ssl站点配置
也就是构建了文件
/etc/apache2/sites-available/default-ssl
。
我们稍后需要修改这个文件,添加自己的证书!
Shell代码
- sudo a2enmod ssl
这个命令用于配置SSL模块,完成操作后,可以在
/etc/ssl
中,发现一些目录、文件。并且
/etc/ssl/private目录仅限root帐户才能查看
!
完成上述操作后一定要重新启动Apache!
Shell代码
- sudo /etc/init.d/apache2 restart
详细内容参考
/usr/share/doc/apache2.2-common/README.Debian.gz
其实,这个时候你可以访问
https://localhost
,查看配置是否生效。如果你打开浏览器会提示你证书(localhost)未验证!
3.生成证书
这里我们需要通过OpenSSL生成证书,如果还没有OpenSSL,那就下载安装:
Shell代码
- sudo apt-get install openssl
然后,我们切换到
/etc/ssl
路径下,构建自签名证书:
Shell代码
- sudo openssl req -x509 -newkey rsa:1024 -keyout private/zlex.key -out certs/zlex.pem -nodes -days 3650 -subj "/C=CN/ST=BJ/L=BJ/O=zlex/OU=zlex/CN=www.zlex.org"
req
请求证书
-x509
签发X.509格式证书
-newkey rsa:1024
非对称加密算法为RSA,密钥长度为1024bits
-keyout private/zlex.key
私钥输出到private中,名为zlex.key
-out certs/zlex.pem
密钥库输出至certs中,名为zlex.pem
-nodes
显示详情
-days 3650
有效期时间,为3650天
-subj "/C=CN/ST=BJ/L=BJ/O=zlex/OU=zlex/CN=www.zlex.org"
证书主题,注意CN指向主机域名,这里为‘www.zlex.org’
再看看certs和private里原始的证书、密钥库,以及我们刚刚生成的证书密钥库。
4.配置生效
由于这里使用www.zlex.org,这就需要通过修改
/etc/hosts
,让系统绑定www.zlex.org到本机:
Shell代码
- sudo /etc/hosts
追加如下内容:
引用
127.0.0.1 www.zlex.org
然后,我们需要修改证书路径,指向刚才生成证书:
Shell代码
- sudo vi /etc/apache2/sites-available/default-ssl
找到
SSLCertificateFile
和
SSLCertificateKeyFile
,修改指向刚才生成的证书和密钥库:
然后,重启apache:
Shell代码
- sudo /etc/init.d/apache2 restart
访问
https://www.zlex.org
,
点击添加例外:
然后看到如下内容:
现在再看看浏览器标识:
点开看看:
我们可以点击查看证书,看看庐山真面目:
这里用的是自签名证书,所以无法验证!
好了,这样就可以完成简单Apache+SSL平台搭建了,当然,这仅仅是基于单向认证服务!
更多细节如下图红框标注,建立证书链,双向认证服务,验证深度等等:
命令
Shell代码
- sudo vi /etc/apache2/sites-available/default-ssl
nginx+tomcat 使用教程
标签:
原文地址:http://my.oschina.net/liting/blog/417188