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:
xfy911 2026-06-09 03:06:50 +08:00
parent ff1b56fc9e
commit 23574ab2ba
7 changed files with 51 additions and 23 deletions

View File

@ -64,13 +64,24 @@
- 当前仅做编译和测试验证,不添加新代码
## 待办池(活跃)
1. **HTTP/2 代理支持** — 将反向代理接入 HTTP/2 流(当前仅 HTTP/1.1
2. 虚拟主机 / 多站点 — 低优先级
3. 加权轮询 / 主动健康检查 — 负载均衡进阶(当前为被动检测)
4. 连接池最大连接数可配置 — 当前固定为4
1. ~~连接池最大连接数可配置 — 当前固定为4~~ ✅ 2026-06-09
2. **HTTP/2 代理支持** — 将反向代理接入 HTTP/2 流(当前仅 HTTP/1.1
3. 虚拟主机 / 多站点 — 低优先级
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**
- `proxy.h`: 新增 `cocoon_pooled_conn_t` / `cocoon_conn_pool_t`pthread_mutex 保护),后端嵌入连接池
- `proxy.c`: 实现 `proxy_pool_init`/`destroy`/`acquire`/`release` + `proxy_config_destroy`

View File

@ -56,6 +56,7 @@ typedef struct cocoon_config {
struct {
char prefix[256];
char target[256];
uint32_t pool_size; /* 连接池大小默认4最大16 */
} proxies[COCOON_MAX_PROXY_RULES];
size_t num_proxies;
} cocoon_config_t;

View File

@ -11,8 +11,8 @@
"plugins": ["plugins/hello.so"],
"access_log": "-",
"proxies": [
{"prefix": "/api", "target": "http://localhost:3000"},
{"prefix": "/api", "target": "http://localhost:3000", "pool_size": 8},
{"prefix": "/api", "target": "http://localhost:3001"},
{"prefix": "/backend", "target": "https://localhost:8443"}
{"prefix": "/backend", "target": "https://localhost:8443", "pool_size": 4}
]
}

View File

@ -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) {
char *v = token_str_dup(&pval);
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);
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;
memcpy(config->proxies[config->num_proxies].target, target, target_len);
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++;
}
} else {

29
proxy.c
View File

@ -32,10 +32,17 @@ static void backend_init_health(cocoon_proxy_backend_t *backend) {
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));
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);
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].tls_conn = NULL;
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) {
if (!backend) return;
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];
if (pc->fd != COCOON_INVALID_SOCKET) {
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);
/* 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];
if (pc->in_use) 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);
/* 先尝试找到这个连接的槽位(如果它原本就在池中) */
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];
if (pc->in_use &&
((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];
if (pc->fd == COCOON_INVALID_SOCKET && !pc->tls_conn) {
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 */
bool https = false;
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') {
return false;
}
@ -261,7 +268,7 @@ bool proxy_add_rule(cocoon_proxy_config_t *cfg, const char *prefix, const char *
return false;
}
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);
log_info("追加后端: %s -> %s://%s:%d%s",
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;
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);
rule->backend_count++;

13
proxy.h
View File

@ -17,7 +17,9 @@
#include <pthread.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_MAX_PROXY_BACKENDS 8
@ -38,8 +40,9 @@ typedef struct {
* cocoon_conn_pool_t -
*/
typedef struct {
cocoon_pooled_conn_t conns[COCOON_MAX_POOL_SIZE]; /**< 空闲连接数组 */
pthread_mutex_t mutex; /**< 保护锁 */
cocoon_pooled_conn_t conns[COCOON_POOL_MAX_CAPACITY]; /**< 空闲连接数组上限16 */
size_t max_size; /**< 实际配置大小默认4 */
pthread_mutex_t mutex; /**< 保护锁 */
} cocoon_conn_pool_t;
/**
@ -90,7 +93,7 @@ void proxy_init(cocoon_proxy_config_t *cfg);
* @param target_url URL "http://localhost:3000"
* @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 -
@ -129,7 +132,7 @@ bool proxy_forward(cocoon_socket_t client_fd, const http_request_t *req,
/**
* 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 -

View File

@ -1265,7 +1265,7 @@ server_context_t *server_create(const cocoon_config_t *config) {
/* 初始化反向代理配置 */
proxy_init(&ctx->proxy_config);
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);
}
/* 加载插件 */