pondělí 27. března 2017

Papírová škálovatelnost, Bcrypt a ladění výkonostních problémů Zonkyho

V poslední době často odpovídám na technické otázky našich uživatelů z řad investorů ohledně problémů s přetíženým Zonkyho v době půjček s vysokým úrokem, o které se pravidelně strhává litý boj. Rád bych na jednom místě sepsal seznam problémů a řešení, které jsme udělali.

Jakékoliv naše řešení je nutně determinované architekturou aplikace a zdroji, které máme k dispozici. Zonky je postavený nad klasickým Java stackem - Spring, JPA a jako databáze se používá Postgres. Jako v každém jiném startupu jsme nejdříve validovali business model a jeho růst namísto toho, abychom tunili architekturu. Podle mého soudu je to naprosto validní a jediná správná cesta. K čemu je vám super škálovatelná architektura, když nemáte platící uživatele. Řečnická otázka samozřejmě.

Naše architektura je tedy resp. byla do jisté míry poplatná tomu, že jsme startup, který šel na trh s MVP. jednalo se o klasický monolit. Škálovatelnost vertikální ano, horizontální na papíře. Proč na papíře, když svět je přece plný technologií s neomezenými škálovacími možnostmi, máme Docker, Kubernetes, Redis, cloud, virtualizaci?

Při použití klasického Java stacku, máte teoretickou možnost škálovat horizontálně. V našem případě nasadit aplikaci na více strojů. Ještě jednou, tohle je teorie. Každý kdo někdy provozoval nějaký distribuovaný systém ví, že jakmile do hry začne vstupovat sdílený stav a síť, začnou se věci dost komplikovat viz CAP theorem a jeho důsledky.

Krátká odbočka k Zonky. V našem případě je sdílený stav reprezentovaný in-process cache, kterou offloadujeme zátěž z databáze. V cache leží všechny kritická data, která jsou nutná pro provedení investice - aktuální stav zainvestování, autentizační tokeny atd.

A teď zpátky k CAPu a jeho dopadům. Máte sice kód a technologie, které se tváří, že fungují v distribuovaném prostředí, ale prakticky nevíte jaké problémy se na vás řítí - rozpady sítí, zpomalení komunikace/zahazování packetu, rozjetí systémových hodin atp., které k vám stejně probublají.

Rozdíl mezi tím, kdy máte aplikaci horizontálně škálovatelnou teoreticky a prakticky, je v tom že tyhle okrajové případy selhání máte podchycené. Nemůžete si říci: můj technologický stack tohle podporuje, fajn jdeme na to. Musíte se podívat na sdílený stav a ten vyřešit. Žádná technologie, která by magicky za vás řešila všechny problémy sdíleného stavu neexistuje.

Náš charakter provozu vypadá následovně: stabilní počet požadavků a při půjčce s vysokým úrokem řádový nárůst, protože faktor času/rychlosti je klíčový. To co nám hraje do karet je, že chvilku před víme, že k takové události dojde. Zase je to teorie, protože pokud nedokážete horizontálně vyškálovat je vám tahle informace k ničemu.

Většina prvotních výkonových problémů šla jednoduše odstranit na databázi. Prostě se přidal chybějící index případně se zoptimalizoval JPA dotaz či jiné další známé ORM optimalizace. Před nějakým časem jsme ovšem narazili na problém, který vyžadoval mnohem větší invenci.

Problém byl v tom, že aplikace začala konzumovat veškerý výpočetní výkon a pak se na chvíli zasekla a pak zase rozběhla. Podle telemetrie všechno ukazovalo na Bcrypt funkci, která se používá na hashování hesel. Vzhledem k době platnosti autentizačního tokenu došlo k tomu, že se stovky uživatelů chtěly v jeden okamžik zalogovat. Bcrypt je jako bezpečná funkce pro hashovani hesel z principu pomalá.

To co nedávalo smysl, bylo zatuhnutí a samovolné rozběhnutí aplikace. Z telemetrie bylo vidět, že jsou obsazené všechny databázové připojení. Při bližším průzkumu jsme zjistili, že za to může použítí návrhového anti-vzoru OpenSessionInView v kombinaci se sideloaderem do cache.

Po celou dobu odbavení požadavku se drželo aktivní databázové připojení. Při saturovaném výkonu CPU to znamenalo, že vlákna, která fakticky databázová připojení nepotřebovala, (neb čekala na CPU) spotřebovala všechnu jejich kapacitu. Buďto se dostala k lizu a nebo skončily timeoutem. V tu chvíli se celý systém rozpohyboval zpět k životu. Jak to?

Máme read-heavy provoz, praktický veškerou komunikaci obsluhujeme z cache a data do cache (Hazelcast) se nahrávají side loaderem z databáze. Ten je reprezentován dedikovaným thread poolem. Čili mezi aplikačním vláknem či vlákny, které čekají na tu cache a vlaknem sideloaderu, které do ní nahrává data z databáze, došlo k vyčerpání připojení. Sideloader(y) do cache čekaly na spojení, která byla zbytečně držena aplikačními vlákny (díky OpenSessionInView), která čekala na CPU plně saturované Bcryptem. Když došlo k timeoutu nebo se uvolnilo spojení, ke kterému se dostalo sideloader vlákno systém se pomalu pohnul dopředu.

Pořadí našich patchů:

  1. Vertikální škálovaní - zvýšit výkon přidáním CPU
  2. Odložit alokaci databázového spojení na nejzašší možný okamžik (typicky zahájení transakce)
  3. Odstranit sideloading do cache pro nejčastější použítí
  4. Dedikovaný databázový pool pro sideloadery, aby nedocházelo k vzájemnému vyčerpání.
  5. Předřazení semaforu před Bcypt, abychom limitovali maxímánlí možmý paralelismus, který systém neochromí (počet CPU - 1)

Úplné odstranění OpenSessionInView nebylo možné a stejně tak přepsání sideloaderu vzhledem k urgenci toho problému.

Dalším krokem, který chystáme, je offloadování Bcryptu na volnou kapacitu, kterou máme v datovém centru k dispozici. Máme mikroslužbu, kterou nasadíme na N strojů a jediné co bude dělat, je hashování s tím, že tam bude vždycky možnost fallbacku zpět na lokální výpočet.

Zde se nabízí otázka jestli neudělat scale out do cloudu. Pro tenhle případ by se perfektně hodil serveless v podobě AWS Lambda. Už teď máme hybridní deployment, kdy nám server side rendering pro SPA běží nad AWS Elastic Beans Talk. Lambda má tu nevýhodu, že by tam byla daleko větší latence a mám trochu obavy, že neexceluje v schopnosti elasticky reagovat na prudký nárůst požadavků během pár desítek sekund. Pak by to znamenalo AWS Lamdy “nažhavit” tedy generovat syntetická provoz, aby se patřičně nafoukl počet instancí schopných odbavit očekávaný provoz. Potřebný infrastrukturní by byl mnohem složitější než samotná mikroslužba.

pondělí 6. března 2017

CZ Podcast 167 - Machine learning startups

At the episode 167. we interviewed Bradford Cross (Google, Flightcaster, Prismatic) who leads machine learning and big data venture capital fund www.ceai.io. We have been discussing various topics - Scala vs. Clojure, Prismatic acquistion by LinkedIn, machine learning at scale etc. One of the key topics was about a culture in startups distributed between Sillicon Valley and Central Europe. An excellent talk worth to listen.

neděle 26. února 2017

Digitální dementi

Jsem digitální dement a otrok chytrého mobilu? Sedím vám takhle s manželkou v restauraci a vzhlédnu od stolu, vidím jak u jiného stolu sedí jiná dvojice a oba koukají do mobilu. Chci něco pohoršeného dodat a všimnu si, že manželka kouká do mobilu. Spolknu myšlenku a vrátím se zpátky k svítícímu displeje mého mobilu. Stop, počkejte chvilku. Protřepat hlavu. Tohle přece není normální. Řekl jsem normální, ale co je normální.

Všimli jste si někdy ikonek aplikací, které vám signalizují, kolik novinek tam přímo na vás čeká? Začal jsem jejich tvůrce podezírat, že to slouží jenom jako vějička pro nalákání uživatelů. A tak sedím na hajzliku s mobilem v ruce a klikám na svítící ikony a jsem zklamán, že pod žádnou z těch ikon není vlastně nic nového, co by mě zajímalo. Stejně mi to nedá a tak pořád koukám.

Kdysi dávno jsem stíhal číst Twitter a dokonce si občas přečíst Facebook statusy a fotky přátel. Už to nedělám, vysoce sofistikované řazení příspěvků, které vás zamkne ve vaší bublině, mi bere poslední zbytky iluzí, že si svobodně volím to co mě zajímá. A bude hůř, strojové učení a petabajty dat budou sloužit právě k tomu, abychom v těch bublinách strávili více času.

Snažím se vypěstovat pár základních návyků, které mi umožní v téhle džungli přežít a nevypadat jako totální otrok sociálních sítí a mobilů.

  • Začal jsem znovu používat Newslettery jako zdroj informací, třeby ty z Oreilly nebo InfoQ. Nemám pak obavu, že zmeškám nějaký zajímavý článek. Články, které mě zaujmou - to nepoznáte podle 140 znaků dlouhé zprávy - si ukládám k pozdějšímu přečtení do Instapaperu.
  • Otáčím mobil displejem dolů, aby mě to nerušilo a nesvádělo k tomu do něj pořád čumět.
  • Dávám si mobil do náprsní kapsy, abych se k němu obtížně dostal, když jsme někde na procházce. Případně ho nechávám v jiné místnosti.

Co se mi nedaří. Neumím nečíst firemní email a Slack po večerech a o víkendech. Je to strašný mor. Člověk je pořád v divné tenzi, že mu něco uniká. Jak mi kdysi pravil jeden velmi moudrý kolega: když budeš pořád něco řešit, nikdy nic nevymyslíš. Musíš se naučit vypnout a nechat mozek flákat.

Proč o tom píšu? Zajímá mě jestli máte nějaké vlastní návyky, jak se tomu bránit nebo jsem sám kdo má pocit, že je digitální dement a otrok chytrého mobilu.

pondělí 20. února 2017

CZ Podcast 166 - Stories

Jednoho čtvrtečního odpoledne vzal Filemon svůj velmi malý mikrofón a vyrazil s ním k I.P. Pavlova vyzpovídat partičku kolem startupu Stories. Konkrétně jsme vyzpovídali Vojtu Ročka, Petera Fedoročka a Filipa Douška. Zajímá vás, co za analytická kouzla peče jeden z nejzajímavějších startupů v České Republice? K tomu se dále dozvíte, co to znamená exponenciální tým, proč se kluci vykašlali na AWS a jak krájejí nekonečný prostor a hledají v něm zajímavá místa. Kluci mají neortodoxní názory a nezdráhají se o ně s vámi podělit. Takže se připravte na díl ostrý jako břitva.

středa 8. února 2017

CZ Podcast 165 - CZ Podcast 165 - Sonda do jádra Mono, Micro, Unikernely

Tentokrát jsme zavítali na akademickou půdu MFF UK za Martinem Děckým z Katedry distribuovaných a spolehlivých systému. Naše povídání se točilo především kolem jádra operačního systému a jeho architektuře takže jsme se dostali od monolitické architektury, přes microkernely až po unikernely. Dotkli jsme se Dockeru, virtualizace a cloudu. To všechno jsou totiž témata, se kterými architektura operačních systému resp. jádra dost úzce souvisí.