M'nkhaniyi, tiwona ins and outs of the I / O reactor ndi momwe zimagwirira ntchito, lembani kukhazikitsa muzitsulo zosachepera 200, ndikupanga njira yosavuta ya seva ya HTTP pa zopempha za 40 miliyoni / min.
Maulosi
Nkhaniyi inalembedwa kuti ithandize kumvetsetsa momwe makina a I / O amagwirira ntchito, choncho kumvetsetsa kuopsa kwake pogwiritsira ntchito.
Kudziwa zoyambira ndikofunikira kuti mumvetsetse nkhaniyi. C chinenero ndi zina zambiri pakukula kwa ma network application.
Ma code onse amalembedwa m'chinenero cha C motsatira (Chenjezo: PDF yayitali) ku C11 standard kwa Linux komanso kupezeka pa GitHub.
Nchifukwa chiyani izi zili zofunika?
Ndi kutchuka kwa intaneti, ma seva a pa intaneti anayamba kufunikira kugwirizanitsa maulendo ambiri nthawi imodzi, choncho njira ziwiri zinayesedwa: kutsekereza I / O pa chiwerengero chachikulu cha ulusi wa OS ndi osatseka I / O kuphatikiza ndi dongosolo lodziwitsa zochitika, lomwe limatchedwanso "system selector" (epoll/ku/Mtengo wa IOCP/ etc).
Njira yoyamba idaphatikizapo kupanga ulusi watsopano wa OS pamalumikizidwe aliwonse omwe akubwera. Zoyipa zake ndizosakhazikika bwino: makina ogwiritsira ntchito ayenera kugwiritsa ntchito zambiri kusintha kwa nkhani и mafoni adongosolo. Ndi ntchito zodula ndipo zimatha kubweretsa kusowa kwa RAM yaulere yokhala ndi maulumikizidwe ambiri.
Mawonekedwe osinthidwa amawunikira chiwerengero chokhazikika cha ulusi (ulusi dziwe), potero kuteteza dongosolo kuchotsa mimba, koma pa nthawi yomweyo kuyambitsa vuto latsopano: ngati ulusi dziwe panopa otsekedwa ndi ntchito kuwerenga kwautali, ndiye sockets ena amene angathe kale kulandira deta sangathe chita chomwecho.
Njira yachiwiri imagwiritsa ntchito dongosolo zidziwitso zochitika (system selector) yoperekedwa ndi OS. Nkhaniyi ikufotokoza za mtundu wodziwika bwino wa osankha makina, kutengera zidziwitso (zochitika, zidziwitso) za kukonzekera kwa ntchito za I/O, osati zidziwitso zakukwaniritsidwa kwawo. Chitsanzo chosavuta chakugwiritsa ntchito kwake chitha kuyimiridwa ndi chithunzi chotsatirachi:
Kusiyana pakati pa njirazi ndi motere:
Kuletsa ntchito za I/O kuyimitsa wosuta kuyenda mpakampaka Os ali bwino defragments obwera IP mapaketi kupita kumtsinje (TCP, kulandira zidziwitso) kapena sipadzakhala malo okwanira muzosunga zolembera zamkati kuti mutumize kudzera NIC (kutumiza deta).
Chosankha chadongosolo popita nthawi imadziwitsa pulogalamu yomwe OS kale mapaketi a IP a defragmented (TCP, kulandila kwa data) kapena malo okwanira muzolemba zamkati kale kupezeka (kutumiza deta).
Kuti tifotokoze mwachidule, kusunga ulusi wa OS pa I / O iliyonse ndikuwononga mphamvu yamakompyuta, chifukwa zenizeni, ulusiwo sukugwira ntchito yothandiza (chifukwa chake mawuwa amatanthauza "kuwononga" "kusokoneza mapulogalamu"). Wosankha dongosolo amathetsa vutoli, kulola pulogalamu ya ogwiritsa ntchito kugwiritsa ntchito zida za CPU mwachuma kwambiri.
Mtundu wa riyakitala wa I/O
The I/O reactor imakhala ngati wosanjikiza pakati pa chosankha chadongosolo ndi code ya ogwiritsa. Mfundo ya ntchito yake ikufotokozedwa ndi chithunzi chotsatirachi:
Ndiroleni ndikukumbutseni kuti chochitika ndi chidziwitso kuti socket inayake imatha kuchita ntchito yosatsekereza ya I / O.
Wothandizira zochitika ndi ntchito yotchedwa I / O reactor pamene chochitika chalandiridwa, chomwe chimagwira ntchito yosatseketsa I / O.
Ndikofunika kuzindikira kuti riyakitala ya I / O ndi tanthawuzo la ulusi umodzi, koma palibe chomwe chimalepheretsa lingalirolo kuti ligwiritsidwe ntchito mu malo okhala ndi ulusi wambiri pa chiŵerengero cha 1 ulusi: 1 reactor, potero amabwezeretsanso ma CPU cores.
Реализация
Tiyika mawonekedwe agulu mu fayilo reactor.h, ndi kukhazikitsa - mu reactor.c. reactor.h izikhala ndi zolengeza izi:
Onetsani zolengeza mu 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);
Kapangidwe ka riyakitala ya I/O imakhala ndi fayilo yofotokozera wosankha epoll и matebulo a hashiGHashTable, yomwe imayika socket iliyonse CallbackData (mapangidwe a wosamalira zochitika ndi mkangano wogwiritsa ntchito).
Chonde dziwani kuti tapangitsa luso logwira mtundu wosakwanira malinga ndi index. MU reactor.h timalengeza dongosolo reactorndi reactor.c timatanthauzira, potero timalepheretsa wogwiritsa ntchito kusintha magawo ake. Ichi ndi chimodzi mwa machitidwe kubisa deta, zomwe zimagwirizana bwino ndi C semantics.
Ntchito reactor_register, reactor_deregister и reactor_reregister sinthani mndandanda wazokonda ndi osamalira zochitika muzosankha zamakina ndi tebulo la hashi.
Pambuyo pa riyakitala ya I / O idasokoneza chochitikacho ndi wofotokozera fd, imayitana woyendetsa zochitika wofananira, kumene amadutsa fd, pang'ono mask zochitika zopangidwa ndi cholozera cha ogwiritsa ntchito void.
Onetsani ntchito ya 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;
}
Kufotokozera mwachidule, mndandanda wa mafoni ogwiritsira ntchito mu code yogwiritsira ntchito utenga mawonekedwe awa:
Seva yokhala ndi ulusi umodzi
Kuti tiyese choyatsira cha I / O pansi pa katundu wambiri, tidzalemba seva yosavuta ya HTTP yomwe imayankha pempho lililonse ndi chithunzi.
Kufotokozera mwachangu kwa protocol ya HTTP
HTTP - iyi ndiye protocol ntchito mlingo, yomwe imagwiritsidwa ntchito makamaka pakulumikizana ndi msakatuli wa seva.
HTTP itha kugwiritsidwa ntchito mosavuta transport ndondomeko TCP, kutumiza ndi kulandira mauthenga mumtundu wotchulidwa kufotokoza.
<КОД СТАТУСА> ndi nambala yomwe ikuyimira zotsatira za ntchito. Seva yathu nthawi zonse imabweza mawonekedwe 200 (ntchito yopambana).
<ОПИСАНИЕ СТАТУСА> - chiwonetsero chazingwe cha code code. Kwa code code 200 iyi ndi OK.
<ЗАГОЛОВОК N> - mutu wamtundu womwewo wa pempho. Tidzabwezeranso maudindo Content-Length (kukula kwa fayilo) ndi Content-Type: text/html (mtundu wa data wobwerera).
<ДАННЫЕ> - zomwe zafunsidwa ndi wogwiritsa ntchito. Kwa ife, iyi ndi njira yopita ku chithunzi mu HTML.
file http_server.c (seva yokhala ndi ulusi umodzi) imaphatikizapo fayilo common.h, yomwe ili ndi ma prototypes otsatirawa:
Onetsani ntchito zofananira zofanana.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 yogwira ntchito ikufotokozedwanso SAFE_CALL() ndipo ntchitoyo imafotokozedwa fail(). The macro amafanizira mtengo wa mawuwo ndi cholakwika, ndipo ngati mkhalidwewo ndi wowona, imayitanitsa ntchitoyi fail():
#define SAFE_CALL(call, error)
do {
if ((call) == error) {
fail("%s", #call);
}
} while (false)
ntchito fail() amasindikiza mfundo zomwe zadutsa ku terminal (monga printf()) ndikuyimitsa pulogalamuyo ndi code EXIT_FAILURE:
ntchito new_server() imabweretsanso fayilo yofotokozera za socket ya "server" yopangidwa ndi mafoni amtundu socket(), bind() и listen() ndi wokhoza kuvomereza maulumikizidwe obwera m'njira yosatsekereza.
Seva yathu yokhala ndi ulusi umodzi idakwanitsa kuchita zopempha zoposa 11 miliyoni pamphindi imodzi kuchokera ku malumikizidwe 100. Osati zotsatira zoipa, koma kodi izo zikhoza kusintha?
Multithreaded seva
Monga tafotokozera pamwambapa, choyatsira cha I / O chikhoza kupangidwa mu ulusi wosiyana, pogwiritsa ntchito ma CPU onse. Tiyeni tigwiritse ntchito njira iyi:
Kugwiritsa ntchito CPU Affinity, kupanga ndi -march=native, PGO, kuwonjezeka kwa chiwerengero cha kugunda posungira, wonjezani MAX_EVENTS ndi kugwiritsa EPOLLET sichinapereke kuwonjezeka kwakukulu kwa ntchito. Koma chimachitika ndi chiyani ngati muwonjezera kuchuluka kwa maulumikizidwe munthawi imodzi?
Chotsatira chomwe chinkafunidwa chinapezedwa, ndipo ndi chithunzi chosangalatsa chomwe chikuwonetsa kudalira kuchuluka kwa zopempha zomwe zasinthidwa mu miniti imodzi pa kuchuluka kwa maulumikizidwe:
Tikuwona kuti pambuyo polumikizana mazana angapo, kuchuluka kwa zopempha zomwe zasinthidwa kwa ma seva onsewa kumatsika kwambiri (mumitundu yamitundu yambiri izi zimawonekera kwambiri). Kodi izi zikugwirizana ndi kukhazikitsa kwa Linux TCP/IP? Khalani omasuka kulemba malingaliro anu pamachitidwe awa a graph ndi kukhathamiritsa kwamitundu yambiri ndi ulusi umodzi mu ndemanga.
Kodi adazindikira m'mawu, kuyesa kwa magwiridwe antchitowa sikuwonetsa machitidwe a I / O reactor pansi pa katundu weniweni, chifukwa pafupifupi nthawi zonse seva imalumikizana ndi database, imatulutsa zipika, imagwiritsa ntchito cryptography ndi TLS etc., chifukwa chake katunduyo amakhala wopanda yunifolomu (zamphamvu). Mayesero pamodzi ndi zigawo za chipani chachitatu adzachitidwa m'nkhani yonena za I/O proactor.
Kuipa kwa I/O riyakitala
Muyenera kumvetsetsa kuti riyakitala ya I / O ilibe zovuta zake, zomwe ndi:
Kugwiritsa ntchito chojambulira cha I / O m'malo okhala ndi ulusi wambiri kumakhala kovuta, chifukwa muyenera kuyang'anira pamanja zoyenda.
Zoyeserera zikuwonetsa kuti nthawi zambiri katunduyo amakhala wopanda yunifolomu, zomwe zingayambitse kudula ulusi umodzi pomwe wina ali wotanganidwa ndi ntchito.
Amathetsa mavutowa Wosewera wa I/O, yomwe nthawi zambiri imakhala ndi ndondomeko yomwe imagawa mofanana katunduyo ku dziwe la ulusi, komanso imakhala ndi API yabwino. Tidzakambirana pambuyo pake, m'nkhani yanga ina.
Pomaliza
Apa ndipamene ulendo wathu kuchokera ku chiphunzitso molunjika ku profil exhaust wafika kumapeto.
Simuyenera kukhazikika pa izi, chifukwa palinso njira zina zambiri zosangalatsa zolembera mapulogalamu apaintaneti omwe ali ndi mwayi wosiyanasiyana komanso kuthamanga. Zosangalatsa, mwa lingaliro langa, maulalo amaperekedwa pansipa.