Kad imate Sber vagu. Korištenje Ab Initio s Hive i GreenPlum

Prije nekog vremena suočili smo se s pitanjem odabira ETL alata za rad s velikim podacima. Prethodno korišteno rješenje Informatica BDM nije nam odgovaralo zbog ograničene funkcionalnosti. Njegova je upotreba svedena na okvir za pokretanje spark-submit naredbi. Na tržištu nije bilo mnogo analoga koji su u načelu bili sposobni raditi s količinom podataka s kojima se svakodnevno susrećemo. Na kraju smo odabrali Ab Initio. Tijekom pilot demonstracija, proizvod je pokazao vrlo veliku brzinu obrade podataka. O Ab Initiu nema gotovo nikakvih informacija na ruskom, pa smo o našem iskustvu odlučili govoriti na Habréu.

Ab Initio ima mnogo klasičnih i neobičnih transformacija, čiji se kod može proširiti pomoću vlastitog PDL jezika. Za malu tvrtku, takav moćan alat vjerojatno će biti pretjeran, a većina njegovih mogućnosti može biti skupa i neiskorištena. Ali ako je vaša ljestvica blizu Sberove, onda bi vam Ab Initio mogao biti zanimljiv.

Pomaže poduzeću da akumulira znanje na globalnoj razini i razvije ekosustav, a programeru da unaprijedi svoje vještine u ETL-u, unaprijedi svoje znanje u ljusci, pruža mogućnost svladavanja PDL jezika, daje vizualnu sliku procesa učitavanja i pojednostavljuje razvoj zbog obilja funkcionalnih komponenti.

U ovom postu govorit ću o mogućnostima Ab Initia i pružiti usporedne karakteristike njegovog rada s Hiveom i GreenPlumom.

  • Opis okvira MDW i rad na njegovoj prilagodbi za GreenPlum
  • Ab initio usporedba performansi između Hive i GreenPlum
  • Rad od početka s GreenPlumom u načinu rada gotovo u stvarnom vremenu


Funkcionalnost ovog proizvoda je vrlo široka i zahtijeva puno vremena za proučavanje. Međutim, uz odgovarajuće radne vještine i pravilne postavke performansi, rezultati obrade podataka su vrlo impresivni. Korištenje Ab Initio za programera može pružiti zanimljivo iskustvo. Ovo je novi pogled na razvoj ETL-a, hibrid između vizualnog okruženja i razvoja preuzimanja u jeziku sličnom skripti.

Poduzeća razvijaju svoje ekosustave i ovaj alat je koristan više nego ikada. Uz Ab Initio, možete akumulirati znanje o svom trenutnom poslovanju i koristiti to znanje za širenje starih i otvaranje novih poslova. Alternative za Ab Initio uključuju vizualna razvojna okruženja Informatica BDM i nevizualna razvojna okruženja Apache Spark.

Opis Ab Initio

Ab Initio, kao i drugi ETL alati, zbirka je proizvoda.

Kad imate Sber vagu. Korištenje Ab Initio s Hive i GreenPlum

Ab Initio GDE (Graphical Development Environment) je okruženje za programera u kojem on konfigurira transformacije podataka i povezuje ih s tokovima podataka u obliku strelica. U ovom slučaju, takav skup transformacija naziva se graf:

Kad imate Sber vagu. Korištenje Ab Initio s Hive i GreenPlum

Ulazni i izlazni priključci funkcionalnih komponenti su portovi i sadrže polja izračunata unutar transformacija. Nekoliko grafova povezanih tokovima u obliku strelica prema redoslijedu njihovog izvođenja naziva se plan.

Ima nekoliko stotina funkcionalnih komponenti, što je jako puno. Mnogi od njih su visoko specijalizirani. Mogućnosti klasičnih transformacija u Ab Initio šire su nego u drugim ETL alatima. Na primjer, Join ima više izlaza. Osim rezultata povezivanja skupova podataka, možete dobiti izlazne zapise ulaznih skupova podataka čiji ključevi nisu mogli biti povezani. Također možete dobiti odbijenice, pogreške i zapisnik operacije transformacije, koji se može čitati u istom stupcu kao tekstualna datoteka i obraditi s drugim transformacijama:

Kad imate Sber vagu. Korištenje Ab Initio s Hive i GreenPlum

Ili, na primjer, možete materijalizirati primatelj podataka u obliku tablice i čitati podatke iz nje u istom stupcu.

Postoje izvorne transformacije. Na primjer, transformacija skeniranja ima funkcionalnost sličnu analitičkim funkcijama. Postoje transformacije s nazivima koji sami po sebi objašnjavaju: Stvori podatke, Čitaj Excel, Normaliziraj, Sortiraj unutar grupa, Pokreni program, Pokreni SQL, Spoji s DB-om itd. Grafovi mogu koristiti parametre vremena izvođenja, uključujući mogućnost prosljeđivanja parametara iz ili u operativni sustav. Datoteke s gotovim skupom parametara proslijeđenih grafu nazivaju se skupovi parametara (psets).

Kao što se i očekivalo, Ab Initio GDE ima vlastito spremište pod nazivom EME (Enterprise Meta Environment). Programeri imaju priliku raditi s lokalnim verzijama koda i provjeriti svoj razvoj u središnjem repozitoriju.

Moguće je, tijekom izvođenja ili nakon izvođenja grafa, kliknuti na bilo koji tijek koji povezuje transformaciju i pogledati podatke koji su prošli između ovih transformacija:

Kad imate Sber vagu. Korištenje Ab Initio s Hive i GreenPlum

Također je moguće kliknuti na bilo koji tok i vidjeti detalje praćenja - u koliko je paralela transformacija radila, koliko je linija i bajtova učitano u koju od paralela:

Kad imate Sber vagu. Korištenje Ab Initio s Hive i GreenPlum

Moguće je izvođenje grafa podijeliti u faze i označiti da neke transformacije treba izvršiti prvo (u nultoj fazi), sljedeće u prvoj fazi, sljedeće u drugoj fazi itd.

Za svaku transformaciju možete odabrati tzv. izgled (gdje će se izvršiti): bez paralela ili u paralelnim nitima, čiji se broj može specificirati. U isto vrijeme, privremene datoteke koje Ab Initio stvara kada se izvode transformacije mogu se smjestiti iu datotečni sustav poslužitelja iu HDFS.

U svakoj transformaciji, na temelju zadanog predloška, ​​možete stvoriti vlastitu skriptu u PDL-u, koja je pomalo poput ljuske.

S PDL-om možete proširiti funkcionalnost transformacija, a posebno možete dinamički (tijekom izvođenja) generirati proizvoljne fragmente koda ovisno o parametrima izvođenja.

Ab Initio također ima dobro razvijenu integraciju s OS-om putem shell-a. Konkretno, Sberbank koristi linux ksh. Možete razmjenjivati ​​varijable s ljuskom i koristiti ih kao parametre grafa. Možete pozvati izvođenje Ab Initio grafova iz ljuske i administrirati Ab Initio.

Uz Ab Initio GDE, mnogi drugi proizvodi uključeni su u isporuku. Postoji vlastiti Co>Operation System koji se može nazvati operativnim sustavom. Postoji Kontrolni>Centar gdje možete planirati i pratiti tokove preuzimanja. Postoje proizvodi za razvoj na primitivnijoj razini nego što to dopušta Ab Initio GDE.

Opis okvira MDW i rad na njegovoj prilagodbi za GreenPlum

Zajedno sa svojim proizvodima, dobavljač isporučuje proizvod MDW (Metadata Driven Warehouse), koji je konfigurator grafikona dizajniran da pomogne u tipičnim zadacima popunjavanja skladišta podataka ili trezora podataka.

Sadrži prilagođene (specifične za projekt) parsere metapodataka i gotove generatore koda.

Kad imate Sber vagu. Korištenje Ab Initio s Hive i GreenPlum
Kao ulaz MDW dobiva podatkovni model, konfiguracijsku datoteku za postavljanje veze s bazom podataka (Oracle, Teradata ili Hive) i neke druge postavke. Dio specifičan za projekt, na primjer, implementira model u bazu podataka. Dio proizvoda izvan okvira generira grafikone i konfiguracijske datoteke za njih učitavanjem podataka u tablice modela. U ovom slučaju, grafikoni (i psets) se stvaraju za nekoliko načina pokretanja i inkrementalnog rada na ažuriranju entiteta.

U slučajevima Hive i RDBMS, generiraju se različiti grafikoni za inicijalizaciju i inkrementalna ažuriranja podataka.

U slučaju Hivea, dolazni delta podaci povezani su putem Ab Initio Join s podacima koji su bili u tablici prije ažuriranja. Učitavači podataka u MDW (u Hiveu i RDBMS-u) ne samo da umeću nove podatke iz delte, već i zatvaraju razdoblja relevantnosti podataka čiji su primarni ključevi primili deltu. Osim toga, morate prepisati nepromijenjeni dio podataka. Ali to se mora učiniti jer Hive nema operacije brisanja ili ažuriranja.

Kad imate Sber vagu. Korištenje Ab Initio s Hive i GreenPlum

U slučaju RDBMS-a, grafikoni za inkrementalno ažuriranje podataka izgledaju optimalnije, jer RDBMS ima stvarne mogućnosti ažuriranja.

Kad imate Sber vagu. Korištenje Ab Initio s Hive i GreenPlum

Primljena delta se učitava u međutablicu u bazi podataka. Nakon toga se delta povezuje s podacima koji su bili u tablici prije ažuriranja. A to se radi pomoću SQL-a pomoću generiranog SQL upita. Zatim se pomoću SQL naredbi delete+insert novi podaci iz delte umeću u ciljnu tablicu i zatvaraju se razdoblja relevantnosti podataka čiji su primarni ključevi primili deltu.
Nema potrebe za prepisivanjem nepromijenjenih podataka.

Tako smo došli do zaključka da u slučaju Hive-a, MDW mora ponovno napisati cijelu tablicu jer Hive nema funkciju ažuriranja. I nije izmišljeno ništa bolje od potpunog ponovnog pisanja podataka prilikom ažuriranja. U slučaju RDBMS-a, naprotiv, kreatori proizvoda smatrali su potrebnim povezivanje i ažuriranje tablica povjeriti korištenju SQL-a.

Za projekt u Sberbanku izradili smo novu, višekratnu implementaciju učitavača baze podataka za GreenPlum. To je učinjeno na temelju verzije koju MDW generira za Teradatu. Teradata, a ne Oracle, bila je najbliža i najbolja za ovo, jer... također je MPP sustav. Pokazalo se da su metode rada, kao i sintaksa Teradate i GreenPluma slične.

Primjeri MDW-kritičnih razlika između različitih RDBMS-ova su sljedeći. U GreenPlumu, za razliku od Teradate, prilikom izrade tablica morate napisati klauzulu

distributed by

Teradata piše:

delete <table> all

, a u GreenPlumu pišu

delete from <table>

U Oracleu pišu za potrebe optimizacije

delete from t where rowid in (<соединение t с дельтой>)

, a pišu Teradata i GreenPlum

delete from t where exists (select * from delta where delta.pk=t.pk)

Također napominjemo da je za Ab Initio rad s GreenPlumom bilo potrebno instalirati GreenPlum klijent na sve čvorove Ab Initio klastera. To je zato što smo se na GreenPlum povezali istovremeno sa svih čvorova u našem klasteru. A kako bi čitanje iz GreenPluma bilo paralelno i kako bi svaka paralelna Ab Initio nit čitala svoj dio podataka iz GreenPluma, morali smo postaviti konstrukciju koju Ab Initio razumije u odjeljak "where" SQL upita

where ABLOCAL()

i odredite vrijednost ove konstrukcije navođenjem očitanja parametra iz transformacijske baze podataka

ablocal_expr=«string_concat("mod(t.", string_filter_out("{$TABLE_KEY}","{}"), ",", (decimal(3))(number_of_partitions()),")=", (decimal(3))(this_partition()))»

, koji se kompilira u nešto poput

mod(sk,10)=3

, tj. morate zatražiti GreenPlum s eksplicitnim filtrom za svaku particiju. Za druge baze podataka (Teradata, Oracle), Ab Initio može automatski izvesti ovu paralelizaciju.

Ab initio usporedba performansi između Hive i GreenPlum

Sberbank je proveo eksperiment kako bi usporedio performanse MDW-generiranih grafova u odnosu na Hive i GreenPlum. Kao dio eksperimenta, u slučaju Hive bilo je 5 čvorova na istom klasteru kao i Ab Initio, au slučaju GreenPluma bila su 4 čvora na zasebnom klasteru. Oni. Hive je imao određenu hardversku prednost u odnosu na GreenPlum.

Razmotrili smo dva para grafikona koji obavljaju isti zadatak ažuriranja podataka u Hive i GreenPlum. Istovremeno su pokrenuti grafikoni koje je generirao MDW konfigurator:

  • početno učitavanje + inkrementalno učitavanje nasumično generiranih podataka u Hive tablicu
  • početno učitavanje + inkrementalno učitavanje nasumično generiranih podataka u istu GreenPlum tablicu

U oba slučaja (Hive i GreenPlum) pokrenuli su prijenose na 10 paralelnih niti na istom Ab Initio klasteru. Ab Initio je spremio međupodatke za izračune u HDFS (u smislu Ab Initio, korišten je MFS raspored koristeći HDFS). Jedna linija nasumično generiranih podataka zauzimala je 200 bajtova u oba slučaja.

Rezultat je bio ovakav:

Košnica:

Početno učitavanje u Hive

Redovi su umetnuti
6 000 000
60 000 000
600 000 000

Trajanje inicijalizacije
preuzimanja u sekundi
41
203
1 601

Inkrementalno učitavanje u Hive

Broj dostupnih redaka u
ciljnu tablicu na početku eksperimenta
6 000 000
60 000 000
600 000 000

Broj delta linija primijenjenih na
ciljnu tablicu tijekom eksperimenta
6 000 000
6 000 000
6 000 000

Trajanje inkrementalnog
preuzimanja u sekundi
88
299
2 541

GreenPlum:

Početno učitavanje u GreenPlum

Redovi su umetnuti
6 000 000
60 000 000
600 000 000

Trajanje inicijalizacije
preuzimanja u sekundi
72
360
3 631

Inkrementalno učitavanje u GreenPlumu

Broj dostupnih redaka u
ciljnu tablicu na početku eksperimenta
6 000 000
60 000 000
600 000 000

Broj delta linija primijenjenih na
ciljnu tablicu tijekom eksperimenta
6 000 000
6 000 000
6 000 000

Trajanje inkrementalnog
preuzimanja u sekundi
159
199
321

Vidimo da brzina početnog učitavanja i u Hiveu i u GreenPlumu linearno ovisi o količini podataka i, zbog boljeg hardvera, nešto je brža za Hive nego za GreenPlum.

Inkrementalno učitavanje u Hive također linearno ovisi o količini prethodno učitanih podataka dostupnih u ciljnoj tablici i odvija se prilično sporo kako količina raste. To je uzrokovano potrebom potpunog ponovnog pisanja ciljne tablice. To znači da primjena malih promjena na ogromne tablice nije dobar slučaj za Hive.

Inkrementalno učitavanje u GreenPlumu slabo ovisi o količini prethodno učitanih podataka dostupnih u ciljnoj tablici i odvija se prilično brzo. To se dogodilo zahvaljujući SQL Joins i GreenPlum arhitekturi, koja omogućuje operaciju brisanja.

Dakle, GreenPlum dodaje deltu koristeći metodu delete+insert, ali Hive nema operacije brisanja ili ažuriranja, tako da je cijeli niz podataka bio prisiljen u potpunosti prepisati tijekom inkrementalnog ažuriranja. Usporedba ćelija označenih podebljanim slovima najviše otkriva, jer odgovara najčešćoj opciji za korištenje preuzimanja koja zahtijevaju velike resurse. Vidimo da je GreenPlum pobijedio Hive u ovom testu 8 puta.

Rad od početka s GreenPlumom u načinu rada gotovo u stvarnom vremenu

U ovom eksperimentu testirat ćemo sposobnost Ab Initia da ažurira tablicu GreenPlum s nasumično generiranim dijelovima podataka u gotovo stvarnom vremenu. Razmotrimo GreenPlum tablicu dev42_1_db_usl.TESTING_SUBJ_org_finval, s kojom ćemo raditi.

Za rad s njim koristit ćemo tri Ab Initio grafikona:

1) Grafikon Create_test_data.mp – stvara podatkovne datoteke u HDFS-u sa 10 redaka u 6 paralelnih niti. Podaci su slučajni, njihova struktura je organizirana za umetanje u našu tablicu

Kad imate Sber vagu. Korištenje Ab Initio s Hive i GreenPlum

Kad imate Sber vagu. Korištenje Ab Initio s Hive i GreenPlum

2) Grafikon mdw_load.day_one.current.dev42_1_db_usl_testing_subj_org_finval.pset – MDW generirani graf inicijaliziranjem umetanja podataka u našu tablicu u 10 paralelnih niti (korišteni su testni podaci generirani grafom (1))

Kad imate Sber vagu. Korištenje Ab Initio s Hive i GreenPlum

3) Grafikon mdw_load.regular.current.dev42_1_db_usl_testing_subj_org_finval.pset – graf koji je generirao MDW za inkrementalno ažuriranje naše tablice u 10 paralelnih niti koristeći dio svježe primljenih podataka (delta) generiran grafom (1)

Kad imate Sber vagu. Korištenje Ab Initio s Hive i GreenPlum

Pokrenimo donju skriptu u NRT modu:

  • generirati 6 testnih linija
  • izvršite početno učitavanje umetnite 6 testnih redaka u praznu tablicu
  • ponovite inkrementalno preuzimanje 5 puta
    • generirati 6 testnih linija
    • izvrši inkrementalno umetanje 6 testnih redaka u tablicu (u ovom slučaju, vrijeme isteka valid_to_ts postavljeno je na stare podatke i umetnuti su noviji podaci s istim primarnim ključem)

Ovaj scenarij emulira način stvarnog rada određenog poslovnog sustava - prilično velik dio novih podataka pojavljuje se u stvarnom vremenu i odmah se ulijeva u GreenPlum.

Sada pogledajmo dnevnik skripte:

Pokrenite Create_test_data.input.pset u 2020-06-04 11:49:11
Završite Create_test_data.input.pset u 2020-06-04 11:49:37
Pokreni mdw_load.day_one.current.dev42_1_db_usl_testing_subj_org_finval.pset u 2020-06-04 11:49:37
Završite mdw_load.day_one.current.dev42_1_db_usl_testing_subj_org_finval.pset u 2020-06-04 11:50:42
Pokrenite Create_test_data.input.pset u 2020-06-04 11:50:42
Završite Create_test_data.input.pset u 2020-06-04 11:51:06
Pokreni mdw_load.regular.current.dev42_1_db_usl_testing_subj_org_finval.pset u 2020-06-04 11:51:06
Završite mdw_load.regular.current.dev42_1_db_usl_testing_subj_org_finval.pset u 2020-06-04 11:53:41
Pokrenite Create_test_data.input.pset u 2020-06-04 11:53:41
Završite Create_test_data.input.pset u 2020-06-04 11:54:04
Pokreni mdw_load.regular.current.dev42_1_db_usl_testing_subj_org_finval.pset u 2020-06-04 11:54:04
Završite mdw_load.regular.current.dev42_1_db_usl_testing_subj_org_finval.pset u 2020-06-04 11:56:51
Pokrenite Create_test_data.input.pset u 2020-06-04 11:56:51
Završite Create_test_data.input.pset u 2020-06-04 11:57:14
Pokreni mdw_load.regular.current.dev42_1_db_usl_testing_subj_org_finval.pset u 2020-06-04 11:57:14
Završite mdw_load.regular.current.dev42_1_db_usl_testing_subj_org_finval.pset u 2020-06-04 11:59:55
Pokrenite Create_test_data.input.pset u 2020-06-04 11:59:55
Završite Create_test_data.input.pset u 2020-06-04 12:00:23
Pokreni mdw_load.regular.current.dev42_1_db_usl_testing_subj_org_finval.pset u 2020-06-04 12:00:23
Završite mdw_load.regular.current.dev42_1_db_usl_testing_subj_org_finval.pset u 2020-06-04 12:03:23
Pokrenite Create_test_data.input.pset u 2020-06-04 12:03:23
Završite Create_test_data.input.pset u 2020-06-04 12:03:49
Pokreni mdw_load.regular.current.dev42_1_db_usl_testing_subj_org_finval.pset u 2020-06-04 12:03:49
Završite mdw_load.regular.current.dev42_1_db_usl_testing_subj_org_finval.pset u 2020-06-04 12:06:46

Ispada ova slika:

Grafikon
Vrijeme početka
Vrijeme završetka
Dužina

Create_test_data.input.pset
04.06.2020 11: 49: 11
04.06.2020 11: 49: 37
00:00:26

mdw_load.day_one.current.
dev42_1_db_usl_testing_subj_org_finval.pset
04.06.2020 11: 49: 37
04.06.2020 11: 50: 42
00:01:05

Create_test_data.input.pset
04.06.2020 11: 50: 42
04.06.2020 11: 51: 06
00:00:24

mdw_load.regular.current.
dev42_1_db_usl_testing_subj_org_finval.pset
04.06.2020 11: 51: 06
04.06.2020 11: 53: 41
00:02:35

Create_test_data.input.pset
04.06.2020 11: 53: 41
04.06.2020 11: 54: 04
00:00:23

mdw_load.regular.current.
dev42_1_db_usl_testing_subj_org_finval.pset
04.06.2020 11: 54: 04
04.06.2020 11: 56: 51
00:02:47

Create_test_data.input.pset
04.06.2020 11: 56: 51
04.06.2020 11: 57: 14
00:00:23

mdw_load.regular.current.
dev42_1_db_usl_testing_subj_org_finval.pset
04.06.2020 11: 57: 14
04.06.2020 11: 59: 55
00:02:41

Create_test_data.input.pset
04.06.2020 11: 59: 55
04.06.2020 12: 00: 23
00:00:28

mdw_load.regular.current.
dev42_1_db_usl_testing_subj_org_finval.pset
04.06.2020 12: 00: 23
04.06.2020 12: 03: 23
00:03:00

Create_test_data.input.pset
04.06.2020 12: 03: 23
04.06.2020 12: 03: 49
00:00:26

mdw_load.regular.current.
dev42_1_db_usl_testing_subj_org_finval.pset
04.06.2020 12: 03: 49
04.06.2020 12: 06: 46
00:02:57

Vidimo da se 6 redaka inkrementa obrađuje u 000 minute, što je prilično brzo.
Pokazalo se da su podaci u ciljnoj tablici raspoređeni na sljedeći način:

select valid_from_ts, valid_to_ts, count(1), min(sk), max(sk) from dev42_1_db_usl.TESTING_SUBJ_org_finval group by valid_from_ts, valid_to_ts order by 1,2;

Kad imate Sber vagu. Korištenje Ab Initio s Hive i GreenPlum
Možete vidjeti korespondenciju umetnutih podataka s vremenom pokretanja grafikona.
To znači da možete pokrenuti inkrementalno učitavanje podataka u GreenPlum u Ab Initio s vrlo velikom učestalošću i promatrati veliku brzinu umetanja tih podataka u GreenPlum. Naravno, neće biti moguće pokrenuti jednom u sekundi, jer Ab Initio, kao i svaki ETL alat, zahtijeva vrijeme da se "pokrene" kada se pokrene.

Zaključak

Ab Initio se trenutno koristi u Sberbanku za izgradnju Unified Semantic Data Layer (ESS). Ovaj projekt podrazumijeva izgradnju jedinstvene verzije stanja različitih bankarskih poslovnih subjekata. Informacije dolaze iz različitih izvora, čije su replike pripremljene na Hadoopu. Na temelju poslovnih potreba izrađuje se podatkovni model i opisuju transformacije podataka. Ab Initio učitava informacije u ESN i preuzeti podaci ne samo da su sami po sebi interesantni za tvrtku, već služe i kao izvor za izgradnju baza podataka. Istovremeno, funkcionalnost proizvoda omogućuje korištenje različitih sustava kao prijemnika (Hive, Greenplum, Teradata, Oracle), što omogućuje jednostavnu pripremu podataka za poslovanje u različitim formatima koji su mu potrebni.

Sposobnosti Ab Initia su široke; na primjer, uključeni MDW okvir omogućuje izradu tehničkih i poslovnih podataka iz okvira. Programerima Ab Initio omogućuje da ne izmišljaju kotač, već da koriste mnoge postojeće funkcionalne komponente, koje su u biti knjižnice potrebne pri radu s podacima.

Autor je stručnjak stručne zajednice Sberbank SberProfi DWH/BigData. Stručna zajednica SberProfi DWH/BigData odgovorna je za razvoj kompetencija u područjima kao što su Hadoop ekosustav, Teradata, Oracle DB, GreenPlum, kao i BI alati Qlik, SAP BO, Tableau itd.

Izvor: www.habr.com

Dodajte komentar