Microservices في C ++. خيال أم حقيقة؟

Microservices في C ++. خيال أم حقيقة؟

سأتحدث في هذه المقالة عن كيفية إنشاء قالب (مقطع ملفات تعريف الارتباط) وإعداد بيئة لكتابة خدمة REST API في لغة C++ باستخدام docker/docker-compose ومدير حزم conan.

خلال الهاكاثون التالي، الذي شاركت فيه كمطور للواجهة الخلفية، نشأ سؤال حول ما يجب استخدامه لكتابة الخدمة المصغرة التالية. كل ما كتب حتى الآن كتبه أنا وصديقي الرفيق في بايثون، نظرًا لأن زميلي كان خبيرًا في هذا المجال وقام بتطوير الواجهات الخلفية بشكل احترافي، بينما كنت بشكل عام مطور أنظمة مضمنة وكتبت بلغة C++ الرائعة والرهيبة، وقد تعلمت للتو بايثون في الجامعة.

لذلك، واجهنا مهمة كتابة خدمة عالية التحميل، وكانت المهمة الرئيسية لها هي المعالجة المسبقة للبيانات الواردة إليها وكتابتها في قاعدة البيانات. وبعد استراحة أخرى، اقترح أحد الأصدقاء أن أقوم، كمطور C++، بكتابة هذه الخدمة باستخدام المحترفين. ويجادل هذا بأن الأمر سيكون أسرع وأكثر إنتاجية، وبشكل عام، ستكون لجنة التحكيم سعيدة بكيفية معرفتنا لكيفية إدارة موارد الفريق. وأجبت عليه أنني لم أفعل مثل هذه الأشياء مطلقًا في لغة C++ ويمكنني بسهولة تخصيص ما يزيد عن 20 ساعة المتبقية للبحث عن المكتبات المناسبة وتجميعها وربطها. بكل بساطة، لقد شعرت بالخوف. هذا ما قررناه وأكملنا كل شيء في بايثون بهدوء.

الآن، أثناء العزلة الذاتية القسرية، قررت معرفة كيفية كتابة الخدمات بلغة C++. أول شيء يجب فعله هو تحديد المكتبة المناسبة. وقع خياري LITTLE، نظرًا لأنه تمت كتابته بأسلوب موجه للكائنات وكان يتباهى أيضًا بالوثائق العادية. كما نشأ السؤال حول اختيار نظام التجميع. حتى هذه اللحظة، عملت فقط مع Visual Studio وIAR والملفات المؤقتة. ولم يعجبني أي من هذه الأنظمة، لأنني خططت لتشغيل الخدمة بأكملها في حاوية إرساء. ثم قررت أن أحاول اكتشاف cmake ومدير الحزم المثير للاهتمام كونان. يسمح لك مدير الحزم هذا بتسجيل جميع التبعيات في ملف واحد

conanfile.txt
[يتطلب] بوكو/1.9.3
ليببك/11.5

[مولدات] كميك

وبأمر بسيط "conan install". تثبيت المكتبات اللازمة. وبطبيعة الحال، كان من الضروري أيضا إجراء تغييرات على

CMakeLists.txt

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

بعد ذلك، بدأت البحث عن مكتبة للعمل مع PostgreSQL، نظرًا لأنها كانت المكتبة التي لم تكن لدي خبرة كبيرة في العمل معها، وكانت أيضًا المكتبة التي تفاعلت معها خدمات Python الخاصة بنا. وهل تعرف ماذا تعلمت؟ إنه في POCO! لكن كونان لا يعرف أنه موجود في POCO ولا يعرف كيفية بنائه، يوجد ملف تكوين قديم في المستودع (لقد كتبت بالفعل عن هذا الخطأ إلى منشئي POCO). هذا يعني أنه سيتعين عليك البحث عن مكتبة أخرى.

ثم وقع اختياري على مكتبة أقل شعبية libpg. وكنت محظوظًا بشكل لا يصدق، فقد كان موجودًا بالفعل في كونان وتم تجميعه وتجميعه.

وكانت الخطوة التالية هي كتابة قالب خدمة يمكنه معالجة الطلبات.
يجب أن نرث فئة TemplateServerApp الخاصة بنا من Poco::Util::ServerApplication وتجاوز الطريقة الرئيسية.

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

في الطريقة الرئيسية يجب علينا تعيين المعلمات: المنفذ وعدد المواضيع وحجم قائمة الانتظار. والأهم من ذلك، يجب عليك تحديد معالج للطلبات الواردة. ويتم ذلك عن طريق إنشاء مصنع

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 بسيط، مثل إنشاء جدول، هناك طريقة تنفيذSQL(). بالنسبة للاستعلامات أو استرجاع البيانات الأكثر تعقيدًا، سيتعين عليك الحصول على اتصال عبر جيتكونيكشن () واستخدم واجهة برمجة تطبيقات 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 وتكوينه

.env

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

يمكنك رؤية كل الكود على جيثب.

Microservices في C ++. خيال أم حقيقة؟

والآن تأتي المرحلة الأخيرة من كتابة ملف dockerfile وdocker-compose.yml. لأكون صادقًا، استغرق هذا معظم الوقت، ليس فقط لأنني مستجد، لأنه كان من الضروري إعادة بناء المكتبات في كل مرة، ولكن بسبب مخاطر كونان. على سبيل المثال، لكي يتمكن conan من تنزيل التبعيات الضرورية وتثبيتها وبناءها، لا يكفي تنزيل "conan install ." أنت تخاطر بالحصول على مجموعة من الأخطاء في مرحلة ربط طلبك. لقد واجهت هذا الخطأ لعدة ساعات وآمل أن تساعد هذه المقالة الأشخاص الآخرين على حل هذه المشكلة في وقت أقل.

بعد ذلك، بعد كتابة docker-compose.yml، قمت بإضافة الدعم بناءً على نصيحة صديقي قطاعة البسكويت والآن يمكنك الحصول على قالب كامل لخدمة REST API في لغة C++، مع بيئة مخصصة وتثبيت PostgreSQL، وذلك ببساطة عن طريق إدخال "cookiecutter" في وحدة التحكم https://github.com/KovalevVasiliy/cpp_rest_api_template.git" ثم "إنشاء عامل الإرساء - البناء".

آمل أن يساعد هذا القالب المبتدئين في طريقهم الصعب لتطوير تطبيقات REST API بلغة رائعة وقوية، ولكن خرقاء مثل C++.
كما أنصح بشدة بالقراءة هنا هذا شرط. يشرح بمزيد من التفصيل كيفية العمل مع POCO وكتابة خدمة REST API الخاصة بك.

المصدر: www.habr.com

إضافة تعليق