میکروسرویس ها در C++. تخیلی یا واقعیت؟

میکروسرویس ها در C++. تخیلی یا واقعیت؟

در این مقاله در مورد نحوه ایجاد یک الگو (کوکی‌کاتر) و راه‌اندازی محیطی برای نوشتن یک سرویس REST API در C++ با استفاده از docker/docker-compose و مدیر بسته‌های conan صحبت خواهم کرد.

در طول هکاتون بعدی، که در آن به عنوان یک توسعه دهنده باطن شرکت کردم، این سوال مطرح شد که از چه چیزی برای نوشتن میکروسرویس بعدی استفاده کنیم. هر آنچه که تا کنون نوشته شده توسط من و من نوشته شده است رفیق در پایتون، از آنجایی که همکارم در این زمینه متخصص بود و بک‌اندها را به طور حرفه‌ای توسعه می‌داد، در حالی که من به طور کلی یک توسعه‌دهنده سیستم‌های جاسازی شده بودم و با سی پلاس پلاس عالی و وحشتناک می‌نوشتم و به تازگی پایتون را در دانشگاه یاد گرفتم.

بنابراین، ما با وظیفه نوشتن یک سرویس با بار بالا مواجه شدیم که وظیفه اصلی آن این بود که داده هایی را که به آن می رسید و نوشتن آن در پایگاه داده پیش پردازش کنیم. و پس از یک دود دیگر، یکی از دوستان به من به عنوان یک توسعه دهنده C++ پیشنهاد داد که این سرویس را با استفاده از حرفه ای ها بنویسم. استدلال این است که سریع‌تر، سازنده‌تر خواهد بود و به طور کلی، هیئت داوران از نحوه مدیریت منابع تیم خوشحال می‌شوند. که من پاسخ دادم که هرگز چنین کارهایی را در C++ انجام نداده ام و به راحتی می توانم بیش از 20 ساعت باقی مانده را به جستجو، گردآوری و پیوند کتابخانه های مناسب اختصاص دهم. به عبارت ساده تر، من از خودم جدا شدم. این چیزی است که ما در مورد آن تصمیم گرفتیم و با آرامش همه چیز را در پایتون تکمیل کردیم.

اکنون، در طول انزوای اجباری، تصمیم گرفتم نحوه نوشتن خدمات در C++ را بیابم. اولین کاری که باید انجام داد تصمیم گیری در مورد یک کتابخانه مناسب بود. انتخاب من افتاد کم، از آنجایی که به سبک شی گرا نوشته شده بود و همچنین دارای اسناد عادی بود. همچنین این سوال در مورد انتخاب سیستم مونتاژ مطرح شد. تا این لحظه من فقط با ویژوال استودیو، IAR و میک‌فایل‌های خالی کار کرده‌ام. و هیچ‌کدام از این سیستم‌ها برای من جذابیت نداشت، زیرا قصد داشتم کل سرویس را در یک داکر کانتینر اجرا کنم. سپس تصمیم گرفتم سعی کنم cmake و یک مدیر بسته جالب را پیدا کنم کانن. این مدیر بسته به شما امکان می دهد تمام وابستگی ها را در یک فایل ثبت کنید

conanfile.txt
[نیاز به]poco/1.9.3
libpq/11.5

[ژنراتور] cmake

و با یک دستور ساده "conan install ." کتابخانه های لازم را نصب کنید. طبیعتاً لازم بود تغییراتی نیز در آن ایجاد شود

CMakeLists.txt

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

پس از آن، من شروع به جستجوی کتابخانه ای برای کار با PostgreSQL کردم، زیرا این کتابخانه ای بود که تجربه کمی در کار با آن داشتم، و همچنین کتابخانه ای بود که سرویس های پایتون ما با آن تعامل داشتند. و میدونی چی یاد گرفتم؟ این در POCO است! اما Conan نمی داند که در POCO است و نمی داند چگونه آن را بسازد؛ یک فایل پیکربندی قدیمی در مخزن وجود دارد (من قبلاً در مورد این خطا برای سازندگان POCO نوشته ام). این بدان معناست که شما باید به دنبال کتابخانه دیگری باشید.

و سپس انتخاب من به یک کتابخانه کمتر محبوب افتاد libpg. و من فوق‌العاده خوش شانس بودم، قبلاً در Conan بود و حتی در حال مونتاژ و مونتاژ بود.

مرحله بعدی نوشتن یک الگوی سرویس بود که بتواند درخواست ها را پردازش کند.
ما باید کلاس TemplateServerApp خود را از Poco::Util::ServerApplication به ارث ببریم و روش اصلی را لغو کنیم.

TemplateServer App

#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;
}

در روش اصلی باید پارامترها را تنظیم کنیم: پورت، تعداد رشته ها و اندازه صف. و مهمتر از همه، شما باید یک کنترل کننده برای درخواست های دریافتی مشخص کنید. این کار با ایجاد یک کارخانه انجام می شود

TemplateRequestHandlerFactory

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

در مورد من، هر بار همان کنترلر را ایجاد می کند - TemplateServerAppHandler. اینجاست که می‌توانیم منطق کسب‌وکار خود را قرار دهیم.

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();
    }
};

من همچنین یک قالب کلاس برای کار با PostgreSQL ایجاد کردم. برای انجام SQL ساده، مانند ایجاد جدول، روشی وجود دارد ExecuteSQL(). برای پرس و جوهای پیچیده تر یا بازیابی داده ها، باید از طریق آن اتصال برقرار کنید GetConnection() و از API libpg استفاده کنید. (شاید بعداً این بی عدالتی را اصلاح کنم).

پایگاه داده

#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;
};

تمام پارامترهای اتصال به پایگاه داده از محیط گرفته شده است، بنابراین شما همچنین باید فایل .env را ایجاد و پیکربندی کنید.

.NS

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

می توانید تمام کدها را در اینجا ببینید github.

میکروسرویس ها در C++. تخیلی یا واقعیت؟

و اکنون مرحله نهایی نوشتن dockerfile و docker-compose.yml فرا می رسد. صادقانه بگویم، این کار بیشتر وقت‌ها را می‌گرفت، و نه تنها به این دلیل که من یک نواب هستم، زیرا لازم بود هر بار کتابخانه‌ها را بازسازی کنم، بلکه به دلیل مشکلات کانن. به عنوان مثال، برای اینکه conan بتواند وابستگی های لازم را دانلود، نصب و ایجاد کند، کافی نیست که "conan install ." را دانلود کند، بلکه باید پارامتر -s compiler.libcxx=libstdc++11 را نیز پاس کند، در غیر این صورت در مرحله پیوند دادن برنامه خود، خطر دریافت تعداد زیادی خطا را دارید. من چندین ساعت است که با این خطا گیر کرده ام و امیدوارم این مقاله به افراد دیگر کمک کند تا در زمان کمتری این مشکل را حل کنند.

بعد بعد از نوشتن docker-compose.yml به توصیه دوستم پشتیبانی اضافه کردم شیرینی بر و اکنون می توانید یک الگوی کامل برای یک سرویس REST API در C++، با یک محیط سفارشی شده و PostgreSQL نصب شده، به سادگی با وارد کردن "cookiecutter" در کنسول دریافت کنید. https://github.com/KovalevVasiliy/cpp_rest_api_template.git" و سپس "docker-compose up -build".

امیدوارم این الگو به مبتدیان در مسیر دشوار توسعه برنامه های REST API در زبان عالی و قدرتمند، اما چنین دست و پا چلفتی مانند C++ کمک کند.
همچنین، خواندن اینجا را به شدت توصیه می کنم این مقاله. نحوه کار با POCO و نوشتن سرویس REST API خود را با جزئیات بیشتری توضیح می دهد.

منبع: www.habr.com

اضافه کردن نظر