从零实现一个API网关:路由与限流

前言

你有没有想过:微服务架构中,几十个服务对外暴露的入口是怎么统一管理的?怎么做鉴权、限流、路由转发?

API网关是微服务架构的统一入口,负责请求路由、限流降级、认证授权、日志监控。

今天我们用C语言从零实现一个API网关:

· 路由转发(路径匹配/权重分流)

· 限流器(令牌桶/漏桶)

· 熔断降级

· 请求过滤(鉴权/日志)

· 动态配置(热更新)

· 高性能异步IO


一、API网关核心原理

  1. 架构图

```

┌─────────────────────────────────────────────────────────┐

│ API Gateway │

│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │

│ │ 路由 │→│ 限流 │→│ 鉴权 │→│ 转发 │ │

│ │ 匹配 │ │ 检查 │ │ 认证 │ │ 请求 │ │

│ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │

└─────────────────────────────────────────────────────────┘

│ │ │

▼ ▼ ▼

┌─────────┐ ┌─────────┐ ┌─────────┐

│ 服务A │ │ 服务B │ │ 服务C │

└─────────┘ └─────────┘ └─────────┘

```

  1. 核心功能

功能 说明

路由 根据路径/Host/Header转发到不同服务

限流 令牌桶/漏桶,防止流量突增

熔断 下游故障时快速失败

鉴权 JWT/OAuth2认证

日志 请求响应日志

监控 指标采集


二、完整代码实现

  1. 基础数据结构

```c

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <unistd.h>

#include <pthread.h>

#include <time.h>

#include <sys/socket.h>

#include <netinet/in.h>

#include <arpa/inet.h>

#include <errno.h>

#include <signal.h>

#include <fcntl.h>

#include <sys/epoll.h>

#define MAX_ROUTES 256

#define BUFFER_SIZE 65536

#define MAX_CONNECTIONS 10000

// 路由定义

typedef struct route {

char path128; // 匹配路径(支持通配符)

char service_name64; // 目标服务名

char target_host32; // 目标主机

int target_port; // 目标端口

int weight; // 权重(灰度)

int strip_prefix; // 是否剥离前缀

char rewrite_path128; // 路径重写

struct route *next;

} route_t;

// 限流器配置

typedef struct rate_limiter {

char key128; // 限流key(IP/用户/路径)

int rate; // 每秒请求数

int burst; // 突发容量

int tokens; // 当前令牌数

time_t last_update; // 最后更新时间

pthread_mutex_t mutex;

struct rate_limiter *next;

} rate_limiter_t;

// API网关结构

typedef struct api_gateway {

route_t *routes;

rate_limiter_t *limiters;

int listen_port;

int epoll_fd;

int running;

pthread_mutex_t mutex;

pthread_t config_thread;

} api_gateway_t;

```

  1. 路由管理

```c

// 添加路由

void gateway_add_route(api_gateway_t *gw, const char *path, const char *service,

const char *host, int port) {

pthread_mutex_lock(&gw->mutex);

route_t *r = malloc(sizeof(route_t));

strcpy(r->path, path);

strcpy(r->service_name, service);

strcpy(r->target_host, host);

r->target_port = port;

r->weight = 100;

r->strip_prefix = 1;

r->rewrite_path0 = '\0';

r->next = gw->routes;

gw->routes = r;

pthread_mutex_unlock(&gw->mutex);

printf("添加路由: %s → %s:%d\n", path, host, port);

}

// 匹配路由

route_t *gateway_match_route(api_gateway_t *gw, const char *path) {

pthread_mutex_lock(&gw->mutex);

route_t *r = gw->routes;

route_t *best_match = NULL;

int best_len = -1;

while (r) {

// 精确匹配

if (strcmp(r->path, path) == 0) {

best_match = r;

break;

}

// 前缀匹配(通配符)

int path_len = strlen(r->path);

if (r->pathpath_len - 1 == '*') {

int prefix_len = path_len - 1;

if (strncmp(r->path, path, prefix_len) == 0) {

if (prefix_len > best_len) {

best_len = prefix_len;

best_match = r;

}

}

}

r = r->next;

}

pthread_mutex_unlock(&gw->mutex);

return best_match;

}

```

  1. 限流器(令牌桶)

```c

// 令牌桶限流器

rate_limiter_t *create_rate_limiter(const char *key, int rate, int burst) {

rate_limiter_t *rl = malloc(sizeof(rate_limiter_t));

strcpy(rl->key, key);

rl->rate = rate;

rl->burst = burst;

rl->tokens = burst;

rl->last_update = time(NULL);

pthread_mutex_init(&rl->mutex, NULL);

return rl;

}

// 获取或创建限流器

rate_limiter_t *get_rate_limiter(api_gateway_t *gw, const char *key,

int rate, int burst) {

pthread_mutex_lock(&gw->mutex);

rate_limiter_t *rl = gw->limiters;

while (rl) {

if (strcmp(rl->key, key) == 0) {

pthread_mutex_unlock(&gw->mutex);

return rl;

}

rl = rl->next;

}

rl = create_rate_limiter(key, rate, burst);

rl->next = gw->limiters;

gw->limiters = rl;

pthread_mutex_unlock(&gw->mutex);

return rl;

}

// 限流检查(返回0允许,返回-1拒绝)

int rate_limiter_allow(rate_limiter_t *rl) {

pthread_mutex_lock(&rl->mutex);

time_t now = time(NULL);

int elapsed = now - rl->last_update;

// 补充令牌

if (elapsed > 0) {

int new_tokens = elapsed * rl->rate;

rl->tokens = (rl->tokens + new_tokens > rl->burst) ?

rl->burst : rl->tokens + new_tokens;

rl->last_update = now;

}

int allow = (rl->tokens > 0);

if (allow) {

rl->tokens--;

}

pthread_mutex_unlock(&rl->mutex);

return allow ? 0 : -1;

}

```

  1. 请求转发

```c

// 转发HTTP请求

int gateway_forward(api_gateway_t *gw, route_t *route,

const char *request, int req_len,

char *response, int *resp_len) {

// 连接到目标服务

int target_fd = socket(AF_INET, SOCK_STREAM, 0);

if (target_fd < 0) return -1;

struct sockaddr_in addr;

addr.sin_family = AF_INET;

addr.sin_port = htons(route->target_port);

inet_pton(AF_INET, route->target_host, &addr.sin_addr);

// 设置超时

struct timeval tv = {3, 0};

setsockopt(target_fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));

setsockopt(target_fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));

if (connect(target_fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {

close(target_fd);

return -1;

}

// 重写请求(剥离前缀)

char modified_reqBUFFER_SIZE;

if (route->strip_prefix && strlen(route->path) > 1) {

// 简单实现:替换路径

// 实际需要解析HTTP请求行

strcpy(modified_req, request);

// ... 路径重写逻辑

} else {

strcpy(modified_req, request);

}

// 发送请求

send(target_fd, modified_req, strlen(modified_req), 0);

// 接收响应(考虑分块)

int total = 0;

int n;

while ((n = recv(target_fd, response + total, BUFFER_SIZE - total - 1, 0)) > 0) {

total += n;

if (total >= BUFFER_SIZE - 1) break;

}

responsetotal = '\0';

*resp_len = total;

close(target_fd);

return 0;

}

```

  1. 请求处理主循环

```c

void handle_request(api_gateway_t *gw, int client_fd) {

char requestBUFFER_SIZE;

int n = recv(client_fd, request, sizeof(request) - 1, 0);

if (n <= 0) {

close(client_fd);

return;

}

requestn = '\0';

// 解析请求路径

char method16, path256, version16;

sscanf(request, "%s %s %s", method, path, version);

// 限流检查(按IP)

struct sockaddr_in addr;

socklen_t addr_len = sizeof(addr);

getpeername(client_fd, (struct sockaddr*)&addr, &addr_len);

char ip32;

inet_ntop(AF_INET, &addr.sin_addr, ip, sizeof(ip));

rate_limiter_t *rl = get_rate_limiter(gw, ip, 100, 200);

if (rate_limiter_allow(rl) < 0) {

char *resp = "HTTP/1.1 429 Too Many Requests\r\n\r\n";

send(client_fd, resp, strlen(resp), 0);

close(client_fd);

return;

}

// 路由匹配

route_t *route = gateway_match_route(gw, path);

if (!route) {

char *resp = "HTTP/1.1 404 Not Found\r\n\r\n";

send(client_fd, resp, strlen(resp), 0);

close(client_fd);

return;

}

// 转发请求

char responseBUFFER_SIZE;

int resp_len;

if (gateway_forward(gw, route, request, n, response, &resp_len) == 0) {

send(client_fd, response, resp_len, 0);

} else {

char *resp = "HTTP/1.1 502 Bad Gateway\r\n\r\n";

send(client_fd, resp, strlen(resp), 0);

}

close(client_fd);

}

```

  1. 动态配置热更新

```c

// 配置更新函数

void reload_config(api_gateway_t *gw) {

// 模拟从配置文件或etcd读取配置

// 实际会读取JSON/YAML并更新路由和限流规则

printf("配置热更新...\n");

// 清除旧路由(示例)

pthread_mutex_lock(&gw->mutex);

route_t *r = gw->routes;

while (r) {

route_t *next = r->next;

free(r);

r = next;

}

gw->routes = NULL;

pthread_mutex_unlock(&gw->mutex);

// 加载新路由

gateway_add_route(gw, "/api/v1/users/*", "user-service", "127.0.0.1", 9001);

gateway_add_route(gw, "/api/v1/orders/*", "order-service", "127.0.0.1", 9002);

gateway_add_route(gw, "/api/v1/products/*", "product-service", "127.0.0.1", 9003);

printf("配置更新完成\n");

}

// 配置热更新线程

void *config_reload_thread(void *arg) {

api_gateway_t *gw = (api_gateway_t*)arg;

while (gw->running) {

sleep(60); // 每分钟检查一次

reload_config(gw);

}

return NULL;

}

```

  1. 完整网关

```c

api_gateway_t *gateway_create(int port) {

api_gateway_t *gw = malloc(sizeof(api_gateway_t));

memset(gw, 0, sizeof(api_gateway_t));

gw->listen_port = port;

gw->running = 1;

pthread_mutex_init(&gw->mutex, NULL);

// 创建epoll

gw->epoll_fd = epoll_create(MAX_CONNECTIONS);

// 加载初始路由

gateway_add_route(gw, "/api/users/*", "user-service", "127.0.0.1", 9001);

gateway_add_route(gw, "/api/orders/*", "order-service", "127.0.0.1", 9002);

gateway_add_route(gw, "/api/*", "backend", "127.0.0.1", 8080);

// 启动配置热更新线程

pthread_create(&gw->config_thread, NULL, config_reload_thread, gw);

printf("API网关启动: 端口 %d\n", port);

return gw;

}

void gateway_destroy(api_gateway_t *gw) {

gw->running = 0;

pthread_join(gw->config_thread, NULL);

route_t *r = gw->routes;

while (r) {

route_t *next = r->next;

free(r);

r = next;

}

rate_limiter_t *rl = gw->limiters;

while (rl) {

rate_limiter_t *next = rl->next;

pthread_mutex_destroy(&rl->mutex);

free(rl);

rl = next;

}

close(gw->epoll_fd);

free(gw);

}

void gateway_run(api_gateway_t *gw) {

int server_fd = socket(AF_INET, SOCK_STREAM, 0);

int opt = 1;

setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

struct sockaddr_in addr;

addr.sin_family = AF_INET;

addr.sin_addr.s_addr = INADDR_ANY;

addr.sin_port = htons(gw->listen_port);

bind(server_fd, (struct sockaddr*)&addr, sizeof(addr));

listen(server_fd, 128);

// 设置非阻塞

fcntl(server_fd, F_SETFL, O_NONBLOCK);

struct epoll_event ev, eventsMAX_CONNECTIONS;

ev.events = EPOLLIN | EPOLLET;

ev.data.fd = server_fd;

epoll_ctl(gw->epoll_fd, EPOLL_CTL_ADD, server_fd, &ev);

printf("API网关运行中: http://localhost:%d\n", gw->listen_port);

while (gw->running) {

int nfds = epoll_wait(gw->epoll_fd, events, MAX_CONNECTIONS, 100);

for (int i = 0; i < nfds; i++) {

int fd = eventsi.data.fd;

if (fd == server_fd) {

while (1) {

int client_fd = accept(server_fd, NULL, NULL);

if (client_fd < 0) break;

fcntl(client_fd, F_SETFL, O_NONBLOCK);

ev.events = EPOLLIN | EPOLLET;

ev.data.fd = client_fd;

epoll_ctl(gw->epoll_fd, EPOLL_CTL_ADD, client_fd, &ev);

}

} else {

handle_request(gw, fd);

epoll_ctl(gw->epoll_fd, EPOLL_CTL_DEL, fd, NULL);

}

}

}

close(server_fd);

}

```

  1. 测试代码

```c

int main() {

printf("=== API网关测试 ===\n\n");

api_gateway_t *gw = gateway_create(8080);

printf("路由列表:\n");

route_t *r = gw->routes;

while (r) {

printf(" %s → %s:%d\n", r->path, r->target_host, r->target_port);

r = r->next;

}

printf("\n");

printf("限流规则: 每IP 100 req/s, burst 200\n");

printf("测试: curl http://localhost:8080/api/users/123\\n\\n");

gateway_run(gw);

gateway_destroy(gw);

return 0;

}

```


三、编译和运行

```bash

gcc -o api_gateway api_gateway.c -lpthread

./api_gateway

```

测试:

```bash

正常请求

curl http://localhost:8080/api/users/123

限流测试(快速发送请求)

for i in {1..300}; do

curl http://localhost:8080/api/users/123 &

done

```


四、总结

通过这篇文章,你学会了:

· API网关的核心功能(路由、限流、转发)

· 令牌桶限流器实现

· 路由匹配(精确/前缀)

· 请求转发和路径重写

· 动态配置热更新

· 异步IO处理

API网关是微服务架构的统一入口。掌握它,你就理解了Kong、Spring Cloud Gateway的底层设计。

下一篇预告:《从零实现一个服务降级框架:熔断与降级策略》


评论区分享一下你对API网关的理解~