Microserveis en C++. Ficció o realitat?

Microserveis en C++. Ficció o realitat?

En aquest article parlaré de com vaig crear una plantilla (cookiecutter) i configurar un entorn per escriure un servei d'API REST en C++ mitjançant docker/docker-compose i el gestor de paquets conan.

Durant el següent hackathon, en què vaig participar com a desenvolupador de backend, va sorgir la pregunta sobre què utilitzar per escriure el proper microservei. Tot el que s'ha escrit fins ara ho hem escrit jo i la meva camarada a Python, ja que el meu col·lega era un expert en aquest camp i desenvolupava professionalment backends, mentre que generalment era un desenvolupador de sistemes integrats i escrivia en el gran i terrible C++, i acabo d'aprendre Python a la universitat.

Per tant, ens vam enfrontar a la tasca d'escriure un servei d'alta càrrega, la tasca principal del qual era preprocessar les dades que hi arribaven i escriure-les a la base de dades. I després d'una altra pausa per fumar, un amic em va suggerir que jo, com a desenvolupador de C++, escrivia aquest servei fent servir els professionals. Argumentant això és que serà més ràpid, més productiu i, en general, el jurat estarà encantat de com sabem gestionar els recursos de l'equip. A la qual cosa vaig respondre que mai havia fet aquestes coses en C++ i que podia dedicar fàcilment les 20 hores restants a cercar, compilar i enllaçar biblioteques adequades. En poques paraules, em vaig quedar malament. Això és el que vam decidir i ho vam completar amb calma tot a Python.

Ara, durant l'autoaïllament forçat, vaig decidir esbrinar com escriure serveis en C++. El primer que cal fer va ser decidir una biblioteca adequada. La meva elecció va caure POC, ja que estava escrit en un estil orientat a objectes i també comptava amb una documentació normal. A més, va sorgir la pregunta sobre l'elecció d'un sistema de muntatge. Fins ara només he treballat amb Visual Studio, IAR i makefiles nus. I cap d'aquests sistemes em va agradar, ja que tenia previst executar tot el servei en un contenidor docker. Llavors vaig decidir intentar esbrinar cmake i un gestor de paquets interessant Conan. Aquest gestor de paquets us va permetre registrar totes les dependències en un sol fitxer

conanfile.txt
[requereix]poco/1.9.3
libpq/11.5

[generadors] cmake

i amb una senzilla comanda "conan install". instal·lar les biblioteques necessàries. Naturalment, també calia fer-hi canvis

CMakeLists.txt

include(build/conanbuildinfo.cmake)
conan_basic_setup()
target_link_libraries(<target_name> ${CONAN_LIBS})

Després d'això, vaig començar a buscar una biblioteca per treballar amb PostgreSQL, ja que era amb la qual tenia poca experiència treballant, i també amb la qual interactuaven els nostres serveis Python. I saps què vaig aprendre? És a POCO! Però en Conan no sap que està a POCO i no sap com construir-lo; hi ha un fitxer de configuració obsolet al repositori (ja he escrit sobre aquest error als creadors de POCO). Això vol dir que hauràs de buscar una altra biblioteca.

I després la meva elecció va recaure en una biblioteca menys popular libpg. I vaig tenir una sort increïble, ja estava en conan i fins i tot s'estava muntant i muntant.

El següent pas va ser escriure una plantilla de servei que pugui processar les sol·licituds.
Hem d'heretar la nostra classe TemplateServerApp de Poco::Util::ServerApplication i anul·lar el mètode principal.

TemplateServerApp

#pragma once

#include <string>
#include <vector>
#include <Poco/Util/ServerApplication.h>

class TemplateServerApp : public Poco::Util::ServerApplication
{
    protected:
        int main(const std::vector<std::string> &);
};

int TemplateServerApp::main(const vector<string> &)
{
    HTTPServerParams* pParams = new HTTPServerParams;

    pParams->setMaxQueued(100);
    pParams->setMaxThreads(16);

    HTTPServer s(new TemplateRequestHandlerFactory, ServerSocket(8000), pParams);

    s.start();
    cerr << "Server started" << endl;

    waitForTerminationRequest();  // wait for CTRL-C or kill

    cerr << "Shutting down..." << endl;
    s.stop();

    return Application::EXIT_OK;
}

En el mètode principal hem d'establir els paràmetres: port, nombre de fils i mida de la cua. I el més important, heu d'especificar un gestor per a les sol·licituds entrants. Això es fa creant una fàbrica

TemplateRequestHandlerFactory

class TemplateRequestHandlerFactory : public HTTPRequestHandlerFactory
{
public:
    virtual HTTPRequestHandler* createRequestHandler(const HTTPServerRequest & request)
    {
        return new TemplateServerAppHandler;
    }
};

En el meu cas, simplement crea el mateix controlador cada vegada: TemplateServerAppHandler. Aquí és on podem situar la nostra lògica empresarial.

TemplateServerAppHandler

class TemplateServerAppHandler : public HTTPRequestHandler
{
public:
    void handleRequest(HTTPServerRequest &req, HTTPServerResponse &resp)
    {
        URI uri(req.getURI());
        string method = req.getMethod();

        cerr << "URI: " << uri.toString() << endl;
        cerr << "Method: " << req.getMethod() << endl;

        StringTokenizer tokenizer(uri.getPath(), "/", StringTokenizer::TOK_TRIM);
        HTMLForm form(req,req.stream());

        if(!method.compare("POST"))
        {
            cerr << "POST" << endl;
        }
        else if(!method.compare("PUT"))
        {
            cerr << "PUT" << endl;
        }
        else if(!method.compare("DELETE"))
        {
            cerr << "DELETE" << endl;
        }

        resp.setStatus(HTTPResponse::HTTP_OK);
        resp.setContentType("application/json");
        ostream& out = resp.send();

        out << "{"hello":"heh"}" << endl;
        out.flush();
    }
};

També vaig crear una plantilla de classe per treballar amb PostgreSQL. Per realitzar un SQL senzill, com ara crear una taula, hi ha un mètode ExecuteSQL(). Per a consultes més complexes o recuperació de dades, haureu d'obtenir una connexió via GetConnection() i utilitzeu l'API libpg. (Potser més endavant corregiré aquesta injustícia).

Base de dades

#pragma once

#include <memory>
#include <mutex>
#include <libpq-fe.h>

class Database
{
public:
    Database();
    std::shared_ptr<PGconn> GetConnection() const;
    bool ExecuteSQL(const std::string& sql);

private:
    void establish_connection();
    void LoadEnvVariables();

    std::string m_dbhost;
    int         m_dbport;
    std::string m_dbname;
    std::string m_dbuser;
    std::string m_dbpass;

    std::shared_ptr<PGconn>  m_connection;
};

Tots els paràmetres per connectar-se a la base de dades s'han extret de l'entorn, de manera que també cal crear i configurar el fitxer .env

.NS

DATABASE_NAME=template
DATABASE_USER=user
DATABASE_PASSWORD=password
DATABASE_HOST=postgres
DATABASE_PORT=5432

Podeu veure tot el codi a github.

Microserveis en C++. Ficció o realitat?

I ara arriba l'etapa final d'escriptura del fitxer dockerfile i docker-compose.yml. Sincerament, això va portar la major part del temps, i no només perquè sóc un noob, perquè era necessari reconstruir les biblioteques cada vegada, sinó per les trampes de Conan. Per exemple, perquè conan descarregui, instal·li i creï les dependències necessàries, no n'hi ha prou amb descarregar "conan install .", també ha de passar el paràmetre -s compiler.libcxx=libstdc++11, en cas contrari. corre el risc d'obtenir un munt d'errors en l'etapa d'enllaç de la vostra aplicació. He estat enganxat amb aquest error durant diverses hores i espero que aquest article ajudi altres persones a resoldre aquest problema en menys temps.

A continuació, després d'escriure docker-compose.yml, per consell del meu amic, vaig afegir suport tallador de galetes i ara podeu aconseguir una plantilla completa per a un servei d'API REST en C++, amb un entorn personalitzat i PostgreSQL instal·lat, simplement introduint "cookiecutter" a la consola https://github.com/KovalevVasiliy/cpp_rest_api_template.git" I després "docker-compose up -build".

Espero que aquesta plantilla ajudi els principiants en el seu difícil camí de desenvolupar aplicacions de l'API REST en un llenguatge fantàstic i potent, però tan maldestre com el C++.
A més, recomano molt llegir aquí això article. S'explica amb més detall com treballar amb POCO i escriure el vostre propi servei d'API REST.

Font: www.habr.com

Afegeix comentari