Operational analytica in microservice architecturae: auxilium et promptum Postgres FDW

Architectura Microservice, sicut omnia in hoc mundo, habet pros et cons. Alii processus cum eo faciliores fiunt, alii difficiliores. Et propter velocitatem mutationis et scalabilitatis melioris, oportet facere sacrificia. Una earum est analyticorum multiplicitas increscens. Si in monolitho omnia analytica perficienda ad SQL interrogationes ad imaginem analyticam reduci possunt, tum in architectura multi servitii unumquodque officium suum datorum habet et videtur una quaestio fieri non posse (vel fortasse potest?). Pro iis qui interest quomodo problema analyticorum operationalium in nostro comitatu solvimus et quomodo cum hac solutione vivere didicerimus - suscipimus.

Operational analytica in microservice architecturae: auxilium et promptum Postgres FDW
Nomen meum est Pavel Sivash, apud DomClick laboro in manipulo qui author est ad analyticas notitias horreis conservandas. Conventione, actiones nostrae pro notitia machinalis collocari possunt, sed re vera operarum ampliatio multo latior est. Vexillum ETL/ELT sunt pro notitia machinalis, adminiculum et aptatio instrumentorum pro analysi et evolutione instrumentorum suorum propriorum. Praesertim, ad relationem perficiendam, "simulare" decrevimus nos monolitum habere et analystas dare unum datorum, qui omnes notitias quas opus habent continebit.

In genere varias optiones consideravimus. Potuit aedificare promptarium plenum discursivum - etiam conati sumus, sed, ut honesti sumus, non potuimus satis frequentes mutationes in logica miscere cum tardiore processu aedificandi repositorium et ad illud mutandum (si quis successerit. in commentarios quomodo scribe). Potuit analystas narrare: "Guys, discite Pythonem et ite ad replicas analyticas", sed hoc addito postulatione conscribendi, et hoc fugiendum si fieri potest videbatur. Nos placuit experiri uti FDW (Aliena Data Wrapper) technicae artis: essentialiter hoc signum dblink est, quod in SQL vexillum est, sed cum sua multo commodius interface. Ex ea solutionem fecimus, quam tandem capiebamus, et in ea consedimus. Singula eius argumenta sunt articuli separati, et fortasse plus quam unum, quoniam loqui de sorte volo: ex schematis datorum synchronising ad potestatem ac depersonalizationem notitiarum personalium accedere. Reservatio quoque necessaria est statuere hanc solutionem non esse reponendam pro realibus analyticis databases ac repositoriis, sed solum problema specificum solvit.

In summo gradu hoc simile est:

Operational analytica in microservice architecturae: auxilium et promptum Postgres FDW
Est PostgreSQL database ubi users notitia operis reponere possunt, ac potissimum, omnium officiorum analyticarum replicationes huic datorum per FDW connectuntur. Quo fit, ut interrogationem pluribus databases scribere possit, nec refert quid sit: PostgreSQL, MySQL, MongoDB vel quid aliud (file, API, si subito deest fascia aptus, scribere potes tuum). Bene, omnia magna videntur! Nos solveret?

Si omnia tam cito et simpliciter finita essent, verisimile non esset articulus.

Praestat ut pateat quomodo processus Postgres petit servientibus remotis. Hoc logicum videtur, sed saepe homines hoc non attendunt: Postgres postulationem dividit in partes quae independenter a servientibus remotis efficiuntur, notitias colligit et rationes finales ipsas perficit, celeritas ergo inquisitionis exsecutionis multum pendet ab. quomodo scriptum est. Animadvertendum etiam est: cum notitia e longinquo servo pervenerit, indices iam non habet, nihil est quod schedulam adiuvet, ergo nos ipsi iuvare et monere possumus. Et hoc ipsum est quod volo fusius loqui.

Simplex quaestio et consilium cum eo

Ut ostenderet quomodo Postgres queritur 6 decies centena milia ordinis mensam in servo remoto, inspiciamus consilium simplex.

explain analyze verbose  
SELECT count(1)
FROM fdw_schema.table;

Aggregate  (cost=418383.23..418383.24 rows=1 width=8) (actual time=3857.198..3857.198 rows=1 loops=1)
  Output: count(1)
  ->  Foreign Scan on fdw_schema."table"  (cost=100.00..402376.14 rows=6402838 width=0) (actual time=4.874..3256.511 rows=6406868 loops=1)
        Output: "table".id, "table".is_active, "table".meta, "table".created_dt
        Remote SQL: SELECT NULL FROM fdw_schema.table
Planning time: 0.986 ms
Execution time: 3857.436 ms

Usura VERBOSE enuntiatio nobis permittit videre interrogationem quae mittetur ad longinquum server et eventus quorum ulterioris processus recipiemus (RemoteSQL linea).

Paulo longius eamus et compluras filamenta ad petitionem nostram adiciamus: unum for Boolean campus, unus per occursus indicatione temporis interuallo et uno jsonb.

explain analyze verbose
SELECT count(1)
FROM fdw_schema.table 
WHERE is_active is True
AND created_dt BETWEEN CURRENT_DATE - INTERVAL '7 month' 
AND CURRENT_DATE - INTERVAL '6 month'
AND meta->>'source' = 'test';

Aggregate  (cost=577487.69..577487.70 rows=1 width=8) (actual time=27473.818..25473.819 rows=1 loops=1)
  Output: count(1)
  ->  Foreign Scan on fdw_schema."table"  (cost=100.00..577469.21 rows=7390 width=0) (actual time=31.369..25372.466 rows=1360025 loops=1)
        Output: "table".id, "table".is_active, "table".meta, "table".created_dt
        Filter: (("table".is_active IS TRUE) AND (("table".meta ->> 'source'::text) = 'test'::text) AND ("table".created_dt >= (('now'::cstring)::date - '7 mons'::interval)) AND ("table".created_dt <= ((('now'::cstring)::date)::timestamp with time zone - '6 mons'::interval)))
        Rows Removed by Filter: 5046843
        Remote SQL: SELECT created_dt, is_active, meta FROM fdw_schema.table
Planning time: 0.665 ms
Execution time: 27474.118 ms

Hoc est ubi punctum quod operam dare debes cum scripturae queries mendacium. Filtra non translata sunt ad servitorem remotum, quod significat illud exsequi, Postgres omnes 6 miliones ordines trahit ut localiter (Collar ordo) et aggregationem perficiat. Clavis ad successum est quaesitum scribere ut filamenta ad machinam remotam transferantur et tantum ordines necessarios accipimus et aggregatur.

Quod quidam Booleanshit est

In campis Booleis omnia simplicia sunt. In originali petitione, quaestio auctori debebatur is. Si repone =ergo consequitur hunc exitum;

explain analyze verbose
SELECT count(1)
FROM fdw_schema.table
WHERE is_active = True
AND created_dt BETWEEN CURRENT_DATE - INTERVAL '7 month' 
AND CURRENT_DATE - INTERVAL '6 month'
AND meta->>'source' = 'test';

Aggregate  (cost=508010.14..508010.15 rows=1 width=8) (actual time=19064.314..19064.314 rows=1 loops=1)
  Output: count(1)
  ->  Foreign Scan on fdw_schema."table"  (cost=100.00..507988.44 rows=8679 width=0) (actual time=33.035..18951.278 rows=1360025 loops=1)
        Output: "table".id, "table".is_active, "table".meta, "table".created_dt
        Filter: ((("table".meta ->> 'source'::text) = 'test'::text) AND ("table".created_dt >= (('now'::cstring)::date - '7 mons'::interval)) AND ("table".created_dt <= ((('now'::cstring)::date)::timestamp with time zone - '6 mons'::interval)))
        Rows Removed by Filter: 3567989
        Remote SQL: SELECT created_dt, meta FROM fdw_schema.table WHERE (is_active)
Planning time: 0.834 ms
Execution time: 19064.534 ms

Ut videre potes, colum ad cultorem remotum volavit, et supplicium tempus ab 27 ad 19 secundis redactum est.

Notatu dignum est quod auctor is diversum ab operator = quia cum Nun valore laborare potest. Hoc est quod non est verum bona falsa et nulla in colum relinquet != Verum falsa bona solum relinquet. Ideo cum reposuit operator non est duae condiciones cum OR operator mittendae sunt ad colum, v.gr. WHERE (col != Verum) OR (col nullum est).

Cum Boolean egimus, transeamus. Nunc enim Boolean colum ad pristinam formam revertamur ut effectum aliarum mutationum independenter consideremus.

timestamptz? hz *

In genere, saepe experiri debes quomodo recte scribere rogationem quae remotis servientibus implicat, et tunc demum quaere explicationem quare id fiat. Minima notitia de hoc in interreti inveniri potest. Itaque in experimentis invenimus filtrum certum diem volare ad remotum servitorem cum crepitu, sed cum velimus date dynamice, exempli gratia nunc() vel CURRENT_DATE, hoc non fit. In exemplo nostro filtrum addimus ut columna creata contineatur notitia ad exacte 1 mensis proxime praeteriti ( INTER CURRENT_DATE - INTERPRETATIO '7 mensis' ET CURRENT_DATE - INTERPRETATIO '6 mensis'). Quid in hoc casu fecimus?

explain analyze verbose
SELECT count(1)
FROM fdw_schema.table 
WHERE is_active is True
AND created_dt >= (SELECT CURRENT_DATE::timestamptz - INTERVAL '7 month') 
AND created_dt <(SELECT CURRENT_DATE::timestamptz - INTERVAL '6 month')
AND meta->>'source' = 'test';

Aggregate  (cost=306875.17..306875.18 rows=1 width=8) (actual time=4789.114..4789.115 rows=1 loops=1)
  Output: count(1)
  InitPlan 1 (returns $0)
    ->  Result  (cost=0.00..0.02 rows=1 width=8) (actual time=0.007..0.008 rows=1 loops=1)
          Output: ((('now'::cstring)::date)::timestamp with time zone - '7 mons'::interval)
  InitPlan 2 (returns $1)
    ->  Result  (cost=0.00..0.02 rows=1 width=8) (actual time=0.002..0.002 rows=1 loops=1)
          Output: ((('now'::cstring)::date)::timestamp with time zone - '6 mons'::interval)
  ->  Foreign Scan on fdw_schema."table"  (cost=100.02..306874.86 rows=105 width=0) (actual time=23.475..4681.419 rows=1360025 loops=1)
        Output: "table".id, "table".is_active, "table".meta, "table".created_dt
        Filter: (("table".is_active IS TRUE) AND (("table".meta ->> 'source'::text) = 'test'::text))
        Rows Removed by Filter: 76934
        Remote SQL: SELECT is_active, meta FROM fdw_schema.table WHERE ((created_dt >= $1::timestamp with time zone)) AND ((created_dt < $2::timestamp with time zone))
Planning time: 0.703 ms
Execution time: 4789.379 ms

Diximus consiliumque ut tempus in subquerio computare in antecessum et paratum factum variabile ad colum transmittere. Et haec admonitio egregium nobis eventum dedit, petitio fere 6 temporum velocior facta est!

Iterum hic cavendum interest: typum notitiae in subquisitione eaedem esse debere ac agri in quo percolamus, alioquin consilium quod cum diversae sint rationes statuet, necesse est primum omnia. data et sparguntur localiter.

Redeamus colum ad pristinum valorem.

Freddy vs. Jsonb

In genere, campi Booleani et dies interrogationem nostram satis iam acceleraverunt, sed unum genus notitiarum restat. Proelium eliquare per id, quod honestum est, adhuc non est, licet hic quoque successus sit. Ita, hoc modo colum per elaboratum est jsonb agrum ad remotiora servo.

explain analyze verbose
SELECT count(1)
FROM fdw_schema.table 
WHERE is_active is True
AND created_dt BETWEEN CURRENT_DATE - INTERVAL '7 month' 
AND CURRENT_DATE - INTERVAL '6 month'
AND meta @> '{"source":"test"}'::jsonb;

Aggregate  (cost=245463.60..245463.61 rows=1 width=8) (actual time=6727.589..6727.590 rows=1 loops=1)
  Output: count(1)
  ->  Foreign Scan on fdw_schema."table"  (cost=1100.00..245459.90 rows=1478 width=0) (actual time=16.213..6634.794 rows=1360025 loops=1)
        Output: "table".id, "table".is_active, "table".meta, "table".created_dt
        Filter: (("table".is_active IS TRUE) AND ("table".created_dt >= (('now'::cstring)::date - '7 mons'::interval)) AND ("table".created_dt <= ((('now'::cstring)::date)::timestamp with time zone - '6 mons'::interval)))
        Rows Removed by Filter: 619961
        Remote SQL: SELECT created_dt, is_active FROM fdw_schema.table WHERE ((meta @> '{"source": "test"}'::jsonb))
Planning time: 0.747 ms
Execution time: 6727.815 ms

Pro eliquare operariorum praesentia uti debetis unius operantis jsonb in alio. 7 seconds vice originali 29. Hactenus haec sola est optio felix per filtras tradendas jsonb servo remoto, hic autem refert unam limitationem considerare: versione 9.6 datorum utimur, sed fine mensis Aprilis cogitamus ultimas probationes perficere et ad versionem movere. Cum renovamus, scribemus quomodo affecta sit, quia satis multae mutationes sunt pro quibus multum spei est: json_via, nova CTE mores, deprimunt (exsistentia cum versione 12). Ego vere volo illud primum experior.

Perficiam

Probavimus quomodo unaquaeque mutatio affectata postulationis celeritatem singillatim. Nunc videamus quid accidit cum omnes tres filtra recte scribuntur.

explain analyze verbose
SELECT count(1)
FROM fdw_schema.table 
WHERE is_active = True
AND created_dt >= (SELECT CURRENT_DATE::timestamptz - INTERVAL '7 month') 
AND created_dt <(SELECT CURRENT_DATE::timestamptz - INTERVAL '6 month')
AND meta @> '{"source":"test"}'::jsonb;

Aggregate  (cost=322041.51..322041.52 rows=1 width=8) (actual time=2278.867..2278.867 rows=1 loops=1)
  Output: count(1)
  InitPlan 1 (returns $0)
    ->  Result  (cost=0.00..0.02 rows=1 width=8) (actual time=0.010..0.010 rows=1 loops=1)
          Output: ((('now'::cstring)::date)::timestamp with time zone - '7 mons'::interval)
  InitPlan 2 (returns $1)
    ->  Result  (cost=0.00..0.02 rows=1 width=8) (actual time=0.003..0.003 rows=1 loops=1)
          Output: ((('now'::cstring)::date)::timestamp with time zone - '6 mons'::interval)
  ->  Foreign Scan on fdw_schema."table"  (cost=100.02..322041.41 rows=25 width=0) (actual time=8.597..2153.809 rows=1360025 loops=1)
        Output: "table".id, "table".is_active, "table".meta, "table".created_dt
        Remote SQL: SELECT NULL FROM fdw_schema.table WHERE (is_active) AND ((created_dt >= $1::timestamp with time zone)) AND ((created_dt < $2::timestamp with time zone)) AND ((meta @> '{"source": "test"}'::jsonb))
Planning time: 0.820 ms
Execution time: 2279.087 ms

Etiam postulatio magis implicata spectat, hoc coactum pretium est, sed celeritas exsecutio secundarum secundarum 2 est, quae plus quam 10 times velocior! Et loquimur de interrogatione simplici contra notitias relative parvas. Rebus postulationibus auctum usque ad aliquot centies percepimus.

Summatim: si PostgreSQL cum FDW uteris, semper inspicias omnes filamenta mitti ad servitorem remotum, et eris felix... Saltem donec iungas inter mensas a diversis servientibus. Sed haec fabula est pro alio articulo.

Gratias tibi ago pro attente! Quaestiones, commentationes, et fabulas de experimentis tuis in commentis audire amem.

Source: www.habr.com