Sebapali se felletseng sa bare-C I/O

Sebapali se felletseng sa bare-C I/O

Selelekela

I/O reactor (ea khoele e le 'ngoe ketsahalo lupu) ke mokhoa oa ho ngola software e boima haholo, e sebelisoang litharollong tse ngata tse tsebahalang:

Sehloohong sena, re tla sheba ins and outs ea I / O reactor le kamoo e sebetsang kateng, ngola ts'ebetsong ka tlase ho mela ea 200 ea khoutu, 'me u etse mokhoa o bonolo oa seva sa HTTP ho feta likopo tse limilione tse 40 / min.

Tlhaloso

  • Sengoliloeng se ngotsoe ho thusa ho utloisisa ts'ebetso ea mochini oa I / O, ka hona ho utloisisa likotsi ha u se sebelisa.
  • Tsebo ea metheo ea hlokahala ho utloisisa sehlooho. C puo le boiphihlelo bo itseng ho nts'etsopele ea ts'ebeliso ea marang-rang.
  • Khoutu eohle e ngotsoe ka puo ea C ho latela (tlhokomeliso: PDF e telele) ho ea ho C11 e tloaelehileng bakeng sa Linux mme e fumaneha ho GitHub.

Ke hobane'ng ha see se hlokahala?

Ka botumo bo ntseng bo eketseha ba Marang-rang, li-server tsa marang-rang li ile tsa qala ho hloka ho sebetsana le palo e kholo ea likhokahano ka nako e le 'ngoe, ka hona ho ile ha lekoa mekhoa e' meli: ho thibela I / O ka palo e kholo ea likhoele tsa OS le I / O e sa thibeleng hammoho le sistimi ea tsebiso ea ketsahalo, eo hape e bitsoang "system selectctor" (epoll/kqueue/IOCP/ joalo-joalo).

Mokhoa oa pele o ne o kenyelletsa ho theha khoele e ncha ea OS bakeng sa khokahano ka 'ngoe e kenang. Bothata ba eona ke bofokoli bo fokolang: sistimi e sebetsang e tla tlameha ho kenya ts'ebetsong tse ngata phetoho ya maemo и mehala ea tsamaiso. Ke ts'ebetso e theko e boima 'me e ka lebisa ho haelloe ke RAM ea mahala e nang le palo e tsotehang ea likhokahano.

Phetolelo e fetotsoeng e totobatsa palo e tsitsitseng ea likhoele (letamo la khoele), ka hona ho thibela tsamaiso hore e se ke ea bolaoa, empa ka nako e ts'oanang e hlahisa bothata bo bocha: haeba letamo la likhoele le koetsoe ke ts'ebetso ea nako e telele, joale li-sockets tse ling tse seng li khona ho fumana data li ke ke tsa khona ho etsa joalo.

Mokhoa oa bobeli o sebelisoa sistimi ea tsebiso ea ketsahalo (sekhetho sa sistimi) se fanoeng ke OS. Sengoliloeng sena se bua ka mofuta o atileng haholo oa khetho ea sistimi, e ipapisitseng le litlhokomeliso (liketsahalo, litsebiso) mabapi le ho itokisetsa ts'ebetso ea I/O, ho fapana le litsebiso mabapi le ho phethoa ha tsona. Mohlala o nolofalitsoeng oa ts'ebeliso ea ona o ka emeloa ke setšoantšo se latelang sa block:

Sebapali se felletseng sa bare-C I/O

Phapang pakeng tsa mekhoa ena ke e latelang:

  • Ho thibela ts'ebetso ea I/O emisa phallo ya mosebedisi ho fihlelaho fihlela OS e nepahetse defragments tse kenang Lipakete tsa IP ho phalla (TCP, ho amohela data) kapa ho ke ke ha e-ba le sebaka se lekaneng se fumanehang ka har'a li-buffers tsa ka hare bakeng sa ho romella ka mor'a moo. NIC (ho romela lintlha).
  • Mokhethi oa tsamaiso ka mor'a nako e itseng e tsebisa lenaneo leo OS se lipakete tsa IP tse senyehileng (TCP, kamohelo ea data) kapa sebaka se lekaneng ho li-buffers tsa ka hare tsa ho ngola se e fumaneha (ho romela data).

Ho e akaretsa, ho boloka khoele ea OS bakeng sa I/O ka 'ngoe ke tšenyo ea matla a komporo, hobane ha e le hantle, likhoele ha li etse mosebetsi oa bohlokoa (ka hona poleloana e reng " "software e sitisa"). Mokhethi oa tsamaiso o rarolla bothata bona, a lumella lenaneo la mosebedisi ho sebelisa lisebelisoa tsa CPU haholo moruong.

Moetso oa actor oa I/O

I/O reactor e sebetsa e le lera lipakeng tsa mokhethoa oa sistimi le khoutu ea mosebelisi. Molao-motheo oa ts'ebetso ea ona o hlalosoa ke setšoantšo se latelang sa block:

Sebapali se felletseng sa bare-C I/O

  • E-re ke u hopotse hore ketsahalo ke tsebiso ea hore sokete e itseng e khona ho etsa ts'ebetso ea I / O e sa thibeleng.
  • Sebatli sa ketsahalo ke ts'ebetso e bitsoang "I/O reactor" ha ketsahalo e amoheloa, ebe e etsa ts'ebetso e sa thibeleng ea I/O.

Ke habohlokoa ho hlokomela hore mochine oa I / O ka tlhaloso o na le khoele e le 'ngoe, empa ha ho letho le thibelang khopolo ho sebelisoa sebakeng se nang le mefuta e mengata ka karolelano ea khoele ea 1: 1 reactor, kahoo e tsosolosa li-cores tsohle tsa CPU.

Ts'ebetsong

Re tla beha sebopeho sa sechaba faeleng reactor.h, le ho kenya tshebetsong - ho reactor.c. reactor.h e tla ba le litsebiso tse latelang:

Hlahisa liphatlalatso ho 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);

Sebopeho sa I/O reactor se na le tlhaloso ea faele mokhethi epoll и litafole tsa hash GHashTable, e etsang limmapa sokete ka 'ngoe ho CallbackData (sebopeho sa motshwari wa ketsahalo le phehisano ya mosebedisi bakeng sa yona).

Hlahisa Reactor le CallbackData

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

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

Ka kopo hlokomela hore re nolofalitse bokhoni ba ho sebetsana mofuta o sa fellang ho latela index. IN reactor.h re phatlalatsa sebopeho reactorle ho reactor.c rea e hlalosa, ka hona re thibela mosebelisi ho fetola masimo a eona ka ho hlaka. Ena ke e 'ngoe ea mekhoa ho pata lintlha, e lumellanang hantle le semantiki ea C.

Mesebetsi reactor_register, reactor_deregister и reactor_reregister ntlafatsa lenane la li-sockets tsa thahasello le batšoasi ba liketsahalo tse tsamaellanang ho mokhethoa oa sistimi le tafole ea hash.

Bontša mesebetsi ea ho ngolisa

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

Kamora hore sebapali sa I/O se kenelle ketsahalo ka mohlalosi fd, e bitsa motshwari wa ketsahalo e tsamaisanang le yona, eo e fetelang ho yona fd, maske hanyane diketsahalo tse hlahisoang le sesupa sa mosebedisi ho void.

Hlahisa ts'ebetso ea 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;
}

Ho akaretsa, letoto la mehala ea ts'ebetso ho khoutu ea mosebelisi le tla nka ka mokhoa o latelang:

Sebapali se felletseng sa bare-C I/O

Seva ea khoele e le 'ngoe

E le ho leka mochine oa I / O tlas'a mojaro o phahameng, re tla ngola sebatli se bonolo sa HTTP se arabelang kopo leha e le efe e nang le setšoantšo.

Tlhahiso e potlakileng ho protocol ea HTTP

http - ena ke protocol boemo ba kopo, haholo-holo e sebelisetsoang ho sebelisana le seva le sebatli.

HTTP e ka sebelisoa habonolo sepalangoang melaoana TCP, ho romela le ho amohela melaetsa ka mokhoa o boletsoeng tlhaloso.

Kopo Format

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

  • CRLF ke tatellano ea litlhaku tse peli: r и n, ho arola mohala oa pele oa kopo, lihlooho le data.
  • <КОМАНДА> - e mong oa CONNECT, DELETE, GET, HEAD, OPTIONS, PATCH, POST, PUT, TRACE. Sebatli se tla romela taelo ho seva sa rona GET, e bolelang "Nthomelle litaba tsa faele."
  • <URI> - sekhetho sa lisebelisoa tse ts'oanang. Ka mohlala, haeba URI = /index.html, joale mofani o kōpa leqephe le ka sehloohong la sebaka seo.
  • <ВЕРСИЯ HTTP> - mofuta oa protocol ea HTTP ka sebopeho HTTP/X.Y. Phetolelo e sebelisoang haholo kajeno ke HTTP/1.1.
  • <ЗАГОЛОВОК N> ke palo ea bohlokoa-boleng ka sebopeho <КЛЮЧ>: <ЗНАЧЕНИЕ>, e rometsoe ho seva bakeng sa tlhahlobo e eketsehileng.
  • <ДАННЫЕ> — data e hlokoang ke seva ho etsa ts'ebetso. Hangata ho bonolo JSON kapa sebopeho sefe kapa sefe.

Sebopeho sa Karabo

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

  • <КОД СТАТУСА> ke nomoro e emelang sephetho sa ts'ebetso. Seva ea rona e tla lula e khutlisetsa boemo ba 200 (ts'ebetso e atlehileng).
  • <ОПИСАНИЕ СТАТУСА> — kemiso ea khoele ea khoutu ea boemo. Bakeng sa khoutu ea boemo 200 sena ke OK.
  • <ЗАГОЛОВОК N> - sehlooho sa sebopeho se tšoanang le sa kopo. Re tla khutlisetsa litlotla Content-Length (boholo ba faele) le Content-Type: text/html (khutlisetsa mofuta oa data).
  • <ДАННЫЕ> - data e kopiloeng ke mosebelisi. Tabeng ea rona, ena ke tsela e lebisang setšoantšong HTML.

faele http_server.c (seva e le 'ngoe ea khoele) e kenyelletsa faele common.h, e nang le li-prototypes tse latelang tsa ts'ebetso:

Bontša li-prototypes tsa ts'ebetso tse tšoanang.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);

Macro e sebetsang e boetse e hlalosoa SAFE_CALL() mme mosebetsi o hlalositsoe fail(). Macro e bapisa boleng ba polelo le phoso, 'me haeba boemo e le' nete, e bitsa mosebetsi fail():

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

Mosebetsi fail() e hatisa likhang tse fetisitsoeng ho terminal (joalo ka printf()) le ho felisa lenaneo ka khoutu 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);
}

Mosebetsi new_server() e khutlisa tlhaloso ea faele ea sokete ea "server" e entsoeng ke mehala ea sistimi socket(), bind() и listen() mme e kgona ho amohela dikgokelo tse kenang ka mokgwa o sa thibeleng.

Hlahisa mosebetsi o mocha_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;
}

  • Hlokomela hore sokete e qalile ka mokhoa o sa thibeleng ho sebelisoa folakha SOCK_NONBLOCKe le hore mosebetsing on_accept() (bala haholoanyane) mohala oa sistimi accept() ha ea ka ea emisa ts'ebetso ea khoele.
  • haeba reuse_port e lekana le true, joale mosebetsi ona o tla lokisa sokete ka khetho SO_REUSEPORT ka setsockopt()ho sebelisa boema-kepe bo le bong sebakeng se nang le likhoele tse ngata (sheba karolo ea "Multi-threaded server").

Mohlokomeli oa Ketsahalo on_accept() e bitsoa ka mor'a hore OS e hlahise ketsahalo EPOLLIN, tabeng ena ho bolela hore khokahano e ncha e ka amoheloa. on_accept() e amohela khokahanyo e ncha, e e fetolela ho mokhoa o sa thibeleng ebe e ngolisa le motho ea sebetsanang le liketsahalo on_recv() ka har'a sebapali sa I/O.

Hlahisa on_accept() tshebetso

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

Mohlokomeli oa Ketsahalo on_recv() e bitsoa ka mor'a hore OS e hlahise ketsahalo EPOLLIN, tabeng ena ho bolela hore khokahano e ngolisitsoe on_accept(), e loketse ho amohela data.

on_recv() e bala lintlha tse tsoang ho khokahanyo ho fihlela kopo ea HTTP e amoheloa ka ho feletseng, ebe e ngolisa mohlokomeli on_send() ho romella karabo ea HTTP. Haeba moreki a roba khokahano, sokete e hlakotsoe mme e koetsoe ho sebelisoa close().

Hlahisa tšebetso ho_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);
    }
}

Mohlokomeli oa Ketsahalo on_send() e bitsoa ka mor'a hore OS e hlahise ketsahalo EPOLLOUT, ho bolelang hore khokahano e ngolisitsoe on_recv(), e loketse ho romela data. Ts'ebetso ena e romela karabo ea HTTP e nang le HTML e nang le setšoantšo ho moreki ebe e fetola sebatli sa ketsahalo ho khutlela ho sona on_recv().

Bontša on_send() tshebetso

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

'Me qetellong, ka faele http_server.c, mosebetsing main() re theha mochini oa motlakase oa I/O re sebelisa reactor_new(), theha sokete ea seva 'me u e ngolise, qala mochini o sebelisang reactor_run() bakeng sa motsotso o le mong hantle, ebe re lokolla lisebelisoa ebe re tsoa lenaneong.

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

Ha re hlahlobeng hore na tsohle li sebetsa kamoo ho neng ho lebelletsoe. Ho bokella (chmod a+x compile.sh && ./compile.sh motsong oa morero) 'me u qale seva se ngotseng, bula http://127.0.0.1:18470 ho sebatli 'me u bone seo re se lebelletseng:

Sebapali se felletseng sa bare-C I/O

Tekanyo ya tshebetso

Hlahisa lintlha tsa koloi eaka

$ 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

Ha re lekanye ts'ebetso ea seva ea khoele e le 'ngoe. Ha re bule li-terminals tse peli: ho e 'ngoe re tla matha ./http_server, ka tsela e fapaneng - wrk. Kamora motsotso, lipalo-palo tse latelang li tla hlahisoa setsing sa bobeli:

$ 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

Seva ea rona e nang le khoele e le 'ngoe e khonne ho sebetsana le likopo tse fetang limilione tse 11 ka motsotso ho tsoa ho likhokahano tse 100. Ha se phello e mpe, empa na e ka ntlafatsoa?

Multithreaded server

Joalokaha ho boletsoe ka holimo, mochine oa I / O o ka etsoa ka likhoele tse arohaneng, kahoo o sebelisa li-cores tsohle tsa CPU. Ha re sebeliseng mokhoa ona ts'ebetsong:

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

Joale khoele e 'ngoe le e 'ngoe e nang le tsa hae reactor:

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

Ka kopo hlokomela hore tlhaloso ea mosebetsi new_server() babuelli true. Sena se bolela hore re fana ka khetho ho sokete ea seva SO_REUSEPORTho e sebelisa sebakeng sa likhoele tse ngata. U ka bala lintlha tse ling mona.

Ho matha la bobeli

Joale ha re lekanye ts'ebetso ea seva e nang le likhoele tse ngata:

$ 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

Palo ea likopo tse sebetsitsoeng ka motsotso o le 1 e eketsehile ka makhetlo a ~ 3.28! Empa re ne re haelloa ke ~ limilione tse XNUMX feela ho palo e potolohileng, kahoo ha re lekeng ho lokisa seo.

Pele a re shebeng lipalo-palo tse hlahisitsoeng sehlahisoa:

$ 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

Ho sebelisa CPU Affinity, pokello le -march=native, PGO, ho eketseha ha palo ea ho otla polokelo, nyollelo MAX_EVENTS le tšebeliso EPOLLET ha ea ka ea fana ka keketseho e kholo ea ts'ebetso. Empa ho etsahala'ng haeba u eketsa palo ea likhokahano ka nako e le 'ngoe?

Lipalopalo tsa likhokahano tse 352 ka nako e le 'ngoe:

$ 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

Sephetho se lakatsehang se ile sa fumanoa, 'me ka eona kerafo e khahlisang e bonts'a ho its'etleha ha palo ea likopo tse sebetsitsoeng ka motsotso o le mong ka palo ea likhokahano:

Sebapali se felletseng sa bare-C I/O

Rea bona hore ka mor'a likhokahano tse makholo a 'maloa, palo ea likopo tse sebetsitsoeng bakeng sa li-server ka bobeli e theoha haholo (ka mofuta oa mefuta e mengata sena se bonahala haholoanyane). Na see se amana le ts'ebetsong ea li-stack tsa Linux TCP/IP? Ikutloe u lokolohile ho ngola maikutlo a hau mabapi le boits'oaro bona ba kerafo le lintlafatso bakeng sa likhetho tse nang le likhoele tse ngata le tse nang le khoele e le 'ngoe maikutlong.

How hlokometsoe litlhalosong, tlhahlobo ena ea ts'ebetso ha e bontše boitšoaro ba mochine oa I / O tlas'a meroalo ea sebele, hobane hoo e batlang e le kamehla seva se sebelisana le database, se hlahisa lintlha, se sebelisa li-cryptography le TLS joalo-joalo, ka lebaka leo mojaro o fetohang o sa ts'oaneng (matla). Liteko hammoho le likarolo tsa mokha oa boraro li tla etsoa sengoloa se mabapi le I/O proactor.

Mefokolo ea I/O reactor

U hloka ho utloisisa hore mochini oa I/O ha o na mathata, e leng:

  • Ho sebelisa mochine oa I/O sebakeng se nang le likhoele tse ngata ho batla ho le thata, hobane o tla tlameha ho laola phallo ka letsoho.
  • Boikoetliso bo bontša hore hangata mojaro ha o tšoane, e leng se ka lebisang ho rengong ha khoele ha e mong a ntse a tšoarehile ka mosebetsi.
  • Haeba sebatli se le seng sa ketsahalo se thiba khoele, joale mokhethoa oa sistimi ka boeona o tla thibela, e leng se ka lebisang ho liphoso tse thata ho fumana.

E rarolla mathata ana Sebapali sa I/O, eo hangata e nang le kemiso e arolelanang mojaro ka mokhoa o lekanang letamong la likhoele, hape e na le API e bonolo haholoanyane. Re tla bua ka eona hamorao, sehloohong sa ka se seng.

fihlela qeto e

Mona ke moo leeto la rona ho tloha khopolo-taba ho ea ho profil exhaust le fihlile pheletsong.

Ha ua lokela ho lula u nahana ka sena, hobane ho na le mekhoa e meng e mengata e khahlisang ka mokhoa o ts'oanang ea ho ngola software ea marang-rang e nang le maemo a fapaneng a bonolo le lebelo. Ho khahlisang, ka maikutlo a ka, lihokelo li fanoe ka tlase.

Ho fihlela nako e tlang!

Merero e khahlisang

Ke eng hape eo u lokelang ho e bala?

Source: www.habr.com

Eketsa ka tlhaloso