Por qué los microservicios C++ no se llevan bien con la red (y cómo service mesh lo soluciona)
\n\nImagine: ha construido un pipeline ideal en C++. Cada microservicio vuela, la memoria se gestiona de forma estricta y la velocidad está más allá del bien y del mal. Pero en cuanto lo ejecuta todo en Kubernetes, comienza el infierno. Timeouts, reintentos, cortes de conexión, pérdida de paquetes. Se mete en el código, inserta curl en cada rincón, escribe sus propias soluciones caseras para reintentos y el proyecto se convierte en un pantano.
¿Le suena familiar? Bienvenido al mundo de los sistemas distribuidos. La buena noticia: el problema lo resuelve service mesh. La mala: la mayoría de los tutoriales están escritos para Go o Java. ¿Y qué hacemos nosotros, los desarrolladores de C++, que no queremos arrastrar un Istio pesado con Envoy, si podemos hacer una solución ligera y comprensible?
\n\nEn este artículo, analizaremos cómo implementar service mesh para microservicios C++ sin dolor y sin dependencias innecesarias. Aprenderá qué es un proxy sidecar, cómo configurar el balanceo de carga y la observabilidad, y obtendrá un ejemplo de código real en C++ con gRPC.
\n\n¿Qué es service mesh y por qué es necesario para proyectos C++?
\n\nService mesh es una capa de infraestructura dedicada para gestionar el tráfico de red entre microservicios. En lugar de integrar la lógica de timeouts, reintentos, balanceo de carga y cifrado en cada servicio, la saca a un contenedor proxy (sidecar) que se ejecuta junto a cada instancia de su servicio.
\n\nPara C++, esto es especialmente relevante porque:
\n- \n
- El código C++ normalmente se escribe para sistemas de alta carga, donde cada microsegundo cuenta; \n
- La lógica de red integrada complica el mantenimiento y las pruebas; \n
- La biblioteca estándar de C++ no proporciona mecanismos listos para service mesh (a diferencia de Go con sus clientes HTTP estándar). \n
Componentes principales de service mesh:
\n- \n
- Data plane — servidores proxy (normalmente Envoy, pero también puede usar los suyos propios en C++); \n
- Control plane — capa de control (por ejemplo, Istio, Consul, o una solución propia). \n
Nos centraremos en el data plane, porque es aquí donde C++ muestra su fuerza.
\n\nEscribiendo nuestro propio proxy sidecar en C++ (ejemplo mínimo)
\n\nSupongamos que tenemos dos microservicios: auth_service y user_service. Se comunican mediante gRPC. Sin service mesh, cada servicio debe manejar por sí mismo las reconexiones, los timeouts y las métricas. Con un proxy, no.
Aquí hay un ejemplo mínimo de un proxy sidecar en C++ utilizando las bibliotecas libcurl y nlohmann/json. Acepta solicitudes HTTP, las redirige al backend, añade reintentos y registra las latencias.
// 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