Apache+Tomcat

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服务
    

开机自启动

  1. 加入Apache服务(使用上文生成的/etc/init.d/httpd
     > chkconfig --add httpd
    
  2. 检查Apache服务是否已经生效

     > chkconfig --list httpd
    

    若返回httpd 0:off 1:off 2:on 3:on 4:on 5:on 6:off,表明apache服务已经生效(在2、3、4、5运行级别随系统启动而自动启动)

  3. 开/关

     > 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下)

  1. 配置apache

    > vi  /etc/httpd/conf/httpd.conf
    ServerName localhost:80
    
  2. 启动apache

    > service httpd start        #启动apache
    > ps aux | grep httpd
    > netstat -tunpl | grep 80    #apache 默认监听TCP协议80端口(https加密端口一般为443)
    
  3. 编写网页

    > cd /var/www               #默认网站根目录
    > cd /var/www/html        #网页存放目录
    > echo "Linux Apache" > index.html
    
  4. 打开防火墙iptables 80端口,使外部能访问(一般都是打开着的)

    > iptables -nvL | grep 8080
    > iptables -I INPUT -p tcp --dport 80 -j ACCEPT
    > service iptables save
    
  5. 测试:访问http://localhost(默认就为80端口),会看到网页呈现

  6. 查看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 和端口, 也可让多个网站拥有不同的域名.

Virtual Host

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

  1. 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
    
  2. 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
    
  3. 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

下载安装

  1. download apache-tomcat-8.0.24.tar.gz

  2. setup

     > tar zxvf apache-tomcat-8.0.24.tar.gz
     > mv apache-tomcat-8.0.24 /usr/local/tomcat8
    
  3. configure

     > vi /etc/profile
     export CATALINA_BASE=/usr/local/tomcat8
     export CATALINA_HOME=/usr/local/tomcat8
    
     > source /etc/profile    #使其生效
    
  4. 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>
    
  5. 打开防火墙 iptables 8080端口,使外部能访问

     > iptables -nvL | grep 8080
     > iptables -I INPUT -p tcp --dport 8080 -j ACCEPT
     > service iptables save
    
  6. 启动关闭Tomcat

     > cd /usr/local/tomcat8/bin
     > ./startup.sh          # ./catalina.sh run (显示tomcat控制台)
     > ./shutdown.sh
    
  7. 开机自启动 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优化

  1. 提高JVM栈内存
  2. 调节并发线程数
  3. 压缩
  4. Tomcat原生库
    • 基于APR,在产品运作中帮助融合原生的服务器技术以展现最佳的性能
    • APR(Apache Portable Runtime:Apache可移植运行时)功能:
      • 访问高级IO功能(例如sendfile,epoll和OpenSSL)
      • OS级别功能(随机数生成,系统状态等等)
      • 本地进程管理(共享内存,NT管道和UNIX sockets)
    • PS:Tomcat中使用APR库,其实就是在Tomcat中使用JNI的方式来读取文件以及进行网络传输,可以大大提升Tomcat对静态文件和SSL的处理性能
  5. 与Apache等静态服务器集成(对于有大量静态页面的系统)
    • 静态页面交由Apache处理
    • 动态部分交由Tomcat处理
    • 能极大解放Tomcat的处理能力
  6. 搭建系统集群方式(对于并发要求较高的系统)
    • 将负载分别分担到多个Tomcat上,能很大的提高系统的性能,充分利用硬件资源

集群方案

单个Tomcat的处理性能是有限的,当并发量较大的时候,就需要有部署多套来进行负载均衡了。

集群的关键点:

  1. 引入负载端

    • 软负载可以使用nginx或者apache来进行,主要是使用一个分发的功能
  2. 共享session处理,目前的处理方式有如下几种:

    • 使用Tomcat本身的Session复制功能
      • 配置简单,但当集群数量较多时,Session复制的时间会比较长,影响响应的效率
    • 使用第三方来存放共享Session
      • 使用memcachedredis将session信息的存储独立出来也是解决session同步问题
      • zookeeper实现的分布式session方案(不是简单的把session独立出来存储而是设计一个完全独立的session机制,它既能给每个web应用提供session的功能又可以实现session同步) Zookeeper
    • 使用黏性session的策略
      • 处理效率高多了,但强会话要求的场合不合适
      • 对于会话要求不太强(不涉及到计费,失败了允许重新请求下等)的场合,同一个用户的session可以由nginx或者apache交给同一个Tomcat来处理,这就是所谓的session sticky策略,目前应用也比较多
  3. 其中1和2可以组合使用,具体场景具体分析

Apache+Tomcat

  • Apache:
    • 可以作为独立的Web服务器来运行
    • 只支持静态网页,如(asp,php,cgi,jsp)等动态网页的无能为力
    • 解释静态页面要比tomcat快速而且稳定
  • Tomcat:
    • 可以作为独立的Web服务器来运行
    • 是应用(java)服务器(Servlet容器),可以解析jsp动态页面
  • 实际整合应用:
    • Apache作为主服务器运行
      • 为网站的静态页面请求提供服务;
      • 监听到有jsp或者servlet的请求,转发给tomcat服务器
    • Tomcat服务器作为一个Servlet/JSP插件,解析显示网站的动态页面;
    • 好处: 提高静态页面访问速度,减少tomcat服务开销,分工合作,实现负载均衡,提高系统的性能
  • 整合的原理:
    • Tomcat中有两个监听的端口
      • 8080:用于提供web服务
      • 8009:用于监听来自于apache的请求
    • Apache监听转发jsp/servlet请求给Tomcat的8009端口
    • 交由Tomcat处理后,再返回给Apache,由Apache返回给Client

Combine

下载生成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不用做其他特殊配置)

  1. 主配置文件中,加载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>
    
  2. 编写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
      
  3. 配置worker(这里定义的是workers.properties文件)

     worker.list=worker1
    
     worker.worker1.type=ajp13
     worker.worker1.host=localhost
     worker.worker1.port=8009
     worker.worker1.lbfactor=1
    
  4. 重启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配置

  1. 从环境变量中去除CATALINA_HOMECATALINA_BASE 配置

    > vi /etc/profile
    # export CATALINA_HOME=/usr/local/tomcat8
    # export CATALINA_BASE=/usr/local/tomcat8
    > source /etc/profile
    
  2. 安装多个tomcat

  3. 配置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结点进行处理

测试

  1. 建立测试项目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>
      
  2. deploy testCluster to tomcat1 & tomcat2

  3. 启动服务

     > service httpd start
     > /usr/local/tomcat1/bin/startup.sh
     > /usr/local/tomcat2/bin/shutdown.sh
    
  4. 测试

    • check tomcat1 Tomcat 1
    • check tomcat2 Tomcat 2
    • => 可以看到 tomcat1、tomcat2 两个节点的 Session 一样
    • check apache (负载均衡集群测试)
      • session粘性测试=> 多次刷新后,请求访问的一直是tomcat1,并且session Id一直保持不变,session中的数据也能够保持,说明session粘性良好 Apache
      • session复制测试:关闭tomcat1> /usr/local/tomcat1/bin/shutdown.sh =>请求被转发给tomcat2,页面访问正常,Session Id保持不变,session数据也全部传递给tomcat2,表明session复制良好 Apache

Session同步说明

Session同步方式

  1. sticky模式

    • 利用负载均衡器的sticky模式的方式把所有同一session的请求都发送到相同的节点
    • 这样不同用户的请求就被平均分配到集群中各个tomcat节点上,实现负载均衡的能力
    • 同一用户同一session只和一个webServer交互,一旦这个webserver发生故障,本次session将丢失,用户不能继续使用
      sticky_session_force=true
      stick_session=true
      
  2. 复制模式

    • 利用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/>

SSL

Http & Https

  • Http:超文本传输协议,信息是明文传输;无状态连接
  • Https:由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议

有两种基本的加解密算法类型:

  • 对称加密:密钥只有一个,加密解密为同一个密码,且速度快,对称加密算法有DES、AES等
  • 非对称加密:密钥成对出现,加密解密使用不同密钥,相对对称加密速度较慢,典型的非对称加密算法有RSA、DSA等
    • 根据公钥无法推知私钥
    • 根据私钥也无法推知公钥
    • 公钥加密需要私钥解密
    • 私钥加密需要公钥解密

Https Https (Https会话过程)

  • 首先服务器端先生成一份密钥,将公钥交给CA,由CA对它签署并生成证书,保存一份并回送给服务器端。
  • 服务器对其进行配置使用,在通话后就将证书发送给客户端,客户端询问CA进行验证。

创建服务器证书

借助openssl命令

  1. 创建key(密钥) => server.key
    > openssl genrsa -out server.key 1024
    
  2. 根据key生成csr文件(证书请求文件) => server.csr
    openssl req -new -key server.key -out server.csr
    
  3. 提交csr生成证书 => server.crt (这里签署的证书仅仅做测试用,真正运行的时候,应该将CSR发送到一个CA,返回真正的证书)
    > openssl x509 -days 365 -req -in server.csr -signkey server.key -out server.crt
    
  4. 查看证书
    > 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格式