前言
你有没有想过:在微服务架构中,几十上百个服务是怎么相互发现的?新服务上线怎么让其他服务知道?服务下线怎么通知?
服务注册中心是微服务架构的"通讯录",所有服务在这里注册和发现。
今天我们用C语言从零实现一个服务注册中心:
· 服务注册与注销
· 服务发现(拉取/推送)
· 心跳健康检查
· 服务缓存与更新
· 保护模式(防止雪崩)
· 集群同步
一、服务注册中心核心原理
- 架构图
```
┌─────────────────────────────────────────────────────────────┐
│ 服务注册中心集群 │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ 节点1 │◄─│ 节点2 │─►│ 节点3 │ │
│ │ (主) │ │ (从) │ │ (从) │ │
│ └──────┬──────┘ └─────────────┘ └─────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 服务注册表 │ │
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │
│ │ │ 服务A │ │ 服务B │ │ 服务C │ │ │
│ │ │ 实例1 │ │ 实例1 │ │ 实例1 │ │ │
│ │ │ 实例2 │ │ 实例2 │ │ 实例2 │ │ │
│ │ └──────────┘ └──────────┘ └──────────┘ │ │
│ └─────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
│ │ │
▼ ▼ ▼
┌─────────┐ ┌─────────┐ ┌─────────┐
│ 服务A │ │ 服务B │ │ 服务C │
└─────────┘ └─────────┘ └─────────┘
```
- 核心功能
功能 说明
服务注册 服务启动时注册自己
服务发现 获取其他服务地址列表
心跳检测 定期发送心跳保活
健康检查 剔除不健康实例
保护模式 防止网络抖动导致误剔除
集群同步 多节点数据一致性
二、完整代码实现
- 基础数据结构
```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>
#define MAX_SERVICE_NAME 64
#define MAX_INSTANCE_ID 128
#define MAX_HOST 32
#define MAX_METADATA 256
#define MAX_INSTANCES 1000
// 服务实例状态
typedef enum {
INSTANCE_UP = 0,
INSTANCE_DOWN,
INSTANCE_STARTING,
INSTANCE_OUT_OF_SERVICE
} instance_status_t;
// 服务实例
typedef struct service_instance {
char instance_idMAX_INSTANCE_ID;
char service_nameMAX_SERVICE_NAME;
char hostMAX_HOST;
int port;
int secure_port;
instance_status_t status;
char metadataMAX_METADATA;
time_t register_time;
time_t last_heartbeat;
time_t last_dirty_time;
int renewal_count;
struct service_instance *next;
} service_instance_t;
// 服务
typedef struct service {
char nameMAX_SERVICE_NAME;
service_instance_t *instances;
int instance_count;
struct service *next;
} service_t;
// 注册中心
typedef struct registry_center {
service_t *services;
int enable_self_preservation;
int renewal_threshold;
int renewal_percent_threshold;
pthread_mutex_t mutex;
int port;
int running;
pthread_t eviction_thread;
} registry_center_t;
```
- 核心注册逻辑
```c
// 创建注册中心
registry_center_t *registry_create(int port) {
registry_center_t *rc = malloc(sizeof(registry_center_t));
memset(rc, 0, sizeof(registry_center_t));
rc->port = port;
rc->enable_self_preservation = 1;
rc->renewal_threshold = 10;
rc->renewal_percent_threshold = 85;
rc->running = 1;
pthread_mutex_init(&rc->mutex, NULL);
printf("服务注册中心启动,端口: %d\n", port);
return rc;
}
// 生成实例ID
void generate_instance_id(const char *service_name, const char *host, int port, char *id) {
snprintf(id, MAX_INSTANCE_ID, "%s:%s:%d", service_name, host, port);
}
// 注册服务
int registry_register(registry_center_t *rc, const char *service_name,
const char *host, int port, const char *metadata) {
pthread_mutex_lock(&rc->mutex);
// 查找服务
service_t *svc = rc->services;
while (svc) {
if (strcmp(svc->name, service_name) == 0) break;
svc = svc->next;
}
if (!svc) {
svc = malloc(sizeof(service_t));
strcpy(svc->name, service_name);
svc->instances = NULL;
svc->instance_count = 0;
svc->next = rc->services;
rc->services = svc;
}
// 检查实例是否已存在
service_instance_t *inst = svc->instances;
char instance_idMAX_INSTANCE_ID;
generate_instance_id(service_name, host, port, instance_id);
while (inst) {
if (strcmp(inst->instance_id, instance_id) == 0) {
// 更新现有实例
inst->last_heartbeat = time(NULL);
inst->status = INSTANCE_UP;
pthread_mutex_unlock(&rc->mutex);
printf("注册 更新实例: %s\n", instance_id);
return 0;
}
inst = inst->next;
}
// 创建新实例
inst = malloc(sizeof(service_instance_t));
strcpy(inst->instance_id, instance_id);
strcpy(inst->service_name, service_name);
strcpy(inst->host, host);
inst->port = port;
inst->status = INSTANCE_UP;
if (metadata) strcpy(inst->metadata, metadata);
inst->register_time = time(NULL);
inst->last_heartbeat = time(NULL);
inst->last_dirty_time = 0;
inst->renewal_count = 0;
inst->next = svc->instances;
svc->instances = inst;
svc->instance_count++;
pthread_mutex_unlock(&rc->mutex);
printf("注册 新实例: %s (%s:%d)\n", service_name, host, port);
return 0;
}
// 续约(心跳)
int registry_renew(registry_center_t *rc, const char *instance_id) {
pthread_mutex_lock(&rc->mutex);
service_t *svc = rc->services;
while (svc) {
service_instance_t *inst = svc->instances;
while (inst) {
if (strcmp(inst->instance_id, instance_id) == 0) {
inst->last_heartbeat = time(NULL);
inst->renewal_count++;
pthread_mutex_unlock(&rc->mutex);
return 0;
}
inst = inst->next;
}
svc = svc->next;
}
pthread_mutex_unlock(&rc->mutex);
return -1; // 实例不存在
}
// 注销服务
int registry_cancel(registry_center_t *rc, const char *instance_id) {
pthread_mutex_lock(&rc->mutex);
service_t *svc = rc->services;
while (svc) {
service_instance_t *inst = svc->instances;
service_instance_t *prev = NULL;
while (inst) {
if (strcmp(inst->instance_id, instance_id) == 0) {
if (prev) {
prev->next = inst->next;
} else {
svc->instances = inst->next;
}
svc->instance_count--;
free(inst);
pthread_mutex_unlock(&rc->mutex);
printf("注销 实例: %s\n", instance_id);
return 0;
}
prev = inst;
inst = inst->next;
}
svc = svc->next;
}
pthread_mutex_unlock(&rc->mutex);
return -1;
}
```
- 服务发现
```c
// 获取服务实例列表
service_instance_t **registry_discover(registry_center_t *rc,
const char *service_name, int *count) {
pthread_mutex_lock(&rc->mutex);
service_t *svc = rc->services;
while (svc) {
if (strcmp(svc->name, service_name) == 0) break;
svc = svc->next;
}
if (!svc) {
*count = 0;
pthread_mutex_unlock(&rc->mutex);
return NULL;
}
// 统计UP实例
service_instance_t *inst = svc->instances;
int up_count = 0;
while (inst) {
if (inst->status == INSTANCE_UP) up_count++;
inst = inst->next;
}
if (up_count == 0) {
*count = 0;
pthread_mutex_unlock(&rc->mutex);
return NULL;
}
service_instance_t **result = malloc(sizeof(service_instance_t*) * up_count);
inst = svc->instances;
int idx = 0;
while (inst) {
if (inst->status == INSTANCE_UP) {
resultidx++ = inst;
}
inst = inst->next;
}
*count = up_count;
pthread_mutex_unlock(&rc->mutex);
return result;
}
```
- 健康检查与剔除
```c
// 剔除过期实例
void registry_evict(registry_center_t *rc) {
pthread_mutex_lock(&rc->mutex);
time_t now = time(NULL);
int evicted = 0;
int lease_expiration_duration = 90; // 90秒无心跳剔除
service_t *svc = rc->services;
while (svc) {
service_instance_t *inst = svc->instances;
service_instance_t *prev = NULL;
while (inst) {
int expired = (now - inst->last_heartbeat) > lease_expiration_duration;
// 保护模式:防止误剔除
if (expired && rc->enable_self_preservation) {
// 检查整体续约率
// 如果低于阈值,进入保护模式
// 简化:不剔除
if (rc->renewal_count < rc->renewal_threshold) {
expired = 0;
}
}
if (expired) {
inst->status = INSTANCE_DOWN;
// 从链表中移除
if (prev) {
prev->next = inst->next;
} else {
svc->instances = inst->next;
}
svc->instance_count--;
printf("剔除 过期实例: %s\n", inst->instance_id);
free(inst);
evicted++;
inst = prev ? prev->next : svc->instances;
continue;
}
prev = inst;
inst = inst->next;
}
svc = svc->next;
}
pthread_mutex_unlock(&rc->mutex);
}
// 剔除线程
void *eviction_thread(void *arg) {
registry_center_t *rc = (registry_center_t*)arg;
while (rc->running) {
sleep(60); // 每分钟检查一次
registry_evict(rc);
}
return NULL;
}
```
- 客户端SDK
```c
// 注册中心客户端
typedef struct registry_client {
char registry_hostMAX_HOST;
int registry_port;
char service_nameMAX_SERVICE_NAME;
char instance_idMAX_INSTANCE_ID;
char hostMAX_HOST;
int port;
int running;
pthread_t heartbeat_thread;
} registry_client_t;
// 创建客户端
registry_client_t *registry_client_create(const char *registry_host, int registry_port,
const char *service_name, const char *host, int port) {
registry_client_t *client = malloc(sizeof(registry_client_t));
strcpy(client->registry_host, registry_host);
client->registry_port = registry_port;
strcpy(client->service_name, service_name);
strcpy(client->host, host);
client->port = port;
client->running = 1;
generate_instance_id(service_name, host, port, client->instance_id);
return client;
}
// 注册到注册中心
int registry_client_register(registry_client_t *client) {
// 实际通过HTTP/RPC调用注册中心
printf("客户端 注册服务: %s (%s:%d)\n",
client->service_name, client->host, client->port);
return 0;
}
// 心跳线程
void *heartbeat_thread_func(void *arg) {
registry_client_t *client = (registry_client_t*)arg;
while (client->running) {
sleep(30); // 每30秒发送心跳
printf("客户端 心跳: %s\n", client->instance_id);
// 实际调用注册中心续约接口
}
return NULL;
}
// 启动客户端
void registry_client_start(registry_client_t *client) {
registry_client_register(client);
pthread_create(&client->heartbeat_thread, NULL, heartbeat_thread_func, client);
}
// 停止客户端
void registry_client_stop(registry_client_t *client) {
client->running = 0;
pthread_join(client->heartbeat_thread, NULL);
// 实际调用注册中心注销接口
printf("客户端 注销: %s\n", client->instance_id);
free(client);
}
```
- 测试代码
```c
void test_registry() {
printf("=== 服务注册中心测试 ===\n");
// 创建注册中心
registry_center_t *rc = registry_create(8761);
// 启动剔除线程
pthread_t evict_tid;
pthread_create(&evict_tid, NULL, eviction_thread, rc);
// 注册服务
registry_register(rc, "user-service", "192.168.1.10", 8080, "version=1.0");
registry_register(rc, "user-service", "192.168.1.11", 8080, "version=1.0");
registry_register(rc, "order-service", "192.168.1.20", 8080, "version=1.0");
// 续约
char id1MAX_INSTANCE_ID, id2MAX_INSTANCE_ID;
generate_instance_id("user-service", "192.168.1.10", 8080, id1);
generate_instance_id("order-service", "192.168.1.20", 8080, id2);
for (int i = 0; i < 3; i++) {
registry_renew(rc, id1);
registry_renew(rc, id2);
sleep(10);
}
// 服务发现
int count;
service_instance_t **instances = registry_discover(rc, "user-service", &count);
printf("\n=== user-service 实例 ===\n");
for (int i = 0; i < count; i++) {
printf(" %s:%d (状态: %d)\n",
instancesi->host, instancesi->port, instancesi->status);
}
free(instances);
// 模拟客户端
printf("\n=== 客户端测试 ===\n");
registry_client_t *client = registry_client_create("127.0.0.1", 8761,
"test-service", "192.168.1.100", 9090);
registry_client_start(client);
sleep(10);
registry_client_stop(client);
rc->running = 0;
pthread_join(evict_tid, NULL);
free(rc);
}
int main() {
test_registry();
return 0;
}
```
三、编译和运行
```bash
gcc -o registry registry.c -lpthread
./registry
```
四、Eureka vs Consul vs 本实现
特性 本实现 Eureka Consul
服务注册 ✅ ✅ ✅
服务发现 ✅ ✅ ✅
心跳检测 ✅ ✅ ✅
保护模式 ✅ ✅ ❌
集群同步 ❌ ✅ ✅
KV存储 ❌ ❌ ✅
健康检查 ✅ ✅ ✅
五、总结
通过这篇文章,你学会了:
· 服务注册中心的核心原理
· 服务注册与注销
· 心跳续约机制
· 健康检查与剔除
· 保护模式防止雪崩
· 客户端SDK设计
服务注册中心是微服务架构的基石。掌握它,你就理解了Spring Cloud Eureka、Consul的底层设计。
下一篇预告:《从零实现一个配置管理平台:Apollo与Nacos》
评论区分享一下你用过什么服务注册中心~