前言
你有没有想过:微服务架构中,几十个服务对外暴露的入口是怎么统一管理的?怎么做鉴权、限流、路由转发?
API网关是微服务架构的统一入口,负责请求路由、限流降级、认证授权、日志监控。
今天我们用C语言从零实现一个API网关:
· 路由转发(路径匹配/权重分流)
· 限流器(令牌桶/漏桶)
· 熔断降级
· 请求过滤(鉴权/日志)
· 动态配置(热更新)
· 高性能异步IO
一、API网关核心原理
- 架构图
```
┌─────────────────────────────────────────────────────────┐
│ API Gateway │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ 路由 │→│ 限流 │→│ 鉴权 │→│ 转发 │ │
│ │ 匹配 │ │ 检查 │ │ 认证 │ │ 请求 │ │
│ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │
└─────────────────────────────────────────────────────────┘
│ │ │
▼ ▼ ▼
┌─────────┐ ┌─────────┐ ┌─────────┐
│ 服务A │ │ 服务B │ │ 服务C │
└─────────┘ └─────────┘ └─────────┘
```
- 核心功能
功能 说明
路由 根据路径/Host/Header转发到不同服务
限流 令牌桶/漏桶,防止流量突增
熔断 下游故障时快速失败
鉴权 JWT/OAuth2认证
日志 请求响应日志
监控 指标采集
二、完整代码实现
- 基础数据结构
```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;
```
- 路由管理
```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;
}
```
- 限流器(令牌桶)
```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;
}
```
- 请求转发
```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;
}
```
- 请求处理主循环
```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);
}
```
- 动态配置热更新
```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;
}
```
- 完整网关
```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);
}
```
- 测试代码
```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网关的理解~