Igwe ihe eji eme ihe efu-C I/O nwere njiri mara zuru oke

Igwe ihe eji eme ihe efu-C I/O nwere njiri mara zuru oke

Okwu Mmalite

I/O reactor (otu eri loop omume) bụ ụkpụrụ maka ide sọftụwia dị elu, nke ejiri n'ọtụtụ ngwọta ewu ewu:

N'isiokwu a, anyị ga-eleba anya na ins na outs nke I / O reactor na otú o si arụ ọrụ, dee mmejuputa na-erughị 200 ahịrị nke koodu, na-eme ka ihe nkesa HTTP dị mfe karịa 40 nde arịrịọ / min.

Okwu mmalite

  • Edere akụkọ ahụ iji nyere aka ịghọta ọrụ nke reactor I/O, yabụ ghọta ihe egwu dị mgbe ị na-eji ya.
  • A chọrọ ihe ọmụma nke ihe ndị bụ isi iji ghọta isiokwu ahụ. C asụsụ na ụfọdụ ahụmahụ na mmepe ngwa netwọk.
  • Edere koodu niile n'asụsụ C nke ọma dịka (ịkpachara anya: ogologo PDF) ruo C11 ọkọlọtọ maka Linux ma dị na GitHub.

Gịnị mere nke a ji dị mkpa?

Site na mgbasawanye nke ịntanetị na-eto eto, sava weebụ malitere mkpa ijikwa ọnụ ọgụgụ dị ukwuu nke njikọ n'otu oge, ya mere a nwalere ụzọ abụọ: igbochi I / O na ọnụ ọgụgụ dị ukwuu nke eriri OS na ndị na-adịghị egbochi I / O jikọtara ya na ya. usoro ngosi mmemme, nke a na-akpọkwa “system selector” (epoll/kwue/IOCP/ wdg).

Ụzọ mbụ gụnyere ịmepụta eriri OS ọhụrụ maka njikọ ọ bụla na-abata. Ọdịmma ya bụ scalability na-adịghị mma: sistemụ arụmọrụ ga-emerịrị ọtụtụ ntụgharị ọnọdụ и oku usoro. Ha na-arụ ọrụ dị oke ọnụ ma nwee ike ibute enweghị RAM n'efu yana ọnụọgụ njikọ dị egwu.

Ụdị gbanwegharịrị na-egosipụta ọnụ ọgụgụ a kapịrị ọnụ nke eri (ọdọ mmiri nke eriri), si otú ahụ na-egbochi usoro ahụ site na nkwụsị nke igbu egbu, ma n'otu oge ahụ na-ebute nsogbu ọhụrụ: ọ bụrụ na a na-egbochi ọdọ mmiri eri ugbu a site na ogologo ọrụ na-agụ ogologo oge, mgbe ahụ, oghere ndị ọzọ nwere ike ịnweta data agaghị enwe ike. mee ya.

Usoro nke abụọ na-eji usoro ngosi omume (onye na-ahọpụta sistemụ) nke OS nyere. Isiokwu a na-atụle ụdị onye na-ahọrọ usoro a na-ahụkarị, dabere na ọkwa (ihe omume, ọkwa) gbasara njikere maka ọrụ I / O, kama na ozi gbasara mmecha ha. Enwere ike ịnọchite anya ihe atụ dị mfe nke iji ya site na eserese ngọngọ ndị a:

Igwe ihe eji eme ihe efu-C I/O nwere njiri mara zuru oke

Ihe dị iche n'etiti ụzọ ndị a bụ ndị a:

  • Na-egbochi ọrụ I/O kwụsịtụ onye ọrụ eruba ruo mgberuo mgbe OS dị mma defragments na-abata IP ngwugwu na iyi byte (TCP, ịnata data) ma ọ bụ agaghị enwe ohere zuru oke na nchekwa ederede nke ime maka izipu na-esote site na Ọ DỊGHỊ (na-eziga data).
  • Nhọrọ sistemu oge n'aga na-agwa mmemme na OS ama Ihe ngwugwu IP defragmented (TCP, nnabata data) ma ọ bụ ohere zuru oke na nchekwa ederede ime ama dị (na-eziga data).

N'ịchịkọta ya, idobe eriri OS maka I / O ọ bụla bụ ihe efu nke ike kọmputa, n'ihi na n'eziokwu, eriri anaghị arụ ọrụ bara uru (ya mere okwu ahụ. "software nkwụsịtụ"). Onye na-ahọrọ sistemụ na-edozi nsogbu a, na-ekwe ka mmemme onye ọrụ jiri akụrụngwa CPU mee ihe n'ụzọ akụ na ụba.

I/O reactor nlereanya

The I/O reactor na-arụ ọrụ dị ka oyi akwa n'etiti onye na-ahọrọ sistemụ na koodu njirimara. A kọwara ụkpụrụ nke ọrụ ya site na eserese ngọngọ ndị a:

Igwe ihe eji eme ihe efu-C I/O nwere njiri mara zuru oke

  • Ka m chetara gị na mmemme bụ ngosi na ụfọdụ oghere nwere ike ịrụ ọrụ I/O anaghị egbochi.
  • Onye na-ahụ maka mmemme bụ ọrụ nke I/O reactor na-akpọ mgbe anatara mmemme, nke na-arụ ọrụ I/O anaghị egbochi.

Ọ dị mkpa iburu n'obi na reactor I / O bụ site na nkọwa otu-threaded, mana ọ nweghị ihe na-egbochi echiche ahụ iji mee ihe na mpaghara multi-threaded na nha nke 1 eri: 1 reactor, si otú ahụ na-emegharị ihe niile CPU cores.

Mmejuputa iwu

Anyị ga-etinye interface ọha na faịlụ reactor.h, na mmejuputa iwu-na reactor.c. reactor.h ga-enwe ọkwa ndị a:

Gosi nkwupụta na 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);

The I/O reactor Ọdịdị mejupụtara onye na-akọwa faịlụ onye nhọpụta epoll и tebụl hash GHashTable, nke maapụ oghere ọ bụla na CallbackData (nhazi nke onye njikwa ihe omume na arụmụka onye ọrụ maka ya).

Gosi Reactor na CallbackData

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

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

Biko mara na anyị enyela ikike ijikwa ya ụdị ezughị ezu dị ka index. N'ime reactor.h anyị na-ekwupụta nhazi ahụ reactor, na n’ime reactor.c anyị kọwapụtara ya, si otú a na-egbochi onye ọrụ ịgbanwe mpaghara ya n'ụzọ doro anya. Nke a bụ otu n'ime ụkpụrụ na-ezo data, nke dabara nkenke na semantics C.

Ọrụ reactor_register, reactor_deregister и reactor_reregister melite ndepụta oghere nke mmasị na ndị na-ahụ maka ihe omume kwekọrọ na onye na-ahọrọ sistemụ na tebụl hash.

Gosi ọrụ ndebanye aha

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

Mgbe reactor I/O ejirila onye nkọwa mechie ihe omume ahụ fd, ọ na-akpọ onye njikwa ihe omume kwekọrọ, nke ọ na-agafe fd, bit nkpuchi emepụtara emume na ntụnye onye ọrụ ka void.

Gosi ọrụ 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;
}

Iji chịkọta ọnụ, usoro oku ọrụ na koodu njirimara ga-ewere ụdị a:

Igwe ihe eji eme ihe efu-C I/O nwere njiri mara zuru oke

Otu ihe nkesa eri eri

Iji nwalee reactor I/O n'okpuru nnukwu ibu, anyị ga-ede sava weebụ HTTP dị mfe nke na-aza arịrịọ ọ bụla na onyonyo.

Ntụ aka ngwa ngwa na protocol HTTP

Http - Nke a bụ protocol ngwa ngwa, nke a na-ejikarị emekọrịta ihe nkesa na ihe nchọgharị.

Enwere ike iji HTTP mee ihe ngwa ngwa njem protocol TCP, izipu na ịnata ozi n'ụdị akọwapụtara nkọwapụta.

Ụdị arịrịọ

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

  • CRLF bụ usoro mkpụrụedemede abụọ: r и n, na-ekewa akara mbụ nke arịrịọ, nkụnye eji isi mee na data.
  • <КОМАНДА> - otu n'ime CONNECT, DELETE, GET, HEAD, OPTIONS, PATCH, POST, PUT, TRACE. Ihe nchọgharị ahụ ga-ezigara sava anyị iwu GET, nke pụtara "Zitere m ọdịnaya nke faịlụ ahụ."
  • <URI> - edo akụrụngwa nchọpụta. Dịka ọmụmaatụ, ọ bụrụ URI = /index.html, mgbe ahụ onye ahịa rịọrọ isi peeji nke saịtị ahụ.
  • <ВЕРСИЯ HTTP> - ụdị nke protocol HTTP n'ụdị HTTP/X.Y. Ụdị nke a na-ejikarị eme ihe taa bụ HTTP/1.1.
  • <ЗАГОЛОВОК N> bụ ụzọ igodo-uru na usoro <КЛЮЧ>: <ЗНАЧЕНИЕ>, ezigara na ihe nkesa maka nyocha ọzọ.
  • <ДАННЫЕ> - data nke ihe nkesa chọrọ iji rụọ ọrụ ahụ. Ọtụtụ mgbe, ọ dị mfe JSON ma ọ bụ usoro ọ bụla ọzọ.

Usoro nzaghachi

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

  • <КОД СТАТУСА> bụ nọmba na-anọchite anya nsonaazụ nke ọrụ ahụ. Ihe nkesa anyị ga-eweghachi ọkwa 200 mgbe niile (ọrụ na-aga nke ọma).
  • <ОПИСАНИЕ СТАТУСА> - eriri eriri nke koodu ọnọdụ. Maka koodu ọnọdụ 200 nke a bụ OK.
  • <ЗАГОЛОВОК N> - nkụnye eji isi mee nke otu usoro dị na arịrịọ ahụ. Anyị ga-eweghachite aha ndị ahụ Content-Length (nha faịlụ) na Content-Type: text/html (ụdị data nloghachi).
  • <ДАННЫЕ> - data onye ọrụ rịọrọ. N'ọnọdụ anyị, nke a bụ ụzọ nke ihe oyiyi na HTML.

file http_server.c (otu eriri ihe nkesa) gụnyere faịlụ common.h, nke nwere ụdị ọrụ ndị a:

Gosi ụdị ọrụ na-ahụkarị.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);

A kọwakwara nnukwu macro na-arụ ọrụ SAFE_CALL() a kọwakwara ọrụ ahụ fail(). Macro na-atụnyere uru nke okwu ahụ na njehie ahụ, ma ọ bụrụ na ọnọdụ ahụ bụ eziokwu, kpọọ ọrụ ahụ fail():

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

ọrụ fail() na-ebipụta arụmụka agafere na njedebe (dịka printf()) ma kwụsị mmemme na koodu 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);
}

ọrụ new_server() weghachite nkọwa faịlụ nke oghere "ihe nkesa" nke oku sistemụ mepụtara socket(), bind() и listen() ma nwee ike ịnakwere njikọ mbata na ọnọdụ anaghị egbochi.

Gosi ọrụ ọhụrụ_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;
}

  • Rịba ama na a na-emepụta oghere ahụ na ọnọdụ anaghị egbochi ya site na iji ọkọlọtọ SOCK_NONBLOCKnke mere na na ọrụ on_accept() (gụkwuo) oku usoro accept() akwụsịghị ogbugbu eri.
  • ma ọ bụrụ na reuse_port ha nhata true, mgbe ahụ, ọrụ a ga-ahazi oghere na nhọrọ SO_REUSEPORT site na setsockopt()iji otu ọdụ ụgbọ mmiri ahụ na gburugburu ebe nwere ọtụtụ eriri (lee ngalaba "Ihe nkesa nwere ọtụtụ ihe").

Onye njikwa mmemme on_accept() a na-akpọ mgbe OS mepụtara ihe omume EPOLLIN, na nke a pụtara na njikọ ọhụrụ nwere ike ịnakwere. on_accept() na-anabata njikọ ọhụrụ, gbanwee ya na ọnọdụ anaghị egbochi ya wee debanye aha ya na onye njikwa mmemme on_recv() n'ime reactor I/O.

Gosi ọrụ 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);
}

Onye njikwa mmemme on_recv() a na-akpọ mgbe OS mepụtara ihe omume EPOLLIN, na nke a pụtara na njikọ aha on_accept(), dị njikere ịnata data.

on_recv() na-agụ data sitere na njikọ ahụ ruo mgbe enwetara arịrịọ HTTP kpamkpam, wee debanye aha onye njikwa on_send() izipu nzaghachi HTTP. Ọ bụrụ na onye ahịa ahụ agbaji njikọ ahụ, ewepụrụ oghere ahụ wee mechie ya site na iji close().

Gosi ọrụ na_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);
    }
}

Onye njikwa mmemme on_send() a na-akpọ mgbe OS mepụtara ihe omume EPOLLOUT, nke pụtara na njikọ ahụ edebanyere aha on_recv(), dị njikere izipu data. Ọrụ a na-eziga nzaghachi HTTP nwere HTML nwere onyonyo nye onye ahịa wee gbanwee onye njikwa ihe omume azụ on_recv().

Gosi ọrụ 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 n'ikpeazụ, na faịlụ http_server.c, na ọrụ main() anyị na-eji ihe na-emepụta I/O reactor reactor_new(), mepụta oghere nkesa wee debanye aha ya, malite reactor site na iji reactor_run() maka otu nkeji, wee hapụ akụrụngwa wee pụọ na mmemme ahụ.

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

Ka anyị lelee na ihe niile na-arụ ọrụ dịka a tụrụ anya ya. Na-achịkọta (chmod a+x compile.sh && ./compile.sh na mgbọrọgwụ oru ngo) wee malite ihe nkesa nke edere onwe ya, mepee http://127.0.0.1:18470 na ihe nchọgharị ma hụ ihe anyị tụrụ anya:

Igwe ihe eji eme ihe efu-C I/O nwere njiri mara zuru oke

Nleta arụmọrụ

Gosi nkọwa ụgbọ ala m

$ 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

Ka anyị tụọ arụmọrụ nke ihe nkesa nwere otu eriri. Ka anyị mepee ọnụ ụzọ abụọ: na otu anyị ga-agba ọsọ ./http_server, n'ụzọ dị iche - ọrụ. Mgbe otu nkeji gachara, a ga-egosipụta ọnụ ọgụgụ ndị a na njedebe nke abụọ:

$ 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

Ihe nkesa anyị nwere otu eriri nwere ike hazie arịrịọ karịrị nde 11 kwa nkeji sitere na njikọ 100. Ọ bụghị nsonaazụ ọjọọ, mana enwere ike imeziwanye ya?

Multithreaded nkesa

Dịka e kwuru n'elu, enwere ike ịmepụta reactor I/O na eriri dị iche iche, si otú a na-eji cores CPU niile. Ka anyị tinye usoro a n'ọrụ:

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

Ugbu a eriri ọ bụla nwe nke ya reactor:

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

Biko mara na arụmụka ọrụ new_server() akwado true. Nke a pụtara na anyị na-ekenye nhọrọ na oghere nkesa SO_REUSEPORTiji ya mee ihe na gburugburu ọtụtụ eriri. Ị nwere ike ịgụ nkọwa ndị ọzọ ebe a.

Agba nke abụọ

Ugbu a, ka anyị tụọ arụmọrụ nke sava nwere ọtụtụ eriri:

$ 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

Ọnụọgụ nke arịrịọ ahaziziri na nkeji 1 mụbara site ~ 3.28 ugboro! Mana anyị bụ naanị ~ XNUMX nde mkpụmkpụ nke ọnụọgụ gburugburu, yabụ ka anyị gbalịa idozi nke ahụ.

Ka anyị buru ụzọ leba anya na ọnụ ọgụgụ ewepụtara zuru oke:

$ 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

Iji CPU Affinity, nchịkọta na -march=native, PGO, mmụba nke ọnụ ọgụgụ hits cache, mụbaa MAX_EVENTS na iji EPOLLET enyeghị mmụba dị ịrịba ama na arụmọrụ. Ma gịnị na-eme ma ọ bụrụ na ị na-abawanye ọnụ ọgụgụ nke njikọ oge?

Ọnụọgụ maka njikọ 352 n'otu oge:

$ 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

Enwetara nsonaazụ achọrọ, yana ya eserese na-adọrọ mmasị na-egosi ndabere nke ọnụọgụ arịrịọ ahazi na nkeji 1 na ọnụọgụ njikọ:

Igwe ihe eji eme ihe efu-C I/O nwere njiri mara zuru oke

Anyị na-ahụ na mgbe narị ole na ole njikọ gachara, ọnụọgụ nke arịrịọ ahazi maka sava abụọ ahụ na-adaba nke ọma (na ụdị multi-threaded nke a na-ahụkarị). Nke a ọ metụtara mmejuputa ngwugwu Linux TCP/IP? Na-enwere onwe gị ide echiche gị gbasara omume a nke eserese na njikarịcha maka nhọrọ multi-threaded na otu-threaded na nkwupụta.

Olee otú kwuru na nkwupụta, ule arụmọrụ a anaghị egosi omume nke reactor I / O n'okpuru ezigbo ibu, n'ihi na ọ fọrọ nke nta ka ọ bụrụ mgbe niile na ihe nkesa na-emekọ ihe na nchekwa data, na-emepụta ndekọ, na-eji cryptography na TLS wdg, n'ihi na ibu ahụ na-aghọ ihe na-adịghị mma (dị ike). A ga-eme ule yana akụrụngwa ndị ọzọ n'ime akụkọ gbasara I/O proactor.

Ọdịmma nke I/O reactor

Ịkwesịrị ịghọta na onye na-ahụ maka I/O enweghị ihe ndọghachi azụ ya, ya bụ:

  • Iji ihe I/O reactor na a multi-threaded gburugburu ebe obibi bụ ihe siri ike karị, n'ihi na ị ga-eji aka gị jikwaa ihe ndị na-asọ asọ.
  • Omume na-egosi na n'ọtụtụ ọnọdụ, ibu anaghị adị n'otu, nke nwere ike iduga n'otu eriri eri mgbe onye ọzọ na-arụsi ọrụ ike.
  • Ọ bụrụ na otu onye na-ahụ maka ihe omume gbochiri eri, onye na-ahọrọ sistemu n'onwe ya ga-egbochikwa, nke nwere ike ibute ahụhụ siri ike ịchọta.

Na-edozi nsogbu ndị a I/O proactor, nke na-enwekarị nhazi nhazi nke na-ekesa ibu ahụ n'otu n'otu na ọdọ mmiri nke eriri, ma nweekwa API dị mma karị. Anyị ga-ekwu maka ya ma emechaa, na edemede m ọzọ.

nkwubi

Nke a bụ ebe njem anyị site na tiori ozugbo banye na ikpochapụ profaịlụ abịala na njedebe.

I kwesịghị ilekwasị anya na nke a, n'ihi na e nwere ọtụtụ ụzọ ndị ọzọ na-adọrọ mmasị maka ide software netwọk na ọkwa dị iche iche nke ịdị mma na ọsọ. Na-akpali mmasị, n'echiche nke m, e nyere njikọ n'okpuru.

hụkwa gị ọzọ!

Ọrụ na-akpali mmasị

Kedu ihe ọzọ m ga-agụ?

isi: www.habr.com

Tinye a comment