mod_jk(Apache+mod_jk+tomcat)详细配置方法_apache tomcat connectors mod_jk-程序员宅基地

技术标签: linux  



 首先虽然这个mod_jk已经过时,但还是放出来大家一起学习一下,文章主要分三部分内容:

1.第一部分:说明主要配置过程

2.第二部分:贴出我的httpd.conf文件

3.第三部分:对mod_jk代码讲解(来源百度)

 

第一部分:配置

1.       准备环境:

操作系统:windows7

httpd-2.2.21-win32-x86-no_ssl.msi

apache-tomcat-6.0.7

apache-tomcat-5.0.7

tomcat-connectors-1.2.32-windows-i386-httpd-2.2.x

jdk1.5

2.       下载APACHE

这里下载的是APACHE2.2.21版本

3.       下载JK(Tomcat
Connector)

Jk是apache和tomcat的连接器,也可以做负载均衡器,主要是apache通过jk找到tomcat。

下载地址:http://archive.apache.org/dist/tomcat/tomcat-connectors/jk/binaries/windows/Jk的版本要与apache的版本对应如:mod_jk-1.2.32-httpd-2.2.x.zip其匹配的Apache为2.2.版本以上可用

4.       下载TOMCAT

apache-tomcat-6.0.7.rar

5.       配置修改过程

1)  Apache配置

将Tomcat Connector文件mod_jk.so拷贝到Apache安装目录的modules目录下。

在Apache安装目录下找到conf/httpd.conf文件,使用文本编辑器打开:

伪静态修改

将注释放开

找到AllowOverride None 将其修改为 All 内容如下:

<Directory />
    Options FollowSymLinks
    AllowOverride All
    Order deny,allow
    Deny from all
</Directory>

Tomcat Connector关联项增加

       
在LoadModules末尾处增加一下内容:

#加载mod_jk连接
LoadModule jk_module modules/mod_jk.so
### 配置 mod_jk
JkWorkersFile "conf\workers.properties" #加载集群中的workers
#此处是指定分配给tomcat的请求 例如*.do *.jsp
JkMount /*.jsp controller
JkLogFile logs/mod_jk.log #指定jk的日志输出文件
JkLogLevel warn #指定日志级别
    找到IfModule dir_module 修改默认访问地址,需要根据具体项目实际情况填写,我这里使用的是index.jsp 修改如下:
<IfModule dir_module>
DirectoryIndex index.jsp
</IfModule>
    找到Virtual hosts 去掉虚拟主机注释
# Virtual hosts
#Include conf/extra/httpd-vhosts.conf 将 “#”去掉
Include conf/extra/httpd-vhosts.conf
加载代理(暂时未去掉)
#LoadModule proxy_module modules/mod_proxy.so
#LoadModule proxy_ajp_module modules/mod_proxy_ajp.so
#LoadModule proxy_balancer_module modules/mod_proxy_balancer.so
#LoadModule proxy_connect_module modules/mod_proxy_connect.so
#LoadModule proxy_ftp_module modules/mod_proxy_ftp.so

2)  Tomcat Connector配置

在Apache配置目录Apache2.2\conf创建workers.properties配置文件,该文件主要用于配置Apache与Tomcat的集成要用到的Tomcat实例和负载均衡分发控制器。

Workers.properties文件放置一下内容;

#下面是分发控制器 注意不要放tomcat实例
worker.list=lbcontroller
#Tomcat1实例配置 这里要和Tomcat配置文件Service.xml的jvmRoute保持一致
worker.test1.host=localhost
worker.test1.port=8009
worker.test1.type=ajp13
#分发权重 值越大负载越大
worker.tomcat1.lbfactor=1
#Tomcat2实例配置
worker.test2.host=localhost
worker.test2.port=9009
worker.test2.type=ajp13
#分发权重 值越大负载越大
worker.tomcat2.lbfactor=1
#负载均衡分发控制器
worker.lbcontroller.type=lb
worker.lbcontroller.balance_workers=test1,test2
Tomcat配置文件Service.xml主要注意两个地方,一个是Engine节点需要增加节点标识jvmRoute,一个是将原本注释掉的Session复制节点改为有效。具体如下:

  

<!--jvmRoute在各个Tomcat配置中不能重复且要与worker.properties文件中的名称一致-->
    <Engine name="Catalina" defaultHost="localhost" jvmRoute="test1">
<!--session复制内容-->
       <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="228.0.0.4"
                        port="45564"
                        frequency="500"
                        dropTime="3000"/>
<Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver"
                      address="auto"
                      port="4000"
                      autoBind="100"
                      selectorTimeout="5000"
                      maxThreads="6"/>
            <!-- timeout="60000"-->
            <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"/>
            <Interceptor className="org.apache.catalina.tribes.group.interceptors.ThroughputInterceptor"/>
          </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"/>
          <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>
      <!--session复制内容-->

           
<!—Host节点增加一下内容表示站点根路径-->

<Context path="/sc" docBase="." privileged="true"/>

我们分别将两个Tomcat配置文件中的jvmRoute设置为tomcat1、tomcat2,Server节点
端口分别配置为8005和9005,
Connector节点端口分别配置为8080和9090,AJPConnector端口分别配置为8009和9009,Connector端口配置参照单主机多站点场景。请注意两个Tomcat配置文件Host节点的域名配置必须一样,Server.xml中的jvmRoute名称必须和worker.properties中的tomcat实例名称一致,不然无法实现session_stricky。

 

*****************************************************************************
 如果需要实现session 复制 需要在Tomcat 下conf/web.xml 中加上<distributable/>
<?xml version="1.0" encoding="ISO-8859-1"?>
省略N多代码。。。。。。
    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
        <welcome-file>index.htm</welcome-file>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>
<distributable/>
</web-app>
*****************************************************************************
第二部分:httpd.conf文件 #
# This is the main Apache HTTP server configuration file. It contains the
# configuration directives that give the server its instructions.
# See <URL:http://httpd.apache.org/docs/2.2> for detailed information.
# In particular, see
# <URL:http://httpd.apache.org/docs/2.2/mod/directives.html>
# for a discussion of each configuration directive.
#
# Do NOT simply read the instructions in here without understanding
# what they do. They're here only as hints or reminders. If you are unsure
# consult the online docs. You have been warned.
#
# Configuration and logfile names: If the filenames you specify for many
# of the server's control files begin with "/" (or "drive:/" for Win32), the
# server will use that explicit path. If the filenames do *not* begin
# with "/", the value of ServerRoot is prepended -- so "logs/foo.log"
# with ServerRoot set to "D:/Program Files/Apache Software Foundation/Apache2.2" will be interpreted by the
# server as "D:/Program Files/Apache Software Foundation/Apache2.2/logs/foo.log".
#
# NOTE: Where filenames are specified, you must use forward slashes
# instead of backslashes (e.g., "c:/apache" instead of "c:\apache").
# If a drive letter is omitted, the drive on which httpd.exe is located
# will be used by default. It is recommended that you always supply
# an explicit drive letter in absolute paths to avoid confusion.
#
# ServerRoot: The top of the directory tree under which the server's
# configuration, error, and log files are kept.
#
# Do not add a slash at the end of the directory path. If you point
# ServerRoot at a non-local disk, be sure to point the LockFile directive
# at a local disk. If you wish to share the same ServerRoot for multiple
# httpd daemons, you will need to change at least LockFile and PidFile.
#
ServerRoot "D:/Program Files/Apache Software Foundation/Apache2.2"
#
# Listen: Allows you to bind Apache to specific IP addresses and/or
# ports, instead of the default. See also the <VirtualHost>
# directive.
#
# Change this to Listen on specific IP addresses as shown below to
# prevent Apache from glomming onto all bound IP addresses.
#
#Listen 12.34.56.78:80
Listen 8080
#
# Dynamic Shared Object (DSO) Support
#
# To be able to use the functionality of a module which was built as a DSO you
# have to place corresponding `LoadModule' lines at this location so the
# directives contained in it are actually available _before_ they are used.
# Statically compiled modules (those listed by `httpd -l') do not need
# to be loaded here.
#
# Example:
# LoadModule foo_module modules/mod_foo.so
#
LoadModule actions_module modules/mod_actions.so
LoadModule alias_module modules/mod_alias.so
LoadModule asis_module modules/mod_asis.so
LoadModule auth_basic_module modules/mod_auth_basic.so
#LoadModule auth_digest_module modules/mod_auth_digest.so
#LoadModule authn_alias_module modules/mod_authn_alias.so
#LoadModule authn_anon_module modules/mod_authn_anon.so
#LoadModule authn_dbd_module modules/mod_authn_dbd.so
#LoadModule authn_dbm_module modules/mod_authn_dbm.so
LoadModule authn_default_module modules/mod_authn_default.so
LoadModule authn_file_module modules/mod_authn_file.so
#LoadModule authnz_ldap_module modules/mod_authnz_ldap.so
#LoadModule authz_dbm_module modules/mod_authz_dbm.so
LoadModule authz_default_module modules/mod_authz_default.so
LoadModule authz_groupfile_module modules/mod_authz_groupfile.so
LoadModule authz_host_module modules/mod_authz_host.so
#LoadModule authz_owner_module modules/mod_authz_owner.so
LoadModule authz_user_module modules/mod_authz_user.so
LoadModule autoindex_module modules/mod_autoindex.so
#LoadModule cache_module modules/mod_cache.so
#LoadModule cern_meta_module modules/mod_cern_meta.so
LoadModule cgi_module modules/mod_cgi.so
#LoadModule charset_lite_module modules/mod_charset_lite.so
#LoadModule dav_module modules/mod_dav.so
#LoadModule dav_fs_module modules/mod_dav_fs.so
#LoadModule dav_lock_module modules/mod_dav_lock.so
#LoadModule dbd_module modules/mod_dbd.so
#LoadModule deflate_module modules/mod_deflate.so
LoadModule dir_module modules/mod_dir.so
#LoadModule disk_cache_module modules/mod_disk_cache.so
#LoadModule dumpio_module modules/mod_dumpio.so
LoadModule env_module modules/mod_env.so
#LoadModule expires_module modules/mod_expires.so
#LoadModule ext_filter_module modules/mod_ext_filter.so
#LoadModule file_cache_module modules/mod_file_cache.so
#LoadModule filter_module modules/mod_filter.so
#LoadModule headers_module modules/mod_headers.so
#LoadModule ident_module modules/mod_ident.so
#LoadModule imagemap_module modules/mod_imagemap.so
LoadModule include_module modules/mod_include.so
#LoadModule info_module modules/mod_info.so
LoadModule isapi_module modules/mod_isapi.so
#LoadModule ldap_module modules/mod_ldap.so
#LoadModule logio_module modules/mod_logio.so
LoadModule log_config_module modules/mod_log_config.so
#LoadModule log_forensic_module modules/mod_log_forensic.so
#LoadModule mem_cache_module modules/mod_mem_cache.so
LoadModule mime_module modules/mod_mime.so
#LoadModule mime_magic_module modules/mod_mime_magic.so
LoadModule negotiation_module modules/mod_negotiation.so
#LoadModule proxy_module modules/mod_proxy.so
#LoadModule proxy_ajp_module modules/mod_proxy_ajp.so
#LoadModule proxy_balancer_module modules/mod_proxy_balancer.so
#LoadModule proxy_connect_module modules/mod_proxy_connect.so
#LoadModule proxy_ftp_module modules/mod_proxy_ftp.so
#LoadModule proxy_http_module modules/mod_proxy_http.so
#LoadModule proxy_scgi_module modules/mod_proxy_scgi.so
#LoadModule reqtimeout_module modules/mod_reqtimeout.so
#url伪静态
LoadModule rewrite_module modules/mod_rewrite.so
LoadModule setenvif_module modules/mod_setenvif.so
#LoadModule speling_module modules/mod_speling.so
#LoadModule ssl_module modules/mod_ssl.so
#LoadModule status_module modules/mod_status.so
#LoadModule substitute_module modules/mod_substitute.so
#LoadModule unique_id_module modules/mod_unique_id.so
#LoadModule userdir_module modules/mod_userdir.so
#LoadModule usertrack_module modules/mod_usertrack.so
#LoadModule version_module modules/mod_version.so
#LoadModule vhost_alias_module modules/mod_vhost_alias.so
#加载mod_jk连接
LoadModule jk_module modules/mod_jk.so
#加载集群中的workers
JkWorkersFile "conf/workers.properties"
#此处是指定分配给tomcat的请求 例如*.do *.jsp
JkMount /*.jsp lbcontroller
#指定jk的日志输出文件
JkLogFile "logs/mod_jk.log"
#指定日志级别
JkLogLevel warn
<IfModule !mpm_netware_module>
<IfModule !mpm_winnt_module>
#
# If you wish httpd to run as a different user or group, you must run
# httpd as root initially and it will switch.
#
# User/Group: The name (or #number) of the user/group to run httpd as.
# It is usually good practice to create a dedicated user and group for
# running httpd, as with most system services.
#
User daemon
Group daemon
</IfModule>
</IfModule>
# 'Main' server configuration
#
# The directives in this section set up the values used by the 'main'
# server, which responds to any requests that aren't handled by a
# <VirtualHost> definition. These values also provide defaults for
# any <VirtualHost> containers you may define later in the file.
#
# All of these directives may appear inside <VirtualHost> containers,
# in which case these default settings will be overridden for the
# virtual host being defined.
#
#
# ServerAdmin: Your address, where problems with the server should be
# e-mailed. This address appears on some server-generated pages, such
# as error documents. e.g. [email protected]
#
ServerAdmin localhost
#
# ServerName gives the name and port that the server uses to identify itself.
# This can often be determined automatically, but we recommend you specify
# it explicitly to prevent problems during startup.
#
# If your host doesn't have a registered DNS name, enter its IP address here.
#
ServerName localhost:8080
#
# DocumentRoot: The directory out of which you will serve your
# documents. By default, all requests are taken from this directory, but
# symbolic links and aliases may be used to point to other locations.
#
DocumentRoot "D:/work/work_bz/test/WebRoot"
#
# Each directory to which Apache has access can be configured with respect
# to which services and features are allowed and/or disabled in that
# directory (and its subdirectories).
#
# First, we configure the "default" to be a very restrictive set of
# features.
# 默认为 AllowOverride None
<Directory />
Options FollowSymLinks
AllowOverride All
#Order deny,allow
#Deny from all
Order allow,deny
Allow from all
Satisfy all
</Directory>
#首次访问页面
<IfModule dir_module>
DirectoryIndex index.jsp
</IfModule>
#
# The following lines prevent .htaccess and .htpasswd files from being
# viewed by Web clients.
#
<FilesMatch "^\.ht">
Order allow,deny
Deny from all
Satisfy All
</FilesMatch>
#
# ErrorLog: The location of the error log file.
# If you do not specify an ErrorLog directive within a <VirtualHost>
# container, error messages relating to that virtual host will be
# logged here. If you *do* define an error logfile for a <VirtualHost>
# container, that host's errors will be logged there and not here.
#
ErrorLog "logs/error.log"
#
# LogLevel: Control the number of messages logged to the error_log.
# Possible values include: debug, info, notice, warn, error, crit,
# alert, emerg.
#
LogLevel warn
<IfModule log_config_module>
#
# The following directives define some format nicknames for use with
# a CustomLog directive (see below).
#
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
LogFormat "%h %l %u %t \"%r\" %>s %b" common
<IfModule logio_module>
# You need to enable mod_logio.c to use %I and %O
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedio
</IfModule>
#
# The location and format of the access logfile (Common Logfile Format).
# If you do not define any access logfiles within a <VirtualHost>
# container, they will be logged here. Contrariwise, if you *do*
# define per-<VirtualHost> access logfiles, transactions will be
# logged therein and *not* in this file.
#
CustomLog "logs/access.log" common
#
# If you prefer a logfile with access, agent, and referer information
# (Combined Logfile Format) you can use the following directive.
#
#CustomLog "logs/access.log" combined
</IfModule>
<IfModule alias_module>
#
# Redirect: Allows you to tell clients about documents that used to
# exist in your server's namespace, but do not anymore. The client
# will make a new request for the document at its new location.
# Example:
# Redirect permanent /foo http://192.168.12.242/bar
#
# Alias: Maps web paths into filesystem paths and is used to
# access content that does not live under the DocumentRoot.
# Example:
# Alias /webpath /full/filesystem/path
#
# If you include a trailing / on /webpath then the server will
# require it to be present in the URL. You will also likely
# need to provide a <Directory> section to allow access to
# the filesystem path.
#
# ScriptAlias: This controls which directories contain server scripts.
# ScriptAliases are essentially the same as Aliases, except that
# documents in the target directory are treated as applications and
# run by the server when requested rather than as documents sent to the
# client. The same rules about trailing "/" apply to ScriptAlias
# directives as to Alias.
#
ScriptAlias /cgi-bin/ "D:/Program Files/Apache Software Foundation/Apache2.2/cgi-bin/"
</IfModule>
<IfModule cgid_module>
#
# ScriptSock: On threaded servers, designate the path to the UNIX
# socket used to communicate with the CGI daemon of mod_cgid.
#
#Scriptsock logs/cgisock
</IfModule>
#
# "D:/Program Files/Apache Software Foundation/Apache2.2/cgi-bin" should be changed to whatever your ScriptAliased
# CGI directory exists, if you have that configured.
#
<Directory "D:/Program Files/Apache Software Foundation/Apache2.2/cgi-bin">
AllowOverride None
Options None
Order allow,deny
Allow from all
</Directory>
#
# DefaultType: the default MIME type the server will use for a document
# if it cannot otherwise determine one, such as from filename extensions.
# If your server contains mostly text or HTML documents, "text/plain" is
# a good value. If most of your content is binary, such as applications
# or images, you may want to use "application/octet-stream" instead to
# keep browsers from trying to display binary files as though they are
# text.
#
DefaultType text/plain
<IfModule mime_module>
#
# TypesConfig points to the file containing the list of mappings from
# filename extension to MIME-type.
#
TypesConfig conf/mime.types
#
# AddType allows you to add to or override the MIME configuration
# file specified in TypesConfig for specific file types.
#
#AddType application/x-gzip .tgz
#
# AddEncoding allows you to have certain browsers uncompress
# information on the fly. Note: Not all browsers support this.
#
#AddEncoding x-compress .Z
#AddEncoding x-gzip .gz .tgz
#
# If the AddEncoding directives above are commented-out, then you
# probably should define those extensions to indicate media types:
#
AddType application/x-compress .Z
AddType application/x-gzip .gz .tgz
#
# AddHandler allows you to map certain file extensions to "handlers":
# actions unrelated to filetype. These can be either built into the server
# or added with the Action directive (see below)
#
# To use CGI scripts outside of ScriptAliased directories:
# (You will also need to add "ExecCGI" to the "Options" directive.)
#
#AddHandler cgi-script .cgi
# For type maps (negotiated resources):
#AddHandler type-map var
#
# Filters allow you to process content before it is sent to the client.
#
# To parse .shtml files for server-side includes (SSI):
# (You will also need to add "Includes" to the "Options" directive.)
#
#AddType text/html .shtml
#AddOutputFilter INCLUDES .shtml
</IfModule>
#
# The mod_mime_magic module allows the server to use various hints from the
# contents of the file itself to determine its type. The MIMEMagicFile
# directive tells the module where the hint definitions are located.
#
#MIMEMagicFile conf/magic
#
# Customizable error responses come in three flavors:
# 1) plain text 2) local redirects 3) external redirects
#
# Some examples:
#ErrorDocument 500 "The server made a boo boo."
#ErrorDocument 404 /missing.html
#ErrorDocument 404 "/cgi-bin/missing_handler.pl"
#ErrorDocument 402 http://192.168.12.242/subscription_info.html
#
#
# MaxRanges: Maximum number of Ranges in a request before
# returning the entire resource, or 0 for unlimited
# Default setting is to accept 200 Ranges
#MaxRanges 0
#
# EnableMMAP and EnableSendfile: On systems that support it,
# memory-mapping or the sendfile syscall is used to deliver
# files. This usually improves server performance, but must
# be turned off when serving from networked-mounted
# filesystems or if support for these functions is otherwise
# broken on your system.
#
#EnableMMAP off
#EnableSendfile off
# Supplemental configuration
#
# The configuration files in the conf/extra/ directory can be
# included to add extra features or to modify the default configuration of
# the server, or you may simply copy their contents here and change as
# necessary.
# Server-pool management (MPM specific)修改连接数
Include conf/extra/httpd-mpm.conf
# Multi-language error messages
#Include conf/extra/httpd-multilang-errordoc.conf
# Fancy directory listings
#Include conf/extra/httpd-autoindex.conf
# Language settings
#Include conf/extra/httpd-languages.conf
# User home directories
#Include conf/extra/httpd-userdir.conf
# Real-time info on requests and configuration
#Include conf/extra/httpd-info.conf
# Virtual hosts 虚拟主机 没有域名不需要设置
#Include conf/extra/httpd-vhosts.conf
# Local access to the Apache HTTP Server Manual
#Include conf/extra/httpd-manual.conf
# Distributed authoring and versioning (WebDAV)
#Include conf/extra/httpd-dav.conf
# Various default settings
#Include conf/extra/httpd-default.conf
# Secure (SSL/TLS) connections
#Include conf/extra/httpd-ssl.conf
#
# Note: The following must must be present to support
# starting without SSL on platforms with no /dev/random equivalent
# but a statically compiled-in mod_ssl.
#
<IfModule ssl_module>
SSLRandomSeed startup builtin
SSLRandomSeed connect builtin
</IfModule>
第三部分:mod_jk代码讲解

mod_jk 分析
1 mod_jk模块的总体功能
由于tomcat的HTTP处理部分都由Java所写(5.5.12版本以后出现了native库,用以
提高其I/O和SSL的性能[1]),在高并发的情况下负载较高。而apache对于静态文件的处
理能力比tomcat强,所以tomcat开发组开发了与apache结合使用的mod_jk模块。该协议
由apache作请求代理,将HTTP协议的请求转化为AJP协议包,并传给后端的
tomcat。mod_jk和apache现在普遍使用AJP1.3协议[2]。它是一个二进制格式的协议,比
字符格式的HTTP协议解析速度要快。
除了性能的提升,mod_jk另外的一个作用可以实现apache与tomcat一对多的对应,
使后端tomcat负载均衡。mod_jk也提供apache与tomcat链接情况的监控。
mod_jk模块的典型工作流程是这样的:一个HTTP请求过来,mod_jk模块根据其URI选
择合适的worker来进行处理。如果是lb_worker(负载均衡的worker),就再根据各种条
件选择后台合适的ajp_worker(处理AJP协议的worker)。ajp_worker将HTTP协议的包,
组装成AJP协议格式的包,然后选取一条空闲的链接,发送给后台的tomcat服务器。等到
后台将数据发送过来时,接收并解析AJP协议,重新组装成HTTP协议,然后把结果发送给
客户端。
2 mod_jk模块的框架
2.1 线程
从宏观上来讲,mod_jk由一个watchdog线程和一组worker线程(进程)组成。
watchdog线程是在apache内部新创建的线程,它是一个维护线程。每隔
JkWatchdogInterval的时间(当然,所有worker线程也有一个统一的worker.maintain 时
间,JkWatchdogInterval应该至少大于worker.maintain),它会扫描所有worker线程。
watchdog线程会检查每个worker线程的空闲链接、负载情况、与后端的链接情况,并使共
享内存同步。worker线程是就是一些ajp13,ajp14,jni,lb或status类型的线程,负责
所有实际的工作。
在mod_jk中,线程内(外)的同步均是通过线程锁(pthread_mutex_lock)来实现的。
而进程之间的全局同步,是用文件记录锁(flock或fcntl)来实现。进程间的数据共享是
用这样做的:进程启动时,创建一个JkShmSize 大小的文件,然后mmap到内存,由于各进
程mmap到内存的是相同的镜像,所以可以实现数据的共享,但是写入共享内存时,要做好
互斥。
由于apache的基本处理方式(prefork和worker模式)就是一个线程/进程负责一个
连接,所以mod_jk各线程中对于网络IO处理都是阻塞的。
2.2 worker对象
从具体的worker对象的角度来讲,mod_jk由ajp_worker、jni_worker、lb_worker和
status_worker组成。这些对象参考了设计模式中factory的模型。每类worker都有生产
workers的factory。
在mod_jk中,其中的worker主要在worker.list中列出。其中,lb_worker可以含有
balance_workers,以lb_sub_worker的形式存储于lb_worker中。lb_sub_worker可以是各
种类型的ajp_worker。所以真正工作的ajp_worker既可以“单干”,也可以由lb_worker
来分配任务。这主要取决于URI到底映射到哪个worker上以及该worker是否在
worker.list配置。
lb_worker,lb_sub_worker和ajp_worker一些配置信息都位于其结构体中,而状态信
息或在运行中可变的参数则位于共享内存中的对应结构体中,当然也并不绝对,有些参数是
冗余的。
从正在运行的某个线程的角度上来讲,ajp_worker就是对应了一个线程。
3 从HTTP到AJP的处理流程
由于mod_jk模块是apache的处理模块,本节主要是讲述mod_jk模块从客户端到后端
服务器的处理流程。中间会涉及一些apache模块的一些结构。
3.1 mod_jk模块在apache中的定义
3.1.1 mod_jk定义
/* 这是jk模块的主要定义结构体*/
module AP_MODULE_DECLARE_DATA jk_module = {
STANDARD20_MODULE_STUFF,
NULL, /* dir config creater */
NULL, /* dir merger --- default is to override */
create_jk_config, /*创建 jk模块的配置结构体*/
merge_jk_config, /* 初始化及合并 jk模块的配置结构体*/
jk_cmds, /* 所有在apahce中的命令及操作函数 */
jk_register_hooks /* 具体的操作函数处理钩子 */
};
3.1.2 mod_jk模块的主要处理函数
/* mod_jk将各处理函数挂到相应的钩子上,钩子实际上就是一些函数指针。针对某个HTTP
请求,这些函数会自上而下执行。*/
static void jk_register_hooks(apr_pool_t * p)
{
/* 该函数在apache读入配置后运行,用以初始化全局互斥锁,jk日志,全局变量的初
始化,以及读入 workers.properties、uriworkermap.properties文件,初始化各worker
的属性,建立worker名称到worker结构体的映射,uri到worker的映射*/
ap_hook_post_config(jk_post_config, NULL, NULL,
APR_HOOK_MIDDLE);
/*该函数在apache主进程fork工作子进程后做的初始化工作,主要包括初始化进程内
互斥锁,开启维护线程,读入共享内存*/
ap_hook_child_init(jk_child_init, NULL, NULL, APR_HOOK_MIDDLE);
/* 将mod_jk的URI到真实URI,然后URI到worker的映射翻译过程,用以找到该URI
相应的worker_name */
ap_hook_translate_name(jk_translate, NULL, NULL,
APR_HOOK_MIDDLE);
#if (MODULE_MAGIC_NUMBER_MAJOR > 20010808)
/* 绑定那些alias_dir的URI到mod_jk的配置,并找到相应worker_name */
ap_hook_map_to_storage(jk_map_to_storage, NULL, NULL,
APR_HOOK_MIDDLE);
/* 这是mod_jk的主要处理函数 */
ap_hook_handler(jk_handler, NULL, NULL, APR_HOOK_MIDDLE);
#endif
}
3.2 jk_handler函数
jk_handler函数是mod_jk的主要处理函数,它负责将HTTP请求从apache发到tomcat,
再从tomcat接受数据,并返回给客户。
它的处理过程如下:
1. 根据前面得到的worker_name,找到相应的jk_worker(其结构体见4.4)。
2. 初始化服务结构体jk_ws_service,主要是针对HTTP服务端的一些设置及函数(服务
的结构体见4.5),与AJP协议关系不大。
3. 调用jk_worker的get_endpoint函数,获取具体的jk_endpoint结构体(函数见
3.3.1和3.4.1,jk_endpoint的结构体定义见4.4)。
4. 调用上述jk_endpoint的service函数。
5. 调用上述jk_endpoint的done函数,结束与tomcat的AJP连接。
6. 根据函数的结果处理各种状态。
7. 释放资源。
3.3 lb_worker的处理函数
3.3.1 lb_worker的get_endpoint
初始化lb_worker的endpoint结构体,挂上其service及done函数。
3.3.2 lb_worker的service函数
它的处理过程如下:
1. 获取共享内存中记录的worker状态。
2. 如果需要绑定sessionID,获取sessionID。
3. 调用get_most_suitable_worker函数,获取相应的lb_sub_worker(也即
ajp_worker)。
4. 调用ajp_worker的get_endpoint函数。
5. 调用上述endpoint的service函数。
6. 调用上述endpoint的done函数。
7. 根据service的返回结果,更新各种记录状态。
3.3.3 get_most_suitable_worker函数
它的处理过程如下:
1. 如果需要绑定sessionID,就根据sessionID找到工作正常的最佳worker。
2. 如果找不到,则调用find_best_worker函数。其处理过程如下:
i. 又调用find_best_byvalue函数。其处理过程如下:按照Round Robin的方式在
本lb_worker中找到第一个不在错误状态、也没有停止、没有disabled 、也不
busy的lb_sub_worker。
ii.如果find_best_byvalue返回错误,说明本lb_worker的lb_sub_worker都处于
非正常工作状态,需要调用find_failover_worker函数,通过
redirect、route、domain指令来进行查找[3]。
3.4 ajp_worker的处理函数
3.4.1 ajp_worker的get_endpoint函数
它的主要功能是:找到与后端tomcat的一个空闲连接。
3.4.2 ajp_worker的ajp_service函数
该函数主要分为 ajp_send_request和and ajp_get_reply两个函数。
它的处理过程如下:
1. 获取共享内存中的状态。
2. 分配AJP请求包、恢复包、POST包的内存。
3. 调用ajp_marshal_into_msgb函数,将HTTP请求包转化为AJP包。
4. 将当前ajp_worker的状态更新。
5. 调用ajp_send_request函数。
6. 如果发送成功,调用ajp_get_reply函数,等待并接受AJP包。
7. 如果成功,更新当前状态。
3.4.2 ajp_worker的ajp_send_request函数
它的处理过程如下:
1. 调用jk_is_socket_connected函数,检查即将发送的socket是否有效。它的检查过
程是运用select函数,等1微妙,如果成功返回说明,该socket的文件描述符至少
在内核中还有效。
2. 如果上一次发送超时,则调用ajp_handle_cping_cpong函数来判断后端连接是否有
效。该函数主要是发出了一个AJP13_CPING_REQUEST类型的AJP包,如果tomcat收
到,应返回一个AJP13_CPONG_REPLY的包。
3. 如果上述的测试都成功,调用ajp_connection_tcp_send_message,发送AJP包。
3.4.3 ajp_worker的ajp_get_reply函数
它的处理过程如下:
1. 调用jk_is_input_event,用select等待接受数据,直到socket有接受数据。
2. 调用ajp_connection_tcp_get_message,接受AJP包,并检查协议头。
3. 调用ajp_process_callback,对该AJP包进行解析处理。其处理过程如下:
i. 如果是JK_AJP13_SEND_HEADERS包,将其解包成HTTP包头。如果没有错误,就调
用jk_ws_service->start_response()函数发送HTTP回复的head。返回
JK_AJP13_SEND_HEADERS。
ii.如果是JK_AJP13_SEND_BODY_CHUNK包,调用jk_ws_service->write发送HTTP回
复的body。返回JK_AJP13_NO_RESPONSE。
iii.如果是JK_AJP13_GET_BODY_CHUNK包,说明还有数据要发送到tomcat,调用
ajp_read_into_msg_buff,继续发送数据。返回JK_AJP13_HAS_RESPONSE。
iv.如果是JK_AJP13_END_RESPONSE包,就说明tomcat的回复已经完成。返回
JK_AJP13_END_RESPONSE。
3.5 jk_ws_service的一些处理函数
3.5.1 jk_ws_service 的 ws_start_response函数
该函数主要是构建HTTP回复包的头部。
3.5.2 jk_ws_service 的 ws_write函数
调用 apache的ap_rwrite函数,发送整个HTTP包。
3.5.3 jk_ws_service 的 ws_read函数
调用apache的ap_get_client_block读入全部的request body数据。
4 mod_jk的主要数据结构
4.1 lb_worker
lb_worker是负载均衡worker。主要负责调配其名下的一些lb_sub_worker 。

dist/common/jk_lb_worker.h
struct lb_worker
{
/* jk模块通用worker结构体。包含一些回调函数,不同的worker有不同的函数实现
*/
jk_worker_t worker;
/* Shared memory worker data */
jk_shm_lb_worker_t *s;
char name[JK_SHM_STR_SIZ+1];
/* Sequence counter starting at 0 and increasing
* every time we change the config
*/
volatile unsigned int sequence;
jk_pool_t p;
jk_pool_atom_t buf[TINY_POOL_SIZE];
JK_CRIT_SEC cs;
/*其名下的workers*/
lb_sub_worker_t *lb_workers;
unsigned int num_of_workers;
int sticky_session;
int sticky_session_force;
int recover_wait_time;
int max_reply_timeouts;
int retries;
int retry_interval;
int lbmethod;
int lblock;
int maintain_time;
unsigned int max_packet_size;
unsigned int next_offset;
/* Session cookie */
char session_cookie[JK_SHM_STR_SIZ+1];
/* Session path */
char session_path[JK_SHM_STR_SIZ+1];
};
lb_sub_worker是由lb_worker支配的ajp_worker。当然lb_sub_worker有不同的类型。
它们的实际类型存储在ajp_worker中。
dist/common/jk_lb_worker.h
struct lb_sub_worker
{
/* 包含ajp_worker的回调函数及其ajp_worker结构体*/
jk_worker_t *worker;
/* Shared memory worker data */
jk_shm_lb_sub_worker_t *s;
char name[JK_SHM_STR_SIZ+1];
/* Sequence counter starting at 0 and increasing
* every time we change the config
*/
volatile unsigned int sequence;
/* route */
char route[JK_SHM_STR_SIZ+1];
/* worker domain */
char domain[JK_SHM_STR_SIZ+1];
/* worker redirect route */
char redirect[JK_SHM_STR_SIZ+1];
/* worker distance */
int distance;
/* current activation state (config) of the worker */
int activation;
/* Current lb factor */
int lb_factor;
/* Current worker index */
int i;
/* Current lb reciprocal factor */
jk_uint64_t lb_mult;
};
typedef struct lb_sub_worker lb_sub_worker_t;
4.2 ajp_worker
ajp_worker是具体工作的worker,对应后端一个tomcat应用服务。
dist/common/jk_ajp_common.c
struct ajp_worker
{
/* 包含ajp_worker的回调函数*/
jk_worker_t worker;
/* Shared memory worker data */
jk_shm_ajp_worker_t *s;
char name[JK_SHM_STR_SIZ+1];
/* Sequence counter starting at 0 and increasing
* every time we change the config
*/
volatile unsigned int sequence;
jk_pool_t p;
jk_pool_atom_t buf[TINY_POOL_SIZE];
JK_CRIT_SEC cs;
struct sockaddr_in worker_inet_addr; /* Contains host and port */
unsigned connect_retry_attempts;
const char *host;
int port;
int maintain_time;
/*
* Open connections cache...
*
* 1. Critical section object to protect the cache.
* 2. Cache size.
* 3. An array of "open" endpoints.
*/
unsigned int ep_cache_sz;
unsigned int ep_mincache_sz;
unsigned int ep_maxcache_sz;
int cache_acquire_timeout;
ajp_endpoint_t **ep_cache;
int proto; /* PROTOCOL USED AJP13/AJP14 */
jk_login_service_t *login;
/* Weak secret similar with ajp12, used in ajp13 */
const char *secret;
/*
* Post physical connect handler.
* AJP14 will set here its login handler
*/
int (*logon) (ajp_endpoint_t * ae, jk_logger_t *l);
/*
* Handle Socket Timeouts
*/
int socket_timeout;
int socket_connect_timeout;
int keepalive;
int socket_buf;
/*
* Handle Cache Timeouts
*/
int cache_timeout;
/*
* Handle Connection/Reply Timeouts
*/
int connect_timeout; /* connect cping/cpong delay in ms (0 means
disabled) */
int reply_timeout; /* reply timeout delay in ms (0 means disabled) */
int prepost_timeout; /* before sending a request cping/cpong timeout
delay in ms (0 means disabled) */
int conn_ping_interval; /* interval for sending keepalive cping packets on
* unused connection */
int ping_timeout; /* generic cping/cpong timeout. Used for keepalive
packets or
* as default for boolean valued connect and
prepost timeouts.
*/
unsigned int ping_mode; /* Ping mode flags (which types of cpings should
be used) */
/*
* Recovery options
*/
unsigned int recovery_opts;
/*
* Public property to enable the number of retry attempts
* on this worker.
*/
int retries;
unsigned int max_packet_size; /* Maximum AJP Packet size */
int retry_interval; /* Number of milliseconds to sleep before
doing a retry */
/*
* HTTP status that will cause failover (0 means disabled)
*/
unsigned int http_status_fail_num;
int http_status_fail[JK_MAX_HTTP_STATUS_FAILS];
};
4.3 status_worker
status_worker用于产生一些状态的统计信息。
dist/common/jk_statuc.c
struct status_worker
{
jk_pool_t p;
jk_pool_atom_t buf[TINY_POOL_SIZE];
const char *name;
const char *css;
const char *ns;
const char *xmlns;
const char *doctype;
const char *prefix;
int read_only;
char **user_names;
unsigned int num_of_users;
int user_case_insensitive;
jk_uint32_t good_mask;
jk_uint32_t bad_mask;
jk_worker_t worker;
jk_worker_env_t *we;
};
4.4 jk_worker和 jk_endpoint
jk_worker是所有worker通用结构体名称, 主要包含的是一些函数指针。它是一个类
似java中抽象类的概念,各成员函数在从factory函数生产时初始化。
dist/common/jk_service.h
struct jk_worker
{
/*
* A 'this' pointer which is used by the subclasses of this class to
* point to data/functions which are specific to a given protocol
* (e.g. ajp12 or ajp13 or ajp14).
*/
void *worker_private;/* 指向ajp_worker,lb_worker结构体 ...*/
int type;
/*
* For all of the below (except destroy), the first argument is
* essentially a 'this' pointer.
*/
/* 先于init函数调用,用于分配各类worker结构体的内存,作必要的初始化
* Given a worker which is in the process of being created, and a list
* of configuration options (or 'properties'), check to see if it the
* options are. This will always be called before the init() method.
* The init/validate distinction is a bit hazy to me.
* See jk_ajp13_worker.c/jk_ajp14_worker.c and jk_worker.c-
>wc_create_worker()
*/
int (JK_METHOD * validate) (jk_worker_t *w,
jk_map_t *props,
jk_worker_env_t *we, jk_logger_t *l);
/*
* Update worker either from jk_status or reloading from workers.properties
*/
int (JK_METHOD * update) (jk_worker_t *w,
jk_map_t *props,
jk_worker_env_t *we, jk_logger_t *l);
/*
* Do whatever initialization needs to be done to start this worker up.
* Configuration options are passed in via the props parameter.
*/
int (JK_METHOD * init) (jk_worker_t *w,
jk_map_t *props,
jk_worker_env_t *we, jk_logger_t *l);
/*
* Obtain an endpoint to service a particular request. A pointer to
* the endpoint is stored in pend.
*/
int (JK_METHOD * get_endpoint) (jk_worker_t *w,
jk_endpoint_t **pend, jk_logger_t *l);
/*
* Shutdown this worker. The first argument is not a 'this' pointer,
* but rather a pointer to 'this', so that the object can be free'd (I
* think -- though that doesn't seem to be happening. Hmmm).
*/
int (JK_METHOD * destroy) (jk_worker_t **w, jk_logger_t *l);
/*
* Maintain this worker.
*/
int (JK_METHOD * maintain) (jk_worker_t *w, time_t now, jk_logger_t *l);
};
/* jk_endpoint可以称之为通用终端服务结构体,各类worker可能有自己的endpoint结构
体。比如ajp_worker, 该终端是用来做具体工作的,比如发出请求,接收AJP数据等等。如
果是lb_worker,该终端是的作用是找出合适ajp_worker, 把任务交给它。* /
struct jk_endpoint
{
jk_uint64_t rd;
jk_uint64_t wr;
/*
* Flag to pass back recoverability status from
* a load balancer member to the load balancer itself.
* Depending on the configuration and request status
* recovery is not allowed.
*/
int recoverable;
/*
* A 'this' pointer which is used by the subclasses of this class to
* point to data/functions which are specific to a given protocol
* (e.g. ajp12 or ajp13 or ajp14).
*/
void *endpoint_private;
/* 该函数是具体的服务函数
* Forward a request to the servlet engine. The request is described
* by the jk_ws_service_t object.
* is_error is either 0 meaning recoverable or set to
* the HTTP error code.
*/
int (JK_METHOD * service) (jk_endpoint_t *e,
jk_ws_service_t *s,
jk_logger_t *l, int *is_error);
/*
* Called when this particular endpoint has finished processing a
* request. For some protocols (e.g. ajp12), this frees the memory
* associated with the endpoint. For others (e.g. ajp13/ajp14), this can
* return the endpoint to a cache of already opened endpoints.
*
* Note that the first argument is *not* a 'this' pointer, but is
* rather a pointer to a 'this' pointer. This is necessary, because
* we may need to free this object.
*/
int (JK_METHOD * done) (jk_endpoint_t **p, jk_logger_t *l);
};
4.5 jk_ws_service
该结构体是与apache相关的一些参数或函数,面向HTTP协议,与AJP协议不太相关。
dist/common/jk_service.h
struct jk_ws_service
{
/*
* A 'this' pointer which is used by the subclasses of this class to
* point to data which is specific to a given web server platform
* (e.g. Apache or IIS).
*/
void *ws_private;
/*
* Provides memory management. All data specific to this request is
* allocated within this pool, which can then be reclaimed at the end
* of the request handling cycle.
*
* Alive as long as the request is alive.
*/
jk_pool_t *pool;
/*
* CGI Environment needed by servlets
*/
const char *method;
const char *protocol;
char *req_uri;
const char *remote_addr;
const char *remote_host;
const char *remote_user;
const char *auth_type;
const char *query_string;
const char *server_name;
unsigned server_port;
char *server_software;
jk_uint64_t content_length; /* 64 bit integer that represents the content */
/* length should be 0 if unknown. */
unsigned is_chunked; /* 1 if content length is unknown (chunked rq) */
unsigned no_more_chunks; /* 1 if last chunk has been read */
jk_uint64_t content_read; /* number of bytes read */
/*
* SSL information
*
* is_ssl - True if request is in ssl connection
* ssl_cert - If available, base64 ASN.1 encoded client certificates.
* ssl_cert_len - Length of ssl_cert, 0 if certificates are not available.
* ssl_cipher - The ssl cipher suite in use.
* ssl_session - The ssl session string
*
* In some servers it is impossible to extract all this information, in this
* case, we are passing NULL.
*/
int is_ssl;
char *ssl_cert;
unsigned ssl_cert_len;
char *ssl_cipher;
char *ssl_session;
/*
* SSL extra information for Servlet 2.3 API
*
* ssl_key_size - ssl key size in use
*/
int ssl_key_size;
/*
* Headers, names and values.
*/
char **headers_names; /* Names of the request headers */
char **headers_values; /* Values of the request headers */
unsigned num_headers; /* Number of request headers */
/*
* Request attributes.
*
* These attributes that were extracted from the web server and are
* sent to Tomcat.
*
* The developer should be able to read them from the ServletRequest
* attributes. Tomcat is required to append org.apache.tomcat. to
* these attribute names.
*/
char **attributes_names; /* Names of the request attributes */
char **attributes_values; /* Values of the request attributes */
unsigned num_attributes; /* Number of request attributes */
/*
* The route is in use when the adapter load balance among
* several workers. It is the ID of a specific target in the load balance
* group. We are using this variable to implement target session
* affinity
*/
const char *route;
/* Temp solution for auth. For native1 it'll be sent on each request,
if an option is present. For native2 it'll be sent with the first
request. On java side, both cases will work. For tomcat3.2 or
a version that doesn't support secret - don't set the secret,
and it'll work.
*/
const char *secret;
/*
* Area to get POST data for fail-over recovery in POST
*/
jk_msg_buf_t *reco_buf;
int reco_status;
/*
* If set call flush after each write
*/
int flush_packets;
/*
* If set call flush after AJP13_SEND_HEADERS.
*/
int flush_header;
/*
* service extensions
*/
svc_extension_t extension;
/*
* JK_TRUE if response headers have been sent back
*/
int response_started;
/*
* JK_TRUE if response should not be send to the client
*/
int response_blocked;
/*
* HTTP status sent from container.
*/
int http_response_status;
/* Uri worker map. Added for virtual host support
*/
jk_uri_worker_map_t *uw_map;
/* 下面这些回调函数实现都可以在mod_jk.c找到
* Callbacks into the web server. For each, the first argument is
* essentially a 'this' pointer. All return JK_TRUE on success
* and JK_FALSE on failure.
*/
/*
* Send the response headers to the browser.
*/
int (JK_METHOD * start_response) (jk_ws_service_t *s,
int status,
const char *reason,
const char *const *header_names,
const char *const *header_values,
unsigned num_of_headers);
/*
* Read a chunk of the request body into a buffer. Attempt to read len
* bytes into the buffer. Write the number of bytes actually read into
* actually_read.
*/
int (JK_METHOD * read) (jk_ws_service_t *s,
void *buffer,
unsigned len, unsigned *actually_read);
/*
* Write a chunk of response data back to the browser.
*/
int (JK_METHOD * write) (jk_ws_service_t *s,
const void *buffer, unsigned len);
/*
* Flush a chunk of response data back to the browser.
*/
void (JK_METHOD * flush) (jk_ws_service_t *s);
/*
* Done with sending response back to the browser.
*/
void (JK_METHOD * done) (jk_ws_service_t *s);
/*
* If set do not reuse socket after each full response
*/
int disable_reuse;
/*
* Add more data to log facilities.
*/
void (JK_METHOD * add_log_items) (jk_ws_service_t *s,
const char *const *log_names,
const char *const *log_values,
unsigned num_of_items);
/*
* Iterate through all vhosts
*/
void *(JK_METHOD * next_vhost) (void *d);
/*
* String representation of a vhost
*/
void (JK_METHOD * vhost_to_text) (void *d, char *buf, size_t len);
/*
* Get uw_map associated with a vhost
*/
jk_uri_worker_map_t *(JK_METHOD * vhost_to_uw_map) (void *d);
};
4.6 共享内存中一些数据结构
共享内存中的数据结构基本上都是记录之用。有些参数在运行中会实时变化。
dist/common/jk_shm.h
/** jk shm generic worker record structure */
struct jk_shm_worker_header
{
int id;
int type;
/* worker name */
char name[JK_SHM_STR_SIZ+1];
/* Sequence counter starting at 0 and increasing
* every time we change the config
*/
volatile unsigned int sequence;
};
typedef struct jk_shm_worker_header jk_shm_worker_header_t;
/** jk shm ajp13/ajp14 worker record structure */
struct jk_shm_ajp_worker
{
jk_shm_worker_header_t h;
/* Configuration data mirrored from ajp_worker */
int cache_timeout;
int connect_timeout;
int reply_timeout;
int prepost_timeout;
unsigned int recovery_opts;
int retries;
int retry_interval;
unsigned int max_packet_size;
/* current error state (runtime) of the worker */
volatile int state;
/* Statistical data */
/* Number of currently busy channels */
volatile int busy;
/* Maximum number of busy channels
该参数并非我们的maxbusy,它是该worker自程序运行以来busy的最大值 */
volatile int max_busy;
volatile time_t error_time;
/* Number of bytes read from remote */
volatile jk_uint64_t readed;
/* Number of bytes transferred to remote */
volatile jk_uint64_t transferred;
/* Number of times the worker was used */
volatile jk_uint64_t used;
/* Number of times the worker was used - snapshot during maintenance */
volatile jk_uint64_t used_snapshot;
/* Number of non 200 responses */
volatile jk_uint32_t errors;
/* Decayed number of reply_timeout errors */
volatile jk_uint32_t reply_timeouts;
/* Number of client errors */
volatile jk_uint32_t client_errors;
/* Last reset time */
volatile time_t last_reset;
volatile time_t last_maintain_time;
};
typedef struct jk_shm_ajp_worker jk_shm_ajp_worker_t;
/** jk shm lb sub worker record structure */
struct jk_shm_lb_sub_worker
{
jk_shm_worker_header_t h;
/* route */
char route[JK_SHM_STR_SIZ+1];
/* worker domain */
char domain[JK_SHM_STR_SIZ+1];
/* worker redirect route */
char redirect[JK_SHM_STR_SIZ+1];
/* Number of currently busy channels */
volatile int busy;
/* worker distance */
volatile int distance;
/* current activation state (config) of the worker */
volatile int activation;
/* current error state (runtime) of the worker */
volatile int state;
/* Current lb factor */
volatile int lb_factor;
/* 我们的参数加在这里*/
volatile int maxbusy;
/* Current lb reciprocal factor */
volatile jk_uint64_t lb_mult;
/* Current lb value */
volatile jk_uint64_t lb_value;
/* Statistical data */
volatile time_t error_time;
/* Number of times the worker was elected - snapshot during maintenance */
volatile jk_uint64_t elected_snapshot;
/* Number of non 200 responses */
volatile jk_uint32_t errors;
};
typedef struct jk_shm_lb_sub_worker jk_shm_lb_sub_worker_t;
/** jk shm lb worker record structure */
struct jk_shm_lb_worker
{
jk_shm_worker_header_t h;
/* Number of currently busy channels,该值是其名下ajp_worker的busy值之和*/
volatile int busy;
/* Maximum number of busy channels,该值是其名下ajp_worker的max_busy值之和
*/
volatile int max_busy;
int sticky_session;
int sticky_session_force;
int recover_wait_time;
int max_reply_timeouts;
int retries;
int retry_interval;
int lbmethod;
int lblock;
unsigned int max_packet_size;
/* Last reset time */
volatile time_t last_reset;
volatile time_t last_maintain_time;
/* Session cookie */
char session_cookie[JK_SHM_STR_SIZ+1];
/* Session path */
char session_path[JK_SHM_STR_SIZ+1];
};
typedef struct jk_shm_lb_worker jk_shm_lb_worker_t;

 

 首先虽然这个mod_jk已经过时,但还是放出来大家一起学习一下,文章主要分三部分内容:

1.第一部分:说明主要配置过程

2.第二部分:贴出我的httpd.conf文件

3.第三部分:对mod_jk代码讲解(来源百度)

 

第一部分:配置

1.       准备环境:

操作系统:windows7

httpd-2.2.21-win32-x86-no_ssl.msi

apache-tomcat-6.0.7

apache-tomcat-5.0.7

tomcat-connectors-1.2.32-windows-i386-httpd-2.2.x

jdk1.5

2.       下载APACHE

这里下载的是APACHE2.2.21版本

3.       下载JK(Tomcat
Connector)

Jk是apache和tomcat的连接器,也可以做负载均衡器,主要是apache通过jk找到tomcat。

下载地址:http://archive.apache.org/dist/tomcat/tomcat-connectors/jk/binaries/windows/Jk的版本要与apache的版本对应如:mod_jk-1.2.32-httpd-2.2.x.zip其匹配的Apache为2.2.版本以上可用

4.       下载TOMCAT

apache-tomcat-6.0.7.rar

5.       配置修改过程

1)  Apache配置

将Tomcat Connector文件mod_jk.so拷贝到Apache安装目录的modules目录下。

在Apache安装目录下找到conf/httpd.conf文件,使用文本编辑器打开:

伪静态修改

将注释放开

找到AllowOverride None 将其修改为 All 内容如下:

<Directory />
    Options FollowSymLinks
    AllowOverride All
    Order deny,allow
    Deny from all
</Directory>

Tomcat Connector关联项增加

       
在LoadModules末尾处增加一下内容:

#加载mod_jk连接
LoadModule jk_module modules/mod_jk.so
### 配置 mod_jk
JkWorkersFile "conf\workers.properties" #加载集群中的workers
#此处是指定分配给tomcat的请求 例如*.do *.jsp
JkMount /*.jsp controller
JkLogFile logs/mod_jk.log #指定jk的日志输出文件
JkLogLevel warn #指定日志级别
    找到IfModule dir_module 修改默认访问地址,需要根据具体项目实际情况填写,我这里使用的是index.jsp 修改如下:
<IfModule dir_module>
DirectoryIndex index.jsp
</IfModule>
    找到Virtual hosts 去掉虚拟主机注释
# Virtual hosts
#Include conf/extra/httpd-vhosts.conf 将 “#”去掉
Include conf/extra/httpd-vhosts.conf
加载代理(暂时未去掉)
#LoadModule proxy_module modules/mod_proxy.so
#LoadModule proxy_ajp_module modules/mod_proxy_ajp.so
#LoadModule proxy_balancer_module modules/mod_proxy_balancer.so
#LoadModule proxy_connect_module modules/mod_proxy_connect.so
#LoadModule proxy_ftp_module modules/mod_proxy_ftp.so

2)  Tomcat Connector配置

在Apache配置目录Apache2.2\conf创建workers.properties配置文件,该文件主要用于配置Apache与Tomcat的集成要用到的Tomcat实例和负载均衡分发控制器。

Workers.properties文件放置一下内容;

#下面是分发控制器 注意不要放tomcat实例
worker.list=lbcontroller
#Tomcat1实例配置 这里要和Tomcat配置文件Service.xml的jvmRoute保持一致
worker.test1.host=localhost
worker.test1.port=8009
worker.test1.type=ajp13
#分发权重 值越大负载越大
worker.tomcat1.lbfactor=1
#Tomcat2实例配置
worker.test2.host=localhost
worker.test2.port=9009
worker.test2.type=ajp13
#分发权重 值越大负载越大
worker.tomcat2.lbfactor=1
#负载均衡分发控制器
worker.lbcontroller.type=lb
worker.lbcontroller.balance_workers=test1,test2
Tomcat配置文件Service.xml主要注意两个地方,一个是Engine节点需要增加节点标识jvmRoute,一个是将原本注释掉的Session复制节点改为有效。具体如下:

  

<!--jvmRoute在各个Tomcat配置中不能重复且要与worker.properties文件中的名称一致-->
    <Engine name="Catalina" defaultHost="localhost" jvmRoute="test1">
<!--session复制内容-->
       <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="228.0.0.4"
                        port="45564"
                        frequency="500"
                        dropTime="3000"/>
<Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver"
                      address="auto"
                      port="4000"
                      autoBind="100"
                      selectorTimeout="5000"
                      maxThreads="6"/>
            <!-- timeout="60000"-->
            <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"/>
            <Interceptor className="org.apache.catalina.tribes.group.interceptors.ThroughputInterceptor"/>
          </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"/>
          <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>
      <!--session复制内容-->

           
<!—Host节点增加一下内容表示站点根路径-->

<Context path="/sc" docBase="." privileged="true"/>

我们分别将两个Tomcat配置文件中的jvmRoute设置为tomcat1、tomcat2,Server节点
端口分别配置为8005和9005,
Connector节点端口分别配置为8080和9090,AJPConnector端口分别配置为8009和9009,Connector端口配置参照单主机多站点场景。请注意两个Tomcat配置文件Host节点的域名配置必须一样,Server.xml中的jvmRoute名称必须和worker.properties中的tomcat实例名称一致,不然无法实现session_stricky。

 

*****************************************************************************
 如果需要实现session 复制 需要在Tomcat 下conf/web.xml 中加上<distributable/>
<?xml version="1.0" encoding="ISO-8859-1"?>
省略N多代码。。。。。。
    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
        <welcome-file>index.htm</welcome-file>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>
<distributable/>
</web-app>
*****************************************************************************
第二部分:httpd.conf文件 #
# This is the main Apache HTTP server configuration file. It contains the
# configuration directives that give the server its instructions.
# See <URL:http://httpd.apache.org/docs/2.2> for detailed information.
# In particular, see
# <URL:http://httpd.apache.org/docs/2.2/mod/directives.html>
# for a discussion of each configuration directive.
#
# Do NOT simply read the instructions in here without understanding
# what they do. They're here only as hints or reminders. If you are unsure
# consult the online docs. You have been warned.
#
# Configuration and logfile names: If the filenames you specify for many
# of the server's control files begin with "/" (or "drive:/" for Win32), the
# server will use that explicit path. If the filenames do *not* begin
# with "/", the value of ServerRoot is prepended -- so "logs/foo.log"
# with ServerRoot set to "D:/Program Files/Apache Software Foundation/Apache2.2" will be interpreted by the
# server as "D:/Program Files/Apache Software Foundation/Apache2.2/logs/foo.log".
#
# NOTE: Where filenames are specified, you must use forward slashes
# instead of backslashes (e.g., "c:/apache" instead of "c:\apache").
# If a drive letter is omitted, the drive on which httpd.exe is located
# will be used by default. It is recommended that you always supply
# an explicit drive letter in absolute paths to avoid confusion.
#
# ServerRoot: The top of the directory tree under which the server's
# configuration, error, and log files are kept.
#
# Do not add a slash at the end of the directory path. If you point
# ServerRoot at a non-local disk, be sure to point the LockFile directive
# at a local disk. If you wish to share the same ServerRoot for multiple
# httpd daemons, you will need to change at least LockFile and PidFile.
#
ServerRoot "D:/Program Files/Apache Software Foundation/Apache2.2"
#
# Listen: Allows you to bind Apache to specific IP addresses and/or
# ports, instead of the default. See also the <VirtualHost>
# directive.
#
# Change this to Listen on specific IP addresses as shown below to
# prevent Apache from glomming onto all bound IP addresses.
#
#Listen 12.34.56.78:80
Listen 8080
#
# Dynamic Shared Object (DSO) Support
#
# To be able to use the functionality of a module which was built as a DSO you
# have to place corresponding `LoadModule' lines at this location so the
# directives contained in it are actually available _before_ they are used.
# Statically compiled modules (those listed by `httpd -l') do not need
# to be loaded here.
#
# Example:
# LoadModule foo_module modules/mod_foo.so
#
LoadModule actions_module modules/mod_actions.so
LoadModule alias_module modules/mod_alias.so
LoadModule asis_module modules/mod_asis.so
LoadModule auth_basic_module modules/mod_auth_basic.so
#LoadModule auth_digest_module modules/mod_auth_digest.so
#LoadModule authn_alias_module modules/mod_authn_alias.so
#LoadModule authn_anon_module modules/mod_authn_anon.so
#LoadModule authn_dbd_module modules/mod_authn_dbd.so
#LoadModule authn_dbm_module modules/mod_authn_dbm.so
LoadModule authn_default_module modules/mod_authn_default.so
LoadModule authn_file_module modules/mod_authn_file.so
#LoadModule authnz_ldap_module modules/mod_authnz_ldap.so
#LoadModule authz_dbm_module modules/mod_authz_dbm.so
LoadModule authz_default_module modules/mod_authz_default.so
LoadModule authz_groupfile_module modules/mod_authz_groupfile.so
LoadModule authz_host_module modules/mod_authz_host.so
#LoadModule authz_owner_module modules/mod_authz_owner.so
LoadModule authz_user_module modules/mod_authz_user.so
LoadModule autoindex_module modules/mod_autoindex.so
#LoadModule cache_module modules/mod_cache.so
#LoadModule cern_meta_module modules/mod_cern_meta.so
LoadModule cgi_module modules/mod_cgi.so
#LoadModule charset_lite_module modules/mod_charset_lite.so
#LoadModule dav_module modules/mod_dav.so
#LoadModule dav_fs_module modules/mod_dav_fs.so
#LoadModule dav_lock_module modules/mod_dav_lock.so
#LoadModule dbd_module modules/mod_dbd.so
#LoadModule deflate_module modules/mod_deflate.so
LoadModule dir_module modules/mod_dir.so
#LoadModule disk_cache_module modules/mod_disk_cache.so
#LoadModule dumpio_module modules/mod_dumpio.so
LoadModule env_module modules/mod_env.so
#LoadModule expires_module modules/mod_expires.so
#LoadModule ext_filter_module modules/mod_ext_filter.so
#LoadModule file_cache_module modules/mod_file_cache.so
#LoadModule filter_module modules/mod_filter.so
#LoadModule headers_module modules/mod_headers.so
#LoadModule ident_module modules/mod_ident.so
#LoadModule imagemap_module modules/mod_imagemap.so
LoadModule include_module modules/mod_include.so
#LoadModule info_module modules/mod_info.so
LoadModule isapi_module modules/mod_isapi.so
#LoadModule ldap_module modules/mod_ldap.so
#LoadModule logio_module modules/mod_logio.so
LoadModule log_config_module modules/mod_log_config.so
#LoadModule log_forensic_module modules/mod_log_forensic.so
#LoadModule mem_cache_module modules/mod_mem_cache.so
LoadModule mime_module modules/mod_mime.so
#LoadModule mime_magic_module modules/mod_mime_magic.so
LoadModule negotiation_module modules/mod_negotiation.so
#LoadModule proxy_module modules/mod_proxy.so
#LoadModule proxy_ajp_module modules/mod_proxy_ajp.so
#LoadModule proxy_balancer_module modules/mod_proxy_balancer.so
#LoadModule proxy_connect_module modules/mod_proxy_connect.so
#LoadModule proxy_ftp_module modules/mod_proxy_ftp.so
#LoadModule proxy_http_module modules/mod_proxy_http.so
#LoadModule proxy_scgi_module modules/mod_proxy_scgi.so
#LoadModule reqtimeout_module modules/mod_reqtimeout.so
#url伪静态
LoadModule rewrite_module modules/mod_rewrite.so
LoadModule setenvif_module modules/mod_setenvif.so
#LoadModule speling_module modules/mod_speling.so
#LoadModule ssl_module modules/mod_ssl.so
#LoadModule status_module modules/mod_status.so
#LoadModule substitute_module modules/mod_substitute.so
#LoadModule unique_id_module modules/mod_unique_id.so
#LoadModule userdir_module modules/mod_userdir.so
#LoadModule usertrack_module modules/mod_usertrack.so
#LoadModule version_module modules/mod_version.so
#LoadModule vhost_alias_module modules/mod_vhost_alias.so
#加载mod_jk连接
LoadModule jk_module modules/mod_jk.so
#加载集群中的workers
JkWorkersFile "conf/workers.properties"
#此处是指定分配给tomcat的请求 例如*.do *.jsp
JkMount /*.jsp lbcontroller
#指定jk的日志输出文件
JkLogFile "logs/mod_jk.log"
#指定日志级别
JkLogLevel warn
<IfModule !mpm_netware_module>
<IfModule !mpm_winnt_module>
#
# If you wish httpd to run as a different user or group, you must run
# httpd as root initially and it will switch.
#
# User/Group: The name (or #number) of the user/group to run httpd as.
# It is usually good practice to create a dedicated user and group for
# running httpd, as with most system services.
#
User daemon
Group daemon
</IfModule>
</IfModule>
# 'Main' server configuration
#
# The directives in this section set up the values used by the 'main'
# server, which responds to any requests that aren't handled by a
# <VirtualHost> definition. These values also provide defaults for
# any <VirtualHost> containers you may define later in the file.
#
# All of these directives may appear inside <VirtualHost> containers,
# in which case these default settings will be overridden for the
# virtual host being defined.
#
#
# ServerAdmin: Your address, where problems with the server should be
# e-mailed. This address appears on some server-generated pages, such
# as error documents. e.g. [email protected]
#
ServerAdmin localhost
#
# ServerName gives the name and port that the server uses to identify itself.
# This can often be determined automatically, but we recommend you specify
# it explicitly to prevent problems during startup.
#
# If your host doesn't have a registered DNS name, enter its IP address here.
#
ServerName localhost:8080
#
# DocumentRoot: The directory out of which you will serve your
# documents. By default, all requests are taken from this directory, but
# symbolic links and aliases may be used to point to other locations.
#
DocumentRoot "D:/work/work_bz/test/WebRoot"
#
# Each directory to which Apache has access can be configured with respect
# to which services and features are allowed and/or disabled in that
# directory (and its subdirectories).
#
# First, we configure the "default" to be a very restrictive set of
# features.
# 默认为 AllowOverride None
<Directory />
Options FollowSymLinks
AllowOverride All
#Order deny,allow
#Deny from all
Order allow,deny
Allow from all
Satisfy all
</Directory>
#首次访问页面
<IfModule dir_module>
DirectoryIndex index.jsp
</IfModule>
#
# The following lines prevent .htaccess and .htpasswd files from being
# viewed by Web clients.
#
<FilesMatch "^\.ht">
Order allow,deny
Deny from all
Satisfy All
</FilesMatch>
#
# ErrorLog: The location of the error log file.
# If you do not specify an ErrorLog directive within a <VirtualHost>
# container, error messages relating to that virtual host will be
# logged here. If you *do* define an error logfile for a <VirtualHost>
# container, that host's errors will be logged there and not here.
#
ErrorLog "logs/error.log"
#
# LogLevel: Control the number of messages logged to the error_log.
# Possible values include: debug, info, notice, warn, error, crit,
# alert, emerg.
#
LogLevel warn
<IfModule log_config_module>
#
# The following directives define some format nicknames for use with
# a CustomLog directive (see below).
#
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
LogFormat "%h %l %u %t \"%r\" %>s %b" common
<IfModule logio_module>
# You need to enable mod_logio.c to use %I and %O
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedio
</IfModule>
#
# The location and format of the access logfile (Common Logfile Format).
# If you do not define any access logfiles within a <VirtualHost>
# container, they will be logged here. Contrariwise, if you *do*
# define per-<VirtualHost> access logfiles, transactions will be
# logged therein and *not* in this file.
#
CustomLog "logs/access.log" common
#
# If you prefer a logfile with access, agent, and referer information
# (Combined Logfile Format) you can use the following directive.
#
#CustomLog "logs/access.log" combined
</IfModule>
<IfModule alias_module>
#
# Redirect: Allows you to tell clients about documents that used to
# exist in your server's namespace, but do not anymore. The client
# will make a new request for the document at its new location.
# Example:
# Redirect permanent /foo http://192.168.12.242/bar
#
# Alias: Maps web paths into filesystem paths and is used to
# access content that does not live under the DocumentRoot.
# Example:
# Alias /webpath /full/filesystem/path
#
# If you include a trailing / on /webpath then the server will
# require it to be present in the URL. You will also likely
# need to provide a <Directory> section to allow access to
# the filesystem path.
#
# ScriptAlias: This controls which directories contain server scripts.
# ScriptAliases are essentially the same as Aliases, except that
# documents in the target directory are treated as applications and
# run by the server when requested rather than as documents sent to the
# client. The same rules about trailing "/" apply to ScriptAlias
# directives as to Alias.
#
ScriptAlias /cgi-bin/ "D:/Program Files/Apache Software Foundation/Apache2.2/cgi-bin/"
</IfModule>
<IfModule cgid_module>
#
# ScriptSock: On threaded servers, designate the path to the UNIX
# socket used to communicate with the CGI daemon of mod_cgid.
#
#Scriptsock logs/cgisock
</IfModule>
#
# "D:/Program Files/Apache Software Foundation/Apache2.2/cgi-bin" should be changed to whatever your ScriptAliased
# CGI directory exists, if you have that configured.
#
<Directory "D:/Program Files/Apache Software Foundation/Apache2.2/cgi-bin">
AllowOverride None
Options None
Order allow,deny
Allow from all
</Directory>
#
# DefaultType: the default MIME type the server will use for a document
# if it cannot otherwise determine one, such as from filename extensions.
# If your server contains mostly text or HTML documents, "text/plain" is
# a good value. If most of your content is binary, such as applications
# or images, you may want to use "application/octet-stream" instead to
# keep browsers from trying to display binary files as though they are
# text.
#
DefaultType text/plain
<IfModule mime_module>
#
# TypesConfig points to the file containing the list of mappings from
# filename extension to MIME-type.
#
TypesConfig conf/mime.types
#
# AddType allows you to add to or override the MIME configuration
# file specified in TypesConfig for specific file types.
#
#AddType application/x-gzip .tgz
#
# AddEncoding allows you to have certain browsers uncompress
# information on the fly. Note: Not all browsers support this.
#
#AddEncoding x-compress .Z
#AddEncoding x-gzip .gz .tgz
#
# If the AddEncoding directives above are commented-out, then you
# probably should define those extensions to indicate media types:
#
AddType application/x-compress .Z
AddType application/x-gzip .gz .tgz
#
# AddHandler allows you to map certain file extensions to "handlers":
# actions unrelated to filetype. These can be either built into the server
# or added with the Action directive (see below)
#
# To use CGI scripts outside of ScriptAliased directories:
# (You will also need to add "ExecCGI" to the "Options" directive.)
#
#AddHandler cgi-script .cgi
# For type maps (negotiated resources):
#AddHandler type-map var
#
# Filters allow you to process content before it is sent to the client.
#
# To parse .shtml files for server-side includes (SSI):
# (You will also need to add "Includes" to the "Options" directive.)
#
#AddType text/html .shtml
#AddOutputFilter INCLUDES .shtml
</IfModule>
#
# The mod_mime_magic module allows the server to use various hints from the
# contents of the file itself to determine its type. The MIMEMagicFile
# directive tells the module where the hint definitions are located.
#
#MIMEMagicFile conf/magic
#
# Customizable error responses come in three flavors:
# 1) plain text 2) local redirects 3) external redirects
#
# Some examples:
#ErrorDocument 500 "The server made a boo boo."
#ErrorDocument 404 /missing.html
#ErrorDocument 404 "/cgi-bin/missing_handler.pl"
#ErrorDocument 402 http://192.168.12.242/subscription_info.html
#
#
# MaxRanges: Maximum number of Ranges in a request before
# returning the entire resource, or 0 for unlimited
# Default setting is to accept 200 Ranges
#MaxRanges 0
#
# EnableMMAP and EnableSendfile: On systems that support it,
# memory-mapping or the sendfile syscall is used to deliver
# files. This usually improves server performance, but must
# be turned off when serving from networked-mounted
# filesystems or if support for these functions is otherwise
# broken on your system.
#
#EnableMMAP off
#EnableSendfile off
# Supplemental configuration
#
# The configuration files in the conf/extra/ directory can be
# included to add extra features or to modify the default configuration of
# the server, or you may simply copy their contents here and change as
# necessary.
# Server-pool management (MPM specific)修改连接数
Include conf/extra/httpd-mpm.conf
# Multi-language error messages
#Include conf/extra/httpd-multilang-errordoc.conf
# Fancy directory listings
#Include conf/extra/httpd-autoindex.conf
# Language settings
#Include conf/extra/httpd-languages.conf
# User home directories
#Include conf/extra/httpd-userdir.conf
# Real-time info on requests and configuration
#Include conf/extra/httpd-info.conf
# Virtual hosts 虚拟主机 没有域名不需要设置
#Include conf/extra/httpd-vhosts.conf
# Local access to the Apache HTTP Server Manual
#Include conf/extra/httpd-manual.conf
# Distributed authoring and versioning (WebDAV)
#Include conf/extra/httpd-dav.conf
# Various default settings
#Include conf/extra/httpd-default.conf
# Secure (SSL/TLS) connections
#Include conf/extra/httpd-ssl.conf
#
# Note: The following must must be present to support
# starting without SSL on platforms with no /dev/random equivalent
# but a statically compiled-in mod_ssl.
#
<IfModule ssl_module>
SSLRandomSeed startup builtin
SSLRandomSeed connect builtin
</IfModule>
第三部分:mod_jk代码讲解

mod_jk 分析
1 mod_jk模块的总体功能
由于tomcat的HTTP处理部分都由Java所写(5.5.12版本以后出现了native库,用以
提高其I/O和SSL的性能[1]),在高并发的情况下负载较高。而apache对于静态文件的处
理能力比tomcat强,所以tomcat开发组开发了与apache结合使用的mod_jk模块。该协议
由apache作请求代理,将HTTP协议的请求转化为AJP协议包,并传给后端的
tomcat。mod_jk和apache现在普遍使用AJP1.3协议[2]。它是一个二进制格式的协议,比
字符格式的HTTP协议解析速度要快。
除了性能的提升,mod_jk另外的一个作用可以实现apache与tomcat一对多的对应,
使后端tomcat负载均衡。mod_jk也提供apache与tomcat链接情况的监控。
mod_jk模块的典型工作流程是这样的:一个HTTP请求过来,mod_jk模块根据其URI选
择合适的worker来进行处理。如果是lb_worker(负载均衡的worker),就再根据各种条
件选择后台合适的ajp_worker(处理AJP协议的worker)。ajp_worker将HTTP协议的包,
组装成AJP协议格式的包,然后选取一条空闲的链接,发送给后台的tomcat服务器。等到
后台将数据发送过来时,接收并解析AJP协议,重新组装成HTTP协议,然后把结果发送给
客户端。
2 mod_jk模块的框架
2.1 线程
从宏观上来讲,mod_jk由一个watchdog线程和一组worker线程(进程)组成。
watchdog线程是在apache内部新创建的线程,它是一个维护线程。每隔
JkWatchdogInterval的时间(当然,所有worker线程也有一个统一的worker.maintain 时
间,JkWatchdogInterval应该至少大于worker.maintain),它会扫描所有worker线程。
watchdog线程会检查每个worker线程的空闲链接、负载情况、与后端的链接情况,并使共
享内存同步。worker线程是就是一些ajp13,ajp14,jni,lb或status类型的线程,负责
所有实际的工作。
在mod_jk中,线程内(外)的同步均是通过线程锁(pthread_mutex_lock)来实现的。
而进程之间的全局同步,是用文件记录锁(flock或fcntl)来实现。进程间的数据共享是
用这样做的:进程启动时,创建一个JkShmSize 大小的文件,然后mmap到内存,由于各进
程mmap到内存的是相同的镜像,所以可以实现数据的共享,但是写入共享内存时,要做好
互斥。
由于apache的基本处理方式(prefork和worker模式)就是一个线程/进程负责一个
连接,所以mod_jk各线程中对于网络IO处理都是阻塞的。
2.2 worker对象
从具体的worker对象的角度来讲,mod_jk由ajp_worker、jni_worker、lb_worker和
status_worker组成。这些对象参考了设计模式中factory的模型。每类worker都有生产
workers的factory。
在mod_jk中,其中的worker主要在worker.list中列出。其中,lb_worker可以含有
balance_workers,以lb_sub_worker的形式存储于lb_worker中。lb_sub_worker可以是各
种类型的ajp_worker。所以真正工作的ajp_worker既可以“单干”,也可以由lb_worker
来分配任务。这主要取决于URI到底映射到哪个worker上以及该worker是否在
worker.list配置。
lb_worker,lb_sub_worker和ajp_worker一些配置信息都位于其结构体中,而状态信
息或在运行中可变的参数则位于共享内存中的对应结构体中,当然也并不绝对,有些参数是
冗余的。
从正在运行的某个线程的角度上来讲,ajp_worker就是对应了一个线程。
3 从HTTP到AJP的处理流程
由于mod_jk模块是apache的处理模块,本节主要是讲述mod_jk模块从客户端到后端
服务器的处理流程。中间会涉及一些apache模块的一些结构。
3.1 mod_jk模块在apache中的定义
3.1.1 mod_jk定义
/* 这是jk模块的主要定义结构体*/
module AP_MODULE_DECLARE_DATA jk_module = {
STANDARD20_MODULE_STUFF,
NULL, /* dir config creater */
NULL, /* dir merger --- default is to override */
create_jk_config, /*创建 jk模块的配置结构体*/
merge_jk_config, /* 初始化及合并 jk模块的配置结构体*/
jk_cmds, /* 所有在apahce中的命令及操作函数 */
jk_register_hooks /* 具体的操作函数处理钩子 */
};
3.1.2 mod_jk模块的主要处理函数
/* mod_jk将各处理函数挂到相应的钩子上,钩子实际上就是一些函数指针。针对某个HTTP
请求,这些函数会自上而下执行。*/
static void jk_register_hooks(apr_pool_t * p)
{
/* 该函数在apache读入配置后运行,用以初始化全局互斥锁,jk日志,全局变量的初
始化,以及读入 workers.properties、uriworkermap.properties文件,初始化各worker
的属性,建立worker名称到worker结构体的映射,uri到worker的映射*/
ap_hook_post_config(jk_post_config, NULL, NULL,
APR_HOOK_MIDDLE);
/*该函数在apache主进程fork工作子进程后做的初始化工作,主要包括初始化进程内
互斥锁,开启维护线程,读入共享内存*/
ap_hook_child_init(jk_child_init, NULL, NULL, APR_HOOK_MIDDLE);
/* 将mod_jk的URI到真实URI,然后URI到worker的映射翻译过程,用以找到该URI
相应的worker_name */
ap_hook_translate_name(jk_translate, NULL, NULL,
APR_HOOK_MIDDLE);
#if (MODULE_MAGIC_NUMBER_MAJOR > 20010808)
/* 绑定那些alias_dir的URI到mod_jk的配置,并找到相应worker_name */
ap_hook_map_to_storage(jk_map_to_storage, NULL, NULL,
APR_HOOK_MIDDLE);
/* 这是mod_jk的主要处理函数 */
ap_hook_handler(jk_handler, NULL, NULL, APR_HOOK_MIDDLE);
#endif
}
3.2 jk_handler函数
jk_handler函数是mod_jk的主要处理函数,它负责将HTTP请求从apache发到tomcat,
再从tomcat接受数据,并返回给客户。
它的处理过程如下:
1. 根据前面得到的worker_name,找到相应的jk_worker(其结构体见4.4)。
2. 初始化服务结构体jk_ws_service,主要是针对HTTP服务端的一些设置及函数(服务
的结构体见4.5),与AJP协议关系不大。
3. 调用jk_worker的get_endpoint函数,获取具体的jk_endpoint结构体(函数见
3.3.1和3.4.1,jk_endpoint的结构体定义见4.4)。
4. 调用上述jk_endpoint的service函数。
5. 调用上述jk_endpoint的done函数,结束与tomcat的AJP连接。
6. 根据函数的结果处理各种状态。
7. 释放资源。
3.3 lb_worker的处理函数
3.3.1 lb_worker的get_endpoint
初始化lb_worker的endpoint结构体,挂上其service及done函数。
3.3.2 lb_worker的service函数
它的处理过程如下:
1. 获取共享内存中记录的worker状态。
2. 如果需要绑定sessionID,获取sessionID。
3. 调用get_most_suitable_worker函数,获取相应的lb_sub_worker(也即
ajp_worker)。
4. 调用ajp_worker的get_endpoint函数。
5. 调用上述endpoint的service函数。
6. 调用上述endpoint的done函数。
7. 根据service的返回结果,更新各种记录状态。
3.3.3 get_most_suitable_worker函数
它的处理过程如下:
1. 如果需要绑定sessionID,就根据sessionID找到工作正常的最佳worker。
2. 如果找不到,则调用find_best_worker函数。其处理过程如下:
i. 又调用find_best_byvalue函数。其处理过程如下:按照Round Robin的方式在
本lb_worker中找到第一个不在错误状态、也没有停止、没有disabled 、也不
busy的lb_sub_worker。
ii.如果find_best_byvalue返回错误,说明本lb_worker的lb_sub_worker都处于
非正常工作状态,需要调用find_failover_worker函数,通过
redirect、route、domain指令来进行查找[3]。
3.4 ajp_worker的处理函数
3.4.1 ajp_worker的get_endpoint函数
它的主要功能是:找到与后端tomcat的一个空闲连接。
3.4.2 ajp_worker的ajp_service函数
该函数主要分为 ajp_send_request和and ajp_get_reply两个函数。
它的处理过程如下:
1. 获取共享内存中的状态。
2. 分配AJP请求包、恢复包、POST包的内存。
3. 调用ajp_marshal_into_msgb函数,将HTTP请求包转化为AJP包。
4. 将当前ajp_worker的状态更新。
5. 调用ajp_send_request函数。
6. 如果发送成功,调用ajp_get_reply函数,等待并接受AJP包。
7. 如果成功,更新当前状态。
3.4.2 ajp_worker的ajp_send_request函数
它的处理过程如下:
1. 调用jk_is_socket_connected函数,检查即将发送的socket是否有效。它的检查过
程是运用select函数,等1微妙,如果成功返回说明,该socket的文件描述符至少
在内核中还有效。
2. 如果上一次发送超时,则调用ajp_handle_cping_cpong函数来判断后端连接是否有
效。该函数主要是发出了一个AJP13_CPING_REQUEST类型的AJP包,如果tomcat收
到,应返回一个AJP13_CPONG_REPLY的包。
3. 如果上述的测试都成功,调用ajp_connection_tcp_send_message,发送AJP包。
3.4.3 ajp_worker的ajp_get_reply函数
它的处理过程如下:
1. 调用jk_is_input_event,用select等待接受数据,直到socket有接受数据。
2. 调用ajp_connection_tcp_get_message,接受AJP包,并检查协议头。
3. 调用ajp_process_callback,对该AJP包进行解析处理。其处理过程如下:
i. 如果是JK_AJP13_SEND_HEADERS包,将其解包成HTTP包头。如果没有错误,就调
用jk_ws_service->start_response()函数发送HTTP回复的head。返回
JK_AJP13_SEND_HEADERS。
ii.如果是JK_AJP13_SEND_BODY_CHUNK包,调用jk_ws_service->write发送HTTP回
复的body。返回JK_AJP13_NO_RESPONSE。
iii.如果是JK_AJP13_GET_BODY_CHUNK包,说明还有数据要发送到tomcat,调用
ajp_read_into_msg_buff,继续发送数据。返回JK_AJP13_HAS_RESPONSE。
iv.如果是JK_AJP13_END_RESPONSE包,就说明tomcat的回复已经完成。返回
JK_AJP13_END_RESPONSE。
3.5 jk_ws_service的一些处理函数
3.5.1 jk_ws_service 的 ws_start_response函数
该函数主要是构建HTTP回复包的头部。
3.5.2 jk_ws_service 的 ws_write函数
调用 apache的ap_rwrite函数,发送整个HTTP包。
3.5.3 jk_ws_service 的 ws_read函数
调用apache的ap_get_client_block读入全部的request body数据。
4 mod_jk的主要数据结构
4.1 lb_worker
lb_worker是负载均衡worker。主要负责调配其名下的一些lb_sub_worker 。

dist/common/jk_lb_worker.h
struct lb_worker
{
/* jk模块通用worker结构体。包含一些回调函数,不同的worker有不同的函数实现
*/
jk_worker_t worker;
/* Shared memory worker data */
jk_shm_lb_worker_t *s;
char name[JK_SHM_STR_SIZ+1];
/* Sequence counter starting at 0 and increasing
* every time we change the config
*/
volatile unsigned int sequence;
jk_pool_t p;
jk_pool_atom_t buf[TINY_POOL_SIZE];
JK_CRIT_SEC cs;
/*其名下的workers*/
lb_sub_worker_t *lb_workers;
unsigned int num_of_workers;
int sticky_session;
int sticky_session_force;
int recover_wait_time;
int max_reply_timeouts;
int retries;
int retry_interval;
int lbmethod;
int lblock;
int maintain_time;
unsigned int max_packet_size;
unsigned int next_offset;
/* Session cookie */
char session_cookie[JK_SHM_STR_SIZ+1];
/* Session path */
char session_path[JK_SHM_STR_SIZ+1];
};
lb_sub_worker是由lb_worker支配的ajp_worker。当然lb_sub_worker有不同的类型。
它们的实际类型存储在ajp_worker中。
dist/common/jk_lb_worker.h
struct lb_sub_worker
{
/* 包含ajp_worker的回调函数及其ajp_worker结构体*/
jk_worker_t *worker;
/* Shared memory worker data */
jk_shm_lb_sub_worker_t *s;
char name[JK_SHM_STR_SIZ+1];
/* Sequence counter starting at 0 and increasing
* every time we change the config
*/
volatile unsigned int sequence;
/* route */
char route[JK_SHM_STR_SIZ+1];
/* worker domain */
char domain[JK_SHM_STR_SIZ+1];
/* worker redirect route */
char redirect[JK_SHM_STR_SIZ+1];
/* worker distance */
int distance;
/* current activation state (config) of the worker */
int activation;
/* Current lb factor */
int lb_factor;
/* Current worker index */
int i;
/* Current lb reciprocal factor */
jk_uint64_t lb_mult;
};
typedef struct lb_sub_worker lb_sub_worker_t;
4.2 ajp_worker
ajp_worker是具体工作的worker,对应后端一个tomcat应用服务。
dist/common/jk_ajp_common.c
struct ajp_worker
{
/* 包含ajp_worker的回调函数*/
jk_worker_t worker;
/* Shared memory worker data */
jk_shm_ajp_worker_t *s;
char name[JK_SHM_STR_SIZ+1];
/* Sequence counter starting at 0 and increasing
* every time we change the config
*/
volatile unsigned int sequence;
jk_pool_t p;
jk_pool_atom_t buf[TINY_POOL_SIZE];
JK_CRIT_SEC cs;
struct sockaddr_in worker_inet_addr; /* Contains host and port */
unsigned connect_retry_attempts;
const char *host;
int port;
int maintain_time;
/*
* Open connections cache...
*
* 1. Critical section object to protect the cache.
* 2. Cache size.
* 3. An array of "open" endpoints.
*/
unsigned int ep_cache_sz;
unsigned int ep_mincache_sz;
unsigned int ep_maxcache_sz;
int cache_acquire_timeout;
ajp_endpoint_t **ep_cache;
int proto; /* PROTOCOL USED AJP13/AJP14 */
jk_login_service_t *login;
/* Weak secret similar with ajp12, used in ajp13 */
const char *secret;
/*
* Post physical connect handler.
* AJP14 will set here its login handler
*/
int (*logon) (ajp_endpoint_t * ae, jk_logger_t *l);
/*
* Handle Socket Timeouts
*/
int socket_timeout;
int socket_connect_timeout;
int keepalive;
int socket_buf;
/*
* Handle Cache Timeouts
*/
int cache_timeout;
/*
* Handle Connection/Reply Timeouts
*/
int connect_timeout; /* connect cping/cpong delay in ms (0 means
disabled) */
int reply_timeout; /* reply timeout delay in ms (0 means disabled) */
int prepost_timeout; /* before sending a request cping/cpong timeout
delay in ms (0 means disabled) */
int conn_ping_interval; /* interval for sending keepalive cping packets on
* unused connection */
int ping_timeout; /* generic cping/cpong timeout. Used for keepalive
packets or
* as default for boolean valued connect and
prepost timeouts.
*/
unsigned int ping_mode; /* Ping mode flags (which types of cpings should
be used) */
/*
* Recovery options
*/
unsigned int recovery_opts;
/*
* Public property to enable the number of retry attempts
* on this worker.
*/
int retries;
unsigned int max_packet_size; /* Maximum AJP Packet size */
int retry_interval; /* Number of milliseconds to sleep before
doing a retry */
/*
* HTTP status that will cause failover (0 means disabled)
*/
unsigned int http_status_fail_num;
int http_status_fail[JK_MAX_HTTP_STATUS_FAILS];
};
4.3 status_worker
status_worker用于产生一些状态的统计信息。
dist/common/jk_statuc.c
struct status_worker
{
jk_pool_t p;
jk_pool_atom_t buf[TINY_POOL_SIZE];
const char *name;
const char *css;
const char *ns;
const char *xmlns;
const char *doctype;
const char *prefix;
int read_only;
char **user_names;
unsigned int num_of_users;
int user_case_insensitive;
jk_uint32_t good_mask;
jk_uint32_t bad_mask;
jk_worker_t worker;
jk_worker_env_t *we;
};
4.4 jk_worker和 jk_endpoint
jk_worker是所有worker通用结构体名称, 主要包含的是一些函数指针。它是一个类
似java中抽象类的概念,各成员函数在从factory函数生产时初始化。
dist/common/jk_service.h
struct jk_worker
{
/*
* A 'this' pointer which is used by the subclasses of this class to
* point to data/functions which are specific to a given protocol
* (e.g. ajp12 or ajp13 or ajp14).
*/
void *worker_private;/* 指向ajp_worker,lb_worker结构体 ...*/
int type;
/*
* For all of the below (except destroy), the first argument is
* essentially a 'this' pointer.
*/
/* 先于init函数调用,用于分配各类worker结构体的内存,作必要的初始化
* Given a worker which is in the process of being created, and a list
* of configuration options (or 'properties'), check to see if it the
* options are. This will always be called before the init() method.
* The init/validate distinction is a bit hazy to me.
* See jk_ajp13_worker.c/jk_ajp14_worker.c and jk_worker.c-
>wc_create_worker()
*/
int (JK_METHOD * validate) (jk_worker_t *w,
jk_map_t *props,
jk_worker_env_t *we, jk_logger_t *l);
/*
* Update worker either from jk_status or reloading from workers.properties
*/
int (JK_METHOD * update) (jk_worker_t *w,
jk_map_t *props,
jk_worker_env_t *we, jk_logger_t *l);
/*
* Do whatever initialization needs to be done to start this worker up.
* Configuration options are passed in via the props parameter.
*/
int (JK_METHOD * init) (jk_worker_t *w,
jk_map_t *props,
jk_worker_env_t *we, jk_logger_t *l);
/*
* Obtain an endpoint to service a particular request. A pointer to
* the endpoint is stored in pend.
*/
int (JK_METHOD * get_endpoint) (jk_worker_t *w,
jk_endpoint_t **pend, jk_logger_t *l);
/*
* Shutdown this worker. The first argument is not a 'this' pointer,
* but rather a pointer to 'this', so that the object can be free'd (I
* think -- though that doesn't seem to be happening. Hmmm).
*/
int (JK_METHOD * destroy) (jk_worker_t **w, jk_logger_t *l);
/*
* Maintain this worker.
*/
int (JK_METHOD * maintain) (jk_worker_t *w, time_t now, jk_logger_t *l);
};
/* jk_endpoint可以称之为通用终端服务结构体,各类worker可能有自己的endpoint结构
体。比如ajp_worker, 该终端是用来做具体工作的,比如发出请求,接收AJP数据等等。如
果是lb_worker,该终端是的作用是找出合适ajp_worker, 把任务交给它。* /
struct jk_endpoint
{
jk_uint64_t rd;
jk_uint64_t wr;
/*
* Flag to pass back recoverability status from
* a load balancer member to the load balancer itself.
* Depending on the configuration and request status
* recovery is not allowed.
*/
int recoverable;
/*
* A 'this' pointer which is used by the subclasses of this class to
* point to data/functions which are specific to a given protocol
* (e.g. ajp12 or ajp13 or ajp14).
*/
void *endpoint_private;
/* 该函数是具体的服务函数
* Forward a request to the servlet engine. The request is described
* by the jk_ws_service_t object.
* is_error is either 0 meaning recoverable or set to
* the HTTP error code.
*/
int (JK_METHOD * service) (jk_endpoint_t *e,
jk_ws_service_t *s,
jk_logger_t *l, int *is_error);
/*
* Called when this particular endpoint has finished processing a
* request. For some protocols (e.g. ajp12), this frees the memory
* associated with the endpoint. For others (e.g. ajp13/ajp14), this can
* return the endpoint to a cache of already opened endpoints.
*
* Note that the first argument is *not* a 'this' pointer, but is
* rather a pointer to a 'this' pointer. This is necessary, because
* we may need to free this object.
*/
int (JK_METHOD * done) (jk_endpoint_t **p, jk_logger_t *l);
};
4.5 jk_ws_service
该结构体是与apache相关的一些参数或函数,面向HTTP协议,与AJP协议不太相关。
dist/common/jk_service.h
struct jk_ws_service
{
/*
* A 'this' pointer which is used by the subclasses of this class to
* point to data which is specific to a given web server platform
* (e.g. Apache or IIS).
*/
void *ws_private;
/*
* Provides memory management. All data specific to this request is
* allocated within this pool, which can then be reclaimed at the end
* of the request handling cycle.
*
* Alive as long as the request is alive.
*/
jk_pool_t *pool;
/*
* CGI Environment needed by servlets
*/
const char *method;
const char *protocol;
char *req_uri;
const char *remote_addr;
const char *remote_host;
const char *remote_user;
const char *auth_type;
const char *query_string;
const char *server_name;
unsigned server_port;
char *server_software;
jk_uint64_t content_length; /* 64 bit integer that represents the content */
/* length should be 0 if unknown. */
unsigned is_chunked; /* 1 if content length is unknown (chunked rq) */
unsigned no_more_chunks; /* 1 if last chunk has been read */
jk_uint64_t content_read; /* number of bytes read */
/*
* SSL information
*
* is_ssl - True if request is in ssl connection
* ssl_cert - If available, base64 ASN.1 encoded client certificates.
* ssl_cert_len - Length of ssl_cert, 0 if certificates are not available.
* ssl_cipher - The ssl cipher suite in use.
* ssl_session - The ssl session string
*
* In some servers it is impossible to extract all this information, in this
* case, we are passing NULL.
*/
int is_ssl;
char *ssl_cert;
unsigned ssl_cert_len;
char *ssl_cipher;
char *ssl_session;
/*
* SSL extra information for Servlet 2.3 API
*
* ssl_key_size - ssl key size in use
*/
int ssl_key_size;
/*
* Headers, names and values.
*/
char **headers_names; /* Names of the request headers */
char **headers_values; /* Values of the request headers */
unsigned num_headers; /* Number of request headers */
/*
* Request attributes.
*
* These attributes that were extracted from the web server and are
* sent to Tomcat.
*
* The developer should be able to read them from the ServletRequest
* attributes. Tomcat is required to append org.apache.tomcat. to
* these attribute names.
*/
char **attributes_names; /* Names of the request attributes */
char **attributes_values; /* Values of the request attributes */
unsigned num_attributes; /* Number of request attributes */
/*
* The route is in use when the adapter load balance among
* several workers. It is the ID of a specific target in the load balance
* group. We are using this variable to implement target session
* affinity
*/
const char *route;
/* Temp solution for auth. For native1 it'll be sent on each request,
if an option is present. For native2 it'll be sent with the first
request. On java side, both cases will work. For tomcat3.2 or
a version that doesn't support secret - don't set the secret,
and it'll work.
*/
const char *secret;
/*
* Area to get POST data for fail-over recovery in POST
*/
jk_msg_buf_t *reco_buf;
int reco_status;
/*
* If set call flush after each write
*/
int flush_packets;
/*
* If set call flush after AJP13_SEND_HEADERS.
*/
int flush_header;
/*
* service extensions
*/
svc_extension_t extension;
/*
* JK_TRUE if response headers have been sent back
*/
int response_started;
/*
* JK_TRUE if response should not be send to the client
*/
int response_blocked;
/*
* HTTP status sent from container.
*/
int http_response_status;
/* Uri worker map. Added for virtual host support
*/
jk_uri_worker_map_t *uw_map;
/* 下面这些回调函数实现都可以在mod_jk.c找到
* Callbacks into the web server. For each, the first argument is
* essentially a 'this' pointer. All return JK_TRUE on success
* and JK_FALSE on failure.
*/
/*
* Send the response headers to the browser.
*/
int (JK_METHOD * start_response) (jk_ws_service_t *s,
int status,
const char *reason,
const char *const *header_names,
const char *const *header_values,
unsigned num_of_headers);
/*
* Read a chunk of the request body into a buffer. Attempt to read len
* bytes into the buffer. Write the number of bytes actually read into
* actually_read.
*/
int (JK_METHOD * read) (jk_ws_service_t *s,
void *buffer,
unsigned len, unsigned *actually_read);
/*
* Write a chunk of response data back to the browser.
*/
int (JK_METHOD * write) (jk_ws_service_t *s,
const void *buffer, unsigned len);
/*
* Flush a chunk of response data back to the browser.
*/
void (JK_METHOD * flush) (jk_ws_service_t *s);
/*
* Done with sending response back to the browser.
*/
void (JK_METHOD * done) (jk_ws_service_t *s);
/*
* If set do not reuse socket after each full response
*/
int disable_reuse;
/*
* Add more data to log facilities.
*/
void (JK_METHOD * add_log_items) (jk_ws_service_t *s,
const char *const *log_names,
const char *const *log_values,
unsigned num_of_items);
/*
* Iterate through all vhosts
*/
void *(JK_METHOD * next_vhost) (void *d);
/*
* String representation of a vhost
*/
void (JK_METHOD * vhost_to_text) (void *d, char *buf, size_t len);
/*
* Get uw_map associated with a vhost
*/
jk_uri_worker_map_t *(JK_METHOD * vhost_to_uw_map) (void *d);
};
4.6 共享内存中一些数据结构
共享内存中的数据结构基本上都是记录之用。有些参数在运行中会实时变化。
dist/common/jk_shm.h
/** jk shm generic worker record structure */
struct jk_shm_worker_header
{
int id;
int type;
/* worker name */
char name[JK_SHM_STR_SIZ+1];
/* Sequence counter starting at 0 and increasing
* every time we change the config
*/
volatile unsigned int sequence;
};
typedef struct jk_shm_worker_header jk_shm_worker_header_t;
/** jk shm ajp13/ajp14 worker record structure */
struct jk_shm_ajp_worker
{
jk_shm_worker_header_t h;
/* Configuration data mirrored from ajp_worker */
int cache_timeout;
int connect_timeout;
int reply_timeout;
int prepost_timeout;
unsigned int recovery_opts;
int retries;
int retry_interval;
unsigned int max_packet_size;
/* current error state (runtime) of the worker */
volatile int state;
/* Statistical data */
/* Number of currently busy channels */
volatile int busy;
/* Maximum number of busy channels
该参数并非我们的maxbusy,它是该worker自程序运行以来busy的最大值 */
volatile int max_busy;
volatile time_t error_time;
/* Number of bytes read from remote */
volatile jk_uint64_t readed;
/* Number of bytes transferred to remote */
volatile jk_uint64_t transferred;
/* Number of times the worker was used */
volatile jk_uint64_t used;
/* Number of times the worker was used - snapshot during maintenance */
volatile jk_uint64_t used_snapshot;
/* Number of non 200 responses */
volatile jk_uint32_t errors;
/* Decayed number of reply_timeout errors */
volatile jk_uint32_t reply_timeouts;
/* Number of client errors */
volatile jk_uint32_t client_errors;
/* Last reset time */
volatile time_t last_reset;
volatile time_t last_maintain_time;
};
typedef struct jk_shm_ajp_worker jk_shm_ajp_worker_t;
/** jk shm lb sub worker record structure */
struct jk_shm_lb_sub_worker
{
jk_shm_worker_header_t h;
/* route */
char route[JK_SHM_STR_SIZ+1];
/* worker domain */
char domain[JK_SHM_STR_SIZ+1];
/* worker redirect route */
char redirect[JK_SHM_STR_SIZ+1];
/* Number of currently busy channels */
volatile int busy;
/* worker distance */
volatile int distance;
/* current activation state (config) of the worker */
volatile int activation;
/* current error state (runtime) of the worker */
volatile int state;
/* Current lb factor */
volatile int lb_factor;
/* 我们的参数加在这里*/
volatile int maxbusy;
/* Current lb reciprocal factor */
volatile jk_uint64_t lb_mult;
/* Current lb value */
volatile jk_uint64_t lb_value;
/* Statistical data */
volatile time_t error_time;
/* Number of times the worker was elected - snapshot during maintenance */
volatile jk_uint64_t elected_snapshot;
/* Number of non 200 responses */
volatile jk_uint32_t errors;
};
typedef struct jk_shm_lb_sub_worker jk_shm_lb_sub_worker_t;
/** jk shm lb worker record structure */
struct jk_shm_lb_worker
{
jk_shm_worker_header_t h;
/* Number of currently busy channels,该值是其名下ajp_worker的busy值之和*/
volatile int busy;
/* Maximum number of busy channels,该值是其名下ajp_worker的max_busy值之和
*/
volatile int max_busy;
int sticky_session;
int sticky_session_force;
int recover_wait_time;
int max_reply_timeouts;
int retries;
int retry_interval;
int lbmethod;
int lblock;
unsigned int max_packet_size;
/* Last reset time */
volatile time_t last_reset;
volatile time_t last_maintain_time;
/* Session cookie */
char session_cookie[JK_SHM_STR_SIZ+1];
/* Session path */
char session_path[JK_SHM_STR_SIZ+1];
};
typedef struct jk_shm_lb_worker jk_shm_lb_worker_t;

 

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/xdfwsl/article/details/43342079

智能推荐

mybatis-plus整合dynamic-datasource-spring-boot-starter之手动切换多数据源支持多种不同数据库类型(“坎坷之路”)_dynamic-datasource-spring-boot3-starter-程序员宅基地

文章浏览阅读2.3k次。mybatis-plus整合dynamic-datasource-spring-boot-starter之手动切换多数据源支持多种不同数据库类型(“坎坷之路”)简介:今天公司有一个这样场景业务,简单来说需要动态第三方数据源数据库,数据源信息,一开始根据想要查看的表进行一个表的信息与表的数据库信息获取,然后保存本地库内,用户可在界面点击获取到的表进行业务数据处理,需求重点:数据库是动态(会有不同类型数据库,也可能会有多种同种类型数据库),表字段是动态(不同数据库不同字段),所以根据这几点来处理你的CRUD_dynamic-datasource-spring-boot3-starter

【Qt学习】01 动态添加按钮_qt循环方式添加动态多个按钮,按钮名称怎么变-程序员宅基地

文章浏览阅读1.1k次。概述学习内容:两种场景下动态添加按钮的方法。环境IDE:Qt creator 4.11.0编译器:MinGW 5.3.0 32bit for C++场景一存在默认ui的场景,new QPushButton一般在setupUi之后。不然new出来的按钮无法点击。MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow){ ui-&.._qt循环方式添加动态多个按钮,按钮名称怎么变

cblas_sgemm和cublasSgemm参数详解-程序员宅基地

文章浏览阅读9.4k次。机器学习最核心的底层运算肯定是矩阵乘法无疑了,为了让矩阵乘法执行更快,大家也是绞尽脑汁。从算法层面,stranssen算法将矩阵乘法复杂度由O(n3)O(n^3)O(n3)降到O(n2.81)O(n^{2.81})O(n2.81),最新的算法好像已经降到O(n2.37)O(n^{2.37})O(n2.37)左右了(Coppersmith–Winograd algorithm),但这只是理论复杂度,..._cblas_sgemm

用RedisTemplate<Object, Object>把对象以json形式存入redis缓存_public redistemplate<object, object>-程序员宅基地

文章浏览阅读3.5k次。对象可以不用实现序列化public class User{ private Integer id ; private String userName ; private String password ; public User(Integer id, String userName, String password) { this.id = id; this.userName = userName; this.pass_public redistemplate

不使用库函数,编写函数int strcmp(char *source, char *dest) 相等返回0,不等返回-1_不使用库函数,编写函数 int strcmp(char *source,char *dest) 相等-程序员宅基地

文章浏览阅读6k次,点赞2次,收藏6次。#include int strcmp(char *source, char *dest){while(*source == *dest && *source != '\0' && *dest != '\0'){ source++; dest++;}if (*source =='\0' && *dest == '\0') return 0;else return_不使用库函数,编写函数 int strcmp(char *source,char *dest) 相等返回0

voice call relevant_voice 状态 alerting ring incoming-程序员宅基地

文章浏览阅读1.7k次。每次收到底层上报的呼叫状态变化时(UNSOL_RESPONSE_CALL_STATE_CHANGED ),都会去查询变化了的具体内容给modem发的信息是RIL_REQUEST_GET_CALL_LIST.handlePollCalls是用来处理查询之后的结果,分析如下:handlePollCalls(AsyncResult ar) List polledC..._voice 状态 alerting ring incoming

随便推点

/etc/fstab文件的详解-程序员宅基地

文章浏览阅读10w+次,点赞48次,收藏220次。一、/etc/fstab文件的作用 磁盘被手动挂载之后都必须把挂载信息写入/etc/fstab这个文件中,否则下次开机启动时仍然需要重新挂载。 系统开机时会主动读取/etc/fstab这个文件中的内容,根据文件里面的配置挂载磁盘。这样我们只需要将磁盘的挂载信息写入这个文件中我们就不需要每次开机启动之后手动进行挂载了。 二、挂载的限制 在说明这..._/etc/fstab

Java基础练习题及详细答案_java基础题 帮同学写的几个iava基础题/1编写 jaa 程序实现: (1)定义如下方法求一-程序员宅基地

文章浏览阅读2.3w次,点赞140次,收藏965次。本文参考 嗨客网 Java 实战前言本篇文章给大家安利一些关于 Java 基础的练习题,每道题都附有答案链接,答案解题的每个步骤到运行结果都十分详细,十分适合小白拿来练习,也十分适合准备面试的各位复习下 Java 基础,这篇文章我会不断更新,题目都是对应 Java 基础中的各个知识点,大家在学习了Java 基础之后,做几道相关的练习题,复习一下该知识点,在学习过程中,觉得十分抽象、晦涩难懂的知识点,配合一道案例题,或许会有意想不到的效果哦! 目录Java入门 Java Hell._java基础题 帮同学写的几个iava基础题/1编写 jaa 程序实现: (1)定义如下方法求一

CSAPP实验之Bomb Lab详解_csapp bomb-程序员宅基地

文章浏览阅读1.5w次,点赞32次,收藏194次。文章目录前言phase 1phase 2phase 3phase 4phase 5phase 6总结和感想前言Bomb Lab来自《深入理解计算机系统》(CSAPP)一书的第三章“程序的机器级表示”的配套实验,该实验的目的是通过反汇编可执行程序,来反推出程序执行内容,进而能够正确破解”密码“,解除“炸弹”。Bomb Lab文件目录如下:├── bomb├── bomb.c└── READMEbomb: 可执行程序,我们需要对其进行反汇编和gdb调试。bomb.c: bomb的主函数mai_csapp bomb

操作系统实验六 文件管理_操作系统文件管理实验-程序员宅基地

文章浏览阅读1.2w次,点赞24次,收藏143次。操作系统实验六 文件管理_操作系统文件管理实验

android 二维码扫描_android 二维码扫描可缩放-程序员宅基地

文章浏览阅读237次。直接效果图简单的封装了可以直接抄到项目里不用改啥,集成自最新的zxing库。增加了手势缩放,双击放大/缩小。可以打开闪光灯本地图片二维码识别识别有音效和震动不想要的或者改声音[ps.可以直接替换raw目录下的beep文件]的看代码注释就知道了新代码优化了扫码识别下载地址github..._android 二维码扫描可缩放

【Go语言】基本类型排序和 slice 排序_go slice sort-程序员宅基地

文章浏览阅读1.8w次,点赞5次,收藏24次。Go 是通过 sort 包提供排序和搜索,因为 Go 暂时不支持泛型(将来也不好说支不支持),所以,Go 的 sort 和 search 使用起来跟类型是有关的,或是需要像 c 一样写比较函数等,稍微显得也不是很方便。引言Go 的排序思路和 C 和 C++ 有些差别。 C 默认是对数组进行排序, C++ 是对一个序列进行排序, Go 则更宽泛一些,待排序的可以是任何对象, 虽然很多情况下是一个 s_go slice sort