KDB+ database: fra økonomi til Formel 1

KDB+, firmaprodukt KX er en meget kendt i snævre cirkler, ekstremt hurtig, søjleformet database designet til lagring af tidsserier og analytiske beregninger baseret på dem. I starten var (og er) det meget populært i den finansielle industri - alle top 10 investeringsbanker og mange kendte hedgefonde, børser og andre organisationer bruger det. For nylig besluttede KX at udvide sin kundebase og tilbyder nu løsninger inden for andre områder, hvor der er en stor mængde data, organiseret efter tid eller på anden måde - telekom, bioinformatik, fremstilling mv. De blev også partner for Aston Martin Red Bull Racing-teamet i Formel 1, hvor de hjælper med at indsamle og behandle data fra bilsensorer og analysere vindtunneltests. I denne artikel vil jeg fortælle dig, hvilke funktioner i KDB+ der gør det super-performende, hvorfor virksomheder er villige til at bruge mange penge på det, og endelig hvorfor det ikke rigtig er en database.
 
KDB+ database: fra økonomi til Formel 1
 
I denne artikel vil jeg forsøge at fortælle dig generelt, hvad KDB+ er, hvilke muligheder og begrænsninger det har, og hvad dets fordele er for virksomheder, der ønsker at behandle store mængder data. Jeg vil ikke gå ind i detaljerne omkring implementeringen af ​​KDB+ eller detaljerne i dets programmeringssprog Q. Begge disse emner er meget brede og fortjener separate artikler. En masse information om disse emner kan findes på code.kx.com, inklusive en bog om Q - Q For Mortals (se linket nedenfor).

Nogle udtryk

  • In-memory database. En database, der gemmer data i RAM for hurtigere adgang. Fordelene ved en sådan database er klare, men ulemperne er muligheden for tab af data og behovet for at have meget hukommelse på serveren.
  • Søjledatabase. En database, hvor data gemmes kolonne for kolonne i stedet for post for post. Den største fordel ved en sådan database er, at data fra én kolonne gemmes sammen på disk og i hukommelsen, hvilket markant fremskynder adgangen til den. Det er ikke nødvendigt at indlæse kolonner, der ikke bruges i forespørgslen. Den største ulempe er, at det er svært at ændre og slette poster.
  • Tidsserier. Data med en dato- eller tidskolonne. Typisk er tidsbestilling vigtig for sådanne data, så du nemt kan bestemme, hvilken post der går forud for eller efter den aktuelle, eller at anvende funktioner, hvis resultater afhænger af rækkefølgen af ​​posterne. Klassiske databaser er bygget efter et helt andet princip - repræsenterende en samling af poster som et sæt, hvor rækkefølgen af ​​posterne i princippet ikke er defineret.
  • Vektor. I forbindelse med KDB+ er dette en liste over grundstoffer af samme atomtype, for eksempel tal. Med andre ord en række elementer. Arrays, i modsætning til lister, kan lagres kompakt og behandles ved hjælp af vektorprocessorinstruktioner.

 

Historie

KX blev grundlagt i 1993 af Arthur Whitney, som tidligere arbejdede i Morgan Stanley Bank på A+-sproget, efterfølgeren til APL - et meget originalt og på et tidspunkt populært sprog i finansverdenen. Naturligvis fortsatte Arthur i KX i samme ånd og skabte det vektorfunktionelle sprog K, styret af ideerne om radikal minimalisme. K-programmer ligner et virvar af tegnsætning og specialtegn, betydningen af ​​tegn og funktioner afhænger af konteksten, og hver operation har meget mere betydning, end den gør i konventionelle programmeringssprog. På grund af dette optager et K-program minimalt med plads - nogle få linjer kan erstatte sider med tekst på et ordsprog som Java - og er en superkoncentreret implementering af algoritmen.
 
En funktion i K, der implementerer det meste af LL1-parsergeneratoren i henhold til en given grammatik:

1. pp:{q:{(x;p3(),y)};r:$[-11=@x;$x;11=@x;q[`N;$*x];10=abs@@x;q[`N;x]  
2.   ($)~*x;(`P;p3 x 1);(1=#x)&11=@*x;pp[{(1#x;$[2=#x;;,:]1_x)}@*x]  
3.      (?)~*x;(`Q;pp[x 1]);(*)~*x;(`M;pp[x 1]);(+)~*x;(`MP;pp[x 1]);(!)~*x;(`Y;p3 x 1)  
4.      (2=#x)&(@x 1)in 100 101 107 7 -7h;($[(@x 1)in 100 101 107h;`Ff;`Fi];p3 x 1;pp[*x])  
5.      (|)~*x;`S,(pp'1_x);2=#x;`C,{@[@[x;-1+#x;{x,")"}];0;"(",]}({$[".s.C"~4#x;6_-2_x;x]}'pp'x);'`pp];  
6.   $[@r;r;($[1<#r;".s.";""],$*r),$[1<#r;"[",(";"/:1_r),"]";""]]}  

 Arthur legemliggjorde denne filosofi om ekstrem effektivitet med et minimum af kropsbevægelser i KDB+, som dukkede op i 2003 (jeg tror det nu er klart, hvor bogstavet K i navnet kommer fra) og er intet andet end en fortolker af den fjerde version af K'et En mere brugervenlig version er blevet tilføjet oven på K K kaldet Q. Q tilføjede også understøttelse af en specifik dialekt af SQL - QSQL, og tolken - understøttelse af tabeller som systemdatatype, værktøjer til at arbejde med tabeller i hukommelse og på disk osv.
 
Så fra en brugers perspektiv er KDB+ simpelthen en Q-sprogsfortolker med understøttelse af tabeller og SQL-lignende LINQ-stil udtryk fra C#. Dette er den vigtigste forskel mellem KDB+ og andre databaser og dens største konkurrencefordel, som ofte overses. Dette er ikke en database + deaktiveret hjælpesprog, men et fuldgyldigt kraftfuldt programmeringssprog + indbygget understøttelse af databasefunktioner. Denne sondring vil spille en afgørende rolle i en liste over alle fordelene ved KDB+. For eksempel…
 

størrelse

Efter moderne standarder er KDB+ ganske enkelt mikroskopisk i størrelse. Det er bogstaveligt talt en sub-megabyte eksekverbar fil og en lille tekstfil med nogle systemfunktioner. I virkeligheden - mindre end en megabyte, og for dette program betaler virksomheder titusindvis af dollars om året for en processor på serveren.

  • Denne størrelse gør det muligt for KDB+ at føles fantastisk på enhver hardware - fra en Pi-mikrocomputer til servere med terabyte hukommelse. Dette påvirker ikke funktionaliteten på nogen måde, desuden starter Q med det samme, hvilket gør det muligt at bruge det blandt andet som scriptsprog.
  • I denne størrelse passer Q-fortolkeren helt ind i processorcachen, hvilket fremskynder programafviklingen.
  • Med denne størrelse af den eksekverbare fil optager Q-processen ubetydelig plads i hukommelsen; du kan køre hundredvis af dem. Ydermere, hvis det er nødvendigt, kan Q arbejde med titusinder eller hundredvis af gigabyte hukommelse inden for en enkelt proces.

Alsidighed

Q er fantastisk til en lang række applikationer. Process Q kan fungere som en historisk database og give hurtig adgang til terabytes af information. For eksempel har vi snesevis af historiske databaser, hvoraf en ukomprimeret dag med data fylder mere end 100 gigabyte. Men under rimelige begrænsninger vil en forespørgsel til databasen blive afsluttet på ti til hundreder af millisekunder. Generelt har vi en universel timeout for brugeranmodninger - 30 sekunder - og det virker meget sjældent.
 
Q kunne lige så nemt være en database i hukommelsen. Nye data føjes til tabeller i hukommelsen så hurtigt, at brugeranmodninger er den begrænsende faktor. Data i tabeller er gemt i kolonner, hvilket betyder, at enhver handling på en kolonne vil bruge processorcachen med fuld kapacitet. Ud over dette forsøgte KX at implementere alle grundlæggende operationer såsom aritmetik gennem vektorinstruktioner fra processoren, hvilket maksimerede deres hastighed. Q kan også udføre opgaver, der ikke er typiske for databaser - for eksempel behandle streamingdata og beregne i "realtid" (med en forsinkelse fra titusvis af millisekunder til flere sekunder afhængigt af opgaven) forskellige aggregeringsfunktioner for finansielle instrumenter for forskellig tid intervaller eller opbygge en model for indflydelsen af ​​perfekte transaktioner på markedet og udføre dens profilering næsten umiddelbart efter dens afslutning. I sådanne opgaver er den vigtigste tidsforsinkelse oftest ikke Q, men behovet for at synkronisere data fra forskellige kilder. Høj hastighed opnås på grund af, at dataene og de funktioner, der behandler dem, er i én proces, og behandlingen reduceres til at udføre flere QSQL-udtryk og joins, som ikke fortolkes, men udføres af binær kode.
 
Endelig kan du skrive alle serviceprocesser i Q. For eksempel Gateway-processer, der automatisk distribuerer brugeranmodninger til de nødvendige databaser og servere. Programmøren har fuld frihed til at implementere enhver algoritme til afbalancering, prioritering, fejltolerance, adgangsrettigheder, kvoter og dybest set alt andet, hans hjerte begærer. Hovedproblemet her er, at du bliver nødt til at implementere alt dette selv.
 
Som eksempel vil jeg liste, hvilke typer af processer vi har. De bruges alle aktivt og arbejder sammen og kombinerer snesevis af forskellige databaser til én, behandler data fra flere kilder og betjener hundredvis af brugere og applikationer.

  • Forbindelser (feedhandler) til datakilder. Disse processer bruger typisk eksterne biblioteker, der indlæses i Q. C-grænsefladen i Q er ekstremt enkel og giver dig mulighed for nemt at oprette proxy-funktioner til ethvert C/C++-bibliotek. Q er hurtig nok til at håndtere f.eks. behandling af en strøm af FIX-meddelelser fra alle europæiske børser samtidigt.
  • Datadistributører (tickerplant), som fungerer som et mellemled mellem stik og forbrugere. Samtidig skriver de indgående data til en speciel binær log, hvilket giver robusthed for forbrugerne mod forbindelsestab eller genstart.
  • In-memory database (rdb). Disse databaser giver den hurtigst mulige adgang til rå, friske data ved at gemme dem i hukommelsen. Typisk akkumulerer de data i tabeller i løbet af dagen og nulstiller dem om natten.
  • Persist database (pdb). Disse databaser sikrer, at data for i dag opbevares i en historisk database. Som regel gemmer de i modsætning til rdb ikke data i hukommelsen, men bruger en speciel cache på disken i løbet af dagen og kopierer dataene ved midnat til den historiske database.
  • Historiske databaser (hdb). Disse databaser giver adgang til data for tidligere dage, måneder og år. Deres størrelse (i dage) er kun begrænset af størrelsen på harddiskene. Data kan placeres hvor som helst, især på forskellige diske for at fremskynde adgangen. Det er muligt at komprimere data ved hjælp af flere algoritmer at vælge imellem. Opbygningen af ​​databasen er veldokumenteret og enkel, dataene lagres kolonne for kolonne i almindelige filer, så de kan behandles, også ved hjælp af styresystemet.
  • Databaser med aggregeret information. De gemmer forskellige sammenlægninger, normalt med, grupperet efter instrumentnavn og tidsinterval. In-memory-databaser opdaterer deres tilstand med hver indkommende besked, og historiske databaser gemmer forudberegnet data for at fremskynde adgangen til historiske data.
  • Endelig gateway processerservicering af applikationer og brugere. Q giver dig mulighed for at implementere fuldstændig asynkron behandling af indgående beskeder, distribuere dem på tværs af databaser, kontrollere adgangsrettigheder osv. Bemærk, at meddelelser ikke er begrænset og oftest ikke er SQL-udtryk, som det er tilfældet i andre databaser. Oftest er SQL-udtrykket skjult i en speciel funktion og er konstrueret ud fra de parametre, brugeren efterspørger - tiden konverteres, filtreres, data normaliseres (f.eks. udlignes aktiekursen, hvis der blev udbetalt udbytte) osv.

Typisk arkitektur for én datatype:

KDB+ database: fra økonomi til Formel 1

hastighed

Selvom Q er et fortolket sprog, er det også et vektorsprog. Det betyder, at mange indbyggede funktioner, især aritmetiske, har argumenter af enhver form - tal, vektorer, matricer, lister - og programmøren forventes at implementere programmet som array-operationer. I et sådant sprog, hvis du tilføjer to vektorer af en million elementer, betyder det ikke længere, at sproget fortolkes; tilføjelsen vil blive udført af en superoptimeret binær funktion. Da brorparten af ​​tiden i Q-programmer bruges på operationer med tabeller, der bruger disse grundlæggende vektoriserede funktioner, er outputtet en meget anstændig driftshastighed, hvilket giver os mulighed for at behandle en enorm mængde data selv i én proces. Dette ligner matematiske biblioteker i Python - selvom Python i sig selv er et meget langsomt sprog, har det mange fremragende biblioteker som numpy, der giver dig mulighed for at behandle numeriske data med hastigheden af ​​et kompileret sprog (i øvrigt er numpy ideologisk tæt på Q ).
 
Derudover tog KX en meget omhyggelig tilgang til at designe tabeller og optimere arbejdet med dem. For det første understøttes flere typer indekser, som understøttes af indbyggede funktioner og kan anvendes ikke kun på tabelkolonner, men også på alle vektorer - gruppering, sortering, unikhedsattribut og speciel gruppering til historiske databaser. Indekset anvendes enkelt og justeres automatisk, når elementer tilføjes til kolonnen/vektoren. Indekser kan med lige så stor succes anvendes på tabelkolonner både i hukommelsen og på disken. Når en QSQL-forespørgsel udføres, bruges indekser automatisk, hvis det er muligt. For det andet arbejdes der med historiske data gennem mekanismen til visning af OS-filer (hukommelseskort). Store tabeller indlæses aldrig i hukommelsen, i stedet bliver de nødvendige kolonner kortlagt direkte i hukommelsen, og kun den del af dem indlæses faktisk (indekser hjælper også her), som er nødvendige. Det gør ingen forskel for programmøren, om data er i hukommelsen eller ej; mekanismen til at arbejde med mmap er fuldstændig skjult i dybden af ​​Q.
 
KDB+ er ikke en relationel database; tabeller kan indeholde vilkårlige data, mens rækkefølgen af ​​rækker i tabellen ikke ændres, når nye elementer tilføjes, og kan og bør bruges, når du skriver forespørgsler. Denne funktion er presserende nødvendig for at arbejde med tidsserier (data fra centraler, telemetri, hændelseslogfiler), for hvis data er sorteret efter tid, så behøver brugeren ikke bruge nogen SQL-tricks for at finde den første eller sidste række eller N rækker i tabellen , bestemme hvilken linje der følger den N. linje osv. Table joins forenkles endnu mere, f.eks. at finde det sidste tilbud for 16000 VOD.L (Vodafone) transaktioner i en tabel med 500 millioner elementer tager omkring et sekund på disken og titusvis af millisekunder i hukommelsen.
 
Et eksempel på en tidssammenføjning - citattabellen er mappet til hukommelsen, så der er ingen grund til at angive VOD.L i hvor, indekset på sym-kolonnen og det faktum, at dataene er sorteret efter tid, er implicit brugt. Næsten alle joins i Q er regulære funktioner, ikke en del af et udvalgt udtryk:

1. aj[`sym`time;select from trade where date=2019.03.26, sym=`VOD.L;select from quote where date=2019.03.26]  

Til sidst er det værd at bemærke, at ingeniørerne hos KX, startende med Arthur Whitney selv, virkelig er besat af effektivitet og går langt for at få mest muligt ud af Q's standardfunktioner og optimere de mest almindelige brugsmønstre.
 

Total

KDB+ er populær blandt virksomheder, primært på grund af dens enestående alsidighed - den fungerer lige så godt som en database i hukommelsen, som en database til lagring af terabyte af historiske data og som en platform til dataanalyse. På grund af det faktum, at databehandling foregår direkte i databasen, opnås høj arbejdshastighed og ressourcebesparelser. Et fuldgyldigt programmeringssprog integreret med databasefunktioner giver dig mulighed for at implementere hele stakken af ​​nødvendige processer på én platform - fra modtagelse af data til behandling af brugeranmodninger.
 

For mere information,

Begrænsninger

En væsentlig ulempe ved KDB+/Q er den høje adgangstærskel. Sproget har en mærkelig syntaks, nogle funktioner er stærkt overbelastede (værdi har f.eks. ca. 11 use cases). Vigtigst af alt kræver det en radikalt anderledes tilgang til at skrive programmer. I et vektorsprog skal du altid tænke i array-transformationer, implementere alle loops gennem flere varianter af map/reducer-funktionerne (som kaldes adverbier i Q), og aldrig forsøge at spare penge ved at erstatte vektoroperationer med atomare. For at finde indekset for den n'te forekomst af et element i en matrix, skal du for eksempel skrive:

1. (where element=vector)[N]  

selvom dette virker frygteligt ineffektivt efter C/Java-standarder (= skaber en boolsk vektor, hvor returnerer de sande indekser for elementerne i den). Men denne notation gør betydningen af ​​udtrykket mere klar, og du bruger hurtige vektoroperationer i stedet for langsomme atomare. Den konceptuelle forskel mellem et vektorsprog og andre kan sammenlignes med forskellen mellem imperative og funktionelle tilgange til programmering, og du skal være forberedt på dette.
 
Nogle brugere er også utilfredse med QSQL. Pointen er, at det kun ligner rigtig SQL. I virkeligheden er det blot en fortolker af SQL-lignende udtryk, der ikke understøtter forespørgselsoptimering. Brugeren skal selv skrive optimale forespørgsler, og i Q, som mange ikke er klar til. På den anden side kan du selvfølgelig altid selv skrive den optimale forespørgsel i stedet for at stole på en black-box optimizer.
 
Som et plus er en bog om Q - Q For Mortals tilgængelig gratis på websted, er der også en masse andre nyttige materialer samlet der.
 
En anden stor ulempe er prisen på licensen. Det er titusindvis af dollars pr. år pr. CPU. Kun store virksomheder har råd til sådanne udgifter. For nylig har KX gjort sin licenspolitik mere fleksibel og giver mulighed for kun at betale for brugstiden eller leje KDB+ i Google- og Amazon-skyerne. KX tilbyder også download gratis version til ikke-kommercielle formål (32 bit version eller 64 bit på forespørgsel).
 

konkurrenter

Der er en del specialiserede databaser bygget på lignende principper - søjleformede, in-memory, fokuseret på meget store mængder data. Problemet er, at disse er specialiserede databaser. Et slående eksempel er Clickhouse. Denne database har et meget lignende princip som KDB+ til lagring af data på disk og opbygning af et indeks; den udfører nogle forespørgsler hurtigere end KDB+, dog ikke væsentligt. Men selv som database er Clickhouse mere specialiseret end KDB+ - webanalyse vs arbitrære tidsserier (denne forskel er meget vigtig - på grund af den er det f.eks. i Clickhouse ikke muligt at bruge rækkefølgen af ​​poster). Men vigtigst af alt har Clickhouse ikke alsidigheden af ​​KDB+, et sprog, der ville tillade behandling af data direkte i databasen, snarere end at indlæse det først i en separat applikation, bygge vilkårlige SQL-udtryk, anvende vilkårlige funktioner i en forespørgsel, skabe processer ikke relateret til udførelsen af ​​historiske databasefunktioner. Derfor er det svært at sammenligne KDB+ med andre databaser, de kan være bedre i visse use cases eller simpelthen bedre, når det kommer til klassiske databaseopgaver, men jeg kender ikke til et andet lige så effektivt og alsidigt værktøj til behandling af midlertidige data.
 

Python integration

For at gøre KDB+ nemmere at bruge for folk, der ikke kender teknologien, skabte KX biblioteker til at integrere tæt med Python i en enkelt proces. Du kan enten kalde enhver Python-funktion fra Q eller omvendt - kalde enhver Q-funktion fra Python (især QSQL-udtryk). Biblioteker konverterer, hvis det er nødvendigt (ikke altid for effektivitetens skyld), data fra formatet på et sprog til formatet på et andet. Som følge heraf lever Q og Python i så tæt en symbiose, at grænserne mellem dem udviskes. Som et resultat har programmøren på den ene side fuld adgang til adskillige nyttige Python-biblioteker, på den anden side får han en hurtig base for at arbejde med big data integreret i Python, hvilket er særligt nyttigt for dem, der er involveret i maskinlæring eller modellering.
 
Arbejde med Q i Python:

1. >>> q()  
2.q)trade:([]date:();sym:();qty:())  
3. q)  
4. >>> q.insert('trade', (date(2006,10,6), 'IBM', 200))  
5. k(',0')  
6. >>> q.insert('trade', (date(2006,10,6), 'MSFT', 100))  
7. k(',1')  

RЎSЃS <P "RєRё

Virksomhedens hjemmeside - https://kx.com/
Hjemmeside for udviklere - https://code.kx.com/v2/
Bog Q For Mortals (på engelsk) - https://code.kx.com/q4m3/
Artikler om KDB+/Q-applikationer fra kx-medarbejdere - https://code.kx.com/v2/wp/

Kilde: www.habr.com

Tilføj en kommentar