Fork me on GitHub
#clojure-finland
<
2023-05-24
>
Paavo Pokkinen19:05:39

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}}}

Paavo Pokkinen19:05:28

@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.

Paavo Pokkinen19:05:54

Lyhyen googlettelun perusteella graalVM vois olla ratkaisu, tosin näyttää aika työläältä saada toimimaan.

valtteri19:05:24

Jos lähdet graal-tietä koluamaan niin täällä on hyvää lukemista https://github.com/clj-easy

juhoteperi19:05:48

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

juhoteperi19:05:05

trufflea en muista nähneeni, deps tree näyttää mistä se tulee, arvaus ois truss tai graphql-builder

juhoteperi19:05:39

clj --help sanoo mistä se tree tulee, oisko -Stree

juhoteperi19:05:42

AOT auttaa käynnistysaikoihin, en nyt muista miten tools.build toimii niin en tiedä onko tuossa jo

juhoteperi19:05:28

Tapauksesta riippuen voi olla vähän raskasta hoitaa noiden resurssien "optimointi" sovelluksen sisällä eikä build aikana

Paavo Pokkinen19:05:30

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ä.

Paavo Pokkinen19:05:45

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.

juhoteperi19:05:35

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

ilmo08:05:40

GraalVM saa nopeammaksi juu mut isoja paketteja tulee

ilmo09:05:57

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.

juhoteperi09:05:30

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.

ilmo09:05:43

Mä kans kysyisin samaa. Devatessa on yleensä isoin ongelma, mut silloinkin systeemitkin voi spinnata päälle REPLin kautta.

ilmo09:05:17

Jossain CLI-sovelluksessa käynnistysajalla on suuri merkitys, jonne sit graalvm istuu aika kivasti. Skriptauksessa myös babashka on ihan kohtuu nopea.

juhoteperi09:05:42

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)

juhoteperi09:05:53

Mut en tiedä tekisinkö Clojurella sellaista systeemiä välttämättä

ilmo09:05:09

Lambdat onkin sit vähän oma juttunsa, niissä toki pystyy pyörittelemään clojurescriptiä, babashkaa tai https://github.com/candid82/joker.

viesti05:05:27

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ä).

👍 8
Paavo Pokkinen19:05:45

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.

👍 2
valtteri19:05:55

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ä.

valtteri19:05:44

Mutta babashka tai clojurescript+node on toki myös vaihtoehtoja

Tuomas-Matti Soikkeli07:05:20

mitenkäs ne graalvm ja native image hommat?

valtteri08:05:55

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.

viesti05:05:27
replied to a thread: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. :sweat: 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}}}

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ä).

👍 8