Johdanto
Monet verkkosovellukset hyödyntävät tavalla tai toisella monia erilaisia ohjelmointirajapintoja (engl. API). Usein verkkosovellusten palvelinpuoli – niin kutsuttu backend – rakennetaan RESTful-arkkitehtuuriin perustuen. Tässä blogissa käyn läpi asioita, joita tulisi muun muassa ottaa huomioon RESTiin perustuvaa backend-palikkaa rakennellessa. Kannattaa muistaa, ettei tämän blogin lista ole tyhjentävä – energiatehokkuusoptimointiin sisältyy paljon tapauskohtaisia tekijöitä, kuten toteutuksessa käytetyn ohjelmointikielen tarjoamat ominaisuudet.
Energiatehokkuus verkkosovelluksissa
Green coding tai vihreä koodi on tutkimusaiheena varsinkin verkkosovellusten näkökulmasta vielä suhteellisen nuori. Kiinnostus sitä kohtaan kuitenkin kasvaa jatkuvasti, ja sitä sivuava lainsäädäntö häämöttää jo horisontissa. Palvelinohjelmiston energiatehokkuus on vain yksi osa-alue verkkosovelluksen energiatehokkuudessa, mutta siihen liittyy jo lukemattomia vaihtoehtoja ja mahdollisuuksia parantaa koko ketjun energiatehokkuutta.
Energiatehokkuusoptimointi on tavanomaisesti painottunut mobiiliohjelmistoihin ja sulautettuihin järjestelmiin, mikä on toki luonnollista - käyttäväthän mobiililaitteet ja monet sulautetut järjestelmät akkuja energianlähteenään. On kuitenkin tärkeää huomioida samat ongelmat myös verkkosovelluksissa energiankäytön minimoimiseksi ja hyötysuhteen parantamiseksi. Osa mobiililaitteiden ohjelmistoissa käytetyistä energiatehokkuusoptimointitekniikoista on hyödynnettävissä suoraan verkkosovelluksissa. [4]
Endpointit ja pyyntöjen minimointi
API-endpoint on lyhyesti kuvailtuna URL-osoite, joka toimii yhteyspisteenä asiakasohjelman ja palvelimen välillä. Endpointeja rakentaessa kannattaa huomioida, ettei sille anneta turhaa dataa pyynnöissä, ja että se palauttaa vain asiakasohjelman tarvitseman datan - ei siis mitään ylimääräistä. Näin minimioidaan siirrettävän datan määrä. Teknisen toteutuksen optimoinnin lisäksi rajapinnan dokumentaation tulee olla kunnossa, jotta sitä myös käytetään paitsi oikein, myös tehokkaasti.
Kun endpointit ottavat vastaan ja palauttavat oikean määrän oikeanlaista dataa, voidaan siirtyä miettimään, miten endpointien handler-funktiot voidaan optimoida energiankulutuksen näkökulmasta. Kun dataa haetaan mahdollisesti useammastakin eri tietokantataulusta, pitää miettiä, onko data jo saatavilla esimerkiksi välimuistissa tai tarvitaanko sitä tai osaa siitä ollenkaan - ei esimerkiksi kannata hakea koko dokumenttia, jos tarvitsee vain yhden kentän arvon. Tietokantakutsujen määrä pitää pyrkiä minimoimaan. Myös itse tietokantajärjestelmä pitää suunnitella tapauskohtaisesti ja mahdollisimman energiatehokkaaksi muun muassa valitsemalla oikeanlainen tietokantahallintajärjestelmä ja tietokantamoottori, mutta näihin syvennytään tarkemmin myöhemmässä blogissa.
Mikäli endpointista voi hakea paljon dataa kerralla, kannattaa huomioida esimerkiksi paginoinnin ja lazy loadingin mahdollisuus; mikäli kaikkea dataa ei ehdottomasti tarvitse ladata kerralla, voidaan se hakea tarpeen mukaan esimerkiksi tietyn kokoisissa erissä. Tällöin tarvittavan verkkoliikenteen määrä korreloi käytetyn – siis aidosti hyödynnetyn – datan kanssa mahdollisimman hyvin.
Rajapintaa suunnitellessa pitää luonnollisesti ottaa huomioon endpointeja käyttävien asiakassovellusten tarvitsema sisältö. Energiatehokkuuden maksimointi vaatii jatkuvaa pohdintaa. Jos esimerkiksi ollessasi kehitystyössä jo melko pitkällä huomaat, että käyttäjillä on tarve hakea dataa useammasta endpointista suorittaakseen tietty yksittäinen operaatio, kannattaa tälle käyttötapaukselle oma endpointinsa. Muissa samantyylisissä tapauksissa voit harkita esimerkiksi batch-operaatioiden [2] tukemista yksittäisten pyyntöjen ryhmittämiseksi yhteen. Joka tapauksessa energiatehokkuuden näkökulmasta tavoitteena on minimoida pyyntöjen määrä ja maksimoida laatu, jotta ylimääräistä verkkoliikennettä ja prosessointiaikaa syntyisi mahdollisimman vähän.
Datan määrän minimointi ja välimuistin käyttö
Jos handler-funktiot esimerkiksi generoivat dataa pyynnön saapuessa - vaikkapa esikatselukuvia kaikkien varsinaisten kuvien lataamisen välttämiseksi - kannattaa todennäköisesti hyödyntää välimuistia. Data voidaan generoida esimerkiksi vain, jos sitä ei löydy välimuistista, ja hakea se muutoin sieltä, sillä mikäli sama data uudelleengeneroitaisiin useaan kertaan, eli jokaisen uuden pyynnön saapuessa, käytettäisiin paljon prosessointiaikaa turhaan. Jatkuvasti käytettyä dataa voidaan siis hakea välimuistista ja generoida se vain tietyin väliajoin, kun taas harvemmin käytetty voidaan generoida tarpeen mukaan.
Riippuen palvelimen maantieteellisestä sijainnista, esimerkiksi CDN:ien eli Content Delivery Networkien käyttäminen voi tulla tarpeeseen ja merkittävästi parantaa energiatehokkuutta, ja dataa ei tarvitse hakea toiselta puolelta maapalloa.
Datan pakkaaminen ja purkaminen verkkoliikenteen minimoimiseksi saattaa myös olla hyvä idea. Tässä kannattaakin ottaa huomioon pakkaus- ja purkualgoritmien resurssi-intensiivisyys ja punnita tilannekohtaisesti optimaalisimman ratkaisun luonne. On näyttöä siitä, että datan pakkaamisella voi parantaa energiatehokkuutta, vaikka siitä aiheutuisi ohjelmistolle ylimääräisiä suoritettavia vaiheita [10] [11]. Lisäksi vaihtoehtoiset tiedonsiirtoratkaisut, kuten Protobuf, saattavat olla tilanteesta riippuen oikeinkin hyviä vaihtoehtoja esimerkiksi JSON:ille. Toisaalta myös tiedostoformaatti - esimerkiksi kuvissa Webp ja AVIF - ja tarjottu resoluutio vaikuttavat sovelluksen energiatehokkuuteen [3] [4]. Näitä optimoimalla saadaan taas tiivistettyä palvelinohjelmiston energiaprofiilia.
Toteutuksen ohjelmointikieli
Ohjelmointikielten välillä on huomattavia energiankulutus-, prosessointiajankäyttö- ja muistinkulutuseroja. Etenkin silloin, jos palvelimen tulee pystyä suorittamaan paljon laskentaintensiivisiä toimenpiteitä, kannattaa valita implementaation toteutuskieleksi energiatehokas ohjelmointikieli, kuten Rust. [1] Lisäksi oikeiden, energiatehokkaiden algoritmien (kuten salaus- tai pakkausalgoritmin) valinta voi huomattavasti vaikuttaa palvelinohjelmiston energiankulutukseen.
Monisäikeisyyden ja niin sanottujen green threadien oikeanlainen hyödyntäminen voivat tapauksesta riippuen parantaa merkittävästi palvelinohjelmiston energiatehokkuutta. Muun muassa Go-ohjelmointikielen goroutinet ovat esimerkki green threadeistä. Pitää muistaa, että käyttöjärjestelmätason säikeiden hyödyntämisen energiatehokkuusvaikutukset ovat varsin tapausriippuvaisia ja määrittyvät muun muassa säikeiden lukumäärän ja hallintarakenteiden valinnan sekä datan määrän perusteella. [12]
Toisaalta, riippuen valitusta ohjelmistokielestä, myös valittu ajoympäristö ja ohjelmointikehys (framework) voivat vaikuttaa merkittävästi ohjelmiston energiatehokkuuteen. Valitaan tarkasteltavaksi ohjelmointikieleksi vaikkapa verkkosovelluskehityksessä hyvin tunnettu TypeScript. Haluamme tässä tapauksessa valita ajoympäristöksi suositun NodeJS:n sijaan esimerkiksi Bunin, sillä se on sekä tehokkaampi että nopeampi [5] [7], mutta mikä tärkeintä, myös energiatehokkaampi [6] vaihtoehto. Kuten aiemmin mainittu, myös ohjelmointikehyksissä on eroja; “klassiseen” ExpressJS-kehykseen verrattuna esimerkiksi Fastify on merkittävästi nopeampi ja tehokkaampi ratkaisu [8] [9]. Tulee siis pitää mielessä, että itse ohjelmointikielen “sisälläkin” voi olla monia valintoja tehtävänä, kuten edellä mainittu ohjelmointikehys, jos paras energiatehokkuus on tavoitteena.
Turhan koodin minimointi ja kolmannen osapuolen kirjastot
Niin palvelin- kuin asiakaspuolen ohjelmistoissakin käytetään usein kolmannen osapuolen kirjastoja. Ohjelmiston “bundlen” koon minimoimiseksi kannattaa välttää turhien kirjastojen asentamista, valita sellaiset kirjastot, jotka toteuttavat vain rajapinnan toteuttamisen kannalta välttämättömiä asioita ja yleisellä tasolla minimoida ylimääräinen koodi. Näin myös ohjelmiston skaalautuvuus paranee. Monet teknologiat myös tarjoavat konfigurointiasetuksia, joilla voi optimoida edellä mainittua prosessia.
Turhan tekemisen minimointi
Mahdolliset ja todennäköiset virhetilanteet kannattaa ottaa huomioon; jos palvelin esimerkiksi hakee ulkoisesta, kolmannen osapuolen rajapinnasta dataa, ei siihen kannata lähettää vastaamatta jääneitä kyselyitä loputtomiin, jos kyseinen rajapinta ei ole saatavilla. Tällaisissa tapauksissa voidaan hyödyntää niin kutsuttua Dynamic Retry Delay -ominaisuutta, jossa edellisen kyselyn ja uudelleenkyselyn väliin jäävä aika kasvaa vaikkapa Fibonaccin lukujonon mukaisesti [4]. Tällöin taas ohjelmisto tekee vähemmän turhaa työtä eli toisin sanoen kuluttaa vähemmän energiaa tarpeettomien tehtävien suorittamiseen.
Muita esimerkkejä käytännöistä, jotka kannattaa pitää mielessä, ovat esimerkiksi käyttämättömien websocket- ja tietokantayhteyksien sulkeminen. Lokien kirjaaminen (engl. logging), joka ei ensituntumalta välttämättä herättäisi suurta huomiota energiatehokkuusoptimoinnin näkökulmasta, kannattaa kuitenkin pitää minimissä [4]. Käytännössä tämä tarkoittaa, että logataan harkitusti vain kriittiset ja tarpeelliset asiat. Yleinen ohjenuora voisi esimerkiksi olla, että ohjelmiston tulisi suorittaa toimintoja vain erillisestä kutsusta - siis vain silloin, kun asiakassovellus sitä pyytää [4].
Energiatehokkuus lähtee asenteesta - ja alkaa koodista
Pohjimmiltaan energiatehokkuusoptimointi on ohjelmiston energiankäyttöön liittyvien asioiden huomioon ottamista kehitystyötä tehdessä. Turhien toimintojen karsiminen ja koko järjestelmän toiminnan yleinen optimointi ovat hyviä lähtökohtia, joita tulisi noudattaa jo lähtökohtaisesti ohjelmistokehityksessä. Energiatehokkuusajattelu on vain lisäys olemassa olevaan ajatusmalliin. Kun motiivi ja asenne ovat kunnossa, on paljon helpompi lähteä soveltamaan varsinaisia energiatehokkuus- ja Green Coding -käytänteitä ja -menetelmiä kehityksen jokaisessa vaiheessa. Tietokanta-, asiakassovellus-, tuotantoonvienti- ja verkkoisännöintioptimoinnit ovat näkökulmia, jotka pitää myös ottaa huomioon, kun arvioidaan koko järjestelmän energiatehokkuutta. Näitä tulemme käsittelemään tarkemmin tulevaisuuden blogeissa!
Verkkosovelluksissa ja palvelinohjelmistoissa on miljoona ja yksi asiaa, jotka pitää ottaa huomioon energiatehokkuusasioita pohtiessa. Tämän blogin vinkit huomioimalla pääsee kuitenkin vähintäänkin alkuun. Kannattaa muistaa, että tarkistuslistan sokea noudattaminen ei ohjaa meitä suoraan parhaaseen lopputulokseen, vaan jokainen vihreän koodin osa-alue tulee arvioida tilanne- ja tapauskohtaisesti. Loppukaneettina voitaneen sanoa, että energiatehokkuus alkaa koodista!
Lähteet
[1] R. Pereira, M. Couto, F. Ribeiro, R. Rua, J. Cunha, J. P. Fernandes, and J. Saraiva, “Energy efficiency across programming languages: how do energy, time, and memory relate?,” in Proceedings of the 10th ACM SIGPLAN international conference on software language engineering, pp. 256–267, 2017.
[2] “Execute batch operations using the Web API” Microsoft. https://learn.microsoft.com/en-us/power-apps/developer/data-platform/webapi/execute-batch-operations-using-web-api (accessed June. 17, 2024).
[3] “Which image format choose to reduce energy consumption and environmental impact?” Greenspector. https://greenspector.com/en/which-image-format-to-choose-to-reduce-its-energy-consumption-and-its-environmental-impact/ (accessed June. 17, 2024).
[4] P. Rani, J. Zellweger, V. Kousadianos, L. Cruz, T. Kehrer, and A. Bacchelli, “Energy patterns for web: An exploratory study,” in Software Engineering in Society (ICSE-SEIS’24), (Lisbon, Portugal), April 14–20 2024.
[5] M. F. Ahmod, “Javascript runtime performance analysis: Node and bun” 2023.
[6] J. J. Merelo-Guerv ́os, M. Garcıa-Valdez, and P. A. Castillo, “An analysis of energy consumption of javascript interpreters with evolutionary algorithm workloads,” 2023.
[7] K. I. and F. A., “CHOOSING THE RIGHT JAVASCRIPT RUNTIME: AN IN-DEPTH COMPARISON OF NODE.JS AND BUN,” Norwegian Journal of development of the International Science, May 2023.
[8] I. P. A. E. Pratama and I. M. S. Raharja, “Node. js performance benchmarking and analysis at virtualbox, docker, and podman environment using node-bench method,” JOIV: International Journal on Informatics Visualization, vol. 7, no. 4, pp. 2240–2246, 2023.
[9] D. Demashov and I. Gosudarev, “Efficiency evaluation of node. js web-server frameworks.,” in MICSECS, 2019
[10] H. M. Al-Kadhim and H. S. Al-Raweshidy, “Energy efficient data compression in cloud based iot,” IEEE Sensors Journal, vol. 21, no. 10, pp. 12212–12219, 2021.
[11] A. Reinhardt, D. Christin, M. Hollick, and R. Steinmetz, “On the energy efficiency of lossless data compression in wireless sensor networks,” in 2009 IEEE 34th Conference on Local Computer Networks, pp. 873–880, IEEE, 2009.
[12] G. Pinto, F. Castor, and Y. D. Liu, “Understanding energy behaviors of thread management constructs,” in Proceedings of the 2014 ACM International Conference on Object Oriented Programming Systems Languages & Applications, pp. 345–360, 2014.