This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2023-05-24
Channels
- # aleph (1)
- # beginners (43)
- # calva (22)
- # cider (51)
- # clerk (1)
- # clj-kondo (20)
- # clojure (29)
- # clojure-denmark (1)
- # clojure-europe (73)
- # clojure-finland (28)
- # clojure-nl (1)
- # clojure-norway (7)
- # clojure-spec (7)
- # clojure-uk (4)
- # clojurescript (12)
- # data-science (2)
- # datomic (51)
- # events (1)
- # fulcro (20)
- # hyperfiddle (28)
- # integrant (6)
- # malli (20)
- # matrix (2)
- # music (1)
- # off-topic (66)
- # reitit (17)
- # releases (5)
- # ring (1)
- # shadow-cljs (31)
- # xtdb (6)
Olen tässä ihmetellyt kun aika simppeli staattisen sivuston generaattori clojurella, toki muutamilla dependencyillä, on uberjarrina 42MB. Jar-paketin kun purkaa, niin com.oracle.truffle on 33M, ja com.ibm.icu on 41M. Onko tämä mukana käytännössä kaikissa softissa aina? Saanko jarrin dependencyistä rakennettuna jonkun puun, jotta näkis mitä kautta nuo tulee mukaan projektiin? Pelkästään M1 macilla javalla main-funktioon saakka kestää 2.76s:
time java -jar target/generator.jar -asdf
2023-05-24 22:15:17.673:INFO::main: Logging initialized @1333ms to org.eclipse.jetty.util.log.StdErrLog
Invalid flag. Supported flags are -generate and -webserver.
java -jar target/generator.jar -df 2.76s user 0.14s system 205% cpu 1.418 total
Ja GCP:n cloud runissa kestää jotain 10 s docker-kontin ylösajo ja javan käynnistys. 😓
Mun depsit on:
{:deps {org.clojure/clojure {:mvn/version "1.11.1"}
com.taoensso/truss {:mvn/version "1.9.0"}
clj-http/clj-http {:mvn/version "3.12.3"}
hiccup/hiccup {:mvn/version "2.0.0-alpha2"}
metosin/muuntaja {:mvn/version "0.6.8"}
floatingpointio/graphql-builder {:mvn/version "0.1.14"}
stasis/stasis {:mvn/version "2.5.1"}
optimus/optimus {:mvn/version "2023-02-08"}
org.clojure/data.json {:mvn/version "2.4.0"}
ring/ring-jetty-adapter {:mvn/version "1.8.2"}
ring/ring-devel {:mvn/version "1.8.2"}
ring/ring-spec {:mvn/version "0.0.4"}
sitemap/sitemap {:mvn/version "0.4.0"}}
:paths ["src" "resources"]
:aliases {:project/run {:main-opts ["-m" "generator.core"]}
:project/generate-sitemap {:main-opts ["-m" "generator.sitemap"]}
:build {:deps {io.github.clojure/tools.build {:mvn/version "0.9.4"}}
:ns-default build}}}
Auttaisikohan tää? https://www.reddit.com/r/Clojure/comments/13p4t9s/thin_ish_clojure_jars_for_better_docker_containers/
@UCQGNA673 Voi olla, joskin kirjoittaja lähinnä ajaa tuossa takaa docker-kontin layerointia jotta viimeinen layer on pienempi. Sinänsä en usko, että tuo käynnistysnopeuteen vaikuttaa paljoakaan, muuta kuin että käynnistys heti uuden deployn jälkeen voi olla nopeampi. Cloud runihan skaalaa kontit nollaan, jos requesteja ei ole 15 minuuttiin. Ja kun requesti tulee, käynnistetään uus kontti. Vähän niin kuin serverless siis.
Lyhyen googlettelun perusteella graalVM vois olla ratkaisu, tosin näyttää aika työläältä saada toimimaan.
Jos lähdet graal-tietä koluamaan niin täällä on hyvää lukemista https://github.com/clj-easy
icu tekee mm. charset tunnistuksen, en ny muista tuleeko Muuntaja kautta, mutta se ei oo täysin pakollinen jos tietää että requestit on esim. aina utf8
trufflea en muista nähneeni, deps tree näyttää mistä se tulee, arvaus ois truss tai graphql-builder
clj --help
sanoo mistä se tree tulee, oisko -Stree
AOT auttaa käynnistysaikoihin, en nyt muista miten tools.build toimii niin en tiedä onko tuossa jo
Näemmä truffle tulee tästä: https://github.com/magnars/optimus
Tapauksesta riippuen voi olla vähän raskasta hoitaa noiden resurssien "optimointi" sovelluksen sisällä eikä build aikana
Tosin, kun JVM alustaa niitä luokkia ajonaikana, niin jar-paketin koko ei taida suoraan korreloida käynnistysaikaan. Vaan se, missä koodipoluissa se alustetaan. Vois ehkä miettiä nuo tuotannon webserverin api-jutut ihan eri entrypointtiin / luokkaan noista lokaalin kehityksen web-serveristä.
No joo, sinänsä me generoidaan vaan staattinen sivu. 🙂 Mutta on tuonne tarkoitus laittaa ainakin yksi formin submitin endpoint, ja joku preview-endpoint Contentfulia varten.
css voi hoitaa ihan perus sass kääntäjällä, uglifyjs on turha cljs kanssa, noi cache headerit voi lisätä suoraan parilla rivillä koodia
GraalVM ei ole mitenkään ongelmaton, pitää vähän varoa ettei depsut hajota buildia. Ei oo mikään mahdoton työmaa, mut selkee tradeoff.
Toisaalta jos on staatisen sivun generaattori niin onko niin väliä jar koolla tai käynnistysajalla? kehittäessä sovellus voi olla käynnissä jatkuvasti jne.
Mä kans kysyisin samaa. Devatessa on yleensä isoin ongelma, mut silloinkin systeemitkin voi spinnata päälle REPLin kautta.
Jossain CLI-sovelluksessa käynnistysajalla on suuri merkitys, jonne sit graalvm istuu aika kivasti. Skriptauksessa myös babashka on ihan kohtuu nopea.
Ehkä joku tapaus missä headless-CMS systeemi lähettää webhookilla päivityksen ja siitä spinnaa ylös joku lambda tms. ja pitäisi nopeasti saada päivitys ulos (tai ennen kaikkea ehkä jos preview tarvii saada näkyville nopeasti)
Mut en tiedä tekisinkö Clojurella sellaista systeemiä välttämättä
Lambdat onkin sit vähän oma juttunsa, niissä toki pystyy pyörittelemään clojurescriptiä, babashkaa tai https://github.com/candid82/joker.
Ehkä vähän AWS mainos, mutta AWS Lambdan JVM runtimessa on nykyään Snapstart -niminen feature, joka deploymentin yhteydessä käynnistää prosessin ja tekee siitä VM tason snapshotin, ja sitten requestia vastaanottaessa palauttaa tämän snapshotin. Nopeuttaa merkittävästi kylmäkäynnistystä JVM alustalla, myös Clojuren kanssa. Käytän yhdessä projektissa, jossa lambdassa reitit/muuntaja yms. kalustolla 8s kylmäkäynnistys nopeutuu ilman sen ihmeempiä optimointeja 500ms tasolle https://docs.aws.amazon.com/lambda/latest/dg/snapstart.html
Deploymenttiin tulee tosin pari minuuttia lisäkestoa ja pitää käyttää lambda versioita (checkpoint teko kytkettävissä lambda version teon yhteydessä päälle), mutta pystyy edelleen pitämään JVM:n mukana ja saaman nopean kylmäkäynistyksen ja sen jälkeen on edelleen se tuttu JVM kalusto pyörimässä, niin yksinkertaisti paljon native-imagen jälkeen buildiprosessiakin (native-image käännös ei sekään kauhean nopea ja resurssi-intensiivinen CPU ja muistin suhteen, riippuen tavukoodin määrästä).
On kyllä ollut positiivinen kokemus tämä Clojure näin muuten. Työkaveri, joka ei ole koskaan aiemmin clojurella mitään tehnyt, on nyt kuukauden päivät värkännyt tätä, enkä ole kädestä edes pitänyt kiinni. Tykännyt kovasti miten tehokkaasti ja vähällä koodilla asioita saa aikaan.
Jvm on aika läski ja hidas käynnistymään, kun sitä ei ole varsinaisesti suunniteltu one-off skriptien, vaan pitkään päällä pysyvien ohjelmien ajamiseen. Kikkailemalla senkin saa tosin aika pieneksi, mutta vaatii ekstratyötä.
mitenkäs ne graalvm ja native image hommat?
Niitä ruodittiin tuossa ylempänä ketjussa myös hieman. 🙂 Eli se on ihan validi keino myös, mutta jos on riippuvuuksia, niin kaikki ei toimi välttämättä suoraan, tai ollenkaan. Babashkahan on käytännössä GraalVM:llä natiiviksi käännetty Clojure-tulkki + paristot.
Ehkä vähän AWS mainos, mutta AWS Lambdan JVM runtimessa on nykyään Snapstart -niminen feature, joka deploymentin yhteydessä käynnistää prosessin ja tekee siitä VM tason snapshotin, ja sitten requestia vastaanottaessa palauttaa tämän snapshotin. Nopeuttaa merkittävästi kylmäkäynnistystä JVM alustalla, myös Clojuren kanssa. Käytän yhdessä projektissa, jossa lambdassa reitit/muuntaja yms. kalustolla 8s kylmäkäynnistys nopeutuu ilman sen ihmeempiä optimointeja 500ms tasolle https://docs.aws.amazon.com/lambda/latest/dg/snapstart.html
Deploymenttiin tulee tosin pari minuuttia lisäkestoa ja pitää käyttää lambda versioita (checkpoint teko kytkettävissä lambda version teon yhteydessä päälle), mutta pystyy edelleen pitämään JVM:n mukana ja saaman nopean kylmäkäynistyksen ja sen jälkeen on edelleen se tuttu JVM kalusto pyörimässä, niin yksinkertaisti paljon native-imagen jälkeen buildiprosessiakin (native-image käännös ei sekään kauhean nopea ja resurssi-intensiivinen CPU ja muistin suhteen, riippuen tavukoodin määrästä).