当前位置:   article > 正文

C++ 中的微服务架构 Microservices Architecture_c++ 微服务

c++ 微服务

在这里插入图片描述

微服务架构的引入源于对传统单体应用架构的不足。在单体应用中,所有功能都集成在一个大型应用程序中,这导致系统难以维护、扩展和部署。 随着业务需求的变化和系统规模的增长,需要一种更加灵活、可扩展和可维护的架构模式来应对这些挑战。

微服务架构核心思想

  1. 服务拆分(Service Decoupling)

    微服务架构的核心侧重点之一是将大型单体应用拆分为一系列小型、独立部署的服务。每个服务都负责一个特定的业务功能,并且可以独立开发、测试、部署和扩展。

    开发团队应该根据业务功能和需求将大型单体应用拆分为一系列小型、独立部署的服务。每个服务都应该有清晰的边界和明确的责任,从而降低系统的复杂性和耦合度

  2. 松耦合(Loose Coupling)

    微服务架构鼓励服务之间的松耦合,即服务之间的依赖应该尽量降低。这使得每个服务可以独立演化和部署,而不会影响到其他服务的功能和性能。

    微服务架构中的服务之间通常通过网络进行通信,可以使用诸如RESTful API、消息队列等机制来实现服务之间的集成和通信。开发团队应该定义清晰的服务接口和通信协议,确保服务之间的可靠通信。

  3. 服务自治(Service Autonomy)

    每个微服务都应该是相对自治的,即它可以独立管理和维护,而不受其他服务的影响。这有助于降低服务之间的依赖性,提高系统的稳定性和可靠性。

    可以使用服务发现和注册中心等工具来帮助管理服务的部署和调用。同时,需要实施适当的服务治理策略,确保系统的稳定性和安全性。

  4. 分布式架构(Distributed Architecture)

    微服务架构是一种分布式架构,其中各个服务可以部署在不同的服务器、容器或云平台上。这种分布式架构可以提高系统的可伸缩性和容错性,同时降低单点故障的风险。


微服务 架构中的角色

在这里插入图片描述

在一个典型的微服务架构中,微服务之间可以分为两种角色:

  1. 服务提供者(Server): 这些微服务负责提供某些特定的服务或功能,它们是系统中的服务端。服务提供者处理来自其他服务或客户端的请求,并返回相应的结果。例如,用户管理服务、订单服务等。
  2. 服务消费者(Client): 这些微服务使用其他服务提供的功能,它们是系统中的客户端。服务消费者发出请求,调用其他服务提供者的接口,并处理接收到的响应。例如,用户界面服务、报告服务等。

在实际的微服务架构中,一个微服务可能既是服务提供者,也是服务消费者。它可能提供某些服务供其他微服务调用,并同时调用其他微服务提供的服务来完成自己的业务逻辑。这种情况下,一个微服务可能扮演着多种角色,形成复杂的服务网络。

补充

一些读者可能已经注意到微服务架构和远程过程调用(RPC)之间存在一些相似之处。接下来我们将解释它们之间的关系。

微服务架构是一种软件架构风格,通过将一个软件系统拆分为多个小型服务,这些服务通过轻量级的通信机制(例如HTTP或消息队列)相互协作。每个服务专注于单一的业务功能,可以独立部署、扩展和管理。微服务架构通过解耦服务之间的依赖关系,提高系统的灵活性和可伸缩性,简化部署和维护,帮助构建复杂的分布式系统。

而RPC是一种远程通信技术,用于不同计算机之间的通信。它允许一个进程调用另一个进程(通常在不同的机器上)的函数或方法,就像调用本地函数一样。在微服务架构中,RPC通常用于实现服务之间的同步通信,以便服务可以直接调用其他服务的功能。

综上所述,微服务是一种架构风格,描述了如何组织和设计分布式系统;而RPC则是一种技术,用于实现服务之间的通信,是微服务架构的一种实现方式之一


实现微服务的步骤

实现微服务架构的步骤在C++程序中与其他编程语言的步骤类似,主要包括以下几个方面:

  1. 确定服务边界和拆分
    • 首先,需要根据业务功能和需求确定服务的边界和拆分方式。这可以通过分析业务领域和现有的单体应用来确定,每个服务应该负责一个特定的业务功能或领域。
  2. 设计服务接口
    • 对于每个服务,需要设计清晰的接口,包括输入参数、输出结果和可能的异常情况等。在C++中,可以使用类和函数来定义服务接口,确保接口的简洁、可理解和易于使用。
  3. 实现服务功能
    • 接下来,针对每个服务的接口,需要实现具体的功能逻辑。在C++中,可以编写相应的类和函数来实现服务的功能,确保功能的正确性和效率。
  4. 服务通信和集成
    • 微服务架构中,服务之间通常通过网络进行通信。在C++中,可以使用各种网络通信库(如Boost.Asio、cpp-netlib等)来实现服务之间的通信。可以选择适合项目需求的通信协议(如HTTP、TCP、ZeroMQ等),并确保通信的稳定性和可靠性。
  5. 服务发现和治理
    • 为了管理和调用服务,需要实施服务发现和治理机制。可以使用服务注册表或服务目录等工具来帮助管理服务的部署和调用。同时,需要实施适当的服务治理策略,确保系统的稳定性和安全性。

为了更好地理解实现微服务架构的流程,让我们通过一个简单的示例来演示。我们将创建一个基于C++和ZeroMQ库的微服务,用于处理用户管理的功能。这个示例将包括服务的初始化、启动、停止以及消息的处理。

首先,我们需要确定服务边界和拆分。在我们的例子中,我们决定将用户管理功能拆分成两个服务:一个用于创建新用户,另一个用于获取用户信息。

接下来,我们设计服务接口。对于创建用户服务,我们将设计一个接受用户信息的接口,并返回新用户的ID。对于获取用户信息服务,我们将设计一个接受用户ID的接口,并返回相应的用户信息。

然后,我们实现服务功能。我们将编写C++代码来实现这两个服务的功能,确保它们正确、高效且可靠。

接着,我们需要实现服务通信和集成。我们将使用ZeroMQ库来实现服务之间的通信。在我们的示例中,我们将使用REQ/REP模式来实现请求-响应式的通信方式。

最后,我们需要实现服务发现和治理。在这个简单的示例中,我们将直接指定服务的端点(Endpoint),但在实际的项目中,可能需要使用服务注册表或服务目录来管理和调用服务。

让我们来看一下完整的示例代码,首先是主函数部分:

#include "Microservice.hpp"
#include <iostream>
#include <unordered_map> // 包含unordered_map用于保存用户信息,实际项目通常使用数据库

// 使用unordered_map来保存用户信息的简单数据库
std::unordered_map<std::string, std::string> userDatabase;

// 示例:创建用户服务
std::string createUser(const std::string& userInfo) {
    // 假设用户信息格式为 "UserID:UserName"
    std::size_t delimiterPos = userInfo.find(':');
    if (delimiterPos != std::string::npos) {
        std::string userId = userInfo.substr(0, delimiterPos);
        std::string userName = userInfo.substr(delimiterPos + 1);
        userDatabase[userId] = userName; // 将用户信息保存到内存中
        std::cout << "Creating user with ID: " << userId << " and name: " << userName << std::endl;
        std::cout << "User database size: " << userDatabase.size() << std::endl;
        // 返回保存成功的消息
        return "User created successfully";
    } else {
        return "Error: Invalid user information format";
    }
}

// 示例:获取用户信息服务
std::string getUserInfo(const std::string& userId) {
    auto it = userDatabase.find(userId);
    if (it != userDatabase.end()) {
        std::cout << "Getting user info for user with ID: " << userId << std::endl;
        // 返回相应的用户信息
        return "User info for user with ID " + userId + ": " + it->second;
    } else {
        std::cout << "User with ID " << userId << " not found" << std::endl;
        return "Error: User with ID " + userId + " not found";
    }
}

int main() {
    // 创建两个微服务实例
    Microservice createUserService("tcp://*:5555");
    Microservice getUserInfoService("tcp://*:5556");

    // 设置服务的消息处理回调函数
    createUserService.setCallback(createUser);
    getUserInfoService.setCallback(getUserInfo);

    // 启动服务
    createUserService.start();
    getUserInfoService.start();

    // 等待服务运行
    std::cout << "Services are running..." << std::endl;
    std::cin.get();

    // 停止服务
    createUserService.stop();
    getUserInfoService.stop();

    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60

在我们的示例中,主函数负责创建并启动两个微服务实例,一个用于创建用户,另一个用于获取用户信息。然后,它设置了每个服务的消息处理回调函数,并启动了这两个服务。最后,它等待用户输入以保持服务的运行,并在用户输入后停止服务。

接下来,让我们来看一下Microservice.hpp类的定义:

#ifndef MICROSERVICE_H
#define MICROSERVICE_H

#include <zmq.hpp>
#include <string>
#include <functional>
#include <thread> // 用于多线程
#include <iostream>
class Microservice {
public:
    // 构造函数,初始化 ZeroMQ 上下文和套接字,设置服务端点
    Microservice(const std::string& endpoint) : context_(1), socket_(context_, ZMQ_REP), endpoint_(endpoint) {}

    // 析构函数,关闭套接字和上下文
    ~Microservice() {
        socket_.close();
        context_.close();
    }

    // 启动服务
    void start() {
        // 绑定到指定的端点
        socket_.bind(endpoint_);

        // 创建一个线程来处理消息
        std::thread t(&Microservice::handleMessages, this);
        t.detach(); // 分离线程,使得主线程可以继续执行
    }

    // 停止服务
    void stop() {
        // 关闭套接字
        socket_.close();
    }

    // 设置消息处理回调函数
    void setCallback(std::function<std::string(const std::string&)> callback) {
        callback_ = callback;
    }

private:
    zmq::context_t context_; // ZeroMQ 上下文
    zmq::socket_t socket_;   // ZeroMQ 套接字
    std::string endpoint_;   // 服务端点
    std::function<std::string(const std::string&)> callback_; // 消息处理回调函数

    // 处理接收到的消息
    void handleMessages() {
        while (true) {
            // 接收消息
            zmq::message_t request;
            // 接收消息,并检查返回值
            zmq::recv_result_t result = socket_.recv(request, zmq::recv_flags::none);
            if (result.has_value()) {
              //   std::cout << "Received message: " << std::string(static_cast<char*>(request.data()), request.size()) << std::endl;
            } else {
                std::cout << "Error receiving message: " << zmq_strerror(zmq_errno()) << std::endl;
            }

            // 转换消息为字符串
            std::string message = std::string(static_cast<char*>(request.data()), request.size());

            std::string response;

            // 调用回调函数处理消息
            if (callback_) {
               response = callback_(message);
            }
            else {
                response = "Error: No callback function set";
            }
            zmq::message_t reply(response.size());
            memcpy(reply.data(), response.data(), response.size());
            // 发送消息,并指定发送标志为默认值
            socket_.send(reply, zmq::send_flags::none);
        }
    }
};

#endif // MICROSERVICE_H

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81

Microservice类是我们定义的一个简单的微服务类。它包含了服务的初始化、启动、停止以及消息处理等方法。在这个类中,我们使用了ZeroMQ库来实现服务之间的通信,同时提供了一个回调函数来处理接收到的消息。

最后,让我们来看一下服务消费者类的定义:

#include <zmq.hpp>
#include <string>
#include <iostream>

int main() {
    // 创建 ZeroMQ 上下文和套接字
    zmq::context_t context(1);
    zmq::socket_t socket(context, ZMQ_REQ);

    // 连接到创建用户服务
    socket.connect("tcp://localhost:5555");

    // 向创建用户服务发送请求
    std::string message = "1127:NewUsercc"; // 假设要创建的用户信息为 "UserID:UserName"
    zmq::message_t request(message.size());
    memcpy(request.data(), message.data(), message.size());
    if (!socket.send(request, zmq::send_flags::none)) { // 检查send函数的返回值
        std::cerr << "Failed to send message to create user service" << std::endl;
        return 1;
    }

    // 接收并打印创建用户服务的响应
    zmq::message_t reply;
    if (!socket.recv(reply, zmq::recv_flags::none)) { // 检查recv函数的返回值
        std::cerr << "Failed to receive reply from create user service" << std::endl;
        return 1;
    }
    std::string replyMessage = std::string(static_cast<char*>(reply.data()), reply.size());
    std::cout << "Received reply from create user service: " << replyMessage << std::endl;

    // 关闭与创建用户服务的连接
    socket.disconnect("tcp://localhost:5555");

    // 连接到获取用户信息服务
    socket.connect("tcp://localhost:5556");

    // 向获取用户信息服务发送请求
    message = "1127"; // 假设要获取的用户ID为1127
    request = zmq::message_t(message.size());
    memcpy(request.data(), message.data(), message.size());
    if (!socket.send(request, zmq::send_flags::none)) { // 检查send函数的返回值
        std::cerr << "Failed to send message to get user info service" << std::endl;
        return 1;
    }

    // 接收并打印获取用户信息服务的响应
    if (!socket.recv(reply, zmq::recv_flags::none)) { // 检查recv函数的返回值
        std::cerr << "Failed to receive reply from get user info service" << std::endl;
        return 1;
    }
    replyMessage = std::string(static_cast<char*>(reply.data()), reply.size());
    std::cout << "Received reply from get user info service: " << replyMessage << std::endl;

    // 关闭套接字和上下文
    socket.close();
    context.close();

    return 0;
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60

服务消费者类负责调用我们创建的两个微服务。它需要知道服务的端点信息以及如何发送和接收消息。在我们的示例中,服务消费者类使用ZeroMQ库来实现与微服务之间的通信,并调用相应的服务接口来完成用户的创建和获取用户信息的操作。

上述示例中,我们选择了一种简单而直接的方法来管理服务的注册和发现,即在启动时直接指定了服务的端点(Endpoint)。这种方法在实际的开发中可能并不够灵活和健壮,但对于我们的示例来说足够了。在实际项目中,根据具体需求和部署环境,您可能需要使用更复杂的服务注册和发现机制。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/844457
推荐阅读
相关标签
  

闽ICP备14008679号