Suorituskyvyn testaaminen on tärkeä vaihe, kun pyritään varmistamaan, että sovellus kestää oikean maailman käyttötilanteita, erityisesti suuren kuorman alaisena. Systemaattisesti suoritetut suorituskykytestit auttavat analysoimaan tuloksia ja optimoimaan sovelluksen käytettävyyttä, vakautta ja skaalautuvuutta. Tämä osa kirjaa esittelee, kuinka suorituskyvyn testaus voidaan toteuttaa Locust-työkalun avulla.

Ennen kuin aloitat, varmista, että sinulla on toimiva sovellus. Tässä esimerkissä käytämme protoapp-sovellusta ja Locust-työkalua, joka on Python-pohjainen testauskehyksestä. Voit tutustua yksityiskohtaisiin ohjeisiin virallisessa dokumentaatiossa: https://docs.locust.io/en/stable/.

Aloittaaksesi, asenna Locust virtuaaliympäristöösi komennolla:

ruby
$ pip install locust

Tämän jälkeen olet valmis määrittämään konfiguraatiotiedoston ja ajamaan Locust-instanssin.

Määrittäminen ja suorittaminen

Kun sovellus on käynnissä ja Locust on asennettu, voidaan aloittaa suorituskykytestin määrittäminen. Luo projektin juureen locustfile.py, joka määrittelee käyttäjien käyttäytymisen testattavassa sovelluksessa. Esimerkiksi:

python
from locust import HttpUser, task
class ProtoappUser(HttpUser): host = "http://localhost:8000" @task def hello_world(self): self.client.get("/home")

Tässä konfiguraatiossa määritellään asiakas, joka käyttää sovellusta osoitteessa http://localhost:8000 ja suuntaa /home-päätepisteeseen.

Kun sovellus on käynnissä, voit testata suorituskykyä käyttämällä komentoa:

ruby
$ uvicorn protoapp.main:app

Avaa sitten toinen terminaali ja suorita Locust:

ruby
$ locust

Tämän jälkeen avaa selain ja mene osoitteeseen http://localhost:8089, joka on Locustin web-käyttöliittymä. Käyttöliittymä on intuitiivinen ja helppokäyttöinen, ja se tarjoaa mahdollisuuden:

  • Määrittää samanaikaisia käyttäjiä: Voit määrittää maksimimäärän käyttäjiä, jotka pääsevät sovellukseen samaan aikaan huipputilanteessa.

  • Asettaa ramp-up nopeuden: Määritä kuinka nopeasti uusia käyttäjiä lisätään sekunnissa simuloimaan kasvavaa liikennettä.

Kun nämä asetukset on tehty, klikkaa "Start"-painiketta ja käynnistä simulaatio, joka generoi liikennettä sovellukseen määritellyn /home-päätepisteen kautta.

Päätelmä

Suorituskyvyn testaus ei rajoitu pelkästään yksittäisten testien suorittamiseen, vaan voi olla olennainen osa laajempaa CI/CD-prosessia ennen sovelluksen julkaisua. Dokumentaatiossa on lisätietoja siitä, kuinka testata sovelluksen liikenteen eri osa-alueita ja varmistaa, että se toimii optimaalisesti.

Erityisesti suurilla käyttäjämäärillä toimivien sovellusten suorituskykytestaus auttaa sinua tunnistamaan pullonkauloja ja ongelmia ennen tuotantoon siirtymistä. Locust tarjoaa tehokkaan tavan luoda kattavia testauksia ja varmistaa, että sovelluksen käytettävyys ei heikkene edes suurten kuormien aikana.

Mitä on tärkeää ymmärtää tässä vaiheessa

Kun suoritat suorituskykytestejä, on tärkeää, että sinulla on selkeä käsitys siitä, mitä haluat mitata ja miksi. Yksinkertaisimmat testit voivat auttaa sinua ymmärtämään, kuinka sovellus käyttäytyy normaalilla kuormalla, mutta monimutkaisemmilla skenaarioilla voidaan simuloida todellisia käyttäjätapoja ja nähdä, miten sovellus reagoi huipputilanteissa. On tärkeää myös dokumentoida ja analysoida kaikki testitulokset huolellisesti, jotta mahdolliset ongelmat voidaan tunnistaa ja korjata ennen sovelluksen julkaisemista.

Miten optimoida FastAPI-sovelluksen suorituskyky ja hallita liikennettä tehokkaasti?

FastAPI-sovelluksen suorituskyvyn optimointi on monivaiheinen prosessi, joka alkaa koodin profiloinnilla. Profiilointityökalut auttavat tunnistamaan suorituskykyongelmat, kuten pullonkaulat ja tehottomat osat koodissa. Kun profiilointityökalu on integroitu FastAPI-sovellukseen, on tärkeää jatkaa sovelluksen suorituskyvyn parantamista hyödyntäen useita tekniikoita, jotka tukevat tehokasta ja skaalautuvaa palvelua.

Ensimmäinen askel on asynkroninen ohjelmointi. FastAPI on rakennettu Starlette-kirjaston päälle, ja se tukee asynkronisia pyyntöjä async ja await -avainsanoilla. Asynkroninen ohjelmointi mahdollistaa useiden pyyntöjen käsittelyn samanaikaisesti ilman, että se kuormittaa liikaa prosessoria. Tämä parantaa sovelluksen vasteaikoja ja skaalautuvuutta, erityisesti I/O-intensiivisissä sovelluksissa. Kun sovelluksessa on paljon samanaikaisia pyyntöjä, asynkroninen käsittely voi vähentää huomattavasti prosessorin käyttöä ja parantaa resurssien hallintaa.

Tätä täydentää Uvicorn-työntekijöiden skaalaaminen. Uvicorn on FastAPI:n käytössä oleva ASGI-palvelin, joka tukee useiden työntekijöiden käynnistämistä samanaikaisesti. Lisäämällä työntekijöitä voidaan jakaa saapuvat pyynnöt useammalle prosessille, mutta tämä ei aina ole paras ratkaisu, erityisesti silloin, kun sovellus keskittyy I/O-operaatioihin. Asynkroninen ohjelmointi yksinkertaistaa tilannetta, koska se vähentää prosessorin kuormitusta ja estää ylimääräisten työntekijöiden jäämisen käyttämättömiksi. On tärkeää ennen uusien työntekijöiden lisäämistä tarkistaa pääprosessin CPU-kuormitus ja varmistaa, että lisäresursseille on oikea tarve.

Toinen tekniikka on välimuistin käyttöönotto. Välimuistin avulla voidaan tallentaa ja uudelleenkäyttää usein pyydettyjä tietoja, mikä vähentää tietokantakyselyjen ja laskentatehon tarvetta. FastAPI tukee useita välimuistikirjastoja, joiden avulla voidaan helposti toteuttaa tehokkaita välimuistiratkaisuja. Välimuisti parantaa suorituskykyä erityisesti sovelluksissa, joissa tiedot eivät muutu usein ja niitä pyydetään useita kertoja.

Tärkeä osa suorituskyvyn optimointia on myös rajoittaa saapuvan liikenteen määrää. Liikenteen hallinta (rate limiting) on välttämätön tekniikka, joka estää palvelun ylikuormittumisen ja suojaa sovellusta väärinkäytöksiltä ja hyökkäyksiltä. FastAPI:ssa tämä onnistuu helposti käyttämällä slowapi-kirjastoa, joka mahdollistaa pyyntöjen määrän rajoittamisen IP-osoitteen tai käyttäjäprofiilin perusteella. Rajoituksia voidaan määritellä yksittäisille päätepisteille, mutta myös globaalisti koko sovellukseen.

Rate limiting -ratkaisun lisääminen alkaa yksinkertaisesta rajoittimen määrittelystä, jossa annetaan rajoitus pyynnöille, kuten esimerkiksi "2/minuutti". Tämä rajoitus voidaan määrittää tietyille päätepisteille, kuten GET /homepage, jolloin ensimmäiset kaksi pyyntöä palauttavat sisällön, mutta kolmas pyyntö tuottaa virheilmoituksen "Rate limit exceeded". Rajoitus voidaan laajentaa koko sovellukseen lisäämällä middleware, joka asettaa globaalin rajoituksen kaikille pyyntöjen määrälle, kuten esimerkiksi "5/minuutti".

Lisäksi on hyvä muistaa, että liikenteen rajoittamisen ja välimuistin hallinnan lisäksi sovelluksen taustatehtävät (background tasks) ovat tärkeä osa suorituskyvyn parantamista. Taustatehtävät mahdollistavat raskaan laskennan tai pitkään kestävien prosessien suorittamisen erillisessä prosessissa, jolloin pääsovellus voi jatkaa käsittelyä ilman viivästyksiä. FastAPI tukee taustatehtäviä, jotka voidaan määrittää niin, että ne eivät estä pyyntöjen käsittelyä, vaan suoritetaan taustalla.

Näiden tekniikoiden tehokas yhdistäminen tuo merkittäviä parannuksia sovelluksen suorituskykyyn ja skaalautuvuuteen. Asynkronisen ohjelmoinnin ja työkuormien skaalaamisen yhdistäminen välimuistiin ja liikenteen rajoittamiseen varmistaa, että FastAPI-sovellus voi käsitellä suuren määrän samanaikaisia pyyntöjä ilman suorituskykyongelmia. Tämä ei vain paranna käyttäjäkokemusta, vaan myös suojaa sovellusta mahdollisilta hyökkäyksiltä ja väärinkäytöksiltä.

Kuinka luoda tehokkaita webhookkeja ja middleware-ratkaisuja FastAPI:lla

FastAPI tarjoaa monia työkaluja modernien ja tehokkaiden web-sovellusten kehittämiseen. Yksi keskeisimmistä ominaisuuksista, joka voi merkittävästi parantaa sovellusten interaktiivisuutta, on webhookien käyttö. Webhookit mahdollistavat eri järjestelmien välisen viestinnän reaaliajassa, ja ne perustuvat HTTP-kutsuihin, joita vastaanotetaan, kun tietty tapahtuma tapahtuu toisessa järjestelmässä. Tässä osassa tarkastelemme, kuinka luodaan webhookkeja FastAPI:ssa, ja kuinka niiden avulla voidaan integroida ulkoisia palveluja ja hallita tapahtumien ilmoittamista.

Middleware ja Webhookit FastAPI:ssa

Webhooks-pohjainen arkkitehtuuri on asynkroninen ja tapahtumaveto, mikä mahdollistaa saumattoman integroinnin kolmannen osapuolen palveluihin ja automaattisten työnkulkujen luomisen. Tämä rakenne on keskeinen monissa moderneissa web-sovelluksissa, joissa ulkoiset palvelut, kuten maksupalvelut tai ilmoitukset, kommunikoivat keskenään reaaliajassa.

FastAPI:ssa voit helposti luoda webhookin, joka ilmoittaa tilauksen tai tapahtuman toteutumisesta. Yksi keskeinen askel tässä on middleware-ratkaisun luominen, joka käsittelee webhookin lähettämisen vastaanottajalle.

TrustedHostMiddleware ja turvallisuus

Kun rakennat sovelluksia, joissa on ulkoisia integraatioita, on tärkeää varmistaa, että ainoastaan luotetut isäntäkoneet voivat käyttää sovellustasi. Tämä voidaan saavuttaa käyttämällä TrustedHostMiddleware:a, joka on osa FastAPI:n ja Starlette-kirjastojen middleware-ratkaisua. Tämän avulla voidaan suojata sovellusta niin, että vain tietyt isäntäkoneet, kuten "localhost" tai muu määritelty isäntä, voivat tehdä pyyntöjä palvelimelle.

Esimerkiksi seuraava koodi lisää middleware:n, joka rajoittaa pyynnöt vain "localhost" isäntäkoneille:

python
from fastapi.middleware.trustedhost import TrustedHostMiddleware app.add_middleware( TrustedHostMiddleware, allowed_hosts=["localhost"], )

Tällä tavoin voit estää luvattomien isäntäkoneiden pääsyn sovellukseesi ja parantaa sovelluksen turvallisuutta.

Webhookin toteuttaminen FastAPI:ssa

Webhookin toteuttaminen FastAPI:ssa vaatii muutamia keskeisiä vaiheita: URL-rekisteröintijärjestelmän luominen, webhook-kutsujen käsitteleminen ja itse webhookin dokumentointi.

  1. URL-rekisteröinti
    Webhookin luominen edellyttää URL-osoitteiden rekisteröimistä, johon webhookit lähettävät tapahtumat. Tämä voidaan tehdä luomalla erillinen päätepiste (endpoint), joka tallentaa URL-osoitteet. Esimerkiksi yksinkertainen URL-rekisteröintipäätepiste voisi näyttää tältä:

    python
    @app.post("/register-webhook-url")
    async def add_webhook_url(request: Request, url: str = Body()): if not url.startswith("http"): url = f"http://{url}" request.state.webhook_urls.append(url) return {"url added": url}

    Tämä päätepiste tallentaa annetut URL-osoitteet sovelluksen tilaan. Huomaa, että URL-osoitteiden tallentaminen on yksinkertaistettu tässä esimerkissä. Suuremmissa sovelluksissa URL-osoitteet voidaan tallentaa esimerkiksi tietokantaan.

  2. Webhook-kutsujen toteuttaminen
    Seuraavaksi luodaan itse webhook-kutsut, jotka lähettävät tietoja rekisteröidyille URL-osoitteille. Tätä varten voidaan luoda erillinen coroutine, joka käsittelee viestien lähettämisen, kuten seuraavassa esimerkissä:

    python
    from httpx import AsyncClient
    client = AsyncClient() async def send_event_to_url(url: str, event: Event): try: await client.post(f"{url}/fastapi-webhook", json=event.model_dump()) except Exception as e: logger.error(f"Error sending webhook event to {url}: {e}")
  3. Middleware webhookin käsittelemiseen
    Seuraavaksi luodaan middleware, joka välittää HTTP-pyynnöt ja lähettää ne rekisteröidyille URL-osoitteille. Tämä middleware interceptoi kaikki pyynnöt, luo tapahtumaobjektin ja lähettää sen määritellyille webhook-osoitteille:

    python
    class WebhookSenderMiddleWare:
    def __init__(self, app: ASGIApp): self.app = app async def __call__(self, scope: Scope, receive: Receive, send: Send): if scope["type"] == "http": message = await receive() body = message.get("body", b"") request = Request(scope=scope) event = Event( host=request.client.host, path=request.url.path, time=datetime.now().isoformat(), body=body, ) urls = request.state.webhook_urls for url in urls: await create_task(send_event_to_url(url, event)) await self.app(scope, receive, send)

    Tämä middleware käsittelee saapuvat HTTP-pyynnöt, luo tapahtumaobjektin, joka sisältää muun muassa isäntäkoneen, polun, ajan ja pyynnön sisällön, ja lähettää sen kaikille rekisteröidyille webhook-osoitteille.

Tärkeitä seikkoja webhookkeja käytettäessä

Webhookkeja käytettäessä on tärkeää huomioida muutamia asioita. Ensinnäkin on varmistettava, että webhook-osoitteet ovat turvallisia ja ne voivat käsitellä saapuvat tiedot luotettavasti. Tämän vuoksi on tärkeää, että webhookit vastaanottavat vain validoituja ja oikein muotoiltuja tietoja.

Toiseksi, on syytä käyttää asynkronisia ratkaisuja, kuten FastAPI tarjoaa, jotta webhookkivientit eivät estä pääsovelluksen suoritusta. Asynkronisuus mahdollistaa samalla serverin käsittelemään useita pyyntöjä samanaikaisesti ilman, että resursseja menee hukkaan odotellessa.

Kolmanneksi, webhookkeja käytettäessä on tärkeää käsitellä virhetilanteet ja epäonnistuneet yritykset asianmukaisesti. Tämä voidaan tehdä esimerkiksi lokituksessa, jossa ilmoitetaan mahdollisista ongelmista webhook-kutsujen lähettämisessä.