Apache
下载安装
> tar zxvf httpd-2.4.12.tar.gz
> cd httpd-2.4.12
> ./configure --prefix=/usr/local/apache2.4
> make && make install
若安装编译过程中,出现如下错误,需先安装对应的依赖包,然后再编译安装apache
- 提示
APR not found
:> tar zxvf apr-1.5.2.tar.gz > cd apr-1.5.2 > ./configure --prefix=/usr/local/apr > make && make install
- 提示
APR-Util not found
:> tar zxvf apr-util-1.5.4.tar.gz > cd apr-util-1.5.4 > ./configure --prefix=/usr/local/apr-util --with-apr=/usr/local/apr > make && make install
提示
PCRE not found
:> tar zxvf pcre2-10.20.tar.gz > cd pcre2-10.20 > ./configure --prefix=/usr/local/pcre > make && make install
再编译安装apache:
> cd httpd-2.4.12 > ./configure --prefix=/usr/local/apache --with-apr=/usr/local/apr --with-apr-util=/usr/local/apr-util/ --with-pcre=/usr/local/pcre > make && make install
在
/usr/local/apache2.4/bin
下有可执行程序> ./apachectl start #启动apache服务 > ./apachectl stop #关闭apache服务 > ./apachectl restart #重启apache服务
> ./httpd -V # apache信息,如下: Server version: Apache/2.4.12 (Unix) Server built: Jul 15 2015 09:34:46 Server's Module Magic Number: 20120211:41 Server loaded: APR 1.5.2, APR-UTIL 1.5.4 Compiled using: APR 1.5.2, APR-UTIL 1.5.4 Architecture: 64-bit Server MPM: event threaded: yes (fixed thread count) forked: yes (variable process count) Server compiled with.... -D APR_HAS_SENDFILE -D APR_HAS_MMAP -D APR_HAVE_IPV6 (IPv4-mapped addresses enabled) -D APR_USE_SYSVSEM_SERIALIZE -D APR_USE_PTHREAD_SERIALIZE -D SINGLE_LISTEN_UNSERIALIZED_ACCEPT -D APR_HAS_OTHER_CHILD -D AP_HAVE_RELIABLE_PIPED_LOGS -D DYNAMIC_MODULE_LIMIT=256 -D HTTPD_ROOT="/usr/local/apache2.4" -D SUEXEC_BIN="/usr/local/apache2.4/bin/suexec" -D DEFAULT_PIDLOG="logs/httpd.pid" -D DEFAULT_SCOREBOARD="logs/apache_runtime_status" -D DEFAULT_ERRORLOG="logs/error_log" -D AP_TYPES_CONFIG_FILE="conf/mime.types" -D SERVER_CONFIG_FILE="conf/httpd.conf"
> cp /usr/local/apache2.4/bin/httpd /usr/local/bin/httpd #加入命令 httpd后,可直接使用httpd命令 > httpd -V
加入系统服务
将apachectl
加入到系统服务(这样就可以使用service
命令来控制apache的启动和停止)
将
apachectl
复制到etc/init.d/httpd
中> cd /etc/init.d > ls -l | grep httpd > cat /usr/local/apache2.4/bin/apachectl > httpd
vi httpd
(在文件最前面插入下面的行,使其支持chkconfig
命令)#!/bin/sh #chkconfig: 2345 85 15 #description:apache
说明:
- 第一行:告诉系统使用的shell
- 第二行:chkconfig后面有三个参数
- 第一个参数:系统启动级别,这里表示2,3,4,5级启动
- 第二个参数:启动优先级
- 第二个参数:终止优先级
- 所谓的优先级,就是在rc脚本中出现在各个符号链接名中的数字,例如:
- 在rc2.d~rc5.d目录下,创建名字为S85auto_run的文件连接,连接到/etc/rc.d/init.d目录下的的auto_run脚本。
- 第一个字符是S,系统在启动的时候,运行脚本auto_run,就会添加一个start参数,告诉脚本,现在是启动模式。
- 在rc0.d和rc6.d目录下,创建名字为K15auto_run的文件连接
- 第一个字符为K,系统在关闭系统的时候,会运行auto_run,添加一个stop,告诉脚本,现在是关闭模式
赋予
httpd
脚本执行权限> chmod +x httpd
使用:
> service httpd start #启动Apache服务,与/etc/init.d/httpd start等效 > service httpd stop #停止Apache服务 > service httpd restart #重启Apache服务
开机自启动
- 加入Apache服务(使用上文生成的
/etc/init.d/httpd
)> chkconfig --add httpd
检查Apache服务是否已经生效
> chkconfig --list httpd
若返回
httpd 0:off 1:off 2:on 3:on 4:on 5:on 6:off
,表明apache服务已经生效(在2、3、4、5运行级别随系统启动而自动启动)开/关
> chkconfig httpd off #关闭开机自启动 > chkconfig httpd on #开启开机自启动
PS:可参看/etc/init.d/rc.local
,/etc/rc.local,
/etc/rcS.local`
使用yum安装(方便)
> yum install -y httpd
> yum install -y httpd-tools
> yum install -y httpd-*
说明:
注意安装httpd-devel
(即apxs)
apxs (APache eXtenSion tool):可独立编译apache的动态模块(DSO)
> which apxs #查看属于哪个文件
#/usr/sbin/apxs
> rpm -qf /usr/sbin/apxs #查看属于哪个安装包
#httpd-devel-xxxx
在上面使用下载编译apache的安装方式中,configure时添加--enable-so
以支持DSO
查看安装:
> rpm -qi httpd
> rpm -qa httpd
> yum list | grep httpd
PS:apache目录会生成在/etc/httpd
下
> ls -l /etc/httpd
conf # 存放主配置文件
conf.d # 存放模块配置文件
logs -> /var/log/httpd # 日志
modules -> /usr/lib/httpd/modules # 模块存放目录,存放*.so文件
run -> /var/run/httpd (httpd.pid) #存放apache主进程id
使用系统服务
使用service
操作apache(apachectrl
命令已自动安装到系统服务中)
> service httpd
> service httpd start
> service httpd stop
> service httpd restart
> service httpd graceful #优雅的开启(完成当前连接请求后开启服务)
> service httpd graceful -stop #优雅的关闭(完成当前连接请求后关闭服务)
开机自启动
> chkconfig httpd on # 打开
> chkconfig httpd off #关闭
测试
(这里apache安装目录在/etc/httpd
下)
配置apache
> vi /etc/httpd/conf/httpd.conf ServerName localhost:80
启动apache
> service httpd start #启动apache > ps aux | grep httpd > netstat -tunpl | grep 80 #apache 默认监听TCP协议80端口(https加密端口一般为443)
编写网页
> cd /var/www #默认网站根目录 > cd /var/www/html #网页存放目录 > echo "Linux Apache" > index.html
打开防火墙
iptables
80端口,使外部能访问(一般都是打开着的)> iptables -nvL | grep 8080 > iptables -I INPUT -p tcp --dport 80 -j ACCEPT > service iptables save
测试:访问
http://localhost
(默认就为80端口),会看到网页呈现查看apache日志
- 访问日志文件access_log
- 错误日志文件error_log
> cd /etc/httpd/logs access_log error_log httpd.pid
介绍
apache默认用户为: apache
> cat /etc/passwd | grep apache
apache 进程
apache服务默认会启动一个主进程(控制进程)和多个子进程
查看apache相关进程
> ps aux | grep httpd
其中,以root
身份运行的是主进程,以apache
身份运行的是子进程
(主进程的进程ID保存在 /etc/httpd/run/httpd.pid
文件内)
apache 模块
Apache是一个模块化设计的服务
> httpd -M #查看模块
> httpd -l #查看静态编译入程序的模块
- 核心只包含主要功能,扩展功能通过模块实现
- 不同的模块可以被静态编译进程序,也可动态加载
- 模块的动态加载通过DSO (Dynamic Shared Object)实现(so_module mod_so.c)
多路处理模块:MPM (Multi-Processing Modules)
- 负责实现网络监听,请求处理等功能
- MPM有很多种,目的是为了在不同平台环境下实现最优化的性能及稳定性
- prefork:预生成多进程型MPM, 会预先启动一些子进程,并根据并发请求数量动态生成子进程(指数级增加),稳定;响应快,但连接数比较大时非常消耗内存
- worker:多进程多线程模型MPM,每个进程可以生成多个线程,每个线程处理一个请求(比worker模式更节省系统的内存资源)
- event:worker模式的变种,它把服务进程从连接中分离出来,在开启KeepAlive场合下相对worker模式能够承受的了更高的并发负载
- 若要切换MPM,需要重新编译apache
MPM配置(httpd.conf中):
<ifModule prefork.c> StartServers 8 #默认启动的子进程数 MinSpareServers 5 #最小空闲进程数量 MaxSpareServers 20 #最大空闲进程数量 ServerLimit 256 #最高并发量 MaxClients 256 #<=ServerLimit MaxRequestsPerChild 4000 #每个子进程可处理的最多请求数量 </ifModule> <ifModule worker.c> ... </ifModule>
- 模拟测试:
> watch -n 1 -d 'ps uax | grep httpd' #周期性(1s)的动态查看 > ab -c 16 -n 10000 http://xxxx/index.html # 压力测试,并发 > top # 查看占用内存数量
apache 虚拟主机
虚拟主机(VirtualHost):在同一台机器搭建属于不同域名或者基于不同 IP 的多个网站服务的技术.
可以为运行在同一物理机器上的各个网站指配不同的 IP 和端口, 也可让多个网站拥有不同的域名.
Apache 中的配置(httpd.conf):
NameVirtualHost *:80
<VirtualHost *:80>
ServerAdmin webmaster@dummy-host.example.com
DocumentRoot /www/docs/dummy-host.example.com
ServerName dummy-host.example.com
ErrorLog logs/dummy-host.example.com-error_log
CustomLog logs/dummy-host.example.com-access_log common
</VirtualHost>
说明:
- NameVirtualHost 使用基于域名的虚拟主机
- 必须指定服务器IP地址(和可能的端口)来使主机接受请求
- 如果服务器上所有的IP地址都会用到, 可以用
*
作为NameVirtualHost的参数 - 注意:在NameVirtualHost指令中指明IP地址并不会使服务器自动侦听那个IP地址 这里设定的IP地址必须对应服务器上的一个网络接口。
<VirtualHost>
为建立的每个虚拟主机设定配置块,其中 ServerName
指定伺服哪个主机DocumentRoot
指令说明这个主机的内容存在于文件系统的什么地方
apache 日志
日志(Log)
手册 logs | rotatelogs
使用 bin/rotatelogs
举例:
> vi httpd.conf
#rotatelogs logfile [ rotationtime [ offset ]] | [ filesizeM ]
#86400表示的是每个天记录一次,这个单位是s,480表示和UTC时间差的分钟数目,我们是东八区要比他们早480分钟。
ErrorLog "| /usr/local/apache2.4/bin/rotatelogs -f logs/error_log.%Y_%m_%d 86400 480"
#CustomLog "logs/access_log" common
#rotatelogs logfile [ rotationtime [ offset ]] | [ filesizeM ]
CustomLog "| /usr/local/apache2.4/bin/rotatelogs -f logs/access_log.%Y_%m_%d 86400 480" common
> vi mod_jk.conf
#指定jk logs文件存放位置
JkLogFile "| /usr/local/apache2.4/bin/rotatelogs /usr/local/apache2.4/logs/mod_jk_%Y_%m_%d.log 86400 480"
主配置文件
conf/httpd.conf
文件,加载模块化配置文件conf.d/*.conf
Section1: Global Environment 全局配置
ServerToken OS # 控制非正常页面的页脚信息的详细程度,等级: Full/OS/Major ServerRoot "/etc/httpd" PidFile run/httpd.pid Timeout 60 KeepAlive Off MaxKeepAliveRequests 100 #KeepAlive on 时有效 KeepAliveTimeout 15 #KeepAlive on 时有效 #MPM <IfModule prefork.c> StartServers 8 #默认启动的子进程数 MinSpareServers 5 #最小空闲进程数量 MaxSpareServers 20 #最大空闲进程数量 ServerLimit 256 #最高并发量 MaxClients 256 #<=ServerLimit MaxRequestsPerChild 4000 #每个子进程可处理的最多请求数量 </IfModule> <IfModule worker.c> ... </IfModule> Listen 80 # 监听端口,可指定ip (多网卡) #DSO support LoadModule auth_basic_module modules/mod_auth_basic.so ... #加载额外的配置文件 Include conf.d/*.conf #加载模块配置文件 #指定apache子进程的运行用户 User apache Group apache
Section2: 'Main' Server Configuration 主服务配置
ServerAdmin root@localhost #管理员邮件地址 ServerName www.example.com:80 #域名 UseCanonicalName Off #严格合法域名,使用虚拟主机的话一定要off DocumentRoot "/var/www/html" #网站根目录 # 目录访问控制 <Directory /> Options FollowSymLinks AllowOverride None </Directory> <Directory "/var/www/html"> Options Indexes FollowSymLinks AllowOverride None Order allow,deny Allow from all </Directory> # 条件化模块配置(如果有某模块则对应配置有效) <IfModule mod_userdir.c> UserDir disabled </IfModule> DirectoryIndex index.html index.html.var #默认加载网页 AccessFileName .htaccess # 加载分布式访问控制的文件 # 文件访问控制 <Files ~ "^\.ht"> Order allow,deny Deny from all Satisfy All </Files> TypesConfig /etc/mime.types #指定mime文件的访问路径加载 DefaultType text/plain #默认返回类型,纯文本 <IfModule mod_mime_magic.c> MIMEMagicFile conf/magic </IfModule> # 日志相关配置 HostnameLookups Off #log是否进行域名解析记录 ErrorLog logs/error_log LogLevel warn LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined LogFormat "%h %l %u %t \"%r\" %>s %b" common LogFormat "%{Referer}i -> %U" referer LogFormat "%{User-agent}i" agent CustomLog logs/access_log combined ServerSignature On #服务器签名,作用类似ServerToken Alias /icons/ "/var/www/icons/" #路径别名,方便快捷链接 <Directory "/var/www/icons"> Options Indexes MultiViews FollowSymLinks AllowOverride None Order allow,deny Allow from all </Directory> <IfModule mod_dav_fs.c> DAVLockDB /var/lib/dav/lockdb </IfModule> ScriptAlias /cgi-bin/ "/var/www/cgi-bin/" #脚本路径别名 <Directory "/var/www/cgi-bin"> AllowOverride None Options None Order allow,deny Allow from all </Directory> IndexOptions FancyIndexing VersionSort NameWidth=* HTMLTable Charset=UTF-8 AddIconByEncoding (CMP,/icons/compressed.gif) x-compress x-gzip AddIconByType (TXT,/icons/text.gif) text/* ... AddIcon /icons/binary.gif .bin .exe ... DefaultIcon /icons/unknown.gif ReadmeName README.html HeaderName HEADER.html IndexIgnore .??* *~ *# HEADER* README* RCS CVS *,v *,t AddLanguage ca .caAddLanguage cs .cz .cs AddLanguage en .en AddLanguage zh-CN .zh-cn AddLanguage zh-TW .zh-tw ... LanguagePriority en ca cs da de el eo es et fr he hr it ja ko ltz nl nn no pl pt pt-BR ru sv zh-CN zh-TW ForceLanguagePriority Prefer Fallback AddDefaultCharset UTF-8 #默认网页编码 AddType application/x-compress .Z AddType application/x-gzip .gz .tgz AddType application/x-x509-ca-cert .crt AddType application/x-pkcs7-crl .crl AddHandler type-map var AddType text/html .shtml AddOutputFilter INCLUDES .shtml Alias /error/ "/var/www/error/" <IfModule mod_negotiation.c> <IfModule mod_include.c> <Directory "/var/www/error"> AllowOverride None Options IncludesNoExec AddOutputFilter Includes html AddHandler type-map var Order allow,deny Allow from all LanguagePriority en es de fr ForceLanguagePriority Prefer Fallback </Directory> </IfModule> </IfModule> # 基于特定的浏览器进行特定的配置 BrowserMatch "Mozilla/2" nokeepalive BrowserMatch "MSIE 4\.0b2;" nokeepalive downgrade-1.0 force-response-1.0 BrowserMatch "RealPlayer 4\.0" force-response-1.0 BrowserMatch "Java/1\.0" force-response-1.0 BrowserMatch "JDK/1\.0" force-response-1.0 BrowserMatch "Microsoft Data Access Internet Publishing Provider" redirect-carefully BrowserMatch "MS FrontPage" redirect-carefully BrowserMatch "^WebDrive" redirect-carefully BrowserMatch "^WebDAVFS/1.[0123]" redirect-carefully BrowserMatch "^gnome-vfs/1.0" redirect-carefully BrowserMatch "^XML Spy" redirect-carefully BrowserMatch "^Dreamweaver-WebDAV-SCM1" redirect-carefully
Section3: Virtual Hosts 虚拟主机配置
NameVirtualHost *:80 <VirtualHost *:80> ServerAdmin webmaster@dummy-host.example.com DocumentRoot /www/docs/dummy-host.example.com ServerName dummy-host.example.com ErrorLog logs/dummy-host.example.com-error_log CustomLog logs/dummy-host.example.com-access_log common </VirtualHost>
Tomcat
下载安装
download
apache-tomcat-8.0.24.tar.gz
setup
> tar zxvf apache-tomcat-8.0.24.tar.gz > mv apache-tomcat-8.0.24 /usr/local/tomcat8
configure
> vi /etc/profile export CATALINA_BASE=/usr/local/tomcat8 export CATALINA_HOME=/usr/local/tomcat8 > source /etc/profile #使其生效
configure:
vi conf/tomcat-users.xml
<?xml version='1.0' encoding='utf-8'?> <tomcat-users> <!-- <role rolename="tomcat"/> <role rolename="role1"/> <user username="tomcat" password="tomcat" roles="tomcat"/> <user username="both" password="tomcat" roles="tomcat,role1"/> <user username="role1" password="tomcat" roles="role1"/> --> <role rolename="manager-gui"/> <role rolename="manager-script"/> <role rolename="manager-jmx"/> <role rolename="admin-gui"/> <user password="admin123" roles="manager-gui" username="manager"/> <user password="admin123" roles="manager-script" username="admin"/> <user password="admin123" roles="admin-gui" username="tomcat"/> </tomcat-users>
打开防火墙
iptables
8080端口,使外部能访问> iptables -nvL | grep 8080 > iptables -I INPUT -p tcp --dport 8080 -j ACCEPT > service iptables save
启动关闭Tomcat
> cd /usr/local/tomcat8/bin > ./startup.sh # ./catalina.sh run (显示tomcat控制台) > ./shutdown.sh
开机自启动
chkconfig tomcat on
PS:For java.lang.OutOfmemoryError: PermGen Space
>vi catalina.sh
JAVA_OPTS="$JAVA_OPTS -XX:PermSize=256m -XX:MaxPermSize=1024m"
-XX:PermSize=256m
-XX:MaxPermSize=1024m
Tomcat优化
- 提高JVM栈内存
- 调节并发线程数
- 压缩
- Tomcat原生库
- 基于APR,在产品运作中帮助融合原生的服务器技术以展现最佳的性能
- APR(Apache Portable Runtime:Apache可移植运行时)功能:
- 访问高级IO功能(例如sendfile,epoll和OpenSSL)
- OS级别功能(随机数生成,系统状态等等)
- 本地进程管理(共享内存,NT管道和UNIX sockets)
- PS:Tomcat中使用APR库,其实就是在Tomcat中使用JNI的方式来读取文件以及进行网络传输,可以大大提升Tomcat对静态文件和SSL的处理性能
- 与Apache等静态服务器集成(对于有大量静态页面的系统)
- 静态页面交由Apache处理
- 动态部分交由Tomcat处理
- 能极大解放Tomcat的处理能力
- 搭建系统集群方式(对于并发要求较高的系统)
- 将负载分别分担到多个Tomcat上,能很大的提高系统的性能,充分利用硬件资源
集群方案
单个Tomcat的处理性能是有限的,当并发量较大的时候,就需要有部署多套来进行负载均衡了。
集群的关键点:
引入负载端
- 软负载可以使用
nginx
或者apache
来进行,主要是使用一个分发的功能
- 软负载可以使用
共享session处理,目前的处理方式有如下几种:
- 使用Tomcat本身的Session复制功能
- 配置简单,但当集群数量较多时,Session复制的时间会比较长,影响响应的效率
- 使用第三方来存放共享Session
- 使用
memcached
,redis
将session信息的存储独立出来也是解决session同步问题 - 用
zookeeper
实现的分布式session方案(不是简单的把session独立出来存储而是设计一个完全独立的session机制,它既能给每个web应用提供session的功能又可以实现session同步)
- 使用
- 使用黏性session的策略
- 处理效率高多了,但强会话要求的场合不合适
- 对于会话要求不太强(不涉及到计费,失败了允许重新请求下等)的场合,同一个用户的session可以由
nginx
或者apache
交给同一个Tomcat来处理,这就是所谓的session sticky策略,目前应用也比较多
- 使用Tomcat本身的Session复制功能
其中1和2可以组合使用,具体场景具体分析
Apache+Tomcat
- Apache:
- 可以作为独立的Web服务器来运行
- 只支持静态网页,如(asp,php,cgi,jsp)等动态网页的无能为力
- 解释静态页面要比tomcat快速而且稳定
- Tomcat:
- 可以作为独立的Web服务器来运行
- 是应用(java)服务器(Servlet容器),可以解析jsp动态页面
- 实际整合应用:
- Apache作为主服务器运行
- 为网站的静态页面请求提供服务;
- 监听到有jsp或者servlet的请求,转发给tomcat服务器
- Tomcat服务器作为一个Servlet/JSP插件,解析显示网站的动态页面;
- 好处: 提高静态页面访问速度,减少tomcat服务开销,分工合作,实现负载均衡,提高系统的性能
- Apache作为主服务器运行
- 整合的原理:
- Tomcat中有两个监听的端口
- 8080:用于提供web服务
- 8009:用于监听来自于apache的请求
- Apache监听转发jsp/servlet请求给Tomcat的8009端口
- 交由Tomcat处理后,再返回给Apache,由Apache返回给Client
- Tomcat中有两个监听的端口
下载生成JK
(Apache Tomcat Connector)
编译生成apache module:mod_jk.so
,放入apache的modules目录下
> tar zxvf tomcat-connectors-1.2.40-src.tar.gz
> mv tomcat-connectors-1.2.40-src /usr/local/tomcat-connector-1.2.40
> cd /usr/local/tomcat-connector-1.2.40
若是使用下载编译安装的apache:
> cd native
> ./configure --with-apxs=/usr/local/apache2.4/bin/apxs
> make && make install
> cp ./apache-2.0/mod_jk.so /usr/local/apache2.4/modules/
若是使用yum安装的apache:
> cd native
> ./configure --with-apxs=/usr/sbin/apxs
> make && make install
> cp ./apache-2.0/mod_jk.so /etc/httpd/modules/
整合配置
修改Apache(Tomcat不用做其他特殊配置)
- 主配置文件中,加载
mod_jk.so
#load module for apache and tomcat integration LoadModule jk_module modules/mod_jk.so <IfModule jk_module> Include conf/extra/mod_jk.conf </IfModule>
编写mod_jk模块的配置文件(这里定义的是
mod_jk.conf
文件),也可将下面内容直接放入<IfModule jk_module>
中JkWorkersFile
JkLogFile
,JkLogLevel
JkMount
,JkUnMount
,JkMountFile
#指定workers.properties文件路径 JkWorkersFile /usr/local/apache2.4/conf/extra/workers.properties #指定jk logs文件存放位置 JkLogFile /usr/local/apache2.4/logs/mod_jk.log JkLogLevel info JkLogStampFormat "[%a %b %d %H:%M:%S %Y]" JkOptions +ForwardKeySize +ForwardURICompat -ForwardDirectories JkRequestLogFormat "%w %V %T %q %U%R" #JkMount 表示使用Tomcat来解析, JkUnMount则相反 JkMount /* worker1 JkUnMount /*/resources/* worker1 JkUnMount /index.html worker1 JkUnMount / worker1
PS:url映射关系除了使用
JkMount
配置外,也可使用JkMountFile
专门放置在一个文件中进行配置,例如: mod_jk.conf中:... #External File for mount points JkMountFile /usr/local/apache2.4/conf/extra/uriworkermap.properties
uriworkmap.properties中:
#JkMount /* worker1 #JkUnMount /*/resources/* worker1 #JkUnMount /index.html worker1 #JkUnMount / worker1 /*=controller #!/*/resources/*=controller !/resources/*=controller !/index.html=controller !/=controller
配置worker(这里定义的是
workers.properties
文件)worker.list=worker1 worker.worker1.type=ajp13 worker.worker1.host=localhost worker.worker1.port=8009 worker.worker1.lbfactor=1
重启Apache,测试
集群配置
Apache配置
与上文中整合Tomcat配置相似,主要区别在于worker的配置
例如:workers.properties
# workers 列表
worker.list=controller,status
# tomcat1
worker.tomcat1.type=ajp13
worker.tomcat1.host=localhost
worker.tomcat1.port=7009 #ajp13端口号,server.xml配置,默认8009
worker.tomcat1.lbfactor=1 #server的加权比重,值越高,分得的请求越多
#Define preferred failover node for tomcat1
#worker.tomcat1.redirect=tomcat2
# tomcat2
worker.tomcat2.type=ajp13
worker.tomcat2.host=localhost
worker.tomcat2.port=9009
worker.tomcat2.lbfactor=1
#Define tomcat2 for all requests except failover
#worker.tomcat2.activation=disabled
# 负载均衡控制器
worker.controller.type=lb
worker.controller.balance_workers=tomcat1,tomcat2 #指定分担请求的tomcat
worker.controller.sticky_session=true #设置为粘性session
worker.controller.sticky_session_force=false #设置当多次请求未响应,请求将转发
#jk-status
worker.status.type=status
#worker.connection_pool_size=3000
#worker.connection_pool_minsize=50
#worker.connection_pool_timeout=50000
说明:
sticky_session_force
- 集群中某台服务器多次请求没有响应,是否转发到其它节点处理
- true : 不转发
- false : 转发
sticky_session
- 粘性session,是否向其他节点进行会话复制
- true:不复制
- false:复制
注意:
workers.properties中配置了worker.list=controller
,则在JkMount时需使用controller
例如:uriworkermap.properties
/*=controller
#!/*/resources/*=controller
!/resources/*=controller
!/index.html=controller
!/=controller
/jk-status=status
Tomcat配置
从环境变量中去除
CATALINA_HOME
和CATALINA_BASE
配置> vi /etc/profile # export CATALINA_HOME=/usr/local/tomcat8 # export CATALINA_BASE=/usr/local/tomcat8 > source /etc/profile
安装多个tomcat
配置tomcat的
server.xml
文件> vi /usr/local/tomcat1/server.xml
> vi /usr/local/tomcat2/server.xml
<!-- 修改各个端口号--> # Shutdown Port 8005 => 7005,9005 <Server port="8005" shutdown="SHUTDOWN"> ... # Http Connector Port 8080 => 7080,9080 <Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443"/> # AJP Connector Port 8009 => 7009,9009 <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" /> # Set jvmRoute to support load-balancing via AJP => jvmRoute="tomcat1",jvmRoute="tomcat2" # 注意:jvmRoute取值必须要与mod_jk的workers.properties中设置的节点名称一致 <Engine name="Catalina" defaultHost="localhost" jvmRoute="..." > ...
<!-- 集群配置(tomcat1和tomcat2配置相同) --> <!-- Cluster Setting: tomcat1 & tomcat2 server.xml (same) --> <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"> <!-- bind="127.0.0.1" 如果主机有vpn-虚拟专用网络,需要要bind下,否则会导致session无法复制 address="228.0.0.4" 广播地址,同一组tomcat集群一样 port="45564" 同一组tomcat集群一样 --> <Membership className="org.apache.catalina.tribes.membership.McastService" address="228.0.0.4" port="45564" frequency="500" dropTime="3000"/> <!-- address="xxx" 修改为本机IP地址,如果用auto的话,在vmware里会与主机的实际ip产生冲突 port="xxx" 若同一台上配置负载,要修改此端口,防止端口冲突不起作用 --> <Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver" address="localhost" 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=""/> <Valve className="org.apache.catalina.ha.session.JvmRouteBinderValve"/> <Deployer className="org.apache.catalina.ha.deploy.FarmWarDeployer" tempDir="/tmp/war-temp/" deployDir="/tmp/war-deploy/" watchDir="/tmp/war-listen/" watchEnabled="false"/> <ClusterListener className="org.apache.catalina.ha.session.JvmRouteSessionIDBinderListener"/> <ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener"/> </Cluster>
注意:server.xml
中配置的jvmRoute
值会出现在由该结点创建的session id中
例如:
- 在非集群环境下,一个sessionid可能是 “xxxxxxxxx” 的格式
- 而在集群环境下,如果当前结点的jvmRtomat1oute被配置为tomcat1,那由该结点生成的sessionid将变成“xxxxxxxxx.tomat1”格式
- mod_jk正是依赖于这个节点后缀实现sticky session的,也就是把所有后缀是tomat1的请求都发送给tomat1结点进行处理
测试
建立测试项目
testCluster
> mkdir testCluster > mkdir WEB-INF > vi testCluster/index.jsp > vi WEB-INF/web.xml
- index.jsp:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <%@ page import="java.text.SimpleDateFormat"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>TestCluster</title> </head> <body> Server Info: <% String dtm = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(new Date()); System.out.println("["+request.getLocalAddr()+":"+ request.getLocalPort()+"]"+dtm); out.println("<br>["+request.getLocalAddr()+":"+request.getLocalPort()+"]"+dtm+"<br>"); %> Session Info: <% session.setAttribute("name","dennisit"); System.out.println("[Session Info] Session ID:"+session.getId()); out.println("<br>[Session Info] Session ID:" + session.getId()+"<br>"); %> </body> </html>
- web.xml:
<?xml version="1.0" encoding="ISO-8859-1"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1" metadata-complete="true"> <display-name>Welcome to Tomcat</display-name> <description> Welcome to Tomcat </description> <!-- 表明集群下某一节点生成或改变的 Session ,将广播到该集群的其它节点 --> <distributable/> </web-app>
- index.jsp:
deploy testCluster to tomcat1 & tomcat2
启动服务
> service httpd start > /usr/local/tomcat1/bin/startup.sh > /usr/local/tomcat2/bin/shutdown.sh
测试
- check tomcat1
- check tomcat2
- => 可以看到 tomcat1、tomcat2 两个节点的 Session 一样
- check apache (负载均衡集群测试)
- session粘性测试=> 多次刷新后,请求访问的一直是tomcat1,并且session Id一直保持不变,session中的数据也能够保持,说明session粘性良好
- session复制测试:关闭tomcat1
> /usr/local/tomcat1/bin/shutdown.sh
=>请求被转发给tomcat2,页面访问正常,Session Id保持不变,session数据也全部传递给tomcat2,表明session复制良好
Session同步说明
Session同步方式
sticky模式
- 利用负载均衡器的sticky模式的方式把所有同一session的请求都发送到相同的节点
- 这样不同用户的请求就被平均分配到集群中各个tomcat节点上,实现负载均衡的能力
- 同一用户同一session只和一个webServer交互,一旦这个webserver发生故障,本次session将丢失,用户不能继续使用
sticky_session_force=true stick_session=true
复制模式
- 利用Tomcat session复制的机制使得所有session在所有Tomcat节点中保持一致
- 当一个节点修改一个session数据的时候,该节点会把这个 session的所有内容序列化,然后广播给所有其它节点
- 当下一个用户请求被负载均衡器分配到另外一个节点的时候,那个节点上有完备的 session信息可以用来服务该请求
- 问题:对session有任何更改要会把整个sessions数据全部序列化 (serialize),并广播给集群中所有节点(不管该节点到底需不需要这个session),造成大量的网络通信,导致网络阻塞。
- 一般采用这种方式,当Tomcat节点超过4个时候,整个集群的吞吐量就不能再上升了
- 此方式是通过tomcat本身提供的功能,只需要修改server.xml文件
- 修改Engine节点信息:
<Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat1">
- 去掉
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/>
的注释符 - web.xml中增加
<distributable/>
- 修改Engine节点信息:
SSL
Http & Https
- Http:超文本传输协议,信息是明文传输;无状态连接
- Https:由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议
有两种基本的加解密算法类型:
- 对称加密:密钥只有一个,加密解密为同一个密码,且速度快,对称加密算法有DES、AES等
- 非对称加密:密钥成对出现,加密解密使用不同密钥,相对对称加密速度较慢,典型的非对称加密算法有RSA、DSA等
- 根据公钥无法推知私钥
- 根据私钥也无法推知公钥
- 公钥加密需要私钥解密
- 私钥加密需要公钥解密
(Https会话过程)
- 首先服务器端先生成一份密钥,将公钥交给CA,由CA对它签署并生成证书,保存一份并回送给服务器端。
- 服务器对其进行配置使用,在通话后就将证书发送给客户端,客户端询问CA进行验证。
创建服务器证书
借助openssl
命令
- 创建key(密钥) => server.key
> openssl genrsa -out server.key 1024
- 根据key生成csr文件(证书请求文件) => server.csr
openssl req -new -key server.key -out server.csr
- 提交csr生成证书 => server.crt
(这里签署的证书仅仅做测试用,真正运行的时候,应该将CSR发送到一个CA,返回真正的证书)
> openssl x509 -days 365 -req -in server.csr -signkey server.key -out server.crt
- 查看证书
> openssl x509 -noout -text -in server.crt
PS:为了便于管理,可将上述三个文件移动至/etc/pki/tls/myCerts
中
Apache SSL
- 浏览器到HttpServer :使用https加密通信
- HttpServer 与 tomcat:使用http通信
所以如果HttpServer开启https,则tomcat可以不用开启https
配置httpd.conf (加载mod_ssl,mod_socache_shmcb模块,ssl配置文件https-ssl.conf)
#For SSL LoadModule socache_shmcb_module modules/mod_socache_shmcb.so #Load SSL Module LoadModule ssl_module modules/mod_ssl.so # Secure (SSL/TLS) connections Include conf/extra/httpd-ssl.conf
配置httpd-ssl.conf
Listen 443 ... <VirtualHost _default_:443> #DocumentRoot "/usr/local/apache2.4/htdocs" #ServerName www.example.com:443 ServerName localhost:443 #ServerAdmin you@example.com #ErrorLog "/usr/local/apache2.4/logs/error_log" #TransferLog "/usr/local/apache2.4/logs/access_log" JkMountFile /usr/local/apache2.4/conf/extra/uriworkermap.properties SSLEngine on SSLCertificateFile "/etc/pki/tls/myCerts/server.crt" SSLCertificateKeyFile "/etc/pki/tls/myCerts/server.key" ... </VirtualHost>
重启apache,测试
PS:若网站无法通过https正常访问,可确认服务器443端口(防火墙)是否开启
Tomcat SSL
Tomcat的SSL配置分为两种情况:
- 不使用APR
- 使用APR
不使用APR
keystore:包含了服务器中被客户端用于验证服务器的数字证书
- 客户端接受了这个证书,就可以使用
public key
加密要发送的数据 服务器端拥有一个
private key
,作为唯一解密数据的密钥创建
.keystore
文件(使用JAVA_HOME/bin
下的keytool
)keytool -genkey -alias tomcat -keyalg RSA -keystore tomcat.keystore
-genkey
:创建一个public-private key pair-alias
:用户别名-keyalg
:加密算法-keystore
:密钥库- 上面命令会创建一个自签证书(self-signed certificate)
在
server.xml
中启用 SSL HTTP/1.1 连接器(已有配置,去除注释修改即可)<!-- "keystorePass" 是生成 .keystore 文件的密码 --> <Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true" maxThreads="150" scheme="https" secure="true" clientAuth="false" sslProtocol="TLS" keystoreFile="tomcat.keystore" keystorePass="123@com"/>
(若修改port,则需要将其他非SSL的redirectPort也进行修改)
重启 Tomcat,测试
Issues:
2012-5-16 13:10:37 org.apache.catalina.core.AprLifecycleListener init
信息: Loaded APR based Apache Tomcat Native library 1.1.23.
2012-5-16 13:10:37 org.apache.catalina.core.AprLifecycleListener init
信息: APR capabilities: IPv6 [true], sendfile [true], accept filters [false], random [true].
2012-5-16 13:10:37 org.apache.coyote.AbstractProtocol init
信息: Initializing ProtocolHandler ["http-apr-8080"]
2012-5-16 13:10:37 org.apache.coyote.AbstractProtocol init
信息: Initializing ProtocolHandler ["http-apr-8443"]
2012-5-16 13:10:37 org.apache.coyote.AbstractProtocol init
严重: Failed to initialize end point associated with ProtocolHandler ["http-apr-8443"]
java.lang.Exception: <span style="background-color: #ffff00;">Connector attribute SSLCertificateFile must be defined when using SSL with APR</span>
at org.apache.tomcat.util.net.AprEndpoint.bind(AprEndpoint.java:484)
at org.apache.tomcat.util.net.AbstractEndpoint.init(AbstractEndpoint.java:566)
at org.apache.coyote.AbstractProtocol.init(AbstractProtocol.java:417)
at org.apache.catalina.connector.Connector.initInternal(Connector.java:956)
at org.apache.catalina.util.LifecycleBase.init(LifecycleBase.java:102)
at org.apache.catalina.core.StandardService.initInternal(StandardService.java:559)
解决方案一:修改conf/server.xml,注释掉下面一段
<!--APR library loader. Documentation at /docs/apr.html --> <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
但这样做将失去APR库的价值,Tomcat性能必然下降(APR库作用 )
解决方案二:修改上面server.xml中protocol的配置为
protocol="org.apache.coyote.http11.Http11Protocol"
(不启用APR)<Connector port="443" protocol="org.apache.coyote.http11.Http11Protocol" SSLEnabled="true" maxThreads="150" scheme="https" secure="true" clientAuth="false" sslProtocol="TLS" keystoreFile="D:\Tomcat7.0\conf\.keystore" keystorePass="xxxx"/>
使用APR
在安装APR并使用后(安装apr,apr-util,tomcat-native),如下配置
<Connector port="8443" protocol="HTTP/1.1"
maxThreads="200"
scheme="https" secure="true" SSLEnabled="true"
SSLCertificateFile="/usr/local/ssl/server.crt"
SSLCertificateKeyFile="/usr/local/ssl/server.pem"
SSLPassword="123456"
clientAuth="optional" SSLProtocol="TLSv1"/>
- SSLCertificateFile:指明证书的路径
- SSLCertificateKeyFile:指明私钥的路径(私钥包含在证书文件里时可不配置此参数)
- SSLPassword:指明私钥的加密密钥(若SSLCertificateKeyFile中的私钥进行了加密,则需要配置)
- Tomcat要求SSLCertificateFile、SSLCertificateKeyFile所指向的文件的内容格式都为PEM格式