从零实现一个API网关:Kong的核心设计

前言

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

API网关是微服务架构的统一入口。

今天我们用C语言从零实现一个API网关的核心功能:

· 路由转发(路径匹配/域名匹配)

· 负载均衡(轮询/随机/加权)

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

· 认证鉴权(API Key/JWT)

· 请求/响应转换

· 日志记录与监控

· 插件化架构


一、API网关核心原理

  1. 架构图

```

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

│ 客户端 │

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

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

│ API网关 │

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

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

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

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

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

│ │ │

▼ ▼ ▼

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

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

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

```

  1. 核心功能

功能 说明

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

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

鉴权 API Key、JWT认证

负载均衡 轮询、随机、加权

插件 可扩展架构


二、完整代码实现

  1. 基础数据结构

```c

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <unistd.h>

#include <pthread.h>

#include <time.h>

#include <errno.h>

#include <sys/socket.h>

#include <netinet/in.h>

#include <arpa/inet.h>

#include <netdb.h>

#define MAX_ROUTES 100

#define MAX_SERVICES 100

#define MAX_PLUGINS 50

#define MAX_HEADERS 32

#define BUFFER_SIZE 65536

// 服务实例

typedef struct service_instance {

char host32;

int port;

int weight;

int healthy;

int connection_count;

time_t last_check;

struct service_instance *next;

} service_instance_t;

// 服务

typedef struct service {

char name64;

service_instance_t *instances;

int instance_count;

int lb_algorithm; // 0: round-robin, 1: random, 2: weighted

int current_index;

pthread_mutex_t mutex;

struct service *next;

} service_t;

// 路由

typedef struct route {

char path128;

char host64;

char service_name64;

int strip_path;

char rewrite_path128;

int priority;

struct route *next;

} route_t;

// 限流器

typedef struct rate_limiter {

char key128;

int rate;

int burst;

int tokens;

time_t last_update;

pthread_mutex_t mutex;

struct rate_limiter *next;

} rate_limiter_t;

// API Key认证

typedef struct api_key {

char key64;

char consumer64;

int enabled;

struct api_key *next;

} api_key_t;

// 插件上下文

typedef struct plugin_context {

char name64;

void *config;

int (*init)(void *config);

int (*exec)(struct http_request *req, void *config);

void (*destroy)(void *config);

struct plugin_context *next;

} plugin_context_t;

// HTTP请求

typedef struct http_request {

char method16;

char uri1024;

char path1024;

char query512;

char version16;

char headersMAX_HEADERS512;

int header_count;

char bodyBUFFER_SIZE;

int body_len;

char client_ip32;

char host256;

} http_request_t;

// HTTP响应

typedef struct http_response {

int status_code;

char headersMAX_HEADERS512;

int header_count;

char bodyBUFFER_SIZE;

int body_len;

} http_response_t;

// API网关

typedef struct api_gateway {

route_t *routes;

service_t *services;

rate_limiter_t *limiters;

api_key_t *api_keys;

plugin_context_t *plugins;

int port;

int running;

pthread_mutex_t mutex;

pthread_t worker_threads10;

} api_gateway_t;

```

  1. 路由管理

```c

// 创建API网关

api_gateway_t *gateway_create(int port) {

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

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

gw->port = port;

gw->running = 1;

pthread_mutex_init(&gw->mutex, NULL);

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

return gw;

}

// 添加路由

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

const char *service, int strip_path, int priority) {

pthread_mutex_lock(&gw->mutex);

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

strcpy(r->path, path);

strcpy(r->host, host);

strcpy(r->service_name, service);

r->strip_path = strip_path;

r->rewrite_path0 = '\0';

r->priority = priority;

r->next = gw->routes;

gw->routes = r;

pthread_mutex_unlock(&gw->mutex);

printf("路由 %s → %s (优先级: %d)\n", path, service, priority);

}

// 添加服务

void gateway_add_service(api_gateway_t *gw, const char *name, int lb_algorithm) {

pthread_mutex_lock(&gw->mutex);

service_t *s = malloc(sizeof(service_t));

strcpy(s->name, name);

s->instances = NULL;

s->instance_count = 0;

s->lb_algorithm = lb_algorithm;

s->current_index = 0;

pthread_mutex_init(&s->mutex, NULL);

s->next = gw->services;

gw->services = s;

pthread_mutex_unlock(&gw->mutex);

printf("服务 %s (LB: %d)\n", name, lb_algorithm);

}

// 添加服务实例

void gateway_add_instance(api_gateway_t *gw, const char *service_name,

const char *host, int port, int weight) {

service_t *s = gw->services;

while (s) {

if (strcmp(s->name, service_name) == 0) break;

s = s->next;

}

if (!s) return;

pthread_mutex_lock(&s->mutex);

service_instance_t *inst = malloc(sizeof(service_instance_t));

strcpy(inst->host, host);

inst->port = port;

inst->weight = weight;

inst->healthy = 1;

inst->connection_count = 0;

inst->last_check = time(NULL);

inst->next = s->instances;

s->instances = inst;

s->instance_count++;

pthread_mutex_unlock(&s->mutex);

printf("实例 %s → %s:%d (权重: %d)\n", service_name, host, port, weight);

}

```

  1. 负载均衡

```c

// 负载均衡选择实例

service_instance_t *lb_select(service_t *service) {

if (!service || !service->instances) return NULL;

pthread_mutex_lock(&service->mutex);

service_instance_t *selected = NULL;

int count = service->instance_count;

switch (service->lb_algorithm) {

case 0: { // Round-Robin

int idx = service->current_index % count;

service_instance_t *inst = service->instances;

for (int i = 0; i < idx && inst; i++) {

inst = inst->next;

}

if (inst && inst->healthy) selected = inst;

service->current_index++;

break;

}

case 1: { // Random

int idx = rand() % count;

service_instance_t *inst = service->instances;

for (int i = 0; i < idx && inst; i++) {

inst = inst->next;

}

if (inst && inst->healthy) selected = inst;

break;

}

case 2: { // Weighted

int total_weight = 0;

service_instance_t *inst = service->instances;

while (inst) {

if (inst->healthy) total_weight += inst->weight;

inst = inst->next;

}

if (total_weight == 0) break;

int r = rand() % total_weight;

inst = service->instances;

while (inst) {

if (inst->healthy) {

r -= inst->weight;

if (r < 0) {

selected = inst;

break;

}

}

inst = inst->next;

}

break;

}

}

if (selected) selected->connection_count++;

pthread_mutex_unlock(&service->mutex);

return selected;

}

```

  1. 限流器

```c

// 令牌桶限流

rate_limiter_t *gateway_get_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 = 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);

rl->next = gw->limiters;

gw->limiters = rl;

pthread_mutex_unlock(&gw->mutex);

return rl;

}

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;

}

```

  1. HTTP转发

```c

// 转发HTTP请求

int gateway_forward(api_gateway_t *gw, http_request_t *req, http_response_t *resp) {

// 匹配路由

route_t *route = gw->routes;

route_t *matched = NULL;

int best_priority = -1;

while (route) {

// 路径匹配

if (strncmp(req->path, route->path, strlen(route->path)) == 0) {

if (route->priority > best_priority) {

best_priority = route->priority;

matched = route;

}

}

route = route->next;

}

if (!matched) {

resp->status_code = 404;

strcpy(resp->body, "{\"error\": \"No route matched\"}");

resp->body_len = strlen(resp->body);

return 0;

}

// 查找服务

service_t *service = gw->services;

while (service) {

if (strcmp(service->name, matched->service_name) == 0) break;

service = service->next;

}

if (!service) {

resp->status_code = 503;

strcpy(resp->body, "{\"error\": \"Service not found\"}");

resp->body_len = strlen(resp->body);

return 0;

}

// 负载均衡

service_instance_t *inst = lb_select(service);

if (!inst) {

resp->status_code = 503;

strcpy(resp->body, "{\"error\": \"No healthy instances\"}");

resp->body_len = strlen(resp->body);

return 0;

}

// 构建转发请求

char forward_reqBUFFER_SIZE;

char *path_start = req->path + strlen(matched->path);

if (matched->strip_path) {

snprintf(forward_req, sizeof(forward_req), "%s %s %s\r\n",

req->method, path_start0 ? path_start : "/", req->version);

} else {

snprintf(forward_req, sizeof(forward_req), "%s %s %s\r\n",

req->method, req->path, req->version);

}

// 转发

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

struct sockaddr_in addr;

addr.sin_family = AF_INET;

addr.sin_port = htons(inst->port);

inet_pton(AF_INET, inst->host, &addr.sin_addr);

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

close(backend_fd);

resp->status_code = 502;

strcpy(resp->body, "{\"error\": \"Connection failed\"}");

resp->body_len = strlen(resp->body);

return 0;

}

send(backend_fd, forward_req, strlen(forward_req), 0);

// 发送headers和body...

send(backend_fd, req->body, req->body_len, 0);

// 接收响应

char bufferBUFFER_SIZE;

int n = recv(backend_fd, buffer, sizeof(buffer) - 1, 0);

close(backend_fd);

if (n <= 0) {

resp->status_code = 502;

strcpy(resp->body, "{\"error\": \"No response\"}");

resp->body_len = strlen(resp->body);

return 0;

}

buffern = '\0';

// 解析响应(简化)

resp->status_code = 200;

strcpy(resp->body, buffer);

resp->body_len = n;

return 0;

}

```

  1. 测试代码

```c

void test_gateway() {

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

api_gateway_t *gw = gateway_create(8080);

// 添加服务

gateway_add_service(gw, "user-service", 0);

gateway_add_instance(gw, "user-service", "127.0.0.1", 9001, 100);

gateway_add_instance(gw, "user-service", "127.0.0.1", 9002, 100);

gateway_add_service(gw, "order-service", 2);

gateway_add_instance(gw, "order-service", "127.0.0.1", 9003, 80);

gateway_add_instance(gw, "order-service", "127.0.0.1", 9004, 120);

// 添加路由

gateway_add_route(gw, "/api/users", "", "user-service", 1, 10);

gateway_add_route(gw, "/api/orders", "", "order-service", 1, 10);

gateway_add_route(gw, "/", "", "user-service", 0, 1);

// 限流器测试

rate_limiter_t *rl = gateway_get_limiter(gw, "192.168.1.100", 5, 10);

printf("\n限流测试 (10次请求, rate=5/s):\n");

int allowed = 0;

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

if (rate_limiter_allow(rl)) allowed++;

printf(" 请求%d: %s\n", i+1, rate_limiter_allow(rl) ? "允许" : "拦截");

}

printf(" 允许: %d, 拦截: %d\n", allowed, 10-allowed);

printf("\n网关启动: http://localhost:%d\n", gw->port);

free(gw);

}

int main() {

srand(time(NULL));

test_gateway();

return 0;

}

```


三、编译和运行

```bash

gcc -o api_gateway api_gateway.c -lpthread

./api_gateway

```


四、Kong vs 本实现

特性 本实现 Kong

路由 ✅ 基础 ✅ 高级

负载均衡 ✅ ✅

限流 ✅ 令牌桶 ✅ 多种

认证 ❌ ✅ 多种

插件系统 ❌ ✅ Lua

数据库配置 ❌ ✅

Admin API ❌ ✅


五、总结

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

· API网关的核心功能(路由、负载均衡、限流)

· 路由匹配和服务发现

· 负载均衡算法(轮询、随机、加权)

· 令牌桶限流器

· HTTP请求转发

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

下一篇预告:《从零实现一个分布式配置中心:Apollo的核心设计》


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

相关推荐
Tim_101 小时前
【C++】014、左值与右值的区别
开发语言·c++
想人陪的玫瑰1 小时前
winform 能用 Native AOT 吗?——TDS 项目的实战尝试
c++·mfc
^yi2 小时前
【C++】类和对象(全)
开发语言·c++
2301_777998342 小时前
C++异常处理
c++
Dovis(誓平步青云)2 小时前
《C/C+++ Boost 轻量级搜索引擎实战:架构流程、技术栈与工程落地指南——HTML文件的清洗(上篇)》
开发语言·数据库·c++·搜索引擎·开源
布朗克1682 小时前
Go 入门到精通-13-指针与内存
开发语言·c++·golang·指针与内存
问君能有几多愁~10 小时前
C++ 数据结构复习笔记
数据结构·c++·笔记
tntxia11 小时前
C++ 基础教程:从入门到精通
c++
Drone_xjw11 小时前
从 GDB 到 CDB:C/C++ 程序调试的两把“手术刀”
c语言·开发语言·c++