微服务架构下的服务发现与注册:gRPC服务治理实战
创建日期 : 2026-03-25
更新日期 : 2026-03-25
作者 : zry
标签: 微服务, 服务发现, 服务注册, gRPC, 负载均衡, 健康检查
📋 目录
引言
在微服务架构中,服务实例动态变化(扩缩容、故障迁移等),客户端无法通过硬编码地址访问服务。服务发现与注册机制解决了这一挑战,使服务间能够动态发现和通信。
本文基于AIDC项目的实践经验,介绍如何在C++中实现基于gRPC的服务治理系统。
服务治理核心概念
服务治理全景
服务治理
服务注册
服务发现
负载均衡
健康检查
熔断限流
服务提供者
服务消费者
服务注册模式
服务端注册
客户端注册
注册自己
注册
服务实例
注册中心
服务实例
Sidecar/Agent
| 模式 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 客户端注册 | 简单直接 | 业务代码侵入 | 简单应用 |
| 服务端注册 | 业务解耦 | 需额外组件 | 大规模系统 |
架构设计
AIDC服务架构
服务消费者
服务提供者
服务注册中心
注册
注册
注册
注册
发现
发现
Registry Center
Redis/etcd
aidc_web:50051
aidc_connect:50053
aidc_isos:50052
aidc_update:50054
客户端1
客户端2
数据模型
cpp
/**
* @brief 服务实例信息
*/
struct ServiceInstance {
std::string service_id; // 服务唯一ID
std::string service_name; // 服务名称
std::string host; // 主机地址
int port; // 端口号
std::string version; // 服务版本
std::map<std::string, std::string> metadata; // 元数据
// 健康状态
bool healthy = true;
int64_t last_heartbeat;
// 权重(用于负载均衡)
int weight = 100;
std::string ToEndpoint() const {
return fmt::format("{}:{}", host, port);
}
std::string ToString() const {
return fmt::format("{}@{}:{}", service_name, host, port);
}
};
/**
* @brief 服务注册信息
*/
struct ServiceRegistration {
std::string service_name;
std::vector<ServiceInstance> instances;
// 服务级别配置
std::string load_balance_strategy = "round_robin";
int health_check_interval_sec = 5;
};
服务注册中心实现
基于Redis的轻量级注册中心
cpp
/**
* @file service_registry.hpp
* @brief 服务注册中心
* @date 2026-03-25
*/
#ifndef ZRY_SERVICE_REGISTRY_HPP
#define ZRY_SERVICE_REGISTRY_HPP
#include <string>
#include <vector>
#include <map>
#include <mutex>
#include <memory>
#include <functional>
#include <chrono>
#include <json/json.h>
namespace zry::discovery {
/**
* @brief 服务注册中心接口
*/
class ServiceRegistry {
public:
virtual ~ServiceRegistry() = default;
/**
* @brief 注册服务实例
*/
virtual bool Register(const ServiceInstance& instance) = 0;
/**
* @brief 注销服务实例
*/
virtual bool Deregister(const std::string& service_id) = 0;
/**
* @brief 心跳续约
*/
virtual bool Heartbeat(const std::string& service_id) = 0;
/**
* @brief 查询服务实例
*/
virtual std::vector<ServiceInstance> Discover(const std::string& service_name) = 0;
/**
* @brief 订阅服务变更
*/
virtual void Subscribe(const std::string& service_name,
std::function<void(const std::vector<ServiceInstance>&)> callback) = 0;
/**
* @brief 取消订阅
*/
virtual void Unsubscribe(const std::string& service_name) = 0;
};
/**
* @brief 基于Redis的服务注册中心实现
*/
class RedisServiceRegistry : public ServiceRegistry {
public:
explicit RedisServiceRegistry(std::shared_ptr<RedisConnectionPool> redis_pool)
: redis_pool_(redis_pool) {}
/**
* @brief 注册服务实例
*/
bool Register(const ServiceInstance& instance) override {
auto conn = redis_pool_->GetConnection();
if (!conn) return false;
try {
// 序列化实例信息
Json::Value root;
root["service_id"] = instance.service_id;
root["service_name"] = instance.service_name;
root["host"] = instance.host;
root["port"] = instance.port;
root["version"] = instance.version;
root["weight"] = instance.weight;
root["timestamp"] = static_cast<Json::Int64>(
std::chrono::system_clock::now().time_since_epoch().count()
);
Json::StreamWriterBuilder builder;
std::string value = Json::writeString(builder, root);
// 存储到Redis
std::string key = fmt::format("service:{}", instance.service_id);
std::string service_key = fmt::format("services:{}", instance.service_name);
// 设置服务实例信息(30秒过期)
auto reply = conn->Execute("SETEX %s 30 %s", key.c_str(), value.c_str());
if (!reply) return false;
// 添加到服务集合
reply = conn->Execute("SADD %s %s", service_key.c_str(), instance.service_id.c_str());
ZRY_LOG_INFO("服务注册成功: {}", instance.ToString());
return true;
} catch (const std::exception& e) {
ZRY_LOG_ERROR("服务注册失败: {}", e.what());
return false;
}
}
/**
* @brief 注销服务
*/
bool Deregister(const std::string& service_id) override {
auto conn = redis_pool_->GetConnection();
if (!conn) return false;
try {
// 先获取服务名称
std::string key = fmt::format("service:{}", service_id);
auto reply = conn->Execute("GET %s", key.c_str());
if (reply && reply->str) {
Json::Value root = JsonTool::Parse(reply->str);
std::string service_name = JsonTool::GetString(root, "service_name");
// 从集合移除
std::string service_key = fmt::format("services:{}", service_name);
conn->Execute("SREM %s %s", service_key.c_str(), service_id.c_str());
}
// 删除实例信息
conn->Execute("DEL %s", key.c_str());
ZRY_LOG_INFO("服务注销成功: {}", service_id);
return true;
} catch (const std::exception& e) {
ZRY_LOG_ERROR("服务注销失败: {}", e.what());
return false;
}
}
/**
* @brief 心跳续约
*/
bool Heartbeat(const std::string& service_id) override {
auto conn = redis_pool_->GetConnection();
if (!conn) return false;
try {
std::string key = fmt::format("service:{}", service_id);
// 延长过期时间
auto reply = conn->Execute("EXPIRE %s 30", key.c_str());
if (reply && reply->integer == 1) {
return true;
}
// key不存在,需要重新注册
ZRY_LOG_WARN("心跳失败,服务未注册: {}", service_id);
return false;
} catch (const std::exception& e) {
ZRY_LOG_ERROR("心跳失败: {}", e.what());
return false;
}
}
/**
* @brief 发现服务
*/
std::vector<ServiceInstance> Discover(const std::string& service_name) override {
std::vector<ServiceInstance> instances;
auto conn = redis_pool_->GetConnection();
if (!conn) return instances;
try {
std::string service_key = fmt::format("services:{}", service_name);
// 获取服务实例ID列表
auto reply = conn->Execute("SMEMBERS %s", service_key.c_str());
if (!reply || reply->type != REDIS_REPLY_ARRAY) {
return instances;
}
// 获取每个实例的详细信息
for (size_t i = 0; i < reply->elements; ++i) {
std::string service_id = reply->element[i]->str;
std::string key = fmt::format("service:{}", service_id);
auto inst_reply = conn->Execute("GET %s", key.c_str());
if (inst_reply && inst_reply->str) {
auto instance = ParseInstance(inst_reply->str);
if (instance) {
instances.push_back(*instance);
}
}
}
} catch (const std::exception& e) {
ZRY_LOG_ERROR("服务发现失败: {}", e.what());
}
return instances;
}
/**
* @brief 订阅服务变更
*/
void Subscribe(const std::string& service_name,
std::function<void(const std::vector<ServiceInstance>&)> callback) override {
std::lock_guard<std::mutex> lock(callbacks_mutex_);
callbacks_[service_name] = callback;
}
void Unsubscribe(const std::string& service_name) override {
std::lock_guard<std::mutex> lock(callbacks_mutex_);
callbacks_.erase(service_name);
}
private:
std::optional<ServiceInstance> ParseInstance(const std::string& json_str) {
Json::Value root = JsonTool::Parse(json_str);
if (root.isNull()) {
return std::nullopt;
}
ServiceInstance instance;
instance.service_id = JsonTool::GetString(root, "service_id");
instance.service_name = JsonTool::GetString(root, "service_name");
instance.host = JsonTool::GetString(root, "host");
instance.port = JsonTool::GetInt(root, "port");
instance.version = JsonTool::GetString(root, "version");
instance.weight = JsonTool::GetInt(root, "weight", 100);
return instance;
}
private:
std::shared_ptr<RedisConnectionPool> redis_pool_;
std::mutex callbacks_mutex_;
std::map<std::string, std::function<void(const std::vector<ServiceInstance>&)>> callbacks_;
};
} // namespace zry::discovery
#endif // ZRY_SERVICE_REGISTRY_HPP
服务发现客户端
服务发现管理器
cpp
/**
* @file service_discovery.hpp
* @brief 服务发现客户端
*/
#ifndef ZRY_SERVICE_DISCOVERY_HPP
#define ZRY_SERVICE_DISCOVERY_HPP
#include "service_registry.hpp"
#include <grpcpp/grpcpp.h>
#include <atomic>
#include <thread>
namespace zry::discovery {
/**
* @brief gRPC通道池
*/
class GrpcChannelPool {
public:
explicit GrpcChannelPool(std::shared_ptr<ServiceRegistry> registry)
: registry_(registry) {}
/**
* @brief 获取服务通道
*/
std::shared_ptr<grpc::Channel> GetChannel(const std::string& service_name) {
std::lock_guard<std::mutex> lock(channels_mutex_);
// 检查是否有可用通道
auto it = channels_.find(service_name);
if (it != channels_.end()) {
auto state = it->second->GetState(false);
if (state == GRPC_CHANNEL_READY) {
return it->second;
}
}
// 发现服务实例
auto instances = registry_->Discover(service_name);
if (instances.empty()) {
ZRY_LOG_ERROR("未发现服务: {}", service_name);
return nullptr;
}
// 选择实例(简单轮询)
static std::atomic<size_t> index{0};
size_t idx = index++ % instances.size();
auto& instance = instances[idx];
// 创建通道
std::string target = fmt::format("{}:{}", instance.host, instance.port);
auto channel = grpc::CreateChannel(target, grpc::InsecureChannelCredentials());
// 等待连接就绪
auto deadline = std::chrono::system_clock::now() + std::chrono::seconds(5);
if (!channel->WaitForConnected(deadline)) {
ZRY_LOG_ERROR("连接服务超时: {}", target);
return nullptr;
}
channels_[service_name] = channel;
ZRY_LOG_INFO("创建服务通道: {} -> {}", service_name, target);
return channel;
}
/**
* @brief 刷新所有通道
*/
void RefreshAll() {
std::lock_guard<std::mutex> lock(channels_mutex_);
channels_.clear();
ZRY_LOG_INFO("刷新所有gRPC通道");
}
private:
std::shared_ptr<ServiceRegistry> registry_;
std::mutex channels_mutex_;
std::map<std::string, std::shared_ptr<grpc::Channel>> channels_;
};
/**
* @brief 服务注册客户端
*/
class ServiceRegistrationClient {
public:
ServiceRegistrationClient(std::shared_ptr<ServiceRegistry> registry,
const ServiceInstance& instance)
: registry_(registry), instance_(instance), running_(false) {}
/**
* @brief 启动注册和心跳
*/
void Start() {
if (running_) return;
running_ = true;
// 首次注册
if (!registry_->Register(instance_)) {
ZRY_LOG_ERROR("服务初始注册失败");
return;
}
// 启动心跳线程
heartbeat_thread_ = std::thread(&ServiceRegistrationClient::HeartbeatLoop, this);
ZRY_LOG_INFO("服务注册客户端已启动: {}", instance_.ToString());
}
/**
* @brief 停止
*/
void Stop() {
if (!running_) return;
running_ = false;
if (heartbeat_thread_.joinable()) {
heartbeat_thread_.join();
}
// 注销服务
registry_->Deregister(instance_.service_id);
ZRY_LOG_INFO("服务注册客户端已停止");
}
~ServiceRegistrationClient() {
Stop();
}
private:
void HeartbeatLoop() {
while (running_) {
// 每10秒发送一次心跳
for (int i = 0; i < 10 && running_; ++i) {
std::this_thread::sleep_for(std::chrono::seconds(1));
}
if (!running_) break;
if (!registry_->Heartbeat(instance_.service_id)) {
ZRY_LOG_WARN("心跳失败,尝试重新注册");
// 重新注册
if (!registry_->Register(instance_)) {
ZRY_LOG_ERROR("重新注册失败");
}
}
}
}
private:
std::shared_ptr<ServiceRegistry> registry_;
ServiceInstance instance_;
std::atomic<bool> running_;
std::thread heartbeat_thread_;
};
} // namespace zry::discovery
#endif // ZRY_SERVICE_DISCOVERY_HPP
负载均衡策略
负载均衡器实现
cpp
/**
* @file load_balancer.hpp
* @brief 负载均衡器
*/
#ifndef ZRY_LOAD_BALANCER_HPP
#define ZRY_LOAD_BALANCER_HPP
#include "service_registry.hpp"
#include <random>
#include <atomic>
namespace zry::discovery {
/**
* @brief 负载均衡器基类
*/
class LoadBalancer {
public:
virtual ~LoadBalancer() = default;
virtual std::optional<ServiceInstance> Select(
const std::vector<ServiceInstance>& instances) = 0;
};
/**
* @brief 轮询负载均衡
*/
class RoundRobinBalancer : public LoadBalancer {
public:
std::optional<ServiceInstance> Select(
const std::vector<ServiceInstance>& instances) override {
if (instances.empty()) {
return std::nullopt;
}
size_t idx = current_.fetch_add(1) % instances.size();
return instances[idx];
}
private:
std::atomic<size_t> current_{0};
};
/**
* @brief 随机负载均衡
*/
class RandomBalancer : public LoadBalancer {
public:
std::optional<ServiceInstance> Select(
const std::vector<ServiceInstance>& instances) override {
if (instances.empty()) {
return std::nullopt;
}
std::uniform_int_distribution<size_t> dist(0, instances.size() - 1);
return instances[dist(gen_)];
}
private:
std::random_device rd_;
std::mt19937 gen_{rd_()};
};
/**
* @brief 加权轮询负载均衡
*/
class WeightedRoundRobinBalancer : public LoadBalancer {
public:
std::optional<ServiceInstance> Select(
const std::vector<ServiceInstance>& instances) override {
if (instances.empty()) {
return std::nullopt;
}
// 计算总权重
int total_weight = 0;
for (const auto& inst : instances) {
total_weight += inst.weight;
}
// 加权选择
int target = current_.fetch_add(1) % total_weight;
int current_weight = 0;
for (const auto& inst : instances) {
current_weight += inst.weight;
if (target < current_weight) {
return inst;
}
}
return instances.back();
}
private:
std::atomic<int> current_{0};
};
/**
* @brief 最小连接数负载均衡(带健康检查)
*/
class LeastConnectionsBalancer : public LoadBalancer {
public:
std::optional<ServiceInstance> Select(
const std::vector<ServiceInstance>& instances) override {
if (instances.empty()) {
return std::nullopt;
}
// 选择连接数最少的实例(简化实现)
// 实际实现需要维护连接数统计
return instances[0];
}
};
} // namespace zry::discovery
#endif // ZRY_LOAD_BALANCER_HPP
健康检查机制
健康检查实现
cpp
/**
* @file health_checker.hpp
* @brief 健康检查器
*/
#ifndef ZRY_HEALTH_CHECKER_HPP
#define ZRY_HEALTH_CHECKER_HPP
#include "service_registry.hpp"
#include <grpcpp/health_check_service_interface.h>
namespace zry::discovery {
/**
* @brief 健康检查接口
*/
class HealthChecker {
public:
virtual ~HealthChecker() = default;
virtual bool Check(const ServiceInstance& instance) = 0;
};
/**
* @brief TCP连接健康检查
*/
class TcpHealthChecker : public HealthChecker {
public:
explicit TcpHealthChecker(int timeout_ms = 3000)
: timeout_ms_(timeout_ms) {}
bool Check(const ServiceInstance& instance) override {
// 创建TCP连接测试
int sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
return false;
}
// 设置超时
struct timeval tv;
tv.tv_sec = timeout_ms_ / 1000;
tv.tv_usec = (timeout_ms_ % 1000) * 1000;
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
// 尝试连接
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(instance.port);
inet_pton(AF_INET, instance.host.c_str(), &addr.sin_addr);
int result = connect(sock, (struct sockaddr*)&addr, sizeof(addr));
close(sock);
return result == 0;
}
private:
int timeout_ms_;
};
/**
* @brief gRPC健康检查
*/
class GrpcHealthChecker : public HealthChecker {
public:
explicit GrpcHealthChecker(int timeout_ms = 5000)
: timeout_ms_(timeout_ms) {}
bool Check(const ServiceInstance& instance) override {
std::string target = fmt::format("{}:{}", instance.host, instance.port);
auto channel = grpc::CreateChannel(target, grpc::InsecureChannelCredentials());
auto deadline = std::chrono::system_clock::now() +
std::chrono::milliseconds(timeout_ms_);
return channel->WaitForConnected(deadline);
}
private:
int timeout_ms_;
};
/**
* @brief 健康检查管理器
*/
class HealthCheckManager {
public:
explicit HealthCheckManager(std::shared_ptr<ServiceRegistry> registry)
: registry_(registry), running_(false) {}
void Start(int check_interval_sec = 10) {
if (running_) return;
running_ = true;
checker_thread_ = std::thread([this, check_interval_sec]() {
while (running_) {
PerformHealthChecks();
// 等待下次检查
for (int i = 0; i < check_interval_sec && running_; ++i) {
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
});
ZRY_LOG_INFO("健康检查管理器已启动");
}
void Stop() {
if (!running_) return;
running_ = false;
if (checker_thread_.joinable()) {
checker_thread_.join();
}
ZRY_LOG_INFO("健康检查管理器已停止");
}
void AddChecker(const std::string& service_name,
std::unique_ptr<HealthChecker> checker) {
std::lock_guard<std::mutex> lock(checkers_mutex_);
checkers_[service_name] = std::move(checker);
}
private:
void PerformHealthChecks() {
// 获取所有服务
// 对每个服务实例执行健康检查
// 更新实例健康状态
// ...
}
private:
std::shared_ptr<ServiceRegistry> registry_;
std::atomic<bool> running_;
std::thread checker_thread_;
std::mutex checkers_mutex_;
std::map<std::string, std::unique_ptr<HealthChecker>> checkers_;
};
} // namespace zry::discovery
#endif // ZRY_HEALTH_CHECKER_HPP
熔断与限流
熔断器实现
cpp
/**
* @brief 熔断器(Circuit Breaker)
*/
class CircuitBreaker {
public:
enum class State {
CLOSED, // 关闭(正常)
OPEN, // 打开(熔断)
HALF_OPEN // 半开(测试恢复)
};
struct Config {
int failure_threshold = 5; // 失败阈值
int success_threshold = 3; // 恢复成功阈值
int timeout_ms = 30000; // 熔断超时
};
explicit CircuitBreaker(const Config& config) : config_(config) {}
bool AllowRequest() {
std::lock_guard<std::mutex> lock(mutex_);
switch (state_) {
case State::CLOSED:
return true;
case State::OPEN:
if (CanAttemptReset()) {
state_ = State::HALF_OPEN;
success_count_ = 0;
return true;
}
return false;
case State::HALF_OPEN:
return true;
}
return false;
}
void RecordSuccess() {
std::lock_guard<std::mutex> lock(mutex_);
if (state_ == State::HALF_OPEN) {
success_count_++;
if (success_count_ >= config_.success_threshold) {
state_ = State::CLOSED;
failure_count_ = 0;
ZRY_LOG_INFO("熔断器关闭,服务恢复");
}
} else {
failure_count_ = 0;
}
}
void RecordFailure() {
std::lock_guard<std::mutex> lock(mutex_);
failure_count_++;
last_failure_time_ = std::chrono::steady_clock::now();
if (state_ == State::HALF_OPEN) {
state_ = State::OPEN;
ZRY_LOG_WARN("熔断器打开(半开状态失败)");
} else if (failure_count_ >= config_.failure_threshold) {
state_ = State::OPEN;
ZRY_LOG_WARN("熔断器打开(失败次数达到阈值)");
}
}
State GetState() const {
std::lock_guard<std::mutex> lock(mutex_);
return state_;
}
private:
bool CanAttemptReset() {
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::steady_clock::now() - last_failure_time_).count();
return elapsed >= config_.timeout_ms;
}
private:
Config config_;
std::atomic<State> state_{State::CLOSED};
int failure_count_ = 0;
int success_count_ = 0;
std::chrono::steady_clock::time_point last_failure_time_;
mutable std::mutex mutex_;
};
生产实践
配置示例
yaml
# service_discovery.yaml
service_registry:
type: redis
redis:
host: localhost
port: 6379
password: ""
db: 0
service_registration:
heartbeat_interval_sec: 10
ttl_sec: 30
load_balance:
default_strategy: round_robin # round_robin, random, weighted_round_robin
health_check:
enabled: true
interval_sec: 10
timeout_ms: 5000
circuit_breaker:
enabled: true
failure_threshold: 5
success_threshold: 3
timeout_ms: 30000
使用示例
cpp
/**
* @brief 服务治理使用示例
*/
void ServiceGovernanceExample() {
// 1. 创建Redis连接池
auto redis_pool = std::make_shared<RedisConnectionPool>(
"localhost", 6379, "", 10);
redis_pool->Initialize();
// 2. 创建服务注册中心
auto registry = std::make_shared<RedisServiceRegistry>(redis_pool);
// 3. 服务提供者:注册服务
ServiceInstance instance;
instance.service_id = "connect-001";
instance.service_name = "aidc_connect";
instance.host = "192.168.1.100";
instance.port = 50053;
instance.weight = 100;
ServiceRegistrationClient reg_client(registry, instance);
reg_client.Start();
// 4. 服务消费者:发现服务
GrpcChannelPool channel_pool(registry);
auto channel = channel_pool.GetChannel("aidc_connect");
if (channel) {
// 使用通道创建gRPC客户端
auto stub = DeviceService::NewStub(channel);
// ...
}
// 5. 负载均衡
auto instances = registry->Discover("aidc_connect");
WeightedRoundRobinBalancer balancer;
auto selected = balancer.Select(instances);
// 6. 熔断保护
CircuitBreaker cb({5, 3, 30000});
if (cb.AllowRequest()) {
try {
// 调用服务
CallService();
cb.RecordSuccess();
} catch (...) {
cb.RecordFailure();
}
} else {
// 熔断状态,执行降级策略
Fallback();
}
}
总结
本文详细介绍了微服务架构下的服务治理实现:
- 服务注册中心:基于Redis的轻量级实现
- 服务发现客户端:通道池、自动刷新
- 负载均衡:轮询、随机、加权策略
- 健康检查:TCP、gRPC健康检查
- 熔断限流:熔断器模式保护服务
关键设计决策
| 决策 | 选择 | 理由 |
|---|---|---|
| 注册中心 | Redis | 轻量级,已有基础设施 |
| 服务协议 | gRPC | 高性能,强类型 |
| 负载均衡 | 客户端侧 | 减少中间件依赖 |
| 健康检查 | 主动探测 | 准确检测服务状态 |
该服务治理方案已在AIDC项目中稳定运行,支撑5个微服务的动态发现和治理。
本文基于AIDC项目服务治理实践编写。