feat(proxy): 连接池大小可配置(默认4,最大16)
- proxy.h: COCOON_MAX_POOL_SIZE → COCOON_POOL_MAX_CAPACITY(16) + COCOON_POOL_DEFAULT_SIZE(4) - proxy.c: proxy_pool_init 接收 max_pool_size,自动裁剪到上限 - proxy.c: proxy_add_rule 新增 pool_size 参数 - cocoon.h: 配置结构新增 pool_size 字段 - config.c: JSON 解析 pool_size 数字字段,默认值为 4 - server.c: 调用 proxy_add_rule 时传入配置值 - cocoon.json: 示例配置添加 pool_size 展示 编译零警告,142 单元测试 + 90 集成测试全部通过。
This commit is contained in:
parent
ff1b56fc9e
commit
23574ab2ba
@ -64,13 +64,24 @@
|
|||||||
- 当前仅做编译和测试验证,不添加新代码
|
- 当前仅做编译和测试验证,不添加新代码
|
||||||
|
|
||||||
## 待办池(活跃)
|
## 待办池(活跃)
|
||||||
1. **HTTP/2 代理支持** — 将反向代理接入 HTTP/2 流(当前仅 HTTP/1.1)
|
1. ~~连接池最大连接数可配置 — 当前固定为4~~ ✅ 2026-06-09
|
||||||
2. 虚拟主机 / 多站点 — 低优先级
|
2. **HTTP/2 代理支持** — 将反向代理接入 HTTP/2 流(当前仅 HTTP/1.1)
|
||||||
3. 加权轮询 / 主动健康检查 — 负载均衡进阶(当前为被动检测)
|
3. 虚拟主机 / 多站点 — 低优先级
|
||||||
4. 连接池最大连接数可配置 — 当前固定为4
|
4. 加权轮询 / 主动健康检查 — 负载均衡进阶(当前为被动检测)
|
||||||
|
|
||||||
## 最近行动记录
|
## 最近行动记录
|
||||||
|
|
||||||
|
- 2026-06-09 03:00: **连接池大小可配置**
|
||||||
|
- `proxy.h`: `COCOON_MAX_POOL_SIZE` → `COCOON_POOL_MAX_CAPACITY`(上限16)+ `COCOON_POOL_DEFAULT_SIZE`(默认4),`cocoon_conn_pool_t` 新增 `max_size` 字段
|
||||||
|
- `proxy.c`: `proxy_pool_init` 接收 `max_pool_size` 参数,自动裁剪到上限;所有循环改用 `backend->pool.max_size`
|
||||||
|
- `proxy.c`: `proxy_add_rule` 新增 `pool_size` 参数,传递给 `parse_backend_url` → `proxy_pool_init`
|
||||||
|
- `cocoon.h`: `proxies` 配置结构新增 `uint32_t pool_size` 字段
|
||||||
|
- `config.c`: JSON 解析器新增 `pool_size` 数字字段解析,默认值为 4
|
||||||
|
- `server.c`: 调用 `proxy_add_rule` 时传入配置的 `pool_size`
|
||||||
|
- `cocoon.json`: 示例配置添加 `pool_size` 展示(`/api` → 8,`/backend` → 4)
|
||||||
|
- 编译零警告,142 单元测试 + 90 集成测试全部通过
|
||||||
|
- 提交已推送 `main`
|
||||||
|
|
||||||
- 2026-06-09 00:15: **后端连接池/keep-alive**
|
- 2026-06-09 00:15: **后端连接池/keep-alive**
|
||||||
- `proxy.h`: 新增 `cocoon_pooled_conn_t` / `cocoon_conn_pool_t`(pthread_mutex 保护),后端嵌入连接池
|
- `proxy.h`: 新增 `cocoon_pooled_conn_t` / `cocoon_conn_pool_t`(pthread_mutex 保护),后端嵌入连接池
|
||||||
- `proxy.c`: 实现 `proxy_pool_init`/`destroy`/`acquire`/`release` + `proxy_config_destroy`
|
- `proxy.c`: 实现 `proxy_pool_init`/`destroy`/`acquire`/`release` + `proxy_config_destroy`
|
||||||
|
|||||||
1
cocoon.h
1
cocoon.h
@ -56,6 +56,7 @@ typedef struct cocoon_config {
|
|||||||
struct {
|
struct {
|
||||||
char prefix[256];
|
char prefix[256];
|
||||||
char target[256];
|
char target[256];
|
||||||
|
uint32_t pool_size; /* 连接池大小(默认4,最大16) */
|
||||||
} proxies[COCOON_MAX_PROXY_RULES];
|
} proxies[COCOON_MAX_PROXY_RULES];
|
||||||
size_t num_proxies;
|
size_t num_proxies;
|
||||||
} cocoon_config_t;
|
} cocoon_config_t;
|
||||||
|
|||||||
@ -11,8 +11,8 @@
|
|||||||
"plugins": ["plugins/hello.so"],
|
"plugins": ["plugins/hello.so"],
|
||||||
"access_log": "-",
|
"access_log": "-",
|
||||||
"proxies": [
|
"proxies": [
|
||||||
{"prefix": "/api", "target": "http://localhost:3000"},
|
{"prefix": "/api", "target": "http://localhost:3000", "pool_size": 8},
|
||||||
{"prefix": "/api", "target": "http://localhost:3001"},
|
{"prefix": "/api", "target": "http://localhost:3001"},
|
||||||
{"prefix": "/backend", "target": "https://localhost:8443"}
|
{"prefix": "/backend", "target": "https://localhost:8443", "pool_size": 4}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
6
config.c
6
config.c
@ -436,6 +436,9 @@ bool config_load_from_file(const char *path, cocoon_config_t *config) {
|
|||||||
} else if (strcmp(pk, "target") == 0 && pval.type == TOKEN_STRING) {
|
} else if (strcmp(pk, "target") == 0 && pval.type == TOKEN_STRING) {
|
||||||
char *v = token_str_dup(&pval);
|
char *v = token_str_dup(&pval);
|
||||||
if (v) { strncpy(target, v, sizeof(target)-1); free(v); }
|
if (v) { strncpy(target, v, sizeof(target)-1); free(v); }
|
||||||
|
} else if (strcmp(pk, "pool_size") == 0 && pval.type == TOKEN_NUMBER) {
|
||||||
|
char *v = token_str_dup(&pval);
|
||||||
|
if (v) { config->proxies[config->num_proxies].pool_size = (uint32_t)atoi(v); free(v); }
|
||||||
}
|
}
|
||||||
free(pk);
|
free(pk);
|
||||||
token_t psep = parser_next_token(&p);
|
token_t psep = parser_next_token(&p);
|
||||||
@ -454,6 +457,9 @@ bool config_load_from_file(const char *path, cocoon_config_t *config) {
|
|||||||
if (target_len >= sizeof(config->proxies[0].target)) target_len = sizeof(config->proxies[0].target) - 1;
|
if (target_len >= sizeof(config->proxies[0].target)) target_len = sizeof(config->proxies[0].target) - 1;
|
||||||
memcpy(config->proxies[config->num_proxies].target, target, target_len);
|
memcpy(config->proxies[config->num_proxies].target, target, target_len);
|
||||||
config->proxies[config->num_proxies].target[target_len] = '\0';
|
config->proxies[config->num_proxies].target[target_len] = '\0';
|
||||||
|
if (config->proxies[config->num_proxies].pool_size == 0) {
|
||||||
|
config->proxies[config->num_proxies].pool_size = 4; /* 默认连接池大小 */
|
||||||
|
}
|
||||||
config->num_proxies++;
|
config->num_proxies++;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
29
proxy.c
29
proxy.c
@ -32,10 +32,17 @@ static void backend_init_health(cocoon_proxy_backend_t *backend) {
|
|||||||
backend->last_check = 0;
|
backend->last_check = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void proxy_pool_init(cocoon_proxy_backend_t *backend) {
|
void proxy_pool_init(cocoon_proxy_backend_t *backend, size_t max_pool_size) {
|
||||||
memset(&backend->pool, 0, sizeof(backend->pool));
|
memset(&backend->pool, 0, sizeof(backend->pool));
|
||||||
|
backend->pool.max_size = max_pool_size;
|
||||||
|
if (backend->pool.max_size > COCOON_POOL_MAX_CAPACITY) {
|
||||||
|
backend->pool.max_size = COCOON_POOL_MAX_CAPACITY;
|
||||||
|
}
|
||||||
|
if (backend->pool.max_size == 0) {
|
||||||
|
backend->pool.max_size = COCOON_POOL_DEFAULT_SIZE;
|
||||||
|
}
|
||||||
pthread_mutex_init(&backend->pool.mutex, NULL);
|
pthread_mutex_init(&backend->pool.mutex, NULL);
|
||||||
for (size_t i = 0; i < COCOON_MAX_POOL_SIZE; i++) {
|
for (size_t i = 0; i < COCOON_POOL_MAX_CAPACITY; i++) {
|
||||||
backend->pool.conns[i].fd = COCOON_INVALID_SOCKET;
|
backend->pool.conns[i].fd = COCOON_INVALID_SOCKET;
|
||||||
backend->pool.conns[i].tls_conn = NULL;
|
backend->pool.conns[i].tls_conn = NULL;
|
||||||
backend->pool.conns[i].in_use = false;
|
backend->pool.conns[i].in_use = false;
|
||||||
@ -46,7 +53,7 @@ void proxy_pool_init(cocoon_proxy_backend_t *backend) {
|
|||||||
void proxy_pool_destroy(cocoon_proxy_backend_t *backend) {
|
void proxy_pool_destroy(cocoon_proxy_backend_t *backend) {
|
||||||
if (!backend) return;
|
if (!backend) return;
|
||||||
pthread_mutex_lock(&backend->pool.mutex);
|
pthread_mutex_lock(&backend->pool.mutex);
|
||||||
for (size_t i = 0; i < COCOON_MAX_POOL_SIZE; i++) {
|
for (size_t i = 0; i < backend->pool.max_size; i++) {
|
||||||
cocoon_pooled_conn_t *pc = &backend->pool.conns[i];
|
cocoon_pooled_conn_t *pc = &backend->pool.conns[i];
|
||||||
if (pc->fd != COCOON_INVALID_SOCKET) {
|
if (pc->fd != COCOON_INVALID_SOCKET) {
|
||||||
cocoon_socket_close(pc->fd);
|
cocoon_socket_close(pc->fd);
|
||||||
@ -74,7 +81,7 @@ bool proxy_pool_acquire(cocoon_proxy_backend_t *backend, cocoon_socket_t *pfd, p
|
|||||||
pthread_mutex_lock(&backend->pool.mutex);
|
pthread_mutex_lock(&backend->pool.mutex);
|
||||||
|
|
||||||
/* 1. 查找可用空闲连接(未超时) */
|
/* 1. 查找可用空闲连接(未超时) */
|
||||||
for (size_t i = 0; i < COCOON_MAX_POOL_SIZE; i++) {
|
for (size_t i = 0; i < backend->pool.max_size; i++) {
|
||||||
cocoon_pooled_conn_t *pc = &backend->pool.conns[i];
|
cocoon_pooled_conn_t *pc = &backend->pool.conns[i];
|
||||||
if (pc->in_use) continue;
|
if (pc->in_use) continue;
|
||||||
if (pc->fd == COCOON_INVALID_SOCKET && !pc->tls_conn) continue;
|
if (pc->fd == COCOON_INVALID_SOCKET && !pc->tls_conn) continue;
|
||||||
@ -141,7 +148,7 @@ void proxy_pool_release(cocoon_proxy_backend_t *backend, cocoon_socket_t fd, pro
|
|||||||
pthread_mutex_lock(&backend->pool.mutex);
|
pthread_mutex_lock(&backend->pool.mutex);
|
||||||
|
|
||||||
/* 先尝试找到这个连接的槽位(如果它原本就在池中) */
|
/* 先尝试找到这个连接的槽位(如果它原本就在池中) */
|
||||||
for (size_t i = 0; i < COCOON_MAX_POOL_SIZE; i++) {
|
for (size_t i = 0; i < backend->pool.max_size; i++) {
|
||||||
cocoon_pooled_conn_t *pc = &backend->pool.conns[i];
|
cocoon_pooled_conn_t *pc = &backend->pool.conns[i];
|
||||||
if (pc->in_use &&
|
if (pc->in_use &&
|
||||||
((use_https && pc->tls_conn == tls_conn) ||
|
((use_https && pc->tls_conn == tls_conn) ||
|
||||||
@ -155,7 +162,7 @@ void proxy_pool_release(cocoon_proxy_backend_t *backend, cocoon_socket_t fd, pro
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* 如果是新建连接,找一个空槽位放入 */
|
/* 如果是新建连接,找一个空槽位放入 */
|
||||||
for (size_t i = 0; i < COCOON_MAX_POOL_SIZE; i++) {
|
for (size_t i = 0; i < backend->pool.max_size; i++) {
|
||||||
cocoon_pooled_conn_t *pc = &backend->pool.conns[i];
|
cocoon_pooled_conn_t *pc = &backend->pool.conns[i];
|
||||||
if (pc->fd == COCOON_INVALID_SOCKET && !pc->tls_conn) {
|
if (pc->fd == COCOON_INVALID_SOCKET && !pc->tls_conn) {
|
||||||
pc->fd = fd;
|
pc->fd = fd;
|
||||||
@ -179,7 +186,7 @@ void proxy_pool_release(cocoon_proxy_backend_t *backend, cocoon_socket_t fd, pro
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void parse_backend_url(const char *target_url, cocoon_proxy_backend_t *backend) {
|
static void parse_backend_url(const char *target_url, cocoon_proxy_backend_t *backend, size_t pool_size) {
|
||||||
/* 解析目标URL */
|
/* 解析目标URL */
|
||||||
bool https = false;
|
bool https = false;
|
||||||
const char *url = target_url;
|
const char *url = target_url;
|
||||||
@ -237,10 +244,10 @@ static void parse_backend_url(const char *target_url, cocoon_proxy_backend_t *ba
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* 初始化连接池 */
|
/* 初始化连接池 */
|
||||||
proxy_pool_init(backend);
|
proxy_pool_init(backend, pool_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool proxy_add_rule(cocoon_proxy_config_t *cfg, const char *prefix, const char *target_url) {
|
bool proxy_add_rule(cocoon_proxy_config_t *cfg, const char *prefix, const char *target_url, size_t pool_size) {
|
||||||
if (!prefix || !target_url || prefix[0] == '\0' || target_url[0] == '\0') {
|
if (!prefix || !target_url || prefix[0] == '\0' || target_url[0] == '\0') {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -261,7 +268,7 @@ bool proxy_add_rule(cocoon_proxy_config_t *cfg, const char *prefix, const char *
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
cocoon_proxy_backend_t *backend = &rule->backends[rule->backend_count];
|
cocoon_proxy_backend_t *backend = &rule->backends[rule->backend_count];
|
||||||
parse_backend_url(target_url, backend);
|
parse_backend_url(target_url, backend, pool_size);
|
||||||
backend_init_health(backend);
|
backend_init_health(backend);
|
||||||
log_info("追加后端: %s -> %s://%s:%d%s",
|
log_info("追加后端: %s -> %s://%s:%d%s",
|
||||||
rule->path_prefix,
|
rule->path_prefix,
|
||||||
@ -286,7 +293,7 @@ bool proxy_add_rule(cocoon_proxy_config_t *cfg, const char *prefix, const char *
|
|||||||
rule->current_index = 0;
|
rule->current_index = 0;
|
||||||
|
|
||||||
cocoon_proxy_backend_t *backend = &rule->backends[rule->backend_count];
|
cocoon_proxy_backend_t *backend = &rule->backends[rule->backend_count];
|
||||||
parse_backend_url(target_url, backend);
|
parse_backend_url(target_url, backend, pool_size);
|
||||||
backend_init_health(backend);
|
backend_init_health(backend);
|
||||||
rule->backend_count++;
|
rule->backend_count++;
|
||||||
|
|
||||||
|
|||||||
13
proxy.h
13
proxy.h
@ -17,7 +17,9 @@
|
|||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
#define COCOON_MAX_POOL_SIZE 4
|
/* === 连接池可配置 === */
|
||||||
|
#define COCOON_POOL_MAX_CAPACITY 16 /**< 连接池最大容量上限 */
|
||||||
|
#define COCOON_POOL_DEFAULT_SIZE 4 /**< 默认连接池大小 */
|
||||||
#define COCOON_POOL_IDLE_TIMEOUT_MS 30000
|
#define COCOON_POOL_IDLE_TIMEOUT_MS 30000
|
||||||
|
|
||||||
#define COCOON_MAX_PROXY_BACKENDS 8
|
#define COCOON_MAX_PROXY_BACKENDS 8
|
||||||
@ -38,8 +40,9 @@ typedef struct {
|
|||||||
* cocoon_conn_pool_t - 连接池
|
* cocoon_conn_pool_t - 连接池
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
cocoon_pooled_conn_t conns[COCOON_MAX_POOL_SIZE]; /**< 空闲连接数组 */
|
cocoon_pooled_conn_t conns[COCOON_POOL_MAX_CAPACITY]; /**< 空闲连接数组(上限16) */
|
||||||
pthread_mutex_t mutex; /**< 保护锁 */
|
size_t max_size; /**< 实际配置大小(默认4) */
|
||||||
|
pthread_mutex_t mutex; /**< 保护锁 */
|
||||||
} cocoon_conn_pool_t;
|
} cocoon_conn_pool_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -90,7 +93,7 @@ void proxy_init(cocoon_proxy_config_t *cfg);
|
|||||||
* @param target_url 目标URL(如 "http://localhost:3000")
|
* @param target_url 目标URL(如 "http://localhost:3000")
|
||||||
* @return true 成功
|
* @return true 成功
|
||||||
*/
|
*/
|
||||||
bool proxy_add_rule(cocoon_proxy_config_t *cfg, const char *prefix, const char *target_url);
|
bool proxy_add_rule(cocoon_proxy_config_t *cfg, const char *prefix, const char *target_url, size_t pool_size);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* proxy_match - 查找匹配路径的代理规则
|
* proxy_match - 查找匹配路径的代理规则
|
||||||
@ -129,7 +132,7 @@ bool proxy_forward(cocoon_socket_t client_fd, const http_request_t *req,
|
|||||||
/**
|
/**
|
||||||
* proxy_pool_init - 初始化后端连接池
|
* proxy_pool_init - 初始化后端连接池
|
||||||
*/
|
*/
|
||||||
void proxy_pool_init(cocoon_proxy_backend_t *backend);
|
void proxy_pool_init(cocoon_proxy_backend_t *backend, size_t max_pool_size);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* proxy_pool_destroy - 销毁后端连接池,关闭所有连接
|
* proxy_pool_destroy - 销毁后端连接池,关闭所有连接
|
||||||
|
|||||||
2
server.c
2
server.c
@ -1265,7 +1265,7 @@ server_context_t *server_create(const cocoon_config_t *config) {
|
|||||||
/* 初始化反向代理配置 */
|
/* 初始化反向代理配置 */
|
||||||
proxy_init(&ctx->proxy_config);
|
proxy_init(&ctx->proxy_config);
|
||||||
for (size_t i = 0; i < ctx->config.num_proxies; i++) {
|
for (size_t i = 0; i < ctx->config.num_proxies; i++) {
|
||||||
proxy_add_rule(&ctx->proxy_config, ctx->config.proxies[i].prefix, ctx->config.proxies[i].target);
|
proxy_add_rule(&ctx->proxy_config, ctx->config.proxies[i].prefix, ctx->config.proxies[i].target, ctx->config.proxies[i].pool_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 加载插件 */
|
/* 加载插件 */
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user