grpc实现分布式


下方实例演示一个客户端和三个服务器进行通信的分布式grpc服务

1、定义服务(proto文件)

calculator.proto:

syntax = "proto3";

service Calculator {
  rpc Add (AddRequest) returns (AddResponse);
}

message AddRequest {
  int32 a = 1;
  int32 b = 2;
}

message AddResponse {
  int32 result = 1;
}

2、生成grpc代码

使用 protoc 工具生成 C++ 的 gRPC 代码:

protoc --cpp_out=. --grpc_out=. --plugin=protoc-gen-grpc=`which grpc_cpp_plugin` calculator.proto

这将生成 calculator.pb.h, calculator.pb.cc, calculator.grpc.pb.h, 和 calculator.grpc.pb.cc 文件。

3、实现服务端

创建多个服务器实例,每个服务器监听不同的 IP 和端口。

#include <iostream>
#include <memory>
#include <string>
#include <grpcpp/grpcpp.h>
#include "calculator.grpc.pb.h"

using grpc::Server;
using grpc::ServerBuilder;
using grpc::ServerContext;
using grpc::Status;
using calculator::Calculator;
using calculator::AddRequest;
using calculator::AddResponse;

class CalculatorServiceImpl final : public Calculator::Service {
    Status Add(ServerContext* context, const AddRequest* request, AddResponse* reply) override {
        int sum = request->a() + request->b();
        reply->set_result(sum);
        return Status::OK;
    }
};

void RunServer(const std::string& server_address) {
    CalculatorServiceImpl service;
    ServerBuilder builder;

    builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
    builder.RegisterService(&service);

    std::unique_ptr<Server> server(builder.BuildAndStart());
    std::cout << "Server listening on " << server_address << std::endl;
    server->Wait();
}

int main(int argc, char** argv) {
    std::string server_address = "0.0.0.0:50051"; // 可以通过argv传入不同的端口
    if (argc > 1) {
        server_address = std::string(argv[1]);
    }
    RunServer(server_address);
    return 0;
}

编译服务器端代码并在不同端口上启动三个实例:

4、实现客户端

在客户端中,设置多个服务器端的 IP 和端口,并使用简单的轮询机制或其他负载均衡策略来分发请求。

#include <iostream>
#include <memory>
#include <string>
#include <grpcpp/grpcpp.h>
#include "calculator.grpc.pb.h"

using grpc::Channel;
using grpc::ClientContext;
using grpc::Status;
using calculator::Calculator;
using calculator::AddRequest;
using calculator::AddResponse;

class CalculatorClient {
public:
    CalculatorClient(std::shared_ptr<Channel> channel) : stub_(Calculator::NewStub(channel)) {}

    int Add(int a, int b) {
        AddRequest request;
        request.set_a(a);
        request.set_b(b);

        AddResponse response;
        ClientContext context;

        Status status = stub_->Add(&context, request, &response);

        if (status.ok()) {
            return response.result();
        } else {
            std::cout << "RPC failed" << std::endl;
            return -1;
        }
    }

private:
    std::unique_ptr<Calculator::Stub> stub_;
};

int main() {
    // 假设三个服务器的 IP 地址和端口如下
    std::vector<std::string> server_addresses = {
        "192.168.1.101:50051",
        "192.168.1.102:50052",
        "192.168.1.103:50053"
    };
    int next_server = 0;

    // 轮询机制来选择服务器
    for (int i = 0; i < 3; ++i) {
        // 创建到当前服务器的通道
        CalculatorClient client(grpc::CreateChannel(server_addresses[next_server], grpc::InsecureChannelCredentials()));

        // 发起 Add 请求
        int result = client.Add(3, 5);
        std::cout << "Add result from server " << server_addresses[next_server] << ": " << result << std::endl;

        // 轮询下一个服务器
        next_server = (next_server + 1) % server_addresses.size();
    }

    return 0;
}

服务器地址配置:在 server_addresses 向量中,列出了每个服务器的 IP 地址和端口。客户端将根据这个列表逐一连接到不同的服务器。
轮询机制:通过 next_server 的索引,客户端会轮流选择下一个服务器地址,从而将请求分发到不同的服务器实例。

5、编译和运行客户端

编译客户端代码:

g++ -std=c++11 client.cpp calculator.pb.cc calculator.grpc.pb.cc -o client -lgrpc++ -lprotobuf -lpthread

运行客户端:

./client

在这个实现中:

服务器端通过在不同的端口上启动三个实例来实现分布式。
客户端通过一个简单的轮询机制来选择服务器,依次发送请求到不同的服务器。
你可以根据需求扩展客户端的负载均衡策略,比如使用随机选择、哈希分片,或集成更复杂的服务发现和负载均衡工具。

grpc实现分布式系统的多种方式,具体选择取决于系统的需求和架构设计。

1、客户端负载均衡(一般用于选择哪一个实例)

客户端负载均衡是指在客户端进行服务实例的选择和请求的分发。客户端可以配置多个服务器地址,通过轮询、随机、哈希分片等策略,将请求分发到不同的服务器实例。
实现方式:
手动配置:客户端显式地配置多个服务器地址并自行实现负载均衡策略(如前面示例中的轮询)。
gRPC 内置负载均衡:gRPC 提供了内置的负载均衡策略,如 round_robin(轮询)和 pick_first(优选第一个可用服务器)。
DNS 负载均衡:使用 DNS 解析来获取多个服务器地址,gRPC 客户端会根据解析结果选择服务器。

2、服务发现(一般用于找到服务器实例)

服务发现系统帮助客户端动态找到可用的服务实例,而不需要在客户端硬编码服务器地址。服务发现通常与负载均衡结合使用。
实现方式:
外部服务发现工具:使用工具如 Consul、etcd、Zookeeper 等进行服务注册和发现,客户端通过查询这些服务发现系统来获取可用的服务器地址。
DNS-SRV 服务发现:一些服务发现工具支持 DNS-SRV 记录,客户端通过查询特定的 DNS-SRV 记录来获取服务实例列表。

3、代理和网关

使用代理或网关集中处理客户端请求的负载均衡、路由和服务发现。这种方式将负载均衡从客户端移到代理层,使客户端只需与单个网关或代理通信。
实现方式
Envoy Proxy:Envoy 是一种流行的 L7 代理,可以用作 gRPC 的服务网格,提供负载均衡、服务发现、熔断等功能。
gRPC Gateway:gRPC Gateway 可以作为反向代理,接收 HTTP/1.1 请求并转发给 gRPC 服务,还可以与 Envoy 结合使用。
Nginx:Nginx 也可以配置为 gRPC 的负载均衡器,处理客户端请求的分发。

4. 服务网格(Service Mesh)

服务网格是一种用于微服务架构的基础设施层,管理服务之间的通信,通常提供动态服务发现、负载均衡、流量管理、安全性等功能。
实现方式:
Istio:Istio 是一种流行的服务网格实现,可以无缝地集成 gRPC 服务,提供流量管理、负载均衡、认证授权等功能。
Linkerd:Linkerd 是另一个服务网格实现,也支持 gRPC,主要用于提高系统的可观测性、弹性和安全性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值