Olli-Pekka Heinisuo
Perustaja, Senior Software Architect
icon

Palvelittomat pilvinatiivit REST APIt Azure Functions-alustalla

Useimmat nykyaikaiset web-sovellukset on tehty erottamalla niin kutsutun taustajärjestelmän (backend) sekä esittävän kerroksen (frontend) toteutukset. Taustajärjestelmä suoritetaan palvelimelle ja esityskerros puolestaan käyttäjän omassa selaimessa. Nämä kaksi kommunikoivat toistensa kanssa ohjelmistorajapinnan (application programming interface, API) kautta. Monissa tapauksissa tämä rajapinta on niin kutsuttu representational state transfer (REST) -rajapinta, joka välittää tietoa HTTP-protokollan ylitse. Myös muunlaisia rajapintoja on olemassa, mutta keskityn tässä tekstissä REST-rajapintoihin.

Taustajärjestelmän julkaisu, ajo sekä skaalaus vaativat paljon konfigurointia infrastruktuurin osalta. Tämän kaiken hallinta taustajärjestelmien kehityksen ohella on monimutkaista ja vie huomattavan paljon aikaa. Onneksemme pilvitoimittajilla on ratkaisuja, joiden avulla voit keskittyä vain itse sovelluksen toteutukseen. Azuressa tätä palvelitonta (serverless) alustaa kutsutaan nimellä Azure Functions. Funktiot ovat pieniä koodinpätkiä, jotka pilvialusta suorittaa jonkin ulkoisen tapahtuman tai pyynnön myötä.

Terminä "palveliton" on melko harhaanjohtava: taustalla on aina palvelinkeskuksia, palvelimia ja muuta fyysistä infrastruktuuria. Azure Functionsin kontekstissa palvelimeton tarkoittaa sitä, että alusta huolehtii kaikesta muusta paitsi koodin kirjoittamisesta. Funktiot ovat kustannustehokkaita, sillä useimmin käytetyssä consumption-tilauksessa vain funktioiden suorituksesta maksetaan. Tilaukseen sisältyy huomattava määrä ilmaisia suorituksia, ja pienet projektit ylittävät sen harvoin. Consumption-tilauksessa funktiot suoritetaan vain pyynnöstä. Mikäli pyyntöjä ei tule, funktiot eivät pysy päällä.

Funktioita käytetään usein viesti- ja tapahtumapohjaisissa järjestelmissä datan prosessointiin, mutta kokemuksieni perusteella ne sopivat yhtä hyvin rajapintojen toteuttamiseen pienissä ja keskisuurissa projekteissa. Nopean kehityssyklin ohella Azure Functionsin kehittäjätyökalut tarjoavat todella hyvin kehittäjäkokemuksen Visual Studio Codella ja Visual Studiolla. Pidän itse enemmän Visual Studiosta. Azure Functions -sovellusta voidaan ajaa ja debugata paikallisessa kehitysympäristössä molemmilla editoreilla.

Azure Functionsin muita hyötyjä ovat nopea julkaisu, automaattinen horisontaalinen skaalaus ja erittäin hyvät integraatiot muiden Azuren palvelujen kanssa. Autentikointi on naurettavan helppo toteuttaa Azure AD:lla ja funktioiden oma identiteetti tekee muiden Azuren palveluiden käytöstä

Huonoina puolina ovat niin kutsutut kylmäkäynnistykset (menee hetki, ennen kuin funktiot heräävät, jos ne eivät ole jo ajossa), rajoitettu laskentateho ja muisti. Useimmissa rajapintatoteutuksissa nämä eivät aiheuta ongelmia.

Azure Functions -sovellusten arkkitehtuuri

Azure Functions -sovellukset koostuvat useista funktioista. API-sovelluksessa näitä funktioita kutsutaan HTTP-triggereiksi. Jokainen HTTP-triggeri on yksittäinen API-päätepiste. Jos rajapinta koostuu esimerkiksi kirjojen luomisesta ja listaamisesta, niin molemmille on oma funktionsa. C#:lle on olemassa laajennos, jolla funktioiden koodissa olevista attribuuteista voidaan luoda OpenAPI-kuvaus ja tarjota se luettavaksi Swagger UI:lla muille kehittäjille. Tämä nopeuttaa kehitystä entisestään ja tekee muiden työstä helpompaa.

Valitettavasti useimmat Azure Functions -tutoriaalit eivät keskity ohjelmistoarkkitehtuuriin. Esimerkiksi kaiken koodin kirjoittaminen HTTP-triggerin sisälle usean rajapintapäätepisteen toteutuksessa ei ole kovin fiksua. Tällöin sovelluksen laajentaminen ja ylläpito on hankalaa.

Esittelen seuraavaksi erään tavan C# Azuren Functions -sovelluksen arkkitehtuurin toteuttamiseen, jolla kehitys sekä ylläpito helpottuu. Jos ASP.NET Core on tuttu teknologia, tämä arkkitehtuuri on sinulle todennäköisesti jo tuttu.

Käytännössä tavoitteena on pitää HTTP-triggereissä oleva koodi niin vähäisenä kuin mahdollista. Rakenna muu sovellus Clean Architecture -arkkitehtuuria noudattaen ja käyttämällä Azure Functionsin tukea dependency injection -menetelmälle. HTTP-triggerit ovat API-sovelluksen esityskerros. En mene yksityiskohtiin tässä kirjoituksessa, sillä arkkitehtuuri on kuvattu hyvin Microsoftin dokumentaatiossa yllä olevan linkin takana.

Helpon kehityksen ja ylläpidon lisäksi arkkitehtuuri mahdollistaa koko Azure Functionsin poistamisen. Esityskerroksen (= kontrollerit) voi vaihtaa helposti muuhun ohjelmistokehykseen, kuten ASP.NET Coreen. Sovelluksen logiikka tai datan käsittely ei ole millään tavalla riippuvainen Azure Functionsista. Tämä tarkoittaa sitä, että toimittajalukkoa Azureen ei pääse syntymään ja voit siirtää koodisi tarvittaessa muualle ajoon.

Azure Functions on todennäköisesti helpoin, nopein ja kustannustehokkain tapa luoda REST API -taustajärjestelmiä Azureen. Kokonaisen pilvisovelluksen arkkitehtuurin suunnittelu ja toteutus on kuitenkin kokonaan eri juttu. Se vaatii syvällistä ymmärrystä pilvialustasta, sillä yksittäinen pilvipalvelu on harvoin riittävä laadukasta pilviarkkitehtuuria toteutettaessa. Jos olet kiinnostunut modernien pilvinatiivien sovellusten toteuttamisesta, vilkaise pilvinatiivia palvelutarjontaamme ja ole yhteydessä.