Por que microsserviços C++ não se dão bem com a rede (e como o service mesh corrige isso)
\n\nImagine: você construiu um pipeline ideal em C++. Cada microsserviço voa, a memória é gerenciada rigidamente e a velocidade está além do bem e do mal. Mas assim que você executa tudo isso no Kubernetes, começa o inferno. Timeouts, retentativas, quedas de conexão, perda de pacotes. Você mexe no código, insere curl em cada canto, escreve suas próprias soluções caseiras para retentativas — e o projeto se transforma em um pântano.
Familiar? Bem-vindo ao mundo dos sistemas distribuídos. A boa notícia: o problema é resolvido pelo service mesh. A má notícia: a maioria dos tutoriais é escrita para Go ou Java. E o que nós, desenvolvedores C++, que não queremos arrastar um Istio pesado com Envoy, podemos fazer se pudermos criar uma solução leve e compreensível?
\n\nNeste artigo, vamos abordar como implementar service mesh para microsserviços C++ sem dor e dependências desnecessárias. Você aprenderá o que é um proxy sidecar, como configurar balanceamento e observabilidade, e obterá um exemplo real de código em C++ com gRPC.
\n\nO que é service mesh e por que ele é necessário para projetos C++?
\n\nService mesh é uma camada de infraestrutura dedicada para gerenciar o tráfego de rede entre microsserviços. Em vez de incorporar a lógica de timeouts, retentativas, balanceamento e criptografia em cada serviço, você a coloca em um contêiner proxy (sidecar) que é executado ao lado de cada instância do seu serviço.
\n\nPara C++, isso é especialmente relevante porque:
\n- \n
- O código C++ geralmente é escrito para sistemas de alta carga, onde cada microssegundo conta; \n
- A lógica de rede embutida complica a manutenção e os testes; \n
- A biblioteca padrão do C++ não fornece mecanismos prontos para service mesh (ao contrário do Go com seus clientes HTTP padrão). \n
Componentes principais do service mesh:
\n- \n
- Data plane — servidores proxy (geralmente Envoy, mas você pode usar os seus próprios em C++); \n
- Control plane — camada de gerenciamento (por exemplo, Istio, Consul ou algo personalizado). \n
Vamos nos concentrar no data plane, porque é aqui que o C++ mostra sua força.
\n\nEscrevendo seu próprio proxy sidecar em C++ (exemplo mínimo)
\n\nSuponha que temos dois microsserviços: auth_service e user_service. Eles se comunicam via gRPC. Sem service mesh, cada serviço precisa lidar com reconexões, timeouts e métricas por conta própria. Com o proxy — não.
Aqui está um exemplo mínimo de um proxy sidecar em C++ usando as bibliotecas libcurl e nlohmann/json. Ele recebe requisições HTTP, as proxy para o backend, adiciona retentativas e registra as latências.
// proxy.cpp\n#include <httplib.h>\n#include <nlohmann/json.hpp>\n#include <curl/curl.h>\n#include <chrono>\n#include <thread>\n\nusing json = nlohmann::json;\nusing namespace std::chrono_literals;\n\nclass SidecarProxy {\npublic:\n SidecarProxy(const std::string& backend_host, int backend_port, int max_retries = 3)\n : backend_host_(backend_host), backend_port_(backend_port), max_retries_(max_retries) {}\n\n void handle_request(const httplib::Request& req, httplib::Response& res) {\n auto start = std::chrono::high_resolution_clock::now();\n CURL* curl = curl_easy_init();\n std::string url = "http://" + backend_host_ + ":" + std::to_string(backend_port_) + req.path;\n curl_easy_setopt(curl, CURLOPT_URL, url.c_str());\n curl_easy_setopt(curl, CURLOPT_TIMEOUT, 5L);\n\n std::string response_string;\n curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, +[](void* ptr, size_t size, size_t nmemb, void* stream) {\n ((std::string*)stream)->append((char*)ptr, size * nmemb);\n return size * nmemb;\n });\n curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_string);\n\n int retries = 0;\n CURLcode code;\n d