Fork me on GitHub
#clojure-norway
<
2022-10-17
>
slipset06:10:57

Ang optimaliseringer/performance. Ardoq har fra tid til annen performance problemer. Vi liker å dele disse problemene i to: De der vi gjør åpenbart idiotiske ting, og de der vi må gjøre noe smartere. En veldig stor andel av problemene ligger i den første kategorien.

cjohansen06:10:40

Interessant!

slipset06:10:53

Forøvrig, og dette er kanskje litt flaut å si, sånn i offentligheten, men vi har liksom levd under en vilfarelse om at 10000 ting er mange ting, og at vi derfor kan forvente at å jobbe med 10000 ting tar tid. Det er feil.

slipset06:10:19

(Det er en del andre ting, rundt dette også, men uansett. 10000 ting er ikke mange ting for en datamaskin idag)

slipset06:10:52

Men, det er klart at hvis du har 10000 ting og bruker bubble sort isteden for quicksort, så tar det jo litt tid å sortere 10000 ting.

👍 1
slowpoke 1
cjohansen06:10:16

Jeg har veldig sjelden jobbet med performance-kritiske greier, og tipper jeg er så full av skylapper på dette temaet som det er mulig å bli.

cjohansen06:10:36

Jeg jobber nesten utelukkende med datamengder som hvilken som helst approach fungerer godt med 😅

😄 1
teodorlu08:10:39

jeg tenkte jeg skulle kverulere litt. Så:

(defn christian* "* - kun heltall!" [x n]
  (let [x (bigint x)
        n (bigint n)]
    (reduce + (repeat n x))))

(defn christian** "^ (**) - kun heltall!" [x a]
  (let [x (bigint x)
        a (bigint a)]
    (reduce christian* (repeat (bigint a) x))))

(let [n 300]
  (time
   (christian** n n)))
Men ...
"Elapsed time: 13.098704 msecs"
-.- For JVM-en var visst det der en smal sak.

teodorlu08:10:00

var visst ikke så lett å framprovosere dårlig ytelse som jeg trodde.

emil0r07:10:20

Latency är också något att ta i betraktande när du använder SQL. Har sett många applikationer med ORM som har spottat ut sig x antal queries där en skulle fungera om det hade blivit skrivit lite smartare

👍 2
Ivar Refsdal08:10:30

Ein kodebase eg jobba med brukte Hibernate og "arving" av tabeller. Det gjorde at SQL inserts ikkje vart batcha, og ein trengte å lesa svaret før neste insert vart gjort. For ein integrasjonstest så hadde ein satt opp at 100 millioner "rader" skulle inn i databasen. Eg rekna ut at det ville ta over 1 år (!) å leggje dei inn med den hastigheita ein fekk med "arving". Med omskriving til manuell inserts (med batching) så tok det ca. 30 minutt (fritt etter hukommelsen). Tipper ein hadde commit per 10K rad. I den grad det er relevant så var dette ein Oracle database, meinar at databasedriveren for lesing der er treig "by default" (om ein ikkje sett fetch size), iallefall var den det den gongen.

👍 1
magnars07:10:08

Mengden dataprosessering Adventur-backenden bedriver for hvert eneste valg spilleren tar, og likevel svarer på noen få millisekunder, er helt hinsides. Jeg overraskes til stadig over hvor mye data dagens datamaskiner kverner unna, så lenge du slipper I/O.

gotta_go_fast 2
teodorlu08:10:29

> Ang optimaliseringer/performance. Ardoq har fra tid til annen performance problemer. Vi liker å dele disse problemene i to: De der vi gjør åpenbart idiotiske ting, og de der vi må gjøre noe smartere. En veldig stor andel av problemene ligger i den første kategorien. @slipset er det mulig å be om litt mer utfyllende definisjoner av "åpenbart idiotiske ting" og "der vi må gjøre noe smartere"? Jeg henger ikke helt med. Et eksempel hadde kanskje hjulpet!

slipset08:10:20

La oss si at du har en fn som ser sånn ut:

(defn add-something [thing]
  (add' xs thing)
  (emit :thing-added thing))
Du kaller den f.eks:
(doseq [t (range 10000)]
  (add-something t))

teodorlu08:10:18

jeg tror fremdeles ikke helt jeg skjønner. Er det et eksempel på det ene eller det andre?

mariuene08:10:29

https://youtu.be/Tq7r97G4b7Y?t=663 Tror det er dette han snakker om

👀 1
mariuene08:10:52

Nå skal det sies at jobben min er å prøve å forstå hva Assum snakker om, så vi kan høre fra han om jeg har faktisk klart det denne gangen 😂

😅 1
😄 1
teodorlu08:10:53

😁 Men det er ofte lettere å få noe forklart fra en annen person som også lærer det samme -- enn direkte fra kilden 🙂 Jeg tror i alle fall veldig mye læringsmateriell blir laget på denne måten.

teodorlu08:10:39

Dette synes jeg er et veldig godt poeng

slipset08:10:24

Jeg rakk ikke helt å skrive ferdig 🙂

teodorlu08:10:44

aah, det forklarer saken 🙂 Hverdag, ass.

slipset09:10:52

Så her er kanskje tanken at man kunne gjøre noe a la:

(defn add-somehting-better [thing]
  (add' xs thing))
(defn commit! []
  (emit :things-added (since-last-commit xs)))
Så kalleren sier da noe a la
(doseq [t (range 10000)]
  (add-something-better t))
(commit!)
Sånn at vi bare emit’er en event med alle changes heller enn en event pr change.

👍 1
teodorlu09:10:17

og det å kjøre commit! 10000 ganger er en "åpenbart idiotisk ting"?

teodorlu09:10:34

ref rich hickey "fast interfaces operate with batches"? (mener jeg har hørt det fra en talk et sted, men husker ikke hvilken, kanskje noe datomic)

slipset09:10:03

Problemet med hva som er smart og hva som er idiotisk avhenger jo hvor en selv er på skalaen 🙂

slipset09:10:57

Å kjøre commit! 10000 ganger frarøver i allefall mottageren muligheten til å gjøre noe som helst smart.

👍 1
cjohansen09:10:56

“Fast interfaces operate with batches” - interessant! Tror ikke jeg har hørt det før, men jeg har internalisert at det ofte er lurt å tenke på “batch-caset” først, og så håndtere “jeg har bare én ting”-caset som en collection med en ting i.

👍 1
teodorlu09:10:48

Jeg tenker feks på at datomic.api/transact tar en liste av transaksjoner https://github.com/kristianmandrup/datascript-tutorial/blob/master/datascript.md

slipset09:10:35

Et annet sted hvor dette appliserer er på api design. Man har en skala på hvor chatty et api er, altså er det mange små requester eller er det færre store requester. Mange små requester gir ikke api’et samme mulighet til å forstå klientens intensjon, og dermed er det vanskeligere for api’et å foreta optimaliseringer.

slipset09:10:28

Man kan tenke seg:

GET /api/all-foos
GET /api/all-bars
GET /api/all-bazes
vs
GET /api/initial-data-load

💯 1
teodorlu09:10:21

Hva tenker dere om JSON+REST vs graphql vs EQL i Ardoq? Er det en norm? Feks GraphQL har jo litt "du kan be om mye i batch hvis du vil" innebygget.

slipset09:10:37

Vi er fortsatt der at vi gjør det GraphQL var ment å løse, nemlig lager en gjeng med ad-hoc endepunkter som sikkert kunne vært uttrykt som et query.

👍 1
slipset09:10:39

Man ser jo at hey, et endepunkt /api/q er en fin ide på papiret, men man ender opp med /api/q?templateQueryId=8 fordi det er enklere hvis man vet noe om hva som spørres etter.

👍 1
slipset10:10:25

Det er litt som over, i et generelt query er det vanskelig å forstå kallerens intensjon, men hvis man har spesifike, navngitte queries er det lettere. Men man kan få en eksplosjon av navn 🤷

👍 1
teodorlu10:10:51

Jeg synes API-design er vanskelig.

slipset10:10:27

Og det er vanskeligere når du designer et åpent api som alle kan bruke.

1
magnars10:10:29

Hos oss vet hver side hvilke data den er interessert i å motta, som er en liste med tupler av typen:

[[:customer-products id]
 [:spot-prices area :hourly]
 [:spot-prices area :daily]]
for eksempel. Når siden skal vises så sammenlignes disse tuplene med hva som allerede er lastet ned, og filtreres til det som trengs å oppdateres. Denne filtrerte listen sendes til et query -endepunkt på serveren, som behandler alle samtidig og sender tilbake til klienten så snart hver er ferdig via SSE.

👍 1
magnars10:10:29

Stemmer. På den måten får klienten dataene så fort serveren har dem klare, istedenfor å få alt samtidig, som ville innebære å vente på det tregeste datapunktet.

👍 1
cjohansen10:10:08

Ja, veldig fornøyd med den løsningen

teodorlu10:10:46

Stemmer - tenkte først at dere snakket om ZombieCLJ. For det er vel websockets. Men dere må kanskje kode litt "jobb-greier" dere også - ikke bare kosekoding 😄

magnars10:10:08

Det stemmer 😅

👍 1
Ivar Refsdal08:10:30

Ein kodebase eg jobba med brukte Hibernate og "arving" av tabeller. Det gjorde at SQL inserts ikkje vart batcha, og ein trengte å lesa svaret før neste insert vart gjort. For ein integrasjonstest så hadde ein satt opp at 100 millioner "rader" skulle inn i databasen. Eg rekna ut at det ville ta over 1 år (!) å leggje dei inn med den hastigheita ein fekk med "arving". Med omskriving til manuell inserts (med batching) så tok det ca. 30 minutt (fritt etter hukommelsen). Tipper ein hadde commit per 10K rad. I den grad det er relevant så var dette ein Oracle database, meinar at databasedriveren for lesing der er treig "by default" (om ein ikkje sett fetch size), iallefall var den det den gongen.

👍 1
teodorlu08:10:10

to slides jeg likte godt fra talken til Erik Assum som ble https://clojurians.slack.com/archives/C061XGG1W/p1665995249625709?thread_ts=1665995118.466099&amp;cid=C061XGG1W. slide 1 - spesifisitet vs generalitet. min formulering: "koden må skrives til å passe inn i det laget den er i. øverst har du spesifikke features som løser domeneproblemer (specific), nederst har du generiske byggeklosser som ikke er avhengig av kontekst"

❤️ 1
msolli09:10:56

God morgen! Jeg også har mange hastighetsproblemer forårsaket av “åpenbart idiotiske ting”. Det er ålreite å problemer å ha, for de er så lett fikse! (Ellers hadde de ikke vært “åpenbart idiotiske”.) Jeg har brukt litt tid på å sette opp tracing med OpenTelemetry, som gir suveren innsikt i hvilke endepunkter (f.eks. ) som lider under åpenbart idiotiske hastighetsproblemer. Bruker clj-otel for instrumentering, og sender dataene til Honeycomb.

👍 2
❤️ 1
magnars10:10:29

Hos oss vet hver side hvilke data den er interessert i å motta, som er en liste med tupler av typen:

[[:customer-products id]
 [:spot-prices area :hourly]
 [:spot-prices area :daily]]
for eksempel. Når siden skal vises så sammenlignes disse tuplene med hva som allerede er lastet ned, og filtreres til det som trengs å oppdateres. Denne filtrerte listen sendes til et query -endepunkt på serveren, som behandler alle samtidig og sender tilbake til klienten så snart hver er ferdig via SSE.

👍 1
slipset11:10:30

Men det viser der er jo helt klart en batching av informasjon, siden dere sender en liste med tupler.

🎯 1
👍 1
magnars11:10:37

Målet var akkurat det å redusere antall requests, og kunne ha et større bilde på oppgaven enn et som var helt "zoomet inn".

👍 1