Millió kérelem másodpercenként a Python segítségével

Lehetséges másodpercenként egymillió kérést elütni a Pythonnal? Valószínűleg nem egészen a közelmúltig.

Sok vállalat áttér a Pythonról és más programozási nyelvekre annak érdekében, hogy növelje működési teljesítményét és spóroljon a szerver árain, de erre nincs igazán szükség. A Python megfelelő eszköz lehet a munkához.

A Python közösség az utóbbi időben sokat teljesít. A CPython 3.6 új szótár-implementációval növelte az általános tolmács teljesítményt. A CPython 3.7 még gyorsabb lesz, köszönhetően a gyorsabb hívásmegállapodás és a szótárkereső gyorsítótárak bevezetésének.

Számgörgető feladatokhoz használhatja a PyPy-t annak éppen az időben történő kódfordításával. Futtathatja a NumPy tesztcsomagját is, amely már javította az általános kompatibilitást a C kiterjesztésekkel. Idén később a PyPy várhatóan eléri a Python 3.5 megfelelőséget.

Mindez a nagyszerű munka inspirált az innovációra az egyik olyan területen, ahol a Python-ot széles körben használják: webes és mikrotovábbítási fejlesztésekben.

Írja be Japronto-t!

A Japronto egy vadonatúj mikrokeret, amely az Ön mikropalvelu igényeihez igazodik. Fő céljai közé tartozik a gyors , skálázható és könnyű . Ez lehetővé teszi szinkron és aszinkron programozás elvégzését az asyncio-nak köszönhetően . És szégyentelenül gyors . Még gyorsabb, mint a NodeJS és a Go.

Korrekció : Amint a @heppu felhasználó rámutat, a Go stdlib HTTP szervere 12% -kal gyorsabb lehet, mint ez a grafikon alaposabban megírva mutatja. Van egy fantasztikus gyorshttp szerver is a Go számára, amely láthatóan csak 18% -kal lassabb, mint a Japronto ebben a referenciaértékben. Fantasztikus! További részletek: //github.com/squeaky-pl/japronto/pull/12 és //github.com/squeaky-pl/japronto/pull/14.

Azt is láthatjuk, hogy a Meinheld WSGI szerver majdnem a NodeJS és a Go szintjén áll. Az eredetileg blokkoló kialakítása ellenére kiváló előadó az előző négyhez képest, amelyek aszinkron Python megoldások. Tehát soha ne bízzon senkiben, aki azt mondja, hogy az aszinkron rendszerek mindig gyorsabbak. Szinte mindig egyidejűbbek, de ennél sokkal többről van szó.

Ezt a mikro benchmarkot egy „Hello world!” Segítségével végeztem alkalmazás, de egyértelműen demonstrálja a kiszolgáló-keretrendszer feletti költségeket számos megoldás esetében.

Ezeket az eredményeket egy AWS c4.2xlarge példányon, amely 8 VCPU-val rendelkezett, São Paulo régióban indítottak, alapértelmezett megosztott bérleti, HVM virtualizációs és mágneses tárolóval. A gép az Ubuntu 16.04.1 LTS-t (Xenial Xerus) futtatta a Linux 4.4.0–53-generikus x86_64 rendszermaggal. Az operációs rendszer Xeon® CPU E5–2666 v3 @ 2.90GHz CPU-t jelentett. A Python 3.6-ot használtam, amelyet frissen állítottam össze a forráskódjából.

Hogy igazságos legyek, az összes versenyző (beleértve a Go-t is) egymunkássá vált. A szervereket terheléssel teszteltük egy szál, 100 kapcsolat és 24 egyidejű (csővezetékes) kérés kapcsolatonként (2400 kérelem kumulatív párhuzamossága).

A HTTP-csővezeték elengedhetetlen itt, mivel ez az egyik optimalizálás, amelyet a Japronto figyelembe vesz a kérések végrehajtásakor.

A legtöbb szerver ugyanúgy hajtja végre a csővezeték-ügyfelek kéréseit, mint a nem csővezeték-kliensekét. Nem próbálják optimalizálni. (Valójában a Sanic és a Meinheld is csendben elveti a pipelining kliensektől érkező kéréseket, ami a HTTP 1.1 protokoll megsértését jelenti.)

Egyszerű szavakkal, a pipelining olyan technika, amelyben az ügyfélnek nem kell megvárnia a választ, mielőtt további kéréseket küldene ugyanazon TCP-kapcsolaton keresztül. A kommunikáció integritásának biztosítása érdekében a szerver több választ küld vissza ugyanazon sorrendben.

Az optimalizálások lényeges részletei

Ha sok kis GET kérést pipeline össze az ügyfél, akkor nagy a valószínűsége, hogy majd érkezik egy TCP csomag (köszönhetően Nagle algoritmus) a szerver oldalon, akkor lehet olvasni vissza egy rendszer hívás .

Rendszerhívás végrehajtása és az adatok áthelyezése a kerneltérből a felhasználói térbe nagyon költséges művelet, mondjuk a memória mozgatása a folyamattérben. Ezért fontos, hogy a lehető legkevesebb rendszerhívást hajtsuk végre (de ne kevesebbet).

Amikor Japronto adatokat kap, és sikeresen feldolgozza több megkeresést belőle, megpróbálja végrehajtani a kérést a lehető leggyorsabban, ragasztó válaszok vissza a helyes sorrendben, majd write vissza egy rendszerben hívást . Valójában a kern segíthet az összeragasztásban, köszönhetően az IO rendszerhívások szórásának / összegyűjtésének, amelyet Japronto még nem használ.

Ne feledje, hogy ez nem mindig lehetséges, mivel néhány kérés túl sokáig tarthat, és a rájuk való várakozás szükségtelenül megnöveli a várakozási időt.

Vigyázzon, amikor hangolja a heurisztikát, és vegye figyelembe a rendszerhívások költségeit és a kérelem várható befejezési idejét.

A folyamatban lévő ügyfelek írásának késleltetése mellett számos más technika is létezik, amelyet a kód alkalmaz.

A Japronto szinte teljes egészében C-be van írva. Az elemző, a protokoll, a kapcsolat-kaszáló, az útválasztó, a kérés és a válaszobjektumok C kiterjesztésként íródnak.

Japronto keményen megpróbálja késleltetni belső struktúráinak Python-megfelelőinek létrehozását, amíg ezt kifejezetten meg nem kérdezik. Például a fejlécek szótárát csak akkor hozzák létre, ha azt egy nézetben kérik. Az összes tokenhatár már meg van jelölve, de a fejléckulcsok normalizálása, és több str objektum létrehozása megtörténik, amikor először elérik őket.

Japronto a kiváló picohttpparser C könyvtárra támaszkodik az állapotsor, a fejlécek és a darabolt HTTP-üzenet törzsének elemzéséhez. A Picohttpparser közvetlenül használja a modern processzorokban található, SSE4.2 kiterjesztésű szövegfeldolgozási utasításokat (szinte minden 10 éves x86_64 CPU rendelkezik vele), hogy gyorsan megfeleljen a HTTP tokenek határainak. Az I / O-t a szuper félelmetes uvloop kezeli, amely maga is a libuv köré tekinti. A legalacsonyabb szinten ez egy híd az epoll rendszerhíváshoz, amely aszinkron értesítéseket nyújt az írás-olvasás készenlétéről.

A Python szemétgyűjtő nyelv, ezért nagy teljesítményű rendszerek tervezésénél ügyelni kell arra, hogy ne növelje feleslegesen a szemétgyűjtőre nehezedő nyomást. A Japronto belső kialakítása megpróbálja elkerülni a referencia-ciklusokat, és a lehető legkevesebb kiosztást / elosztást végez. Ezt úgy csinálja, hogy egyes tárgyakat előre úgynevezett arénákba oszt. Megpróbálja újból felhasználni a Python-objektumokat a jövőbeli kérésekhez, ha már nem hivatkoznak rájuk ahelyett, hogy kidobnák őket.

Az összes allokáció a 4KB többszöröseként történik. A belső struktúrákat gondosan kell kialakítani, hogy a gyakran együtt használt adatok elég közel legyenek a memóriában, minimalizálva a gyorsítótár-kimaradások lehetőségét.

Japronto megpróbál feleslegesen nem másolni a pufferek között, és számos műveletet elvégez a helyén. Például százalékosan dekódolja az útvonalat, mielőtt az útválasztó folyamatban egyezik.

Nyílt forráskódú közreműködők, igénybe vehetném a segítségedet.

Az elmúlt 3 hónapban folyamatosan dolgoztam a Japronto-n - gyakran hétvégén, valamint normál munkanapokon. Ez csak annak volt köszönhető, hogy szünetet tartottam a szokásos programozói munkámtól, és minden erőmet a projektre fordítottam.

Azt hiszem, ideje megosztani munkám gyümölcsét a közösséggel.

Jelenleg a Japronto egy elég szilárd funkciókészletet valósít meg:

  • HTTP 1.x implementáció a darabolt feltöltések támogatásával
  • A HTTP-vezetékek teljes támogatása
  • Tartsa életben a csatlakozásokat a konfigurálható aratógéppel
  • Szinkron és aszinkron nézetek támogatása
  • Elágazáson alapuló mester-többmunkás modell
  • A kód újratöltésének támogatása a változásoknál
  • Egyszerű útválasztás

Ezután szeretnék utánanézni a webhálózatoknak és a HTTP-válaszok aszinkron szinkronizálásának.

Sok munkát kell elvégezni a dokumentálás és a tesztelés terén. Ha szeretnél segíteni, kérlek, fordulj hozzám közvetlenül a Twitteren. Itt található Japronto GitHub projekt tárháza.

Továbbá, ha cége olyan Python fejlesztőt keres, aki teljesítményőrült és DevOps-ot is végez, akkor nyitott vagyok erre. Világszerte figyelembe veszem a pozíciókat.

Utolsó szavak

Az itt említett technikák nem igazán a Pythonra vonatkoznak. Valószínűleg más nyelveken is alkalmazhatók, például Ruby, JavaScript vagy akár PHP. Engem is érdekelne egy ilyen munka, de ez sajnos nem fog bekövetkezni, hacsak valaki nem tudja finanszírozni.

Szeretnék köszönetet mondani a Python közösségnek a teljesítménymérnöki munkába való folyamatos befektetésükért. Nevezetesen Victor Stinner @VictorStinner, INADA Naoki @methane és Yury Selivanov @ 1st1, valamint a teljes PyPy csapat.

A Python szeretetére.