欢迎光临
我们一直在努力

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

前言

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

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

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

· 路由转发(路径匹配/域名匹配)
· 负载均衡(轮询/随机/加权)
· 限流器(令牌桶/漏桶)
· 认证鉴权(API Key/JWT)
· 请求/响应转换
· 日志记录与监控
· 插件化架构

一、API网关核心原理

1. 架构图

```
┌─────────────────────────────────────────────────────────────┐
│                        客户端                               │
└─────────────────────────────────────────────────────────────┘
                            │
                            ▼
┌─────────────────────────────────────────────────────────────┐
│                      API网关                                │
│  ┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐      │
│  │ 路由    │→│ 限流    │→│ 鉴权    │→│ 转发    │      │
│  │ 匹配    │  │ 检查    │  │ 认证    │  │ 请求    │      │
│  └─────────┘  └─────────┘  └─────────┘  └─────────┘      │
└─────────────────────────────────────────────────────────────┘
          │              │              │
          ▼              ▼              ▼
    ┌─────────┐    ┌─────────┐    ┌─────────┐
    │ 服务A   │    │ 服务B   │    │ 服务C   │
    └─────────┘    └─────────┘    └─────────┘
```

2. 核心功能

功能 说明
路由 根据路径/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 host[32];
    int port;
    int weight;
    int healthy;
    int connection_count;
    time_t last_check;
    struct service_instance *next;
} service_instance_t;

// 服务
typedef struct service {
    char name[64];
    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 path[128];
    char host[64];
    char service_name[64];
    int strip_path;
    char rewrite_path[128];
    int priority;
    struct route *next;
} route_t;

// 限流器
typedef struct rate_limiter {
    char key[128];
    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 key[64];
    char consumer[64];
    int enabled;
    struct api_key *next;
} api_key_t;

// 插件上下文
typedef struct plugin_context {
    char name[64];
    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 method[16];
    char uri[1024];
    char path[1024];
    char query[512];
    char version[16];
    char headers[MAX_HEADERS][512];
    int header_count;
    char body[BUFFER_SIZE];
    int body_len;
    char client_ip[32];
    char host[256];
} http_request_t;

// HTTP响应
typedef struct http_response {
    int status_code;
    char headers[MAX_HEADERS][512];
    int header_count;
    char body[BUFFER_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_threads[10];
} api_gateway_t;
```

2. 路由管理

```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_path[0] = '\\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);
}
```

3. 负载均衡

```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;
}
```

4. 限流器

```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;
}
```

5. 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_req[BUFFER_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_start[0] ? 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 buffer[BUFFER_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;
    }
    buffer[n] = '\\0';
    
    // 解析响应(简化)
    resp->status_code = 200;
    strcpy(resp->body, buffer);
    resp->body_len = n;
    
    return 0;
}
```

6. 测试代码

```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网关的理解~

赞(0)
未经允许不得转载:171主机测评 » 从零实现一个API网关:Kong的核心设计
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址