Tag nrho-featured liab qab-C I / O reactor

Tag nrho-featured liab qab-C I / O reactor

Taw qhia

I/O reactor (ib threaded xov xwm txheej) yog ib tug qauv rau kev sau ntawv siab load software, siv nyob rau hauv ntau txoj kev nrov:

Hauv tsab xov xwm no, peb yuav saib cov ins thiab outs ntawm I / O reactor thiab nws ua haujlwm li cas, sau ib qho kev siv tsawg dua 200 kab ntawm cov cai, thiab ua kom yooj yim HTTP server txheej txheem tshaj 40 lab thov / min.

Lus Qhia Tshab

  • Tsab ntawv tau sau los pab kom nkag siab txog kev ua haujlwm ntawm I / O reactor, thiab yog li nkag siab txog qhov txaus ntshai thaum siv nws.
  • Kev paub txog cov hauv paus ntsiab lus yuav tsum nkag siab txog kab lus. C lus thiab qee qhov kev paub dhau los hauv kev txhim kho kev siv network.
  • Tag nrho cov cai sau ua lus C nruj me ntsis raws li (ceev faj: ntev PDF) rau C11 standard rau Linux thiab muaj nyob rau ntawm GitHub.

Vim li cas thiaj li tsim nyog?

Nrog rau kev loj hlob ntawm Internet, web servers pib xav tau los tswj ntau qhov kev sib txuas ib txhij, thiab yog li ob txoj hauv kev tau sim: thaiv I / O ntawm ntau OS threads thiab tsis thaiv I / O ua ke nrog. ib qho kev ceeb toom kev tshwm sim, kuj hu ua "system selector" (epol/kque ua/IOCP/etc).

Thawj txoj hauv kev koom nrog tsim cov xov tshiab OS rau txhua qhov kev sib txuas tuaj. Nws qhov tsis zoo yog qhov tsis zoo scalability: lub operating system yuav tsum tau siv ntau cov ntsiab lus hloov и hu xovtooj. Lawv yog cov haujlwm kim heev thiab tuaj yeem ua rau tsis muaj RAM dawb nrog cov kev sib txuas zoo heev.

Cov hloov kho version tseem ceeb taag naj npawb ntawm threads (xov pas dej), yog li tiv thaiv lub kaw lus los ntawm kev rho tawm kev tua, tab sis tib lub sij hawm qhia txog qhov teeb meem tshiab: yog tias lub pas dej yog tam sim no thaiv los ntawm kev nyeem ntawv ntev, ces lwm lub qhov (socket) uas twb tau txais cov ntaub ntawv yuav tsis muaj peev xwm. ua li ntawd.

Qhov thib ob txoj kev siv kev ceeb toom qhov system (system selector) muab los ntawm OS. Kab lus no tham txog hom kev xaiv ntau tshaj plaws, raws li kev ceeb toom (xws li, ceeb toom) txog kev npaj rau kev ua haujlwm I / O, es tsis yog ntawm cov ntawv ceeb toom txog lawv ua tiav. Ib qho piv txwv yooj yim ntawm nws siv tuaj yeem sawv cev los ntawm cov duab thaiv hauv qab no:

Tag nrho-featured liab qab-C I / O reactor

Qhov sib txawv ntawm cov txheej txheem no yog raws li nram no:

  • Thaiv kev ua haujlwm I/O ncua neeg siv flow mus txog thaummus txog rau thaum OS zoo defragments tuaj IP pob ntawv mus byte kwj (TCP, tau txais cov ntaub ntawv) los yog yuav tsis muaj chaw txaus nyob rau hauv lub internal sau buffers rau xa tom qab ntawm NIC (xa cov ntaub ntawv).
  • Qhov system selector dhau sijhawm ceeb toom rau qhov kev pab cuam uas OS twb defragmented IP pob ntawv (TCP, txais cov ntaub ntawv) lossis qhov chaw txaus hauv kev sau ntawv buffers twb muaj (xa cov ntaub ntawv).

Txhawm rau suav nws, khaws cov xov OS rau txhua I / O yog qhov pov tseg ntawm kev suav lub zog, vim tias qhov tseeb, cov xov tsis ua haujlwm tseem ceeb (qhov no yog lo lus los ntawm "software cuam tshuam"). Lub system selector daws qhov teeb meem no, tso cai rau cov neeg siv kev pab cuam siv CPU cov peev txheej ntau dua kev lag luam.

I/O reactor qauv

Lub I/O reactor ua raws li ib txheej ntawm qhov system selector thiab tus neeg siv code. Lub hauv paus ntsiab lus ntawm nws txoj haujlwm yog piav qhia los ntawm daim duab thaiv hauv qab no:

Tag nrho-featured liab qab-C I / O reactor

  • Cia kuv ceeb toom rau koj tias ib qho kev tshwm sim yog ib qho kev ceeb toom tias ib lub qhov (socket) muaj peev xwm ua tau qhov kev ua haujlwm tsis thaiv I / O.
  • Tus neeg saib xyuas kev tshwm sim yog ib qho haujlwm hu ua I / O reactor thaum tau txais qhov xwm txheej, uas tom qab ntawd ua haujlwm tsis thaiv I / O.

Nws yog ib qho tseem ceeb uas yuav tsum nco ntsoov tias I / O reactor yog los ntawm kev txhais ib leeg xov, tab sis tsis muaj ib yam dab tsi txwv tsis pub lub tswv yim los ntawm kev siv nyob rau hauv ib qho chaw sib txuas ntawm qhov sib piv ntawm 1 xov: 1 reactor, yog li rov ua dua tag nrho CPU cores.

Kev siv

Peb yuav tso pej xeem interface rau hauv ib cov ntaub ntawv reactor.h, thiab kev siv-hauv reactor.c. reactor.h yuav muaj cov lus tshaj tawm hauv qab no:

Qhia cov lus tshaj tawm hauv 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);

I/O reactor qauv muaj cov ntaub ntawv piav qhia xaiv epol и rooj rooj GHashTable, uas maps txhua lub qhov (socket) rau CallbackData (Cov qauv ntawm tus tuav kev tshwm sim thiab tus neeg siv kev sib cav rau nws).

Qhia Reactor thiab CallbackData

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

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

Thov nco ntsoov tias peb tau ua kom muaj peev xwm ua tau hom tsis tiav raws li qhov ntsuas. IN reactor.h peb tshaj tawm cov qauv reactor, thiab hauv reactor.c peb txhais nws, yog li tiv thaiv tus neeg siv los ntawm kev hloov pauv nws cov teb. Nov yog ib qho ntawm cov qauv zais cov ntaub ntawv, uas succinctly haum rau C semantics.

Zog reactor_register, reactor_deregister и reactor_reregister hloov kho cov npe ntawm cov khoom txaus siab thiab cov neeg ua haujlwm sib raug zoo nyob rau hauv qhov system selector thiab hash table.

Qhia sau npe ua haujlwm

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

Tom qab I/O reactor tau cuam tshuam qhov xwm txheej nrog tus piav qhia fd, nws hu rau tus neeg saib xyuas kev tshwm sim, uas nws dhau mus fd, bit Mask generated txheej xwm thiab tus neeg siv pointer rau void.

Qhia reactor_run() muaj nuj nqi

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

Txhawm rau ua kom tiav, cov saw hlau ntawm kev ua haujlwm hu hauv tus neeg siv code yuav siv daim ntawv hauv qab no:

Tag nrho-featured liab qab-C I / O reactor

Ib leeg threaded server

Txhawm rau kuaj I / O reactor nyob rau hauv siab load, peb yuav sau ib qho yooj yim HTTP web server uas teb rau txhua qhov kev thov nrog cov duab.

Kev siv ceev ceev rau HTTP raws tu qauv

HTTP - qhov no yog txoj cai daim ntawv thov qib, feem ntau yog siv rau server-browser kev sib cuam tshuam.

HTTP tuaj yeem siv tau yooj yim dua thauj raws tu qauv TCP, xa thiab txais cov lus hauv ib hom ntawv teev tseg specification.

Thov Format

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

  • CRLF yog ib ntu ntawm ob lub cim: r и n, cais thawj kab ntawm kev thov, headers thiab cov ntaub ntawv.
  • <КОМАНДА> -ib CONNECT, DELETE, GET, HEAD, OPTIONS, PATCH, POST, PUT, TRACE. Lub browser yuav xa cov lus txib rau peb lub server GET, lub ntsiab lus "Xa kuv cov ntsiab lus ntawm cov ntaub ntawv."
  • <URI> - uniform peev xwm identifier. Piv txwv li, yog URI = /index.html, ces tus neeg thov cov nplooj ntawv tseem ceeb ntawm lub xaib.
  • <ВЕРСИЯ HTTP> - version ntawm HTTP raws tu qauv hauv hom HTTP/X.Y. Qhov feem ntau siv version niaj hnub no yog HTTP/1.1.
  • <ЗАГОЛОВОК N> yog qhov tseem ceeb-tus nqi khub hauv hom ntawv <КЛЮЧ>: <ЗНАЧЕНИЕ>, xa mus rau lub server rau kev tshuaj xyuas ntxiv.
  • <ДАННЫЕ> - cov ntaub ntawv xav tau los ntawm server los ua haujlwm. Feem ntau nws yooj yim JSON los yog lwm hom ntawv.

Teb hom ntawv

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

  • <КОД СТАТУСА> yog tus lej sawv cev ntawm qhov kev ua haujlwm. Peb cov neeg rau zaub mov yuav ib txwm rov qab cov xwm txheej 200 (kev ua haujlwm tiav).
  • <ОПИСАНИЕ СТАТУСА> - kab sawv cev ntawm cov xwm txheej code. Rau cov xwm txheej code 200 qhov no yog OK.
  • <ЗАГОЛОВОК N> - header ntawm tib hom ntawv raws li nyob rau hauv qhov kev thov. Peb yuav rov qab cov npe Content-Length (file size) thiab Content-Type: text/html (rov qab hom ntaub ntawv).
  • <ДАННЫЕ> - cov ntaub ntawv thov los ntawm tus neeg siv. Hauv peb cov ntaub ntawv, qhov no yog txoj hauv kev rau cov duab hauv HTML.

cov ntaub ntawv http_server.c (ib leeg threaded server) suav nrog cov ntaub ntawv common.h, uas muaj cov haujlwm hauv qab no prototypes:

Qhia ua haujlwm prototypes hauv common.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);

Cov kev ua haujlwm macro kuj tau piav qhia SAFE_CALL() thiab muaj nuj nqi yog txhais fail(). Lub macro piv tus nqi ntawm qhov kev qhia nrog qhov yuam kev, thiab yog tias qhov xwm txheej muaj tseeb, hu rau qhov ua haujlwm fail():

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

muaj nuj nqi fail() luam cov lus sib cav dhau mus rau lub davhlau ya nyob twg (xws li printf()) thiab terminates qhov kev pab cuam nrog cov code 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);
}

muaj nuj nqi new_server() rov qab cov ntaub ntawv piav qhia ntawm "server" qhov (socket) tsim los ntawm kev hu xov tooj socket(), bind() и listen() thiab muaj peev xwm lees txais cov kev sib txuas nkag hauv hom tsis thaiv.

Qhia new_server() muaj nuj nqi

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

  • Nco ntsoov tias lub qhov (socket) tau pib tsim nyob rau hauv hom tsis thaiv kev siv tus chij SOCK_NONBLOCKyog li ntawd hauv kev ua haujlwm on_accept() (nyeem ntxiv) system hu accept() tsis tau tso tseg txoj xov execution.
  • Yog hais tias tus reuse_port yog muaj sib npaug true, ces qhov no muaj nuj nqi yuav configure lub qhov (socket) nrog cov kev xaiv SO_REUSEPORT dhau setsockopt()siv tib qhov chaw nres nkoj hauv ib puag ncig ntau txoj xov (saib ntu "Multi-threaded server").

Txheej xwm Handler on_accept() hu ua tom qab OS tsim ib qho kev tshwm sim EPOLLIN, qhov no txhais tau hais tias qhov kev sib txuas tshiab tuaj yeem txais tau. on_accept() lees txais qhov kev sib txuas tshiab, hloov nws mus rau hom tsis thaiv thiab sau npe nrog tus tuav kev tshwm sim on_recv() hauv I/O reactor.

Qhia on_accept() muaj nuj nqi

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

Txheej xwm Handler on_recv() hu ua tom qab OS tsim ib qho kev tshwm sim EPOLLIN, nyob rau hauv cov ntaub ntawv no txhais tau hais tias cov kev twb kev txuas sau npe on_accept(), npaj tau txais cov ntaub ntawv.

on_recv() nyeem cov ntaub ntawv los ntawm kev sib txuas kom txog rau thaum qhov kev thov HTTP tau txais tag nrho, ces nws sau npe rau tus tuav on_send() xa HTTP teb. Yog tias tus neeg siv khoom tawg qhov kev sib txuas, lub qhov (socket) raug deregistered thiab kaw siv close().

Qhia ua haujlwm 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);
    }
}

Txheej xwm Handler on_send() hu ua tom qab OS tsim ib qho kev tshwm sim EPOLLOUT, txhais tau hais tias kev sib txuas sau npe on_recv(), npaj xa cov ntaub ntawv. Qhov kev ua haujlwm no xa HTTP cov lus teb uas muaj HTML nrog cov duab rau tus neeg siv khoom thiab tom qab ntawd hloov cov xwm txheej tuav rov qab mus rau on_recv().

Qhia on_send() muaj nuj nqi

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

Thiab thaum kawg, hauv cov ntaub ntawv http_server.c, hauv kev ua haujlwm main() Peb tsim I / O reactor siv reactor_new(), tsim ib lub qhov (socket) server thiab sau npe rau nws, pib lub reactor siv reactor_run() raws nraim ib feeb, thiab tom qab ntawd peb tso cov peev txheej thiab tawm ntawm qhov program.

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

Cia peb xyuas tias txhua yam ua haujlwm raws li qhov xav tau. Compiling (chmod a+x compile.sh && ./compile.sh hauv qhov project hauv paus) thiab tso tus kheej sau tus neeg rau zaub mov, qhib http://127.0.0.1:18470 hauv qhov browser thiab pom qhov peb xav tau:

Tag nrho-featured liab qab-C I / O reactor

Kev ntsuas kev ua haujlwm

Qhia kuv lub tsheb specifications

$ 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

Cia peb ntsuas qhov ua tau zoo ntawm ib lub xov tooj server. Cia peb qhib ob lub terminals: hauv ib qho peb yuav khiav ./http_server, nyob rau hauv sib txawv - wb wrk. Tom qab ib feeb, cov kev txheeb cais hauv qab no yuav tshwm sim hauv lub davhlau ya nyob twg thib ob:

$ 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

Peb cov neeg siv xov tooj ib leeg tuaj yeem ua tiav ntau dua 11 lab thov ib feeb los ntawm 100 kev sib txuas. Tsis yog qhov tshwm sim tsis zoo, tab sis nws puas tuaj yeem txhim kho?

Multithreaded server

Raws li tau hais los saum no, I / O reactor tuaj yeem tsim hauv cov xov sib cais, yog li siv tag nrho CPU cores. Cia peb muab txoj hauv kev no rau kev xyaum:

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

Tam sim no txhua txoj xov muaj nws tus kheej reactor:

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

Thov nco ntsoov tias qhov kev sib cav muaj nuj nqi new_server() cov neeg tawm tswv yim true. Qhov no txhais tau tias peb muab qhov kev xaiv rau lub qhov (socket) server SO_REUSEPORTsiv nws nyob rau hauv ib tug multi-threaded ib puag ncig. Koj tuaj yeem nyeem cov ntsiab lus ntxiv S, SѓS,.

Qhov thib ob khiav

Tam sim no cia peb ntsuas qhov ua tau zoo ntawm ntau lub xov tooj server:

$ 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

Tus naj npawb ntawm kev thov ua tiav hauv 1 feeb tau nce los ntawm ~ 3.28 npaug! Tab sis peb tsuas yog ~ XNUMX lab luv ntawm tus lej puag ncig, yog li cia peb sim kho qhov ntawd.

Ua ntej cia peb saib cov txheeb cais tsim tawm zoo tag nrho:

$ 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

Siv CPU Affinity, compilation nrog -march=native, PGO, nce tus naj npawb ntawm hits cache, nce MAX_EVENTS thiab siv EPOLLET tsis tau ua kom muaj txiaj ntsig zoo hauv kev ua haujlwm. Tab sis yuav ua li cas yog tias koj nce tus naj npawb ntawm kev sib txuas ib txhij?

Statistics rau 352 ib txhij sib txuas:

$ 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

Cov txiaj ntsig xav tau tau txais, thiab nrog nws cov duab nthuav qhia qhia qhov kev cia siab ntawm tus lej ntawm kev thov ua tiav hauv 1 feeb ntawm tus lej ntawm kev sib txuas:

Tag nrho-featured liab qab-C I / O reactor

Peb pom tias tom qab ob peb puas kev sib txuas, tus naj npawb ntawm cov kev thov ua tiav rau ob lub servers poob qis (hauv ntau txoj xov xov no yog qhov pom ntau dua). Qhov no puas cuam tshuam rau Linux TCP / IP pawg siv? Xav tias dawb sau koj cov kev xav txog tus cwj pwm no ntawm daim duab thiab kev ua kom zoo rau ntau txoj xov thiab ib leeg-xov xaiv hauv cov lus.

Yuav ua li cas sau tseg nyob rau hauv cov lus, qhov kev ntsuam xyuas kev ua tau zoo no tsis qhia tus cwj pwm ntawm I / O reactor nyob rau hauv cov loads tiag tiag, vim hais tias yuav luag txhua tus neeg rau zaub mov cuam tshuam nrog cov ntaub ntawv, tso tawm cov cav, siv cryptography nrog TLS thiab lwm yam, raws li qhov tshwm sim ntawm qhov load ua tsis zoo (dynamic). Kev sim ua ke nrog cov khoom thib peb yuav raug ua nyob rau hauv tsab xov xwm hais txog I / O proactor.

Disadvantages ntawm I / O reactor

Koj yuav tsum nkag siab tias I / O reactor tsis yog tsis muaj nws qhov tsis zoo, xws li:

  • Kev siv I / O reactor nyob rau hauv ib puag ncig ntau txoj xov yog qhov nyuaj dua, vim tias koj yuav tau manually tswj cov ntws.
  • Kev xyaum qhia tau hais tias nyob rau hauv feem ntau cov load yog tsis-uniform, uas yuav ua tau rau ib tug xov txiav thaum lwm tus neeg ua hauj lwm tsis khoom.
  • Yog hais tias ib qho kev tshwm sim handler blocks ib txoj xov, ces qhov system selector nws tus kheej kuj yuav thaiv, uas tuaj yeem ua rau nyuaj-rau-nrhiav kab.

daws cov teeb meem no I/O proactor, uas feem ntau muaj lub sijhawm teem sijhawm uas sib npaug faib cov khoom thauj mus rau lub pas dej ntawm cov xov, thiab tseem muaj API yooj yim dua. Peb yuav tham txog nws tom qab, hauv kuv tsab xov xwm.

xaus

Qhov no yog qhov uas peb txoj kev los ntawm txoj kev xav ncaj nraim mus rau hauv lub qhov hluav taws xob profiler tau los txog qhov kawg.

Koj yuav tsum tsis txhob nyob ntawm qhov no, vim tias muaj ntau lwm txoj hauv kev zoo sib xws los sau cov software network nrog ntau qib ntawm kev yooj yim thiab nrawm. Nthuav, hauv kuv lub tswv yim, cov ntawv txuas tau muab hauv qab no.

Yog lawm!

Nthuav tej yaam num

Kuv yuav tsum nyeem dab tsi ntxiv?

Tau qhov twg los: www.hab.com

Ntxiv ib saib