Tutustu nopeudenrajoitusstrategioihin keskittyen Token Bucket -algoritmiin. Opi sen toteutuksesta, eduista, haitoista ja käytännön sovelluskohteista vikasietoisten ja skaalautuvien sovellusten rakentamiseksi.
Nopeudenrajoitus: Syväsukellus Token Bucket -toteutukseen
Nykypäivän verkottuneessa digitaalisessa maailmassa sovellusten ja API-rajapintojen vakauden ja saatavuuden varmistaminen on ensisijaisen tärkeää. Nopeudenrajoitus on ratkaisevassa roolissa tämän tavoitteen saavuttamisessa hallitsemalla nopeutta, jolla käyttäjät tai asiakkaat voivat tehdä pyyntöjä. Tämä blogikirjoitus tarjoaa kattavan tutkimusmatkan nopeudenrajoitusstrategioihin, keskittyen erityisesti Token Bucket -algoritmiin, sen toteutukseen, etuihin ja haittoihin.
Mitä on nopeudenrajoitus?
Nopeudenrajoitus on tekniikka, jolla hallitaan palvelimelle tai palveluun tietyn ajanjakson aikana lähetettävän liikenteen määrää. Se suojaa järjestelmiä ylikuormittumiselta liiallisten pyyntöjen vuoksi, estäen palvelunestohyökkäyksiä (DoS), väärinkäyttöä ja odottamattomia liikennepiikkejä. Asettamalla rajoituksia pyyntöjen määrälle nopeudenrajoitus varmistaa reilun käytön, parantaa järjestelmän yleistä suorituskykyä ja lisää turvallisuutta.
Kuvittele verkkokauppa-alusta pikamyynnin aikana. Ilman nopeudenrajoitusta äkillinen käyttäjäpyyntöjen tulva voisi ylikuormittaa palvelimet, mikä johtaisi hitaisiin vasteaikoihin tai jopa palvelukatkoksiin. Nopeudenrajoitus voi estää tämän rajoittamalla pyyntöjen määrää, jonka käyttäjä (tai IP-osoite) voi tehdä tietyn ajan kuluessa, varmistaen sujuvamman kokemuksen kaikille käyttäjille.
Miksi nopeudenrajoitus on tärkeää?
Nopeudenrajoitus tarjoaa lukuisia etuja, kuten:
- Palvelunestohyökkäysten (DoS) estäminen: Rajoittamalla pyyntönopeutta mistä tahansa yksittäisestä lähteestä nopeudenrajoitus lieventää DoS-hyökkäysten vaikutusta, joiden tavoitteena on ylikuormittaa palvelin haitallisella liikenteellä.
- Suojaus väärinkäytöltä: Nopeudenrajoitus voi estää haitallisia toimijoita väärinkäyttämästä API-rajapintoja tai palveluita, kuten kaapimasta tietoja tai luomasta väärennettyjä tilejä.
- Reilun käytön varmistaminen: Nopeudenrajoitus estää yksittäisiä käyttäjiä tai asiakkaita monopolisoimasta resursseja ja varmistaa, että kaikilla käyttäjillä on reilu mahdollisuus käyttää palvelua.
- Järjestelmän suorituskyvyn parantaminen: Hallitsemalla pyyntönopeutta nopeudenrajoitus estää palvelimien ylikuormittumisen, mikä johtaa nopeampiin vasteaikoihin ja parempaan yleiseen järjestelmän suorituskykyyn.
- Kustannusten hallinta: Pilvipohjaisissa palveluissa nopeudenrajoitus voi auttaa hallitsemaan kustannuksia estämällä liiallisen käytön, joka voisi johtaa odottamattomiin veloituksiin.
Yleiset nopeudenrajoitusalgoritmit
Nopeudenrajoituksen toteuttamiseen voidaan käyttää useita algoritmeja. Joitakin yleisimmistä ovat:
- Token Bucket: Tämä algoritmi käyttää käsitteellistä "säiliötä", joka sisältää poletteja (tokeneita). Jokainen pyyntö kuluttaa yhden poletin. Jos säiliö on tyhjä, pyyntö hylätään. Poletteja lisätään säiliöön määritellyllä nopeudella.
- Leaky Bucket: Samankaltainen kuin Token Bucket, mutta pyynnöt käsitellään kiinteällä nopeudella saapumisnopeudesta riippumatta. Ylimääräiset pyynnöt joko jonotetaan tai hylätään.
- Fixed Window Counter: Tämä algoritmi jakaa ajan kiinteän kokoisiin ikkunoihin ja laskee pyyntöjen määrän kussakin ikkunassa. Kun raja saavutetaan, seuraavat pyynnöt hylätään, kunnes ikkuna nollautuu.
- Sliding Window Log: Tämä lähestymistapa ylläpitää lokia pyyntöjen aikaleimoista liukuvassa ikkunassa. Pyyntöjen määrä ikkunan sisällä lasketaan lokin perusteella.
- Sliding Window Counter: Hybridimalli, joka yhdistää kiinteän ikkunan ja liukuvan ikkunan algoritmien piirteitä parantaakseen tarkkuutta.
Tämä blogikirjoitus keskittyy Token Bucket -algoritmiin sen joustavuuden ja laajan sovellettavuuden vuoksi.
Token Bucket -algoritmi: Yksityiskohtainen selitys
Token Bucket -algoritmi on laajalti käytetty nopeudenrajoitustekniikka, joka tarjoaa tasapainon yksinkertaisuuden ja tehokkuuden välillä. Se toimii ylläpitämällä käsitteellisesti "säiliötä", joka sisältää poletteja. Jokainen saapuva pyyntö kuluttaa yhden poletin säiliöstä. Jos säiliössä on tarpeeksi poletteja, pyyntö sallitaan; muuten pyyntö hylätään (tai jonotetaan, toteutuksesta riippuen). Poletteja lisätään säiliöön määritellyllä nopeudella, täydentäen käytettävissä olevaa kapasiteettia.
Avainkäsitteet
- Säiliön kapasiteetti: Suurin määrä poletteja, jonka säiliö voi sisältää. Tämä määrittää purskekapasiteetin, joka mahdollistaa tietyn määrän pyyntöjä käsiteltäväksi nopeassa peräkkäisyydessä.
- Täyttönopeus: Nopeus, jolla poletteja lisätään säiliöön, tyypillisesti mitattuna poletteina sekunnissa (tai muussa aikayksikössä). Tämä hallitsee keskimääräistä nopeutta, jolla pyyntöjä voidaan käsitellä.
- Pyyntöjen kulutus: Jokainen saapuva pyyntö kuluttaa tietyn määrän poletteja säiliöstä. Tyypillisesti jokainen pyyntö kuluttaa yhden poletin, mutta monimutkaisemmissa skenaarioissa eri tyyppisille pyynnöille voidaan määrittää erilaiset polettikustannukset.
Miten se toimii
- Kun pyyntö saapuu, algoritmi tarkistaa, onko säiliössä tarpeeksi poletteja.
- Jos poletteja on tarpeeksi, pyyntö sallitaan, ja vastaava määrä poletteja poistetaan säiliöstä.
- Jos poletteja ei ole tarpeeksi, pyyntö joko hylätään (palauttaen "Too Many Requests" -virheen, tyypillisesti HTTP 429) tai jonotetaan myöhempää käsittelyä varten.
- Pyyntöjen saapumisesta riippumatta poletteja lisätään säännöllisesti säiliöön määritellyllä täyttönopeudella säiliön kapasiteettiin asti.
Esimerkki
Kuvittele Token Bucket, jonka kapasiteetti on 10 polettia ja täyttönopeus 2 polettia sekunnissa. Aluksi säiliö on täynnä (10 polettia). Näin algoritmi voisi käyttäytyä:
- Sekunti 0: Saapuu 5 pyyntöä. Säiliössä on tarpeeksi poletteja, joten kaikki 5 pyyntöä sallitaan, ja säiliö sisältää nyt 5 polettia.
- Sekunti 1: Ei saapuvia pyyntöjä. Säiliöön lisätään 2 polettia, jolloin kokonaismäärä on 7 polettia.
- Sekunti 2: Saapuu 4 pyyntöä. Säiliössä on tarpeeksi poletteja, joten kaikki 4 pyyntöä sallitaan, ja säiliö sisältää nyt 3 polettia. Myös 2 polettia lisätään, jolloin kokonaismäärä on 5 polettia.
- Sekunti 3: Saapuu 8 pyyntöä. Vain 5 pyyntöä voidaan sallia (säiliössä on 5 polettia), ja loput 3 pyyntöä joko hylätään tai jonotetaan. Myös 2 polettia lisätään, jolloin kokonaismäärä on 2 polettia (jos 5 pyyntöä palveltiin ennen täyttösykliä, tai 7, jos täyttö tapahtui ennen pyyntöjen palvelemista).
Token Bucket -algoritmin toteuttaminen
Token Bucket -algoritmi voidaan toteuttaa useilla eri ohjelmointikielillä. Tässä esimerkkejä Golangilla, Pythonilla ja Javalla:
Golang
```go package main import ( "fmt" "sync" "time" ) // TokenBucket represents a token bucket rate limiter. type TokenBucket struct { capacity int tokens int rate time.Duration lastRefill time.Time mu sync.Mutex } // NewTokenBucket creates a new TokenBucket. func NewTokenBucket(capacity int, rate time.Duration) *TokenBucket { return &TokenBucket{ capacity: capacity, tokens: capacity, rate: rate, lastRefill: time.Now(), } } // Allow checks if a request is allowed based on token availability. func (tb *TokenBucket) Allow() bool { tb.mu.Lock() defer tb.mu.Unlock() now := time.Now() tb.refill(now) if tb.tokens > 0 { tb.tokens-- return true } return false } // refill adds tokens to the bucket based on the elapsed time. func (tb *TokenBucket) refill(now time.Time) { elapsed := now.Sub(tb.lastRefill) newTokens := int(elapsed.Seconds() * float64(tb.capacity) / tb.rate.Seconds()) if newTokens > 0 { tb.tokens += newTokens if tb.tokens > tb.capacity { tb.tokens = tb.capacity } tb.lastRefill = now } } func main() { bucket := NewTokenBucket(10, time.Second) for i := 0; i < 15; i++ { if bucket.Allow() { fmt.Printf("Pyyntö %d sallittu\n", i+1) } else { fmt.Printf("Pyyntö %d nopeusrajoitettu\n", i+1) } time.Sleep(100 * time.Millisecond) } } ```
Python
```python import time import threading class TokenBucket: def __init__(self, capacity, refill_rate): self.capacity = capacity self.tokens = capacity self.refill_rate = refill_rate self.last_refill = time.time() self.lock = threading.Lock() def allow(self): with self.lock: self._refill() if self.tokens > 0: self.tokens -= 1 return True return False def _refill(self): now = time.time() elapsed = now - self.last_refill new_tokens = elapsed * self.refill_rate self.tokens = min(self.capacity, self.tokens + new_tokens) self.last_refill = now if __name__ == '__main__': bucket = TokenBucket(capacity=10, refill_rate=2) # 10 tokens, refills 2 per second for i in range(15): if bucket.allow(): print(f"Pyyntö {i+1} sallittu") else: print(f"Pyyntö {i+1} nopeusrajoitettu") time.sleep(0.1) ```
Java
```java import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.TimeUnit; public class TokenBucket { private final int capacity; private double tokens; private final double refillRate; private long lastRefillTimestamp; private final ReentrantLock lock = new ReentrantLock(); public TokenBucket(int capacity, double refillRate) { this.capacity = capacity; this.tokens = capacity; this.refillRate = refillRate; this.lastRefillTimestamp = System.nanoTime(); } public boolean allow() { try { lock.lock(); refill(); if (tokens >= 1) { tokens -= 1; return true; } else { return false; } } finally { lock.unlock(); } } private void refill() { long now = System.nanoTime(); double elapsedTimeInSeconds = (double) (now - lastRefillTimestamp) / TimeUnit.NANOSECONDS.toNanos(1); double newTokens = elapsedTimeInSeconds * refillRate; tokens = Math.min(capacity, tokens + newTokens); lastRefillTimestamp = now; } public static void main(String[] args) throws InterruptedException { TokenBucket bucket = new TokenBucket(10, 2); // 10 tokens, refills 2 per second for (int i = 0; i < 15; i++) { if (bucket.allow()) { System.out.println("Pyyntö " + (i + 1) + " sallittu"); } else { System.out.println("Pyyntö " + (i + 1) + " nopeusrajoitettu"); } TimeUnit.MILLISECONDS.sleep(100); } } } ```
Token Bucket -algoritmin edut
- Joustavuus: Token Bucket -algoritmi on erittäin joustava ja voidaan helposti mukauttaa erilaisiin nopeudenrajoitustilanteisiin. Säiliön kapasiteettia ja täyttönopeutta voidaan säätää nopeudenrajoituskäyttäytymisen hienosäätämiseksi.
- Purskeiden käsittely: Säiliön kapasiteetti mahdollistaa tietyn määrän purskeliikennettä käsiteltäväksi ilman nopeudenrajoitusta. Tämä on hyödyllistä satunnaisten liikennepiikkien käsittelyssä.
- Yksinkertaisuus: Algoritmi on suhteellisen helppo ymmärtää ja toteuttaa.
- Konfiguroitavuus: Se mahdollistaa tarkan hallinnan keskimääräisestä pyyntönopeudesta ja purskekapasiteetista.
Token Bucket -algoritmin haitat
- Monimutkaisuus: Vaikka konseptina yksinkertainen, säiliön tilan ja täyttöprosessin hallinta vaatii huolellista toteutusta, erityisesti hajautetuissa järjestelmissä.
- Mahdollisuus epätasaiseen jakautumiseen: Joissakin skenaarioissa purskekapasiteetti voi johtaa pyyntöjen epätasaiseen jakautumiseen ajan myötä.
- Konfiguroinnin vaiva: Optimaalisen säiliön kapasiteetin ja täyttönopeuden määrittäminen voi vaatia huolellista analysointia ja kokeilua.
Token Bucket -algoritmin käyttökohteet
Token Bucket -algoritmi soveltuu monenlaisiin nopeudenrajoituksen käyttökohteisiin, mukaan lukien:
- API-nopeudenrajoitus: Suojaa API-rajapintoja väärinkäytöltä ja varmistaa reilun käytön rajoittamalla pyyntöjen määrää käyttäjää tai asiakasta kohden. Esimerkiksi sosiaalisen median API voi rajoittaa käyttäjän tuntikohtaisten julkaisujen määrää roskapostin estämiseksi.
- Verkkosovellusten nopeudenrajoitus: Estää käyttäjiä tekemästä liiallisia pyyntöjä verkkopalvelimille, kuten lähettämästä lomakkeita tai käyttämästä resursseja. Verkkopankkisovellus voi rajoittaa salasanan nollausyritysten määrää raa'an voiman hyökkäysten estämiseksi.
- Verkon nopeudenrajoitus: Hallitsee verkon läpi virtaavan liikenteen nopeutta, kuten rajoittamalla tietyn sovelluksen tai käyttäjän käyttämää kaistanleveyttä. Internet-palveluntarjoajat käyttävät usein nopeudenrajoitusta verkon ruuhkautumisen hallintaan.
- Viestijonojen nopeudenrajoitus: Hallitsee nopeutta, jolla viestijono käsittelee viestejä, estäen kuluttajien ylikuormittumisen. Tämä on yleistä mikropalveluarkkitehtuureissa, joissa palvelut kommunikoivat asynkronisesti viestijonojen kautta.
- Mikropalveluiden nopeudenrajoitus: Suojaa yksittäisiä mikropalveluita ylikuormitukselta rajoittamalla niiden vastaanottamien pyyntöjen määrää muilta palveluilta tai ulkoisilta asiakkailta.
Token Bucket -toteutus hajautetuissa järjestelmissä
Token Bucket -algoritmin toteuttaminen hajautetussa järjestelmässä vaatii erityishuomioita johdonmukaisuuden varmistamiseksi ja kilpa-ajotilanteiden välttämiseksi. Tässä on joitain yleisiä lähestymistapoja:
- Keskitetty Token Bucket: Yksi, keskitetty palvelu hallinnoi kaikkien käyttäjien tai asiakkaiden token bucketteja. Tämä lähestymistapa on helppo toteuttaa, mutta siitä voi tulla pullonkaula ja yksittäinen vikaantumispiste.
- Hajautettu Token Bucket Redisillä: Redisiä, muistissa olevaa tietovarastoa, voidaan käyttää token buckettien tallentamiseen ja hallintaan. Redis tarjoaa atomisia operaatioita, joita voidaan käyttää säiliön tilan turvalliseen päivittämiseen samanaikaisessa ympäristössä.
- Asiakaspuolen Token Bucket: Jokainen asiakas ylläpitää omaa token bucketiaan. Tämä lähestymistapa on erittäin skaalautuva, mutta voi olla vähemmän tarkka, koska nopeudenrajoitusta ei valvota keskitetysti.
- Hybridimalli: Yhdistää keskitetyn ja hajautetun lähestymistavan piirteitä. Esimerkiksi hajautettua välimuistia voidaan käyttää token buckettien tallentamiseen, ja keskitetty palvelu vastaa säiliöiden täyttämisestä.
Esimerkki Redisin käytöstä (käsitteellinen)
Redisin käyttö hajautetussa Token Bucketissa perustuu sen atomisten operaatioiden (kuten `INCRBY`, `DECR`, `TTL`, `EXPIRE`) hyödyntämiseen polettien määrän hallinnassa. Perusprosessi olisi seuraava:
- Tarkista olemassa oleva säiliö: Tarkista, onko Redisissä avainta käyttäjälle/API-päätepisteelle.
- Luo tarvittaessa: Jos ei ole, luo avain, alusta polettien määrä kapasiteettiin ja aseta vanhenemisaika (TTL) vastaamaan täyttöjaksoa.
- Yritä kuluttaa poletti: Vähennä atomisesti polettien määrää. Jos tulos on >= 0, pyyntö sallitaan.
- Käsittele polettien loppuminen: Jos tulos on < 0, peru vähennys (lisää atomisesti takaisin) ja hylkää pyyntö.
- Täyttölogiikka: Taustaprosessi tai säännöllinen tehtävä voi täyttää säiliöitä, lisäten poletteja kapasiteettiin asti.
Tärkeitä huomioita hajautetuissa toteutuksissa:
- Atomisuus: Käytä atomisia operaatioita varmistaaksesi, että polettien määrät päivittyvät oikein samanaikaisessa ympäristössä.
- Johdonmukaisuus: Varmista, että polettien määrät ovat johdonmukaisia kaikissa hajautetun järjestelmän solmuissa.
- Vikasietoisuus: Suunnittele järjestelmä vikasietoiseksi, jotta se voi jatkaa toimintaansa, vaikka jotkin solmut vikaantuisivat.
- Skaalautuvuus: Ratkaisun tulisi skaalautua käsittelemään suurta määrää käyttäjiä ja pyyntöjä.
- Valvonta: Toteuta valvonta seurataksesi nopeudenrajoituksen tehokkuutta ja tunnistaaksesi mahdolliset ongelmat.
Vaihtoehtoja Token Bucketille
Vaikka Token Bucket -algoritmi on suosittu valinta, muut nopeudenrajoitustekniikat voivat olla sopivampia riippuen erityisvaatimuksista. Tässä on vertailu joihinkin vaihtoehtoihin:
- Leaky Bucket: Yksinkertaisempi kuin Token Bucket. Se käsittelee pyyntöjä kiinteällä nopeudella. Hyvä liikenteen tasoittamiseen, mutta vähemmän joustava purskeiden käsittelyssä kuin Token Bucket.
- Fixed Window Counter: Helppo toteuttaa, mutta voi sallia kaksinkertaisen rajoitusnopeuden ikkunoiden rajoilla. Vähemmän tarkka kuin Token Bucket.
- Sliding Window Log: Tarkka, mutta vaatii enemmän muistia, koska se kirjaa kaikki pyynnöt. Sopii tilanteisiin, joissa tarkkuus on ensisijaisen tärkeää.
- Sliding Window Counter: Kompromissi tarkkuuden ja muistinkäytön välillä. Tarjoaa paremman tarkkuuden kuin Fixed Window Counter vähemmällä muistikuormalla kuin Sliding Window Log.
Oikean algoritmin valinta:
Parhaan nopeudenrajoitusalgoritmin valinta riippuu tekijöistä, kuten:
- Tarkkuusvaatimukset: Kuinka tarkasti nopeusrajoitus on pantava täytäntöön?
- Purskeiden käsittelytarpeet: Onko tarpeen sallia lyhyitä liikennepurskeita?
- Muistirajoitukset: Kuinka paljon muistia voidaan varata nopeudenrajoitusdatan tallentamiseen?
- Toteutuksen monimutkaisuus: Kuinka helppo algoritmi on toteuttaa ja ylläpitää?
- Skaalautuvuusvaatimukset: Kuinka hyvin algoritmi skaalautuu käsittelemään suurta määrää käyttäjiä ja pyyntöjä?
Nopeudenrajoituksen parhaat käytännöt
Tehokkaan nopeudenrajoituksen toteuttaminen vaatii huolellista suunnittelua ja harkintaa. Tässä on joitain parhaita käytäntöjä, joita noudattaa:
- Määrittele nopeusrajoitukset selkeästi: Määritä sopivat nopeusrajoitukset palvelimen kapasiteetin, odotettujen liikennemallien ja käyttäjien tarpeiden perusteella.
- Tarjoa selkeät virheilmoitukset: Kun pyyntö on nopeusrajoitettu, palauta käyttäjälle selkeä ja informatiivinen virheilmoitus, joka sisältää syyn rajoitukselle ja milloin he voivat yrittää uudelleen (esim. käyttämällä `Retry-After` HTTP-otsaketta).
- Käytä standardoituja HTTP-tilakoodeja: Käytä sopivia HTTP-tilakoodeja osoittamaan nopeudenrajoitusta, kuten 429 (Too Many Requests).
- Toteuta hallittu palvelutason lasku: Sen sijaan, että vain hylkäät pyyntöjä, harkitse hallitun palvelutason laskun toteuttamista, kuten palvelun laadun heikentämistä tai käsittelyn viivästyttämistä.
- Seuraa nopeudenrajoituksen mittareita: Seuraa nopeusrajoitettujen pyyntöjen määrää, keskimääräistä vasteaikaa ja muita olennaisia mittareita varmistaaksesi, että nopeudenrajoitus on tehokas eikä aiheuta tahattomia seurauksia.
- Tee nopeusrajoituksista konfiguroitavia: Anna ylläpitäjien säätää nopeusrajoituksia dynaamisesti muuttuvien liikennemallien ja järjestelmän kapasiteetin perusteella.
- Dokumentoi nopeusrajoitukset: Dokumentoi nopeusrajoitukset selkeästi API-dokumentaatiossa, jotta kehittäjät ovat tietoisia rajoista ja voivat suunnitella sovelluksensa sen mukaisesti.
- Käytä mukautuvaa nopeudenrajoitusta: Harkitse mukautuvan nopeudenrajoituksen käyttöä, joka säätää nopeusrajoituksia automaattisesti nykyisen järjestelmän kuormituksen ja liikennemallien perusteella.
- Eriytä nopeusrajoitukset: Sovella erilaisia nopeusrajoituksia erityyppisille käyttäjille tai asiakkaille. Esimerkiksi todennetuilla käyttäjillä voi olla korkeammat nopeusrajoitukset kuin anonyymeillä käyttäjillä. Vastaavasti eri API-päätepisteillä voi olla erilaiset nopeusrajoitukset.
- Harkitse alueellisia eroja: Ole tietoinen siitä, että verkkoolosuhteet ja käyttäjäkäyttäytyminen voivat vaihdella eri maantieteellisillä alueilla. Räätälöi nopeusrajoitukset vastaavasti tarvittaessa.
Yhteenveto
Nopeudenrajoitus on olennainen tekniikka vikasietoisten ja skaalautuvien sovellusten rakentamisessa. Token Bucket -algoritmi tarjoaa joustavan ja tehokkaan tavan hallita nopeutta, jolla käyttäjät tai asiakkaat voivat tehdä pyyntöjä, suojaten järjestelmiä väärinkäytöltä, varmistaen reilun käytön ja parantaen yleistä suorituskykyä. Ymmärtämällä Token Bucket -algoritmin periaatteet ja noudattamalla toteutuksen parhaita käytäntöjä, kehittäjät voivat rakentaa vankkoja ja luotettavia järjestelmiä, jotka kestävät vaativimmatkin liikennekuormat.
Tämä blogikirjoitus on tarjonnut kattavan yleiskatsauksen Token Bucket -algoritmista, sen toteutuksesta, eduista, haitoista ja käyttökohteista. Hyödyntämällä tätä tietoa voit tehokkaasti toteuttaa nopeudenrajoituksen omissa sovelluksissasi ja varmistaa palveluidesi vakauden ja saatavuuden käyttäjille ympäri maailmaa.