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 两个函数。
它的处理过程如下:
- 获取共享内存中的状态。
- 分配 AJP 请求包、恢复包、POST 包的内存。
- 调用 ajp_marshal_into_msgb 函数,将 HTTP 请求包转化为 AJP 包。
- 将当前 ajp_worker 的状态更新。
- 调用 ajp_send_request 函数。
- 如果发送成功,调用 ajp_get_reply 函数,等待并接受 AJP 包。
- 如果成功,更新当前状态。
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
/* 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
}
lb_sub_worker 是由 lb_worker 支配的 ajp_worker。当然 lb_sub_worker 有不同的类型。
它们的实际类型存储在 ajp_worker 中。
dist/common/jk_lb_worker.h
/* 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
}
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 meansdisabled) */
int reply_timeout; /* reply timeout delay in ms (0 means disabled) */
int prepost_timeout; /* before sending a request cping/cpong timeoutdelay 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 keepalivepackets or
* as default for boolean valued connect andprepost timeouts.
*/
unsigned int ping_mode; /* Ping mode flags (which types of cpings shouldbe 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_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 meansdisabled) */
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.4 jk_worker 和 jk_endpoint
jk_worker 是所有 worker 通用结构体名称, 主要包含的是一些函数指针。它是一个类似 java 中抽象类的概念,各成员函数在从 factory 函数生产时初始化。
dist/common/jk_service.h
1 dist/common/jk_ajp_common.c
2 struct ajp_worker
3 {
4 /* 包含 ajp_worker 的回调函数*/
5 jk_worker_t worker;
6 /* Shared memory worker data */
7 jk_shm_ajp_worker_t *s;
8 char name[JK_SHM_STR_SIZ+1];
9 /* Sequence counter starting at 0 and increasing
10 * every time we change the config
11 */
12 volatile unsigned int sequence;jk_pool_t p;
13 jk_pool_atom_t buf[TINY_POOL_SIZE];
14 JK_CRIT_SEC cs;
15 struct sockaddr_in worker_inet_addr; /* Contains host and port */
16 unsigned connect_retry_attempts;
17 const char *host;
18 int port;
19 int maintain_time;
20 /*
21 * Open connections cache...
22 *
23 * 1. Critical section object to protect the cache.
24 * 2. Cache size.
25 * 3. An array of "open" endpoints.
26 */
27 unsigned int ep_cache_sz;
28 unsigned int ep_mincache_sz;
29 unsigned int ep_maxcache_sz;
30 int cache_acquire_timeout;
31 ajp_endpoint_t **ep_cache;
32 int proto; /* PROTOCOL USED AJP13/AJP14 */
33 jk_login_service_t *login;
34 /* Weak secret similar with ajp12, used in ajp13 */
35 const char *secret;
36 /*
37 * Post physical connect handler.
38 * AJP14 will set here its login handler
39 */
40 int (*logon) (ajp_endpoint_t * ae, jk_logger_t *l);
41 /*
42 * Handle Socket Timeouts
43 */
44 int socket_timeout;
45 int socket_connect_timeout;
46 int keepalive;
47 int socket_buf;
48 /*
49 * Handle Cache Timeouts
50 */int cache_timeout;
51 /*
52 * Handle Connection/Reply Timeouts
53 */
54 int connect_timeout; /* connect cping/cpong delay in ms (0 means
55 disabled) */
56 int reply_timeout; /* reply timeout delay in ms (0 means disabled) */
57 int prepost_timeout; /* before sending a request cping/cpong timeout
58 delay in ms (0 means disabled) */
59 int conn_ping_interval; /* interval for sending keepalive cping packets on
60 * unused connection */
61 int ping_timeout; /* generic cping/cpong timeout. Used for keepalive
62 packets or
63 * as default for boolean valued connect and
64 prepost timeouts.
65 */
66 unsigned int ping_mode; /* Ping mode flags (which types of cpings should
67 be used) */
68 /*
69 * Recovery options
70 */
71 unsigned int recovery_opts;
72 /*
73 * Public property to enable the number of retry attempts
74 * on this worker.
75 */
76 int retries;
77 unsigned int max_packet_size; /* Maximum AJP Packet size */
78 int retry_interval; /* Number of milliseconds to sleep before
79 doing a retry */
80 /*
81 * HTTP status that will cause failover (0 means disabled)
82 */
83 unsigned int http_status_fail_num;
84 int http_status_fail[JK_MAX_HTTP_STATUS_FAILS];
85 };
/* 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 协议不太相关。
1 dist/common/jk_service.h
2 struct jk_ws_service
3 {
4 /*
5 * A 'this' pointer which is used by the subclasses of this class to
6 * point to data which is specific to a given web server platform
7 * (e.g. Apache or IIS).
8 */
9 void *ws_private;
10 /*
11 * Provides memory management. All data specific to this request is
12 * allocated within this pool, which can then be reclaimed at the end
13 * of the request handling cycle.
14 *
15 * Alive as long as the request is alive.
16 */
17 jk_pool_t *pool;
18 /*
19 * CGI Environment needed by servlets
20 */
21 const char *method;
22 const char *protocol;
23 char *req_uri;
24 const char *remote_addr;
25 const char *remote_host;
26 const char *remote_user;
27 const char *auth_type;
28 const char *query_string;
29 const char *server_name;
30 unsigned server_port;
31 char *server_software;
32 jk_uint64_t content_length; /* 64 bit integer that represents the content */
33 /* length should be 0 if unknown. */
34 unsigned is_chunked; /* 1 if content length is unknown (chunked rq) */
35 unsigned no_more_chunks; /* 1 if last chunk has been read */
36 jk_uint64_t content_read; /* number of bytes read */
37 /*
38 * SSL information
39 ** is_ssl - True if request is in ssl connection
40 * ssl_cert - If available, base64 ASN.1 encoded client certificates.
41 * ssl_cert_len - Length of ssl_cert, 0 if certificates are not available.
42 * ssl_cipher - The ssl cipher suite in use.
43 * ssl_session - The ssl session string
44 *
45 * In some servers it is impossible to extract all this information, in this
46 * case, we are passing NULL.
47 */
48 int is_ssl;
49 char *ssl_cert;
50 unsigned ssl_cert_len;
51 char *ssl_cipher;
52 char *ssl_session;
53 /*
54 * SSL extra information for Servlet 2.3 API
55 *
56 * ssl_key_size - ssl key size in use
57 */
58 int ssl_key_size;
59 /*
60 * Headers, names and values.
61 */
62 char **headers_names; /* Names of the request headers */
63 char **headers_values; /* Values of the request headers */
64 unsigned num_headers; /* Number of request headers */
65 /*
66 * Request attributes.
67 *
68 * These attributes that were extracted from the web server and are
69 * sent to Tomcat.
70 *
71 * The developer should be able to read them from the ServletRequest
72 * attributes. Tomcat is required to append org.apache.tomcat. to
73 * these attribute names.
74 */
75 char **attributes_names; /* Names of the request attributes */
76 char **attributes_values; /* Values of the request attributes */
77 unsigned num_attributes; /* Number of request attributes */
78 /*
79 * 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
80 * group. We are using this variable to implement target session
81 * affinity
82 */
83 const char *route;
84 /* Temp solution for auth. For native1 it'll be sent on each request,
85 if an option is present. For native2 it'll be sent with the first
86 request. On java side, both cases will work. For tomcat3.2 or
87 a version that doesn't support secret - don't set the secret,
88 and it'll work.
89 */
90 const char *secret;
91 /*
92 * Area to get POST data for fail-over recovery in POST
93 */
94 jk_msg_buf_t *reco_buf;
95 int reco_status;
96 /*
97 * If set call flush after each write
98 */
99 int flush_packets;
100 /*
101 * If set call flush after AJP13_SEND_HEADERS.
102 */
103 int flush_header;
104 /*
105 * service extensions
106 */
107 svc_extension_t extension;
108 /*
109 * JK_TRUE if response headers have been sent back
110 */
111 int response_started;
112 /*
113 * JK_TRUE if response should not be send to the client
114 */
115 int response_blocked;
116 /** HTTP status sent from container.
117 */
118 int http_response_status;
119 /* Uri worker map. Added for virtual host support
120 */
121 jk_uri_worker_map_t *uw_map;
122 /* 下面这些回调函数实现都可以在 mod_jk.c 找到
123 * Callbacks into the web server. For each, the first argument is
124 * essentially a 'this' pointer. All return JK_TRUE on success
125 * and JK_FALSE on failure.
126 */
127 /*
128 * Send the response headers to the browser.
129 */
130 int (JK_METHOD * start_response) (jk_ws_service_t *s,
131 int status,
132 const char *reason,
133 const char *const *header_names,
134 const char *const *header_values,
135 unsigned num_of_headers);
136 /*
137 * Read a chunk of the request body into a buffer. Attempt to read len
138 * bytes into the buffer. Write the number of bytes actually read into
139 * actually_read.
140 */
141 int (JK_METHOD * read) (jk_ws_service_t *s,
142 void *buffer,
143 unsigned len, unsigned *actually_read);
144 /*
145 * Write a chunk of response data back to the browser.
146 */
147 int (JK_METHOD * write) (jk_ws_service_t *s,
148 const void *buffer, unsigned len);
149 /*
150 * Flush a chunk of response data back to the browser.
151 */
152 void (JK_METHOD * flush) (jk_ws_service_t *s);
153 /*
154 * Done with sending response back to the browser.
155 */void (JK_METHOD * done) (jk_ws_service_t *s);
156 /*
157 * If set do not reuse socket after each full response
158 */
159 int disable_reuse;
160 /*
161 * Add more data to log facilities.
162 */
163 void (JK_METHOD * add_log_items) (jk_ws_service_t *s,
164 const char *const *log_names,
165 const char *const *log_values,
166 unsigned num_of_items);
167 /*
168 * Iterate through all vhosts
169 */
170 void *(JK_METHOD * next_vhost) (void *d);
171 /*
172 * String representation of a vhost
173 */
174 void (JK_METHOD * vhost_to_text) (void *d, char *buf, size_t len);
175 /*
176 * Get uw_map associated with a vhost
177 */
178 jk_uri_worker_map_t *(JK_METHOD * vhost_to_uw_map) (void *d);
179 };
4.6 共享内存中一些数据结构
共享内存中的数据结构基本上都是记录之用。有些参数在运行中会实时变化。
1 dist/common/jk_shm.h
2 /** jk shm generic worker record structure */
3 struct jk_shm_worker_header
4 {
5 int id;
6 int type;
7 /* worker name */
8 char name[JK_SHM_STR_SIZ+1];
9 /* Sequence counter starting at 0 and increasing
10 * every time we change the config
11 */
12 volatile unsigned int sequence;
13 };typedef struct jk_shm_worker_header jk_shm_worker_header_t;
14 /** jk shm ajp13/ajp14 worker record structure */
15 struct jk_shm_ajp_worker
16 {
17 jk_shm_worker_header_t h;
18 /* Configuration data mirrored from ajp_worker */
19 int cache_timeout;
20 int connect_timeout;
21 int reply_timeout;
22 int prepost_timeout;
23 unsigned int recovery_opts;
24 int retries;
25 int retry_interval;
26 unsigned int max_packet_size;
27 /* current error state (runtime) of the worker */
28 volatile int state;
29 /* Statistical data */
30 /* Number of currently busy channels */
31 volatile int busy;
32 /* Maximum number of busy channels
33 该参数并非我们的 maxbusy,它是该 worker 自程序运行以来 busy 的最大值 */
34 volatile int max_busy;
35 volatile time_t error_time;
36 /* Number of bytes read from remote */
37 volatile jk_uint64_t readed;
38 /* Number of bytes transferred to remote */
39 volatile jk_uint64_t transferred;
40 /* Number of times the worker was used */
41 volatile jk_uint64_t used;
42 /* Number of times the worker was used - snapshot during maintenance */
43 volatile jk_uint64_t used_snapshot;
44 /* Number of non 200 responses */
45 volatile jk_uint32_t errors;
46 /* Decayed number of reply_timeout errors */
47 volatile jk_uint32_t reply_timeouts;
48 /* Number of client errors */
49 volatile jk_uint32_t client_errors;
50 /* Last reset time */
51 volatile time_t last_reset;
52 volatile time_t last_maintain_time;
53 };
54 typedef struct jk_shm_ajp_worker jk_shm_ajp_worker_t;
55 /** jk shm lb sub worker record structure */struct jk_shm_lb_sub_worker
56 {
57 jk_shm_worker_header_t h;
58 /* route */
59 char route[JK_SHM_STR_SIZ+1];
60 /* worker domain */
61 char domain[JK_SHM_STR_SIZ+1];
62 /* worker redirect route */
63 char redirect[JK_SHM_STR_SIZ+1];
64 /* Number of currently busy channels */
65 volatile int busy;
66 /* worker distance */
67 volatile int distance;
68 /* current activation state (config) of the worker */
69 volatile int activation;
70 /* current error state (runtime) of the worker */
71 volatile int state;
72 /* Current lb factor */
73 volatile int lb_factor;
74 /* 我们的参数加在这里*/
75 volatile int maxbusy;
76 /* Current lb reciprocal factor */
77 volatile jk_uint64_t lb_mult;
78 /* Current lb value */
79 volatile jk_uint64_t lb_value;
80 /* Statistical data */
81 volatile time_t error_time;
82 /* Number of times the worker was elected - snapshot during maintenance */
83 volatile jk_uint64_t elected_snapshot;
84 /* Number of non 200 responses */
85 volatile jk_uint32_t errors;
86 };
87 typedef struct jk_shm_lb_sub_worker jk_shm_lb_sub_worker_t;
88 /** jk shm lb worker record structure */
89 struct jk_shm_lb_worker
90 {
91 jk_shm_worker_header_t h;
92 /* Number of currently busy channels,该值是其名下 ajp_worker 的 busy 值之和*/
93 volatile int busy;
94 /* Maximum number of busy channels,该值是其名下 ajp_worker 的 max_busy 值之和
95 */
96 volatile int max_busy;
97 int sticky_session;int sticky_session_force;
98 int recover_wait_time;
99 int max_reply_timeouts;
100 int retries;
101 int retry_interval;
102 int lbmethod;
103 int lblock;
104 unsigned int max_packet_size;
105 /* Last reset time */
106 volatile time_t last_reset;
107 volatile time_t last_maintain_time;
108 /* Session cookie */
109 char session_cookie[JK_SHM_STR_SIZ+1];
110 /* Session path */
111 char session_path[JK_SHM_STR_SIZ+1];
112 };
113 typedef struct jk_shm_lb_worker jk_shm_lb_worker_t;
参考链接:
1. http://tomcat.apache.org/tomcat-5.5-doc/apr.html
Tomcat 的 native 库由 C 语言开发,使用了 APR 库和 openssl 库,以动态链接库的形式由java 调用。
2. http://tomcat.apache.org/connectors-doc/ajp/ajpv13a.html
3. http://tomcat.apache.org/connectors-doc/reference/workers.html
后记: 有任何疑问请联系本人:xhuangtao@126.com