Base de datos KDB+: das finanzas á Fórmula 1

KDB+, produto da empresa KX é unha base de datos en columnas moi coñecida en círculos estreitos, extremadamente rápida, deseñada para almacenar series de tempo e cálculos analíticos baseados nelas. Inicialmente, era (e é) moi popular no sector financeiro: os 10 principais bancos de investimento e moitos fondos de cobertura, bolsas e outras organizacións coñecidos úsano. Recentemente, KX decidiu ampliar a súa base de clientes e agora ofrecer solucións noutros ámbitos onde hai unha gran cantidade de datos, organizados por tempo ou doutro xeito: telecomunicacións, bioinformática, fabricación, etc. Tamén se converteron en socios do equipo Aston Martin Red Bull Racing na Fórmula 1, onde axudan a recoller e procesar datos dos sensores dos coches e analizar as probas do túnel de vento. Neste artigo, quero dicirche cales son as características de KDB+ que o fan superperformante, por que as empresas están dispostas a gastar moito diñeiro nel e, finalmente, por que non é realmente unha base de datos.
 
Base de datos KDB+: das finanzas á Fórmula 1
 
Neste artigo intentarei dicirche en xeral que é KDB+, que capacidades e limitacións ten e cales son os seus beneficios para as empresas que queiran procesar grandes cantidades de datos. Non entrarei nos detalles da implementación de KDB+ nin nos detalles da súa linguaxe de programación Q. Estes dous temas son moi amplos e merecen artigos separados. Pódese atopar moita información sobre estes temas en code.kx.com, incluíndo un libro sobre Q - Q For Mortals (consulta a ligazón a continuación).

Algúns termos

  • Base de datos en memoria. Unha base de datos que almacena datos na memoria RAM para un acceso máis rápido. As vantaxes desta base de datos son claras, pero as desvantaxes son a posibilidade de perda de datos e a necesidade de ter moita memoria no servidor.
  • Base de datos columnar. Unha base de datos onde os datos se almacenan columna por columna en lugar de rexistro por rexistro. A principal vantaxe desta base de datos é que os datos dunha columna gárdanse xuntos no disco e na memoria, o que acelera significativamente o acceso a ela. Non é necesario cargar columnas que non se utilicen na consulta. A principal desvantaxe é que é difícil modificar e eliminar rexistros.
  • Serie temporal. Datos cunha columna de data ou hora. Normalmente, a ordenación do tempo é importante para estes datos, de xeito que pode determinar facilmente que rexistro precede ou segue ao actual, ou para aplicar funcións cuxos resultados dependen da orde dos rexistros. As bases de datos clásicas están construídas sobre un principio completamente diferente: representar unha colección de rexistros como un conxunto, onde a orde dos rexistros, en principio, non está definida.
  • Vector. No contexto de KDB+, esta é unha lista de elementos do mesmo tipo atómico, por exemplo, números. Noutras palabras, unha matriz de elementos. As matrices, a diferenza das listas, pódense almacenar de forma compacta e procesarse mediante instrucións do procesador vectorial.

 

Información histórica

KX foi fundada en 1993 por Arthur Whitney, quen traballou anteriormente no Morgan Stanley Bank na linguaxe A+, o sucesor de APL, unha linguaxe moi orixinal e á vez popular no mundo financeiro. Por suposto, en KX, Arthur continuou co mesmo espírito e creou a linguaxe vector-funcional K, guiada polas ideas do minimalismo radical. Os programas K semellan un revolto de signos de puntuación e caracteres especiais, o significado dos signos e funcións depende do contexto e cada operación ten moito máis significado que nas linguaxes de programación convencionais. Debido a isto, un programa K ocupa un espazo mínimo (algunhas liñas poden substituír páxinas de texto nunha linguaxe verbosa como Java) e é unha implementación súper concentrada do algoritmo.
 
Unha función en K que implementa a maior parte do xerador de analizadores LL1 segundo unha gramática determinada:

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 encarnou esta filosofía de eficacia extrema cun mínimo de movementos corporais en KDB+, que apareceu en 2003 (creo que agora está claro de onde provén a letra K do nome) e non é máis que un intérprete da cuarta versión da K. Engadiuse unha versión máis fácil de usar enriba de K K chamada Q. Q tamén engadiu soporte para un dialecto específico de SQL - QSQL e o intérprete - soporte para táboas como tipo de datos do sistema, ferramentas para traballar con táboas en memoria e en disco, etc.
 
Polo tanto, desde a perspectiva do usuario, KDB+ é simplemente un intérprete de linguaxe Q con soporte para táboas e expresións tipo LINQ de C#. Esta é a diferenza máis importante entre KDB+ e outras bases de datos e a súa principal vantaxe competitiva, que moitas veces se pasa por alto. Esta non é unha base de datos + linguaxe auxiliar desactivada, senón unha potente linguaxe de programación completa + soporte integrado para funcións de base de datos. Esta distinción terá un papel decisivo na lista de todos os beneficios de KDB+. Por exemplo…
 

Tamaño

Segundo os estándares modernos, KDB+ é simplemente de tamaño microscópico. É literalmente un ficheiro executable de sub-megabyte e un pequeno ficheiro de texto con algunhas funcións do sistema. En realidade - menos dun megabyte, e para este programa as empresas pagan decenas de miles de dólares ao ano por un procesador no servidor.

  • Este tamaño permite que KDB+ se sinta ben en calquera hardware, desde un microordenador Pi ata servidores con terabytes de memoria. Isto non afecta de ningún xeito á funcionalidade; ademais, Q arranca ao instante, o que permite empregalo, entre outras cousas, como linguaxe de script.
  • Con este tamaño, o intérprete Q encaixa totalmente na caché do procesador, o que acelera a execución do programa.
  • Con este tamaño do ficheiro executable, o proceso Q ocupa pouco espazo na memoria; podes executar centos deles. Ademais, se é necesario, Q pode operar con decenas ou centos de gigabytes de memoria nun só proceso.

versatilidade

Q é excelente para unha ampla gama de aplicacións. O proceso Q pode actuar como unha base de datos histórica e proporcionar acceso rápido a terabytes de información. Por exemplo, temos ducias de bases de datos históricas, nalgunhas das cales un día de datos sen comprimir ocupa máis de 100 gigabytes. Non obstante, baixo restricións razoables, unha consulta á base de datos completarase en decenas a centos de milisegundos. En xeral, temos un tempo de espera universal para as solicitudes dos usuarios -30 segundos- e funciona moi raramente.
 
Q podería ser facilmente unha base de datos en memoria. Engádense novos datos ás táboas en memoria tan rápido que as solicitudes dos usuarios son o factor limitante. Os datos das táboas almacénanse en columnas, o que significa que calquera operación nunha columna usará a caché do procesador a plena capacidade. Ademais disto, KX intentou implementar todas as operacións básicas como a aritmética a través de instrucións vectoriais do procesador, maximizando a súa velocidade. Q tamén pode realizar tarefas que non son típicas das bases de datos, por exemplo, procesar datos de transmisión e calcular en "tempo real" (cun ​​retraso de decenas de milisegundos a varios segundos, dependendo da tarefa) varias funcións de agregación para instrumentos financeiros durante diferentes tempos. intervalos ou construír un modelo da influencia das transaccións perfectas no mercado e realizar o seu perfil case inmediatamente despois da súa finalización. En tales tarefas, a maioría das veces o atraso de tempo principal non é Q, senón a necesidade de sincronizar datos de diferentes fontes. Conséguese unha alta velocidade debido a que os datos e as funcións que os procesan están nun só proceso, e o procesamento redúcese a executar varias expresións e unións QSQL, que non se interpretan, senón que se executan mediante código binario.
 
Finalmente, pode escribir calquera proceso de servizo en Q. Por exemplo, os procesos de pasarela que distribúen automaticamente as solicitudes dos usuarios ás bases de datos e servidores necesarios. O programador ten total liberdade para implementar calquera algoritmo de equilibrio, priorización, tolerancia a fallos, dereitos de acceso, cotas e, basicamente, calquera outra cousa que o seu corazón desexe. O principal problema aquí é que terás que implementar todo isto ti mesmo.
 
Como exemplo, enumerarei que tipos de procesos temos. Todos eles úsanse activamente e traballan xuntos, combinando decenas de bases de datos diferentes nunha soa, procesando datos de varias fontes e atendendo a centos de usuarios e aplicacións.

  • Conectores (feedhandler) a fontes de datos. Estes procesos normalmente usan bibliotecas externas que se cargan en Q. A interface C en Q é moi sinxela e permítelle crear facilmente funcións de proxy para calquera biblioteca C/C++. Q é o suficientemente rápido como para procesar, por exemplo, unha avalancha de mensaxes FIX de todas as bolsas europeas de forma simultánea.
  • Distribuidores de datos (tickerplant), que serven de enlace intermedio entre conectores e consumidores. Ao mesmo tempo, escriben os datos entrantes nun rexistro binario especial, proporcionando robustez aos consumidores fronte a perdas de conexión ou reinicios.
  • Base de datos en memoria (rdb). Estas bases de datos proporcionan o acceso máis rápido posible a datos en bruto e frescos almacenándoos na memoria. Normalmente, acumulan datos en táboas durante o día e restablecen durante a noite.
  • Base de datos Persist (pdb). Estas bases de datos garanten que os datos de hoxe se almacenen nunha base de datos histórica. Como regra xeral, a diferenza de rdb, non almacenan datos na memoria, pero usan unha caché especial no disco durante o día e copian os datos á media noite na base de datos histórica.
  • Bases de datos históricas (hdb). Estas bases de datos proporcionan acceso aos datos de días, meses e anos anteriores. O seu tamaño (en días) está limitado só polo tamaño dos discos duros. Os datos pódense localizar en calquera lugar, en particular en diferentes discos para acelerar o acceso. É posible comprimir datos usando varios algoritmos para escoller. A estrutura da base de datos está ben documentada e sinxela, os datos gárdanse columna por columna en ficheiros habituais, para que poidan ser procesados, incluso mediante o sistema operativo.
  • Bases de datos con información agregada. Almacenan varias agregacións, xeralmente con, agrupadas por nome do instrumento e intervalo de tempo. As bases de datos en memoria actualizan o seu estado con cada mensaxe entrante e as bases de datos históricas almacenan datos precalculados para acelerar o acceso aos datos históricos.
  • Finalmente procesos de pasarelaservizo de aplicacións e usuarios. Q permítelle implementar un procesamento completamente asíncrono das mensaxes entrantes, distribuíndoas entre bases de datos, comprobando os dereitos de acceso, etc. Teña en conta que as mensaxes non están limitadas e a maioría das veces non son expresións SQL, como ocorre noutras bases de datos. Na maioría das veces, a expresión SQL escóndese nunha función especial e constrúese en función dos parámetros solicitados polo usuario: o tempo convértese, fíltrase, os datos normalízanse (por exemplo, o prezo das accións se iguala se se pagaban dividendos), etc.

Arquitectura típica para un tipo de datos:

Base de datos KDB+: das finanzas á Fórmula 1

Acelerar

Aínda que Q é unha linguaxe interpretada, tamén é unha linguaxe vectorial. Isto significa que moitas funcións integradas, especialmente as aritméticas, toman argumentos de calquera forma -números, vectores, matrices, listas- e espérase que o programador implemente o programa como operacións de matriz. Nesta linguaxe, se engades dous vectores dun millón de elementos, xa non importa que a linguaxe sexa interpretada; a adición realizarase mediante unha función binaria superoptimizada. Dado que a maior parte do tempo nos programas Q se gasta en operacións con táboas que usan estas funcións vectorizadas básicas, a saída é unha velocidade de operación moi decente, o que nos permite procesar unha gran cantidade de datos mesmo nun proceso. Isto é semellante ás bibliotecas matemáticas en Python: aínda que o propio Python é unha linguaxe moi lenta, ten moitas bibliotecas excelentes como numpy que che permiten procesar datos numéricos á velocidade dunha linguaxe compilada (por certo, numpy é ideoloxicamente próximo a Q). ).
 
Ademais, KX adoptou un enfoque moi coidadoso para deseñar táboas e optimizar o traballo con elas. En primeiro lugar, son compatibles varios tipos de índices, que son compatibles con funcións integradas e que se poden aplicar non só ás columnas da táboa, senón tamén a calquera vector: agrupación, clasificación, atributo de singularidade e agrupación especial para bases de datos históricas. O índice aplícase de forma sinxela e axústase automaticamente ao engadir elementos á columna/vector. Os índices pódense aplicar igualmente con éxito ás columnas da táboa tanto na memoria como no disco. Cando se executa unha consulta QSQL, os índices utilízanse automaticamente se é posible. En segundo lugar, o traballo con datos históricos realízase mediante o mecanismo de visualización de ficheiros do SO (mapa de memoria). As táboas grandes nunca se cargan na memoria; en cambio, as columnas necesarias son asignadas directamente á memoria e só se carga realmente a parte delas (os índices tamén axudan aquí) que son necesarias. Para o programador non importa se os datos están na memoria ou non; o mecanismo para traballar con mmap está completamente oculto nas profundidades de Q.
 
KDB+ non é unha base de datos relacional; as táboas poden conter datos arbitrarios, mentres que a orde das filas da táboa non cambia cando se engaden novos elementos e pode e debe usarse ao escribir consultas. Esta función é urxente para traballar con series temporais (datos de intercambios, telemetría, rexistros de eventos), porque se os datos están ordenados por tempo, entón o usuario non necesita usar ningún truco SQL para atopar a primeira ou a última fila ou N. filas da táboa , determine que liña segue á liña N, etc. As combinacións de táboas simplifícanse aínda máis, por exemplo, atopar a última cotización de 16000 transaccións de VOD.L (Vodafone) nunha táboa de 500 millóns de elementos leva aproximadamente un segundo no disco e decenas de milisegundos na memoria.
 
Un exemplo de unión de tempo: a táboa de citas está asignada á memoria, polo que non é necesario especificar VOD.L onde se usan implícitamente o índice da columna sym e o feito de que os datos están ordenados por tempo. Case todas as unións en Q son funcións regulares, non forman parte dunha expresión seleccionada:

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

Por último, cabe destacar que os enxeñeiros de KX, comezando polo propio Arthur Whitney, están verdadeiramente obsesionados coa eficiencia e fan todo o posible para sacar o máximo proveito das funcións estándar do Q e optimizar os patróns de uso máis comúns.
 

Total

KDB+ é popular entre as empresas principalmente debido á súa excepcional versatilidade: serve igualmente ben como base de datos en memoria, como base de datos para almacenar terabytes de datos históricos e como plataforma para análise de datos. Debido ao feito de que o procesamento de datos ocorre directamente na base de datos, conséguese unha alta velocidade de traballo e aforro de recursos. Unha linguaxe de programación completa integrada con funcións de base de datos permítelle implementar toda a pila de procesos necesarios nunha plataforma, desde a recepción de datos ata o procesamento das solicitudes dos usuarios.
 

Para máis información,

Limitacións

Unha desvantaxe significativa de KDB+/Q é o alto limiar de entrada. A linguaxe ten unha sintaxe estraña, algunhas funcións están moi sobrecargadas (o valor, por exemplo, ten uns 11 casos de uso). O máis importante é que require un enfoque radicalmente diferente para escribir programas. Nunha linguaxe vectorial, hai que pensar sempre en termos de transformacións de matriz, implementar todos os bucles a través de varias variantes das funcións map/reduce (que se chaman adverbios en Q), e nunca tentar aforrar diñeiro substituíndo as operacións vectoriais por atómicas. Por exemplo, para atopar o índice da enésima aparición dun elemento nunha matriz, debes escribir:

1. (where element=vector)[N]  

aínda que isto parece terriblemente ineficiente para os estándares C/Java (= crea un vector booleano, onde devolve os verdadeiros índices dos elementos nel). Pero esta notación fai que o significado da expresión sexa máis claro e utilizas operacións vectoriais rápidas en lugar de lentas atómicas. A diferenza conceptual entre unha linguaxe vectorial e outras é comparable á diferenza entre os enfoques imperativos e funcionais da programación, e hai que estar preparado para iso.
 
Algúns usuarios tamén están descontentos con QSQL. A cuestión é que só parece SQL real. En realidade, é só un intérprete de expresións tipo SQL que non admite a optimización de consultas. O usuario debe escribir consultas óptimas por si mesmo, e en Q, para as que moitas non están preparadas. Por outra banda, por suposto, sempre pode escribir vostede mesmo a consulta óptima, en lugar de confiar nun optimizador de caixa negra.
 
Como vantaxe, un libro sobre Q - Q For Mortals está dispoñible de balde en páxina web da empresa, tamén hai moitos outros materiais útiles recollidos alí.
 
Outra gran desvantaxe é o custo da licenza. Son decenas de miles de dólares ao ano por CPU. Só as grandes empresas poden pagar tales gastos. Recentemente, KX flexibilizou a súa política de licenzas e ofrece a oportunidade de pagar só polo tempo de uso ou alugar KDB+ nas nubes de Google e Amazon. KX tamén ofrece para descargar versión gratuíta para fins non comerciais (versión de 32 bits ou 64 bits baixo petición).
 

Competidores

Hai bastantes bases de datos especializadas construídas con principios similares: columnas, en memoria, centradas en cantidades moi grandes de datos. O problema é que se trata de bases de datos especializadas. Un exemplo rechamante é Clickhouse. Esta base de datos ten un principio moi similar ao KDB+ para almacenar datos no disco e construír un índice; realiza algunhas consultas máis rápido que KDB+, aínda que non de forma significativa. Pero mesmo como base de datos, Clickhouse é máis especializado que KDB+: analítica web vs series temporales arbitrarias (esta diferenza é moi importante, por iso, por exemplo, en Clickhouse non é posible usar a ordenación dos rexistros). Pero, o máis importante, Clickhouse non ten a versatilidade de KDB+, unha linguaxe que lle permitiría procesar datos directamente na base de datos, en lugar de cargalos primeiro nunha aplicación separada, construír expresións SQL arbitrarias, aplicar funcións arbitrarias nunha consulta, crear procesos non relacionados coa execución das funcións da base de datos histórica . Polo tanto, é difícil comparar KDB+ con outras bases de datos; poden ser mellores nalgúns casos de uso ou simplemente mellores cando se trata de tarefas clásicas de bases de datos, pero non coñezo outra ferramenta igualmente eficaz e versátil para procesar datos temporais.
 

Integración de Python

Para que KDB+ sexa máis fácil de usar para persoas que non están familiarizadas coa tecnoloxía, KX creou bibliotecas para integrarse estreitamente con Python nun único proceso. Podes chamar a calquera función de Python desde Q ou viceversa: chamar a calquera función Q desde Python (en particular, expresións QSQL). As bibliotecas converten, se é necesario (non sempre por motivos de eficiencia), os datos do formato dun idioma ao formato doutro. Como resultado, Q e Python viven nunha simbiose tan estreita que os límites entre eles están borrosos. Como resultado, o programador, por unha banda, ten acceso total a numerosas bibliotecas útiles de Python, por outra banda, recibe unha base rápida para traballar con grandes datos integrados en Python, que resulta especialmente útil para aqueles implicados na aprendizaxe automática. ou modelado.
 
Traballando con Q en 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')  

referencias

O sitio da empresa - https://kx.com/
Sitio web para programadores - https://code.kx.com/v2/
Libro Q For Mortals (en inglés) - https://code.kx.com/q4m3/
Artigos sobre aplicacións KDB+/Q dos empregados de kx - https://code.kx.com/v2/wp/

Fonte: www.habr.com

Engadir un comentario