Ko te reactor I/O te ahua-katoa

Ko te reactor I/O te ahua-katoa

Whakataki

Reactor I/O (kotahi miro takahanga takahanga) he tauira mo te tuhi i nga raupaparorohiko uta nui, e whakamahia ana i roto i nga otinga rongonui maha:

I roto i tenei tuhinga, ka titiro tatou ki nga waahi me nga putanga o te reactor I/O me te pehea e mahi ai, tuhia he whakatinanatanga i raro iho i te 200 rarangi o te waehere, me te hanga i tetahi tukanga tūmau HTTP ngawari mo te 40 miriona tono / min.

Kupuhipa

  • I tuhia te tuhinga hei awhina i te mohio ki te mahi o te reactor I/O, na reira ka mohio koe ki nga raru ka whakamahia.
  • Me mohio ki nga kaupapa matua kia mohio ai koe ki te tuhinga. C reo me etahi wheako ki te whakawhanaketanga tono whatunga.
  • Kua tuhia nga waehere katoa ki te reo C kia rite ki te (tūpato: PDF roa) ki te paerewa C11 mo Linux me te waatea i runga GitHub.

He aha i tika ai tenei?

Na te piki haere o te rongonui o te Ipurangi, ka tiimata nga kaiwhakarato paetukutuku ki te hapai i te maha o nga hononga i te wa kotahi, na reira e rua nga huarahi i whakamatauhia: te aukati i te I/O i runga i te maha o nga miro OS me te kore aukati I/O me te he punaha whakamohiotanga takahanga, e kiia ana ko te "kaiwhiriwhiri punaha" (epoll/kqueue/IOCP/etc).

Ko te huarahi tuatahi ko te hanga i tetahi miro OS hou mo ia hononga taumai. Ko tana ngoikoretanga he iti noa te tauine: he maha nga mahi ka mahia e te punaha whakahaere whakawhitinga horopaki и waea pūnaha. He utu nui nga mahi ka taea te kore o te RAM kore utu me te maha o nga hononga hono.

Ko te putanga whakarerekē nga mea nui te maha o nga miro (pokau miro), na reira ka aukati i te punaha ki te whakakore i te mahi, engari i te wa ano ka puta he raru hou: mena kei te aukatihia te puna miro e nga mahi panui roa, na etahi atu turanga kua taea te whiwhi raraunga ka kore e taea. mahia.

Ka whakamahia e te huarahi tuarua pūnaha whakamohiotanga takahanga (kaiwhiriwhiri punaha) na te OS. Ka matapakihia e tenei tuhinga te momo kaikowhiri punaha tino noa, i runga i nga matohi (nga kaupapa, nga whakamohiotanga) mo te reri mo nga mahi I/O, kaua ki runga whakamohiotanga mo to ratou otinga. Ka taea te whakaatu i tetahi tauira ngawari o tana whakamahinga e te hoahoa poraka e whai ake nei:

Ko te reactor I/O te ahua-katoa

Ko te rereketanga o enei huarahi e whai ake nei:

  • Te aukati i nga mahi I/O whakatarewa rere kaiwhakamahi tae noa kikia tika te OS whakawetiweti taumai Ngā pākete IP ki te awa paita (TCP, ka whiwhi raraunga) karekau ranei e nui te mokowā kei roto i nga papaa tuhi o roto mo te tuku atu ma te NIC (te tuku raraunga).
  • Kaiwhiringa punaha i runga i te waa whakamōhio te hōtaka e te OS kua nga paatete IP kua wetewetehia (TCP, tango raraunga) he nui ranei te mokowā i roto i nga papaa tuhi o roto kua e wātea ana (tuku raraunga).

Hei whakarapopototanga, ko te rahui i te miro OS mo ia I/O he moumou mo te mana rorohiko, na te mea, karekau nga miro e mahi whai hua (no reira te kupu "rorohiko te aukati"). Ka whakatauhia e te kaikowhiri punaha tenei raru, ka taea e te hotaka kaiwhakamahi te whakamahi i nga rauemi CPU kia nui ake te ohanga.

tauira reactor I/O

Ka mahi te reactor I/O hei paparanga i waenga i te kaiwhiriwhiri punaha me te waehere kaiwhakamahi. Ko te maapono o tana mahi e whakaahuatia ana e te hoahoa poraka e whai ake nei:

Ko te reactor I/O te ahua-katoa

  • Me whakamahara ahau ki a koe ko tetahi huihuinga he panui ka taea e tetahi turanga te mahi I/O kore-aukati.
  • Ko te kaikawe takahanga he mahi e kiia ana e te reactor I/O ina tae mai he huihuinga, katahi ka mahia he mahi I/O kore-aukati.

He mea nui kia mohiohia ko te reactor I/O na roto i te whakamaramatanga o te miro kotahi, engari kaore he mea hei aukati i te ariā kia whakamahia i roto i te taiao miro-maha i te tauwehenga o te 1 miro: 1 reactor, na reira ka hangarua i nga matua CPU katoa.

Реализация

Ka waiho e matou te atanga tūmatanui ki tetahi konae reactor.h, me te whakatinanatanga - in reactor.c. reactor.h ka whai i nga panui e whai ake nei:

Whakaatuhia nga korero ki te reactor.h

typedef struct reactor Reactor;

/*
 * Указатель на функцию, которая будет вызываться I/O реактором при поступлении
 * события от системного селектора.
 */
typedef void (*Callback)(void *arg, int fd, uint32_t events);

/*
 * Возвращает `NULL` в случае ошибки, не-`NULL` указатель на `Reactor` в
 * противном случае.
 */
Reactor *reactor_new(void);

/*
 * Освобождает системный селектор, все зарегистрированные сокеты в данный момент
 * времени и сам I/O реактор.
 *
 * Следующие функции возвращают -1 в случае ошибки, 0 в случае успеха.
 */
int reactor_destroy(Reactor *reactor);

int reactor_register(const Reactor *reactor, int fd, uint32_t interest,
                     Callback callback, void *callback_arg);
int reactor_deregister(const Reactor *reactor, int fd);
int reactor_reregister(const Reactor *reactor, int fd, uint32_t interest,
                       Callback callback, void *callback_arg);

/*
 * Запускает цикл событий с тайм-аутом `timeout`.
 *
 * Эта функция передаст управление вызывающему коду если отведённое время вышло
 * или/и при отсутствии зарегистрированных сокетов.
 */
int reactor_run(const Reactor *reactor, time_t timeout);

Ko te hanganga reactor I/O ko whakaahua kōnae kaiwhiriwhiri epoll и ripanga hash GHashTable, e mahere ana ia turanga ki CallbackData (te hanganga o te kaikawe takahanga me te tohenga kaiwhakamahi mo taua mea).

Whakaatu Reactor me CallbackData

struct reactor {
    int epoll_fd;
    GHashTable *table; // (int, CallbackData)
};

typedef struct {
    Callback callback;
    void *arg;
} CallbackData;

Kia mahara kua taea e matou te kaha ki te hapai momo kore oti e ai ki te taurangi. IN reactor.h ka whakapuaki matou i te hanganga reactor, a roto reactor.c ka tautuhia e matou, na reira ka aukati i te kaiwhakamahi ki te whakarereke i ana mara. Koinei tetahi o nga tauira huna raraunga, e tika ana ki roto i nga kupu C semantics.

Nga Mahi reactor_register, reactor_deregister и reactor_reregister whakahōuhia te rārangi o ngā tūāpapa o te hiahia me ngā kaikawe takahanga e hāngai ana ki te kaikōwhiri pūnaha me te ripanga hash.

Whakaatuhia nga mahi rehitatanga

#define REACTOR_CTL(reactor, op, fd, interest)                                 
    if (epoll_ctl(reactor->epoll_fd, op, fd,                                   
                  &(struct epoll_event){.events = interest,                    
                                        .data = {.fd = fd}}) == -1) {          
        perror("epoll_ctl");                                                   
        return -1;                                                             
    }

int reactor_register(const Reactor *reactor, int fd, uint32_t interest,
                     Callback callback, void *callback_arg) {
    REACTOR_CTL(reactor, EPOLL_CTL_ADD, fd, interest)
    g_hash_table_insert(reactor->table, int_in_heap(fd),
                        callback_data_new(callback, callback_arg));
    return 0;
}

int reactor_deregister(const Reactor *reactor, int fd) {
    REACTOR_CTL(reactor, EPOLL_CTL_DEL, fd, 0)
    g_hash_table_remove(reactor->table, &fd);
    return 0;
}

int reactor_reregister(const Reactor *reactor, int fd, uint32_t interest,
                       Callback callback, void *callback_arg) {
    REACTOR_CTL(reactor, EPOLL_CTL_MOD, fd, interest)
    g_hash_table_insert(reactor->table, int_in_heap(fd),
                        callback_data_new(callback, callback_arg));
    return 0;
}

Whai muri i te haukoti a te reactor I/O i te kaupapa me te kaiwhakaahua fd, ka karangahia e ia te kaihautu takahanga e tika ana, ka tukuna atu fd, kanohi moka i hangaia nga huihuinga me tetahi tohu kaiwhakamahi ki void.

Whakaatu mahi reactor_run().

int reactor_run(const Reactor *reactor, time_t timeout) {
    int result;
    struct epoll_event *events;
    if ((events = calloc(MAX_EVENTS, sizeof(*events))) == NULL)
        abort();

    time_t start = time(NULL);

    while (true) {
        time_t passed = time(NULL) - start;
        int nfds =
            epoll_wait(reactor->epoll_fd, events, MAX_EVENTS, timeout - passed);

        switch (nfds) {
        // Ошибка
        case -1:
            perror("epoll_wait");
            result = -1;
            goto cleanup;
        // Время вышло
        case 0:
            result = 0;
            goto cleanup;
        // Успешная операция
        default:
            // Вызвать обработчиков событий
            for (int i = 0; i < nfds; i++) {
                int fd = events[i].data.fd;

                CallbackData *callback =
                    g_hash_table_lookup(reactor->table, &fd);
                callback->callback(callback->arg, fd, events[i].events);
            }
        }
    }

cleanup:
    free(events);
    return result;
}

Hei whakarāpopoto, ko te mekameka o nga waea mahi i roto i te waehere kaiwhakamahi ka whai i te ahua e whai ake nei:

Ko te reactor I/O te ahua-katoa

Tūmau miro kotahi

Hei whakamatautau i te reactor I/O i raro i te kawenga nui, ka tuhia e matou he tūmau tukutuku HTTP ngawari e whakautu ana ki tetahi tono me te ahua.

He tohutoro tere ki te kawa HTTP

HTTP - koinei te kawa taumata tono, i whakamahia tuatahi mo te taunekeneke-kaitirotiro.

Ka taea te whakamahi i te HTTP kawe waka kawa TCP, te tuku me te whiwhi karere i roto i te whakatakotoranga kua tohua whakaritenga.

Hōputu Tono

<КОМАНДА> <URI> <ВЕРСИЯ HTTP>CRLF
<ЗАГОЛОВОК 1>CRLF
<ЗАГОЛОВОК 2>CRLF
<ЗАГОЛОВОК N>CRLF CRLF
<ДАННЫЕ>

  • CRLF he raupapa o nga tohu e rua: r и n, ka wehe i te rarangi tuatahi o te tono, nga pane me nga raraunga.
  • <КОМАНДА> - tetahi o CONNECT, DELETE, GET, HEAD, OPTIONS, PATCH, POST, PUT, TRACE. Ka tukuna e te kaitirotiro he whakahau ki to maatau tūmau GET, te tikanga "Tukua mai nga ihirangi o te konae."
  • <URI> - pūtāutu rauemi kākahu. Hei tauira, ki te URI = /index.html, ka tono te kiritaki i te wharangi matua o te pae.
  • <ВЕРСИЯ HTTP> — putanga o te kawa HTTP i te whakatakotoranga HTTP/X.Y. Ko te putanga tino whakamahia i enei ra ko HTTP/1.1.
  • <ЗАГОЛОВОК N> he takirua uara matua kei te whakatakotoranga <КЛЮЧ>: <ЗНАЧЕНИЕ>, ka tukuna ki te tūmau mo te tātari anō.
  • <ДАННЫЕ> — nga raraunga e hiahiatia ana e te tūmau hei mahi i te mahi. I te nuinga o te waa he ngawari JSON tetahi atu whakatakotoranga ranei.

Hōputu Whakautu

<ВЕРСИЯ HTTP> <КОД СТАТУСА> <ОПИСАНИЕ СТАТУСА>CRLF
<ЗАГОЛОВОК 1>CRLF
<ЗАГОЛОВОК 2>CRLF
<ЗАГОЛОВОК N>CRLF CRLF
<ДАННЫЕ>

  • <КОД СТАТУСА> he tau e tohu ana i te hua o te mahi. Ka hoki tonu ta matou tūmau i te mana 200 (mahi angitu).
  • <ОПИСАНИЕ СТАТУСА> — tohu aho o te waehere mana. Mo te waehere mana 200 ko tenei OK.
  • <ЗАГОЛОВОК N> — pane o te ahua rite i roto i te tono. Ka whakahokia e matou nga taitara Content-Length (rahi kōnae) me Content-Type: text/html (momo raraunga whakahoki).
  • <ДАННЫЕ> - nga raraunga i tonohia e te kaiwhakamahi. I roto i to maatau, koinei te huarahi ki te ahua o roto HTML.

kōnae http_server.c (tūmau miro kotahi) kei roto ko te konae common.h, kei roto nga tauira mahi e whai ake nei:

Whakaatuhia nga tauira mahi i roto noa.h

/*
 * Обработчик событий, который вызовется после того, как сокет будет
 * готов принять новое соединение.
 */
static void on_accept(void *arg, int fd, uint32_t events);

/*
 * Обработчик событий, который вызовется после того, как сокет будет
 * готов отправить HTTP ответ.
 */
static void on_send(void *arg, int fd, uint32_t events);

/*
 * Обработчик событий, который вызовется после того, как сокет будет
 * готов принять часть HTTP запроса.
 */
static void on_recv(void *arg, int fd, uint32_t events);

/*
 * Переводит входящее соединение в неблокирующий режим.
 */
static void set_nonblocking(int fd);

/*
 * Печатает переданные аргументы в stderr и выходит из процесса с
 * кодом `EXIT_FAILURE`.
 */
static noreturn void fail(const char *format, ...);

/*
 * Возвращает файловый дескриптор сокета, способного принимать новые
 * TCP соединения.
 */
static int new_server(bool reuse_port);

Kei te whakaahuatia ano te tonotono mahi SAFE_CALL() a kua tautuhia te mahi fail(). Ka whakatauritehia e te tonotono te uara o te whakahuatanga me te hapa, a, ki te pono te ahuatanga, ka karangahia te mahi fail():

#define SAFE_CALL(call, error)                                                 
    do {                                                                       
        if ((call) == error) {                                                   
            fail("%s", #call);                                                 
        }                                                                      
    } while (false)

mahi fail() ka tā i ngā tohenga kua tukuna ki te kāpeka (pērā printf()) me te whakamutu i te papatono me te waehere EXIT_FAILURE:

static noreturn void fail(const char *format, ...) {
    va_list args;
    va_start(args, format);
    vfprintf(stderr, format, args);
    va_end(args);
    fprintf(stderr, ": %sn", strerror(errno));
    exit(EXIT_FAILURE);
}

mahi new_server() ka whakahoki i te kaiwhakaahua konae mo te turanga "tūmau" i hangaia e nga waea punaha socket(), bind() и listen() me te kaha ki te whakaae ki nga hononga taumai i roto i te aratau aukati-kore.

Whakaatu mahi new_server().

static int new_server(bool reuse_port) {
    int fd;
    SAFE_CALL((fd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP)),
              -1);

    if (reuse_port) {
        SAFE_CALL(
            setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &(int){1}, sizeof(int)),
            -1);
    }

    struct sockaddr_in addr = {.sin_family = AF_INET,
                               .sin_port = htons(SERVER_PORT),
                               .sin_addr = {.s_addr = inet_addr(SERVER_IPV4)},
                               .sin_zero = {0}};

    SAFE_CALL(bind(fd, (struct sockaddr *)&addr, sizeof(addr)), -1);
    SAFE_CALL(listen(fd, SERVER_BACKLOG), -1);
    return fd;
}

  • Kia mahara ko te turanga i hangaia i te tuatahi i roto i te aratau aukati-kore ma te whakamahi i te haki SOCK_NONBLOCKkia i roto i te mahi on_accept() (panui atu) waea punaha accept() kihai i mutu te mahi miro.
  • ki te reuse_port rite tonu true, na tenei mahi ka whirihora i te turanga me te whiringa SO_REUSEPORT na roto setsockopt()ki te whakamahi i taua tauranga i roto i te taiao miro-maha (tirohia te waahanga "Tumau miro-maha").

Kaiwhakahaere Takahanga on_accept() ka karangahia i muri i te mahi a te OS i tetahi huihuinga EPOLLIN, i tenei keehi ko te tikanga ka taea te whakaae ki te hononga hou. on_accept() ka whakaae ki tetahi hononga hou, ka huri ki te aratau aukati-kore me te rehita me tetahi kaihautu huihuinga on_recv() i roto i te reactor I/O.

Whakaatu mahi on_accept().

static void on_accept(void *arg, int fd, uint32_t events) {
    int incoming_conn;
    SAFE_CALL((incoming_conn = accept(fd, NULL, NULL)), -1);
    set_nonblocking(incoming_conn);
    SAFE_CALL(reactor_register(reactor, incoming_conn, EPOLLIN, on_recv,
                               request_buffer_new()),
              -1);
}

Kaiwhakahaere Takahanga on_recv() ka karangahia i muri i te mahi a te OS i tetahi huihuinga EPOLLIN, i roto i tenei take te tikanga kua rehitatia te hononga on_accept(), kua rite ki te whiwhi raraunga.

on_recv() ka panui i nga raraunga mai i te hononga kia tae ra ano te tono HTTP kia tino riro, katahi ka rehitatia he kaihautu on_send() ki te tuku urupare HTTP. Mena ka pakaru te hononga e te kiritaki, ka whakakorehia te turanga, ka kati ma te whakamahi close().

Whakaatu mahi on_recv()

static void on_recv(void *arg, int fd, uint32_t events) {
    RequestBuffer *buffer = arg;

    // Принимаем входные данные до тех пор, что recv возвратит 0 или ошибку
    ssize_t nread;
    while ((nread = recv(fd, buffer->data + buffer->size,
                         REQUEST_BUFFER_CAPACITY - buffer->size, 0)) > 0)
        buffer->size += nread;

    // Клиент оборвал соединение
    if (nread == 0) {
        SAFE_CALL(reactor_deregister(reactor, fd), -1);
        SAFE_CALL(close(fd), -1);
        request_buffer_destroy(buffer);
        return;
    }

    // read вернул ошибку, отличную от ошибки, при которой вызов заблокирует
    // поток
    if (errno != EAGAIN && errno != EWOULDBLOCK) {
        request_buffer_destroy(buffer);
        fail("read");
    }

    // Получен полный HTTP запрос от клиента. Теперь регистрируем обработчика
    // событий для отправки данных
    if (request_buffer_is_complete(buffer)) {
        request_buffer_clear(buffer);
        SAFE_CALL(reactor_reregister(reactor, fd, EPOLLOUT, on_send, buffer),
                  -1);
    }
}

Kaiwhakahaere Takahanga on_send() ka karangahia i muri i te mahi a te OS i tetahi huihuinga EPOLLOUT, te tikanga kua rehitatia te hononga on_recv(), kua rite ki te tuku raraunga. Ka tukuna e tenei mahi he whakautu HTTP kei roto HTML me tetahi ahua ki te kiritaki ka huri i te kaihautu takahanga ki te hoki on_recv().

Whakaatu mahi on_send().

static void on_send(void *arg, int fd, uint32_t events) {
    const char *content = "<img "
                          "src="https://habrastorage.org/webt/oh/wl/23/"
                          "ohwl23va3b-dioerobq_mbx4xaw.jpeg">";
    char response[1024];
    sprintf(response,
            "HTTP/1.1 200 OK" CRLF "Content-Length: %zd" CRLF "Content-Type: "
            "text/html" DOUBLE_CRLF "%s",
            strlen(content), content);

    SAFE_CALL(send(fd, response, strlen(response), 0), -1);
    SAFE_CALL(reactor_reregister(reactor, fd, EPOLLIN, on_recv, arg), -1);
}

Na ka mutu, i roto i te konae http_server.c, i roto i te mahi main() ka hangaia e matou he reactor I/O ma te whakamahi reactor_new(), hanga he turanga tūmau ka rēhitatia, tīmatahia te reactor ki te whakamahi reactor_run() mo te meneti kotahi, katahi ka tuku rauemi ka puta atu i te kaupapa.

Whakaatu http_server.c

#include "reactor.h"

static Reactor *reactor;

#include "common.h"

int main(void) {
    SAFE_CALL((reactor = reactor_new()), NULL);
    SAFE_CALL(
        reactor_register(reactor, new_server(false), EPOLLIN, on_accept, NULL),
        -1);
    SAFE_CALL(reactor_run(reactor, SERVER_TIMEOUT_MILLIS), -1);
    SAFE_CALL(reactor_destroy(reactor), -1);
}

Kia tirohia kei te mahi nga mea katoa i runga i te tumanako. Kei te whakahiato (chmod a+x compile.sh && ./compile.sh i roto i te pakiaka kaupapa) me te whakarewa i te tūmau tuhi whaiaro, tuwhera http://127.0.0.1:18470 i roto i te pūtirotiro ka kite i ta matou i tumanako ai:

Ko te reactor I/O te ahua-katoa

Te inenga mahi

Whakaatuhia aku whakaritenga waka

$ screenfetch
 MMMMMMMMMMMMMMMMMMMMMMMMMmds+.        OS: Mint 19.1 tessa
 MMm----::-://////////////oymNMd+`     Kernel: x86_64 Linux 4.15.0-20-generic
 MMd      /++                -sNMd:    Uptime: 2h 34m
 MMNso/`  dMM    `.::-. .-::.` .hMN:   Packages: 2217
 ddddMMh  dMM   :hNMNMNhNMNMNh: `NMm   Shell: bash 4.4.20
     NMm  dMM  .NMN/-+MMM+-/NMN` dMM   Resolution: 1920x1080
     NMm  dMM  -MMm  `MMM   dMM. dMM   DE: Cinnamon 4.0.10
     NMm  dMM  -MMm  `MMM   dMM. dMM   WM: Muffin
     NMm  dMM  .mmd  `mmm   yMM. dMM   WM Theme: Mint-Y-Dark (Mint-Y)
     NMm  dMM`  ..`   ...   ydm. dMM   GTK Theme: Mint-Y [GTK2/3]
     hMM- +MMd/-------...-:sdds  dMM   Icon Theme: Mint-Y
     -NMm- :hNMNNNmdddddddddy/`  dMM   Font: Noto Sans 9
      -dMNs-``-::::-------.``    dMM   CPU: Intel Core i7-6700 @ 8x 4GHz [52.0°C]
       `/dMNmy+/:-------------:/yMMM   GPU: NV136
          ./ydNMMMMMMMMMMMMMMMMMMMMM   RAM: 2544MiB / 7926MiB
             .MMMMMMMMMMMMMMMMMMM

Me ine i te mahi o te tūmau miro kotahi. Me whakatuwhera e rua nga tauranga: kotahi ka rere tatou ./http_server, i roto i tetahi atu - kaipuke. Whai muri i te meneti, ka whakaatuhia nga tatauranga e whai ake nei ki te tauranga tuarua:

$ wrk -c100 -d1m -t8 http://127.0.0.1:18470 -H "Host: 127.0.0.1:18470" -H "Accept-Language: en-US,en;q=0.5" -H "Connection: keep-alive"
Running 1m test @ http://127.0.0.1:18470
  8 threads and 100 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   493.52us   76.70us  17.31ms   89.57%
    Req/Sec    24.37k     1.81k   29.34k    68.13%
  11657769 requests in 1.00m, 1.60GB read
Requests/sec: 193974.70
Transfer/sec:     27.19MB

I taea e ta maatau tūmau miro kotahi te tukatuka neke atu i te 11 miriona tono mo ia meneti mai i nga hononga 100. Ehara i te hua kino, engari ka taea te whakapai ake?

Tūmau miro maha

Ka rite ki te korero i runga ake nei, ka taea te hanga i te reactor I/O i roto i nga miro motuhake, ma te whakamahi i nga waahanga CPU katoa. Kia whakatinanahia tenei huarahi:

Whakaatu http_server_multithreaded.c

#include "reactor.h"

static Reactor *reactor;
#pragma omp threadprivate(reactor)

#include "common.h"

int main(void) {
#pragma omp parallel
    {
        SAFE_CALL((reactor = reactor_new()), NULL);
        SAFE_CALL(reactor_register(reactor, new_server(true), EPOLLIN,
                                   on_accept, NULL),
                  -1);
        SAFE_CALL(reactor_run(reactor, SERVER_TIMEOUT_MILLIS), -1);
        SAFE_CALL(reactor_destroy(reactor), -1);
    }
}

Inaianei ia miro nona ake reactor:

static Reactor *reactor;
#pragma omp threadprivate(reactor)

Kia mahara ko te tautohe mahi new_server() tu ana true. Ko te tikanga ka tautapa tatou i te whiringa ki te turanga tūmau SO_REUSEPORTki te whakamahi i roto i te taiao miro-maha. Ka taea e koe te panui etahi atu korero konei.

Rere tuarua

Inaianei me ine i te mahinga o te tūmau miro-maha:

$ wrk -c100 -d1m -t8 http://127.0.0.1:18470 -H "Host: 127.0.0.1:18470" -H "Accept-Language: en-US,en;q=0.5" -H "Connection: keep-alive"
Running 1m test @ http://127.0.0.1:18470
  8 threads and 100 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     1.14ms    2.53ms  40.73ms   89.98%
    Req/Sec    79.98k    18.07k  154.64k    78.65%
  38208400 requests in 1.00m, 5.23GB read
Requests/sec: 635876.41
Transfer/sec:     89.14MB

Ko te maha o nga tono i tukatuka i roto i te 1 meneti i piki ake ma ~3.28 nga wa! Engari he ~XNUMX miriona noa to maatau i te tau a tawhio noa, na me ngana ki te whakatika i tera.

Tuatahi ka titiro tatou ki nga tatauranga kua mahia tino tika:

$ sudo perf stat -B -e task-clock,context-switches,cpu-migrations,page-faults,cycles,instructions,branches,branch-misses,cache-misses ./http_server_multithreaded

 Performance counter stats for './http_server_multithreaded':

     242446,314933      task-clock (msec)         #    4,000 CPUs utilized          
         1 813 074      context-switches          #    0,007 M/sec                  
             4 689      cpu-migrations            #    0,019 K/sec                  
               254      page-faults               #    0,001 K/sec                  
   895 324 830 170      cycles                    #    3,693 GHz                    
   621 378 066 808      instructions              #    0,69  insn per cycle         
   119 926 709 370      branches                  #  494,653 M/sec                  
     3 227 095 669      branch-misses             #    2,69% of all branches        
           808 664      cache-misses                                                

      60,604330670 seconds time elapsed

Te whakamahi i te PTM Affinity, whakahiato me -march=native, PGO, te pikinga o te maha o nga taia keteroki, whakanui MAX_EVENTS me te whakamahi EPOLLET kaore i tino piki ake te mahi. Engari ka aha mena ka whakanuia e koe te maha o nga hononga tukutahi?

Tatauranga mo nga hononga tukutahi 352:

$ wrk -c352 -d1m -t8 http://127.0.0.1:18470 -H "Host: 127.0.0.1:18470" -H "Accept-Language: en-US,en;q=0.5" -H "Connection: keep-alive"
Running 1m test @ http://127.0.0.1:18470
  8 threads and 352 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     2.12ms    3.79ms  68.23ms   87.49%
    Req/Sec    83.78k    12.69k  169.81k    83.59%
  40006142 requests in 1.00m, 5.48GB read
Requests/sec: 665789.26
Transfer/sec:     93.34MB

I whiwhi te hua e hiahiatia ana, me te kauwhata whakamere e whakaatu ana i te ti'aturi o te maha o nga tono tukatuka i roto i te 1 meneti i runga i te maha o nga hononga:

Ko te reactor I/O te ahua-katoa

Ka kite matou i muri i nga hononga e rua rau, ka tino heke te maha o nga tono tukatuka mo nga kaitoro e rua (i roto i te momo miro-maha ka tino kitea tenei). E pa ana tenei ki te whakatinanatanga puranga TCP/IP Linux? Tena koa ki te tuhi i o whakaaro mo tenei whanonga o te kauwhata me nga arotautanga mo nga whiringa miro-maha me nga miro kotahi i roto i nga korero.

Kia pehea te tuhia i roto i nga korero, kaore tenei whakamatautau mahi e whakaatu ana i te whanonga o te reactor I/O i raro i nga taumahatanga pono, no te mea tata tonu te mahi a te tūmau ki te pātengi raraunga, te whakaputa i nga raarangi, ka whakamahi i te tuhinga tuhi me te TLS me etahi atu, na te mea ka kore e rite te kawenga (he hihiri). Ko nga whakamatautau me nga waahanga tuatoru ka mahia i roto i te tuhinga mo te I/O proactor.

Nga ngoikoretanga o te reactor I/O

Me mohio koe ko te reactor I/O karekau he ngoikoretanga, ara:

  • Ko te whakamahi i te reactor I/O i roto i te taiao miro-maha he ahua uaua ake, na te mea me whakahaere a ringa koe i nga rerenga.
  • E whakaatu ana te parakatihi i te nuinga o te waa karekau he rite te utaina, tera pea ka uru mai tetahi miro i te wa e pukumahi ana tetahi ki te mahi.
  • Mena ka poraka tetahi kaihautu takahanga i tetahi miro, ka aukati ano te kaiwhiriwhiri punaha, tera pea ka arai nga pepeke uaua ki te kitea.

Te whakaoti i enei raruraru I/O proactor, i te nuinga o te waa he raarangi ka tohatoha i te kawenga ki te puna o nga miro, a he pai ake te API. Ka korero tatou i muri mai, i roto i taku atu tuhinga.

mutunga

I konei ka mutu to maatau haerenga mai i te ariā ki roto i te ngongo profiler.

Kaua koe e noho ki runga i tenei, na te mea he maha atu nga huarahi whakahihiri mo te tuhi rorohiko whatunga me nga taumata rereke me te tere. He mea whakamiharo, ki taku whakaaro, ko nga hononga kei raro nei.

Kia tutaki ano tatou!

Nga kaupapa whakamere

He aha atu me panui ahau?

Source: will.com

Tāpiri i te kōrero