Vela → smart cache för tidsserier och mer

In fintech, we often have to process quite large volumes of currency exchange rate data. We obtain data from various sources, each of which has its own way of extrapolating values for tomorrow, the day after tomorrow, next month, and even the next three years. If someone could predict rates correctly, it would be time to close the business and simply exchange money back and forth. correctly, it would be time to close the business and just trade money back and forth. Some sources are more trusted, while others provide mostly junk, with rare instances of almost correct values, especially for exotic pairs. Our job is to sift through these tens of thousands of values per second and determine what to show our clients. We need to filter out the single correct value from a ton of dirt and mud, just like flamingos do during lunch.

Vela → smart cache för tidsserier och mer

A distinguishing feature of flamingos is their massive downturned beak, which they use to filter food from water or mud.
 — Wiki

Thus, the library was born Vela, which holds a cache of states for multiple values over specified time intervals. Under the hood, it automatically filters out bad and outdated data while providing access to the latest N validated values for each key (currency pairs, in our case).

Let's say we are collecting rates for three currency pairs. The simplest definition Vela for storing the current state would look something like this:

defmodule Pairs do
  use Vela,
    eurusd: [sorter: &Kernel. 0
end

Updating values

Vela.put/3 the function will sequentially perform the following:

  • call validator on the value if it is defined (see chapter Validation below);
  • add the value to either the list of good values if validation was successful, or to the error queue :__errors__ otherwise;
  • call sorting if the sorter is defined for this key, or simply place the value at the head of the list (LIFO, see chapter Sortera below);
  • trim the list according to the parameter :limit passed during creation;
  • return the updated structure Vela.

iex|1 > par = %Pairs{}
iex|2 > Vela.put(par, :eurcad, 1.0)
#⇒ %Pairs{..., eurcad: [1.0], ...}
iex|3 > Vela.put(par, :eurcad, -1.0)
#⇒ %Pairs{__errors__: [eurcad: -1.0], ...}
iex|4 > par |> Vela.put(:eurusd, 2.0) |> Vela.put(:eurusd, 1.0)
#⇒ %Pairs{... eurusd: [1.0, 2.0]}

Även Vela implementerar Åtkomst, sĂ„ att du kan anvĂ€nda nĂ„gon av de standardfunktioner för djupuppdatering av strukturer frĂ„n arsenalen Kernel: Kernel.get_in/2, Kernel.put_in/3, Kernel.update_in/3, Kernel.pop_in/2, och Kernel.get_and_update_in/3.

Validation

Validatorn kan definieras som:

  • en extern funktion med ett argument (&MyMod.my_fun/1), den kommer endast att fĂ„ vĂ€rdet för validering;
  • en extern funktion med tvĂ„ argument, &MyMod.my_fun/2, den kommer att fĂ„ paret serie, vĂ€rde för validering;
  • modul som implementerar Vela.Validator;
  • konfigurationsparameter tröskelvĂ€rde, och – valfritt – jĂ€mför_efter, see chapter JĂ€mförelse under.

Om valideringen lyckas lÀggs vÀrdet till i listan under motsvarande nyckel, i motsatt fall skickas en tuple {serie, vÀrde} till :__errors_.

JÀmförelse

VÀrdena som lagras i dessa rader kan vara vilka som helst. För att lÀra Vela dem att jÀmföra mÄste du skicka jÀmför_efter parametern i radens definition (om inte vÀrdena kan jÀmföras med standard Kernel.</2); denna parameter ska ha typ (Vela.value() -> number()). Som standard Àr detta bara & &1.

Dessutom kan man i radens definition skicka parameter komparator för att berÀkna vÀrdena för deltal.min/max); till exempel kan man genom att skicka Date.diff/2 som komparator fÄ rÀtt deltal för datum.

Ett annat bekvÀmt sÀtt att arbeta Àr att skicka parameter tröskelvÀrde, som definierar det maximalt tillÄtna förhÄllandet av det nya vÀrdet till {min, max} intervallet. Eftersom det anges i procent anvÀnds inte komparator, men anvÀnds fortfarande jÀmför_efter. Till exempel, för att ange ett tröskelvÀrde för tidsstÀmplar mÄste du ange jÀmför_efter: &DateTime.to_unix/1 (för att fÄ ett heltal) och tröskelvÀrde: 1, vilket gör att nya vÀrden endast tillÄts om de ligger inom ±band intervallet frÄn nuvarande vÀrden.

Slutligen kan du anvÀnda Vela.equal?/2 jÀmför/2 , om vÀrden definierar funktionen eller equal?/2jÀmför/2 ==/2.

, sÄ kommer dessa funktioner att anvÀndas för jÀmförelse, annars anvÀnder vi slaviskt

HÀmtning av vÀrden Bearbetning av det aktuella tillstÄndet börjar vanligtvis med att kalla pÄVela.purge/1 validator , som tar bort förÄldrade vÀrden (om kopplade till timestamps). DÀrför kan man anropa Vela.slice/1, som returnerar keyword med radnamn som nycklar och de aktuella vÀrdena som första vÀrde.

Man kan ocksÄ anvÀnda get_in/2/pop_in/2 för lÄg nivÄ Ätkomst till vÀrden i varje rad.

Applikation

Vela kan vara extremt anvÀndbart som en cache för tidsserier i tillstÄndet för en process av typen GenServer/Agent. Vi vill aldrig anvÀnda förÄldrade vÀrden av kurser, och för detta hÄller vi bara en process med tillstÄnd behandlat Vela, med en validator som visas nedan.

@impl Vela.Validator
def valid?(_key, %Rate{} = rate),
  do: Rate.age(rate) < @death_age

och Bearbetning av det aktuella tillstĂ„ndet börjar vanligtvis med att kalla pĂ„ raderar lugnt alla förĂ„ldrade vĂ€rden varje gĂ„ng vi behöver data. För att fĂ„ tillgĂ„ng till aktuella vĂ€rden anropar vi bara Vela.slice/1, och nĂ€r vi behöver en liten historik över kursen (hela raden) returnerar vi helt enkelt den – redan sorterad – med validerade vĂ€rden.

Lycka till med cachandet av tidsserier!

KĂ€lla: habr.com

Köp pĂ„litlig webbhotell med DDoS-skydd, VPS VDS-servrar đŸ”„ Köp pĂ„litlig webbhotell med DDoS-skydd, VPS VDS-servrar | ProHoster