Yakazara-inoratidzwa isina-C I/O reactor

Yakazara-inoratidzwa isina-C I/O reactor

Nhanganyaya

I/O reactor (single threaded chiitiko loop) inzira yekunyora yakakwira-mutoro software, inoshandiswa mumhinduro dzakawanda dzakakurumbira:

Muchikamu chino, tichatarisa ins uye kunze kweI / O reactor uye kuti inoshanda sei, nyora kushandiswa mune isingasviki mitsara ye200 yekodhi, uye ita nyore HTTP server process pamusoro pemamiriyoni makumi mana ekukumbira / min.

Foreword

  • Chinyorwa chakanyorwa kuti chibatsire kunzwisisa kushanda kweI / O reactor, uye saka kunzwisisa njodzi kana uchiishandisa.
  • Kuziva zvekutanga kunodiwa kuti unzwisise chinyorwa. C mutauro uye humwe ruzivo mukuvandudza network application.
  • Yese kodhi yakanyorwa mumutauro weC zvakanyatsoenderana ne (chenjedzo: refu PDF) kusvika kuC11 standard yeLinux uye inowanikwa pa GitHub.

Sei izvi zvichidiwa?

Nekuwedzera kukurumbira kweInternet, maseva ewebhu akatanga kuda kubata nhamba huru yekubatanidza panguva imwe chete, uye saka nzira mbiri dzakaedzwa: kuvharira I / O pane yakakura nhamba yeOS tambo uye isingavhare I/O pamwe chete. chiitiko chekuzivisa chiitiko, chinonziwo "system selector" (epoll/kqueue/IOCP/etc).

Nzira yekutanga yaisanganisira kugadzira tambo itsva yeOS kune yega yega inopinda. Kukanganisa kwayo kushata scalability: iyo inoshanda sisitimu ichafanirwa kuita akawanda shanduko yemamiriro ezvinhu и system inofona. Iwo anodhura mashandiro uye anogona kutungamira mukushaikwa kwemahara RAM ine nhamba inoshamisa yekubatanidza.

Iyo yakagadziridzwa vhezheni inosimbisa nhamba yakatarwa ye threads (thread pool), nokudaro kudzivirira hurongwa kubva pakubvisa kuurayiwa, asi panguva imwe chete kuunza dambudziko idzva: kana tambo dziva ikozvino yakavharwa nekushanda kwenguva refu kuverenga, saka mamwe masokisi anenge atokwanisa kugamuchira data haazokwanisi. ita saizvozvo.

Nzira yechipiri inoshandisa chiitiko chekuzivisa system (system selector) yakapihwa neOS. Ichi chinyorwa chinokurukura nezve yakajairika mhando yekusarudza sisitimu, zvichibva pane ziviso (zviitiko, zviziviso) nezve kugadzirira kweI/O mashandiro, pane zviziviso nezve kupera kwavo. Muenzaniso wakareruka wekushandiswa kwayo unogona kumiririrwa neinotevera block diagram:

Yakazara-inoratidzwa isina-C I/O reactor

Musiyano uripo pakati pemaitiro aya ndeokuti:

  • Kuvharisa I/O mashandiro kumisa mushandisi kuyerera kusvikirakusvikira OS yakwana defragments inouya IP mapaketi kuenda kurwizi (TCP, kugamuchira data) kana hakuzove nenzvimbo yakakwana inowanikwa mukati mekunyora mabuffers kuti utumire unotevera kuburikidza NIC (kutumira data).
  • Sistimu yekusarudza kupfuuridza nguva inozivisa chirongwa icho OS kare defragmented IP packets (TCP, reception data) kana nzvimbo yakakwana mumabhafa ekunyora emukati kare iripo (kutumira data).

Kuzvipedzisa, kuchengetedza OS tambo yeI/O yega yega kutambisa simba rekombuta, nekuti muchokwadi, tambo hadzisi kuita basa rinobatsira (saka izwi iri. "kukanganisa software") Iyo yekusarudza sisitimu inogadzirisa dambudziko iri, ichibvumira mushandisi chirongwa kushandisa CPU zviwanikwa zvakanyanya mune hupfumi.

I/O reactor modhi

Iyo I / O reactor inoita senge dhizaini pakati peanosarudza sisitimu uye kodhi yemushandisi. Nheyo yekushanda kwayo inotsanangurwa neinotevera block diagraph:

Yakazara-inoratidzwa isina-C I/O reactor

  • Rega ndikuyeuchidze kuti chiitiko chiziviso chekuti imwe soketi inokwanisa kuita isingavhare I / O oparesheni.
  • Mubati wechiitiko ibasa rinodanwa neI/O reactor kana chiitiko chagamuchirwa, icho chinozoita chisingavharidzi I/O oparesheni.

Zvakakosha kuziva kuti iyo I/O reactor iri netsanangudzo ine shinda imwe chete, asi hapana chinomisa pfungwa kuti isashandiswe munzvimbo ine tambo dzakawanda pachiyero che1 thread: 1 reactor, nekudaro ichidzokorodza ese CPU cores.

Kutevedzera

Isu tichaisa iyo yeruzhinji interface mufaira reactor.h, uye kuita - in reactor.c. reactor.h ichave nezviziviso zvinotevera:

Ratidza zviziviso mureactor.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);

Iyo I/O reactor chimiro chine file descriptor selector epoll и hash tables GHashTable, iyo inoratidzira soketi imwe neimwe CallbackData (chimiro chemuiti wechiitiko uye nharo yemushandisi nokuda kwayo).

Ratidza Reactor uye CallbackData

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

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

Ndapota cherechedza kuti takagonesa kukwanisa kubata rudzi rusina kukwana maererano nendekisi. IN reactor.h tinozivisa chimiro reactor, uye mukati reactor.c tinozvitsanangura, nokudaro tichidzivirira mushandisi kuti asanyatso kushandura minda yayo. Iyi ndeimwe yemhando kuvanza data, iyo inonyatsokwana muC semantics.

Mabasa reactor_register, reactor_deregister и reactor_reregister gadziridza rondedzero yezvigadziko zvekufarira uye inoenderana chiitiko vanobata mune sisitimu yekusarudza uye hashi tafura.

Ratidza mabasa ekunyoresa

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

Mushure mekunge I/O reactor yabata chiitiko netsananguro fd, inodana chibatiso chechiitiko chinoenderana, kwainopfuudza fd, bit mask dzakagadzirwa zviitiko uye mushandisi chinongedzo kune void.

Ratidza reactor_run () basa

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

Kupfupisa, iyo ketani yebasa rekufona mune mushandisi kodhi inotora inotevera fomu:

Yakazara-inoratidzwa isina-C I/O reactor

Single threaded server

Kuti uedze iyo I / O reactor pasi pemutoro wakakwira, isu tichanyora iri nyore HTTP web server inopindura kune chero chikumbiro chine mufananidzo.

Chirevo chekukurumidza kune HTTP protocol

HTTP - iyi ndiyo protocol application level, inonyanya kushandiswa kune server-browser kusangana.

HTTP inogona kushandiswa nyore nyore pamusoro transport protocol TCP, kutumira uye kugamuchira mameseji muchimiro chakataurwa tsanangudzo.

Request Format

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

  • CRLF kutevedzana kwemavara maviri: r и n, kuparadzanisa mutsara wekutanga wekukumbira, misoro uye data.
  • <КОМАНДА> - imwe ye CONNECT, DELETE, GET, HEAD, OPTIONS, PATCH, POST, PUT, TRACE. Iyo browser inotumira murairo kune server yedu GET, zvichireva kuti "Nditumirewo zviri mufaira racho."
  • <URI> - yunifomu resource identifier. Somuenzaniso, kana URI = /index.html, ipapo mutengi anokumbira peji huru yesaiti.
  • <ВЕРСИЯ HTTP> - vhezheni yeHTTP protocol mune iyo fomati HTTP/X.Y. Iyo inonyanya kushandiswa shanduro nhasi ndeye HTTP/1.1.
  • <ЗАГОЛОВОК N> iri kiyi-value peya mufomati <КЛЮЧ>: <ЗНАЧЕНИЕ>, yakatumirwa kuseva kuti iwedzere kuongororwa.
  • <ДАННЫЕ> - data inodiwa neserver kuita oparesheni. Kazhinji zviri nyore JSON kana chero imwe fomu.

Response Format

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

  • <КОД СТАТУСА> inhamba inomiririra mhedzisiro yekushanda. Sevha yedu inogara ichidzorera chimiro 200 (kushanda kwakabudirira).
  • <ОПИСАНИЕ СТАТУСА> - tambo inomiririra yekodhi yemamiriro. Yechimiro kodhi 200 iyi OK.
  • <ЗАГОЛОВОК N> - musoro weiyo fomati yakafanana neyekukumbira. Tichadzorera mazita Content-Length (saizi yefaira) uye Content-Type: text/html (dzosa rudzi rwe data).
  • <ДАННЫЕ> - data yakakumbirwa nemushandisi. Muchiitiko chedu, iyi ndiyo nzira inoenda kumufananidzo mukati HTML.

faira http_server.c (single threaded server) inosanganisira faira common.h, iyo ine zvinotevera basa prototypes:

Ratidza basa prototypes zvakafanana.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);

Iyo inoshanda macro inotsanangurwa zvakare SAFE_CALL() uye basa racho rinotsanangurwa fail(). Iyo macro inofananidza kukosha kwekutaura nekanganiso, uye kana mamiriro acho ari echokwadi, anodana basa fail():

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

shanda fail() inodhinda nharo dzakapfuura kune terminal (se printf()) uye inogumisa purogiramu nekodhi 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);
}

shanda new_server() inodzosera iyo faira tsananguro ye "server" socket yakagadzirwa nehurongwa hwekufona socket(), bind() и listen() uye inokwanisa kugamuchira zvinongedzo zvinopinda mune isiri-blocking mode.

Ratidza new_server() basa

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

  • Ziva kuti socket yakatanga kugadzirwa mune isiri-blocking mode uchishandisa mureza SOCK_NONBLOCKkuitira kuti mubasa on_accept() (verenga zvakawanda) system call accept() haina kumisa kuuraya kweshinda.
  • kana reuse_port yakaenzana true, ipapo basa iri richagadzirisa socket ine sarudzo SO_REUSEPORT kuburikidza setsockopt()kushandisa chiteshi chimwe chete munzvimbo ine tambo dzakawanda (ona chikamu "Multi-threaded server").

Chiitiko Handler on_accept() inodanwa mushure mekunge OS yagadzira chiitiko EPOLLIN, munyaya iyi zvinoreva kuti kubatana kutsva kunogona kugamuchirwa. on_accept() inogamuchira chinongedzo chitsva, chinochichinjisa kune chisiri-yekuvharisa modhi uye inonyoresa nemuiti wechiitiko on_recv() muI/O reactor.

Ratidza pa_kugamuchira () basa

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

Chiitiko Handler on_recv() inodanwa mushure mekunge OS yagadzira chiitiko EPOLLIN, muchiitiko ichi zvinoreva kuti kubatana kwakanyoreswa on_accept(), yakagadzirira kugamuchira data.

on_recv() inoverenga data kubva pakubatanidza kusvika chikumbiro cheHTTP chagamuchirwa zvachose, ipapo inonyoresa mubati on_send() kutumira mhinduro yeHTTP. Kana mutengi akatyora chinongedzo, socket inodzimwa uye yakavharwa uchishandisa close().

Ratidza basa pa_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);
    }
}

Chiitiko Handler on_send() inodanwa mushure mekunge OS yagadzira chiitiko EPOLLOUT, zvichireva kuti kubatana kwakanyoreswa on_recv(), yakagadzirira kutumira data. Iri basa rinotumira mhinduro yeHTTP ine HTML ine mufananidzo kune mutengi uyezve inoshandura chiitiko chibatiso kudzokera on_recv().

Ratidza pa_send () basa

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

Uye pakupedzisira, mufaira http_server.c, mubasa main() tinogadzira I/O reactor tichishandisa reactor_new(), gadzira socket ye server uye uinyore, tanga reactor uchishandisa reactor_run() kweminiti imwe chete, tobva taburitsa zviwanikwa tobuda muchirongwa.

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

Ngatitarisei kuti zvese zviri kushanda sezvazvinotarisirwa. Kuunganidza (chmod a+x compile.sh && ./compile.sh mumudzi weprojekiti) uye tanga iyo-yakanyorwa sevha, vhura http://127.0.0.1:18470 mubrowser uye ona zvataitarisira:

Yakazara-inoratidzwa isina-C I/O reactor

Kuyera kwekuita

Ratidza zvinodikanwa zvemota yangu

$ 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

Ngatiyere kuita kwesevha ine tambo imwe chete. Ngativhure materminals maviri: mune imwe tichamhanya ./http_server, mune zvakasiyana- wrk. Mushure meminiti, nhamba dzinotevera dzicharatidzwa mune yechipiri terminal:

$ 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

Sevha yedu ine tambo imwe chete yakakwanisa kugadzirisa zvinopfuura 11 miriyoni zvikumbiro paminiti zvichibva ku100 kubatana. Kwete mhedzisiro yakaipa, asi inogona kuvandudzwa here?

Multithreaded server

Sezvambotaurwa pamusoro, iyo I / O reactor inogona kugadzirwa mune dzakasiyana tambo, nekudaro uchishandisa ese CPU cores. Ngatishandise nzira iyi mukuita:

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

Iye zvino thread yese ane yake reactor:

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

Ndokumbira utarise kuti iyo basa nharo new_server() vatsigiri true. Izvi zvinoreva kuti isu tinopa sarudzo kune server socket SO_REUSEPORTkuishandisa munzvimbo ine tambo dzakawanda. Unogona kuverenga mamwe mashoko pano.

Kumhanya kechipiri

Zvino ngatiyera kuita kwesevha ine tambo dzakawanda:

$ 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

Nhamba yezvikumbiro zvakagadziriswa muminiti 1 yakawedzera ne ~ 3.28 nguva! Asi isu taingova ~ XNUMX miriyoni pfupi yenhamba yakatenderedza, saka ngatiedze kugadzirisa izvo.

Kutanga ngatitarisei nhamba dzakagadzirwa zvakakwana:

$ 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

Kushandisa CPU Affinity, kubatanidza ne -march=native, PGO, kuwedzera kwenhamba yekurova cache, kuwedzera MAX_EVENTS uye kushandisa EPOLLET haina kupa kuwedzera kukuru kwekuita. Asi chii chinoitika kana iwe ukawedzera nhamba yekubatanidza panguva imwe chete?

Nhamba dze 352 zvinongedzo panguva imwe chete:

$ 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

Mhedzisiro yaidiwa yakawanikwa, uye nayo inonakidza girafu inoratidza kutsamira kwenhamba yezvikumbiro zvakagadziriswa muminiti 1 pahuwandu hwekubatanidza:

Yakazara-inoratidzwa isina-C I/O reactor

Isu tinoona kuti mushure memazana mashoma ekubatanidza, nhamba yezvikumbiro zvakagadziriswa zvemasevha ese ari maviri inodonha zvakanyanya (mune-multi-threaded vhezheni izvi zvinonyanya kuoneka). Izvi zvine chekuita neLinux TCP/IP stack kuita? Inzwa wakasununguka kunyora fungidziro yako nezve maitiro aya egirafu uye optimizations kune akawanda-akarukwa uye ane tambo imwe chete sarudzo mune zvakataurwa.

sei noted mune zvakataurwa, iyi bvunzo yekuita hairatidze maitiro eI / O reactor pasi pemitoro chaiyo, nekuti kanenge nguva dzese sevha inodyidzana nedatabase, inoburitsa matanda, inoshandisa cryptography ne. TLS nezvimwewo, semugumisiro wekuti mutoro unova usina kufanana (simba). Miedzo pamwe chete neyechitatu-bato zvikamu zvichaitwa muchinyorwa nezve I/O proactor.

Zvakaipa zveI/O reactor

Iwe unofanirwa kunzwisisa kuti iyo I / O reactor haina zvipingamupinyi zvayo, zvinoti:

  • Kushandisa I/O reactor munzvimbo ine tambo dzakawanda kwakatooma, nekuti iwe uchafanirwa kugadzirisa nemaoko kuyerera.
  • Kudzidzira kunoratidza kuti muzviitiko zvizhinji mutoro wacho hauna kufanana, izvo zvinogona kutungamirira kune imwe tambo yekutema apo imwe iri kubatikana nebasa.
  • Kana mumwe mugadziri wechiitiko akavhara tambo, ipapo iyo system yekusarudza pachayo inovharisa, izvo zvinogona kutungamirira kune zvakaoma-ku-kuwana-zvipembenene.

Anogadzirisa matambudziko aya Ini/O mutambi, iyo inowanzove ine scheduler inogovera zvakaenzana mutoro kune dziva reshinda, uye ine zvakare iri nyore API. Tichazotaura nezvazvo gare gare, mune chimwe chinyorwa changu.

mhedziso

Apa ndipo pakasvika rwendo rwedu kubva padzidziso yakananga kuprofiler exhaust.

Iwe haufanirwe kugara pane izvi, nekuti kune dzimwe dzakawanda dzakaenzana dzinonakidza nzira dzekunyora network software ine mazinga akasiyana ekureruka uye kumhanya. Zvinonakidza, mumaonero angu, zvinongedzo zvinopihwa pazasi.

Ndichakuona zvakare!

Mapurojekiti anonakidza

Chii chimwe chandinofanira kuverenga?

Source: www.habr.com

Voeg