Development2021.10.26 5 min. czytania

Podróże w czasie – Data Lake

Łukasz Okrąglewski Big Data Developer

Gdy data lakes (jeziora danych) dynamicznie się rozwijały, ogromne firmy, takie jak Netflix czy Apple, niestrudzone w swoim nowatorstwie musiały znaleźć wydajniejszą metodę porządkowania formatów tabel. Po co? By szybciej gromadzić informacje. W tym wpisie wyjaśnię jedną z najnowszych funkcji współczesnych data lakes, coś co poetycko możemy nazwać “Podróżami w czasie”, a w praktyce sprowadza się do odczytywania danych z konkretnej daty lub wersji.

Data lake – co to jest?  

Zacznijmy od podstaw. Oto najprostsza definicja dla ludzi, którzy nie zetknęli się wcześniej z tym terminem: data lake to takie miejsce, w którym gromadzi się dane z wielu źródeł. W efekcie dane stają się łatwo dostępne w szerokim zakresie dla każdego, kto ich potrzebuje.

Może się zdarzyć, że data lake będzie wyglądać tak:

ale tak naprawdę można tego uniknąć 🙂    

Rozwój data lakes 

W początkowym okresie funkcjonowania data lakes, pliki znajdowały się w rozproszonym systemie HDFS, toteż dostęp do danych mieli tylko doświadczeni inżynierowie. Jego uzyskanie wymagało bowiem napisania w Javie niestandardowego kodu MapReduce, umożliwiającego otrzymanie poszukiwanych odpowiedzi. Rozwiązanie to było zawodne, więc inżynierowie z Facebooka opracowali Hive – hurtownię danych, która pobiera zapytania SQL i automatycznie tłumaczy je na instrukcje MapReduce operujące na danych w HDFS. Projekt Hive oferował jednak znacznie więcej niż tylko możliwość tłumaczenia skryptów SQL. Wprowadził także formaty tabel. W ten sposób – dzięki uporządkowaniu danych w tabelach – udało się zwiększyć szybkość wykonywania zapytań. Z biegiem czasu na arenie pojawili się nowi gracze gotowi stawić czoła problemom, których Hive nie był w stanie rozwiązać. Mowa tutaj m.in. o Apache Hudi, Apache Iceberg i Delta Lake. Ogólna idea sprowadzała się do stworzenia kolejnej warstwy zapewniającej dodatkowe możliwości obsługi danych na dużą skalę. 

Czym jest podróżowanie w czasie?  

Jednym z najlepszych narzędzi, które pojawiły się wraz z formatami tabel, okazały się “podróże w czasie”. Brzmi nieźle, prawda? Niestety, tym razem tylko twoje dane będą przenosić się w czasie. DeLoreana zostaw na razie w garażu.  Sposoby podróżowania w czasie różnią się w zależności od formatu, ale ogólna zasada pozostaje ta sama. Wybieramy punkt w przeszłości i otrzymujemy stan danych z tego momentu niezależnie od ich aktualnego statusu.

Jak to działa? 

Aby wyruszyć w “podróż w czasie”, musimy najpierw uzyskać dostęp do każdego stanu danych w określonym czasie. Jest to możliwe dzięki snapshotom przechowywanym w logach. W zależności od technologii operacja ta może nosić różne nazwy, ale mechanizm jest zawsze bardzo podobny. Do przeglądania logów i wyświetlania pożądanych snapshotów wykorzystuje się silnik do obliczeń równoregłych .    

Mamy już ogólne pojęcie, na czym polegają “podróże czasie”. Zobaczmy teraz, jak odbywają się w trzech najpopularniejszych formatach data lakes: Delta Lake, Iceberg i Hudi.  

Delta Lake 

Delta Lake to transakcyjna warstwa dostępu do danych zaprojektowana do współpracy z Apache Spark i rozwiązań chmurowych.    

Projekt rozpoczął się od współpracy z Apple. Podczas jednej z konferencji Spark Summit Michael Armburst miał okazję porozmawiać z inżynierem z zespołu InfoSec w Apple. Okazało się, że jego zadaniem było przetwarzanie danych z monitora sieciowego, który rejestrował każde połączenie TCP i DHCP w firmie. Operacja ta przynosiła owoc w postaci trylionów rekordów dziennie. Inżynier do owego przetwarzania chciał wykorzystać Spark, jednak sama platforma była niewystarczająca, by sprostać takiej ilości danych. Tak właśnie narodziło się Delta Lake.  

Delta Lake powstało jako log transakcji, tj. zbiór plików w formacie parquet i rekordów metadanych, który zapewnia skalowalność i niepodzielność danych. Log transakcji Delta jest napisany tak, że może być przetwarzany przez Spark. Transakcje skalowalne dla całego systemu usprawniają zarządzanie danymi w data lake i przyczyniają się do poprawy ich jakości.  

Delta Lake jako część platformy Databricks umożliwia “podróże w czasie”, które obejmują dane przechowywane w data lake i możliwość dostępu do ich dowolnej historycznej wersji.    

Prosty przykład 

Dostęp do danych historycznych można uzyskać na dwa sposoby.

Sygnatura czasowa:

df = spark.read 
    .format("delta")
    .option("timestampAsOf", "2019-01-01") 
    .load("/path/to/my/table") 

SELECT count(*) FROM my_table TIMESTAMP AS OF "2019-01-01" 
SELECT count(*) FROM my_table TIMESTAMP AS OF date_sub(current_date(), 1) 
SELECT count(*) FROM my_table TIMESTAMP AS OF "2019-01-01 01:30:00.000" 

Numer wersji:  

df = spark.read 
     .format("delta") 
     .option("versionAsOf", "5238") 
     .load("/path/to/my/table") 
df = spark.read 
     .format("delta") 
     .load("/path/to/my/table@v5238") 

SELECT count(*) FROM my_table VERSION AS OF 5238  
SELECT count(*) FROM my_table@v5238  
SELECT count(*) FROM delta.`/path/to/my/table@v5238

Apache Iceberg 

Iceberg w odróżnieniu od Delta Lake i Hudi jest uniwersalnym formatem tabel nieograniczonym do jednego silnika obliczeniowego. Z tego powodu może być wykorzystywany przez dowolną usługę streamingową. Sam wywodzi się z Netfliksa. 

Oto lista terminów używanych w Iceberg i związanych z porządkowaniem danych w tym formacie:  

Snapshot – stan tabeli w określonym momencie. 

Każdy snapshot zawiera listę wszystkich plików danych, które składają się na zawartość tabeli w momencie jego utworzenia.  

Manifest list (lista manifestów) – plik metadanych, który zawiera indeks manifestów składających się na snapshot tabeli.  

W celu przyspieszenia operacji na metadanych każdy plik manifestu przechowywany jest na indeksie manifestów wraz z informacjami o jego zawartości, takimi jak zakresy wartości partycji.  

Manifest file (plik manifestu) – plik metadanych, który zawiera zbiór plików danych składających się na snapshot tabeli. 

Każdy plik danych w manifeście przechowywany jest wraz z krotką partycji (partition tuple), statystykami na poziomie kolumny i zbiorczymi informacjami wykorzystywanymi do usuwania podziałów podczas planowania skanowania. 

Bardziej szczegółowo o architekturze Apache Iceberg pisał na swoim blogu Jason Hughes z zespołu Dremio:  

https://www.dremio.com/apache-iceberg-an-architectural-look-under-the-covers/  

Prosty przykład 

Dla zachowania spójności w przykładach będziemy nadal korzystać z Apache Spark jako silnika. “Podróżować w czasie” można na dwa sposoby: albo za pomocą sygnatury czasowej, albo za pomocą numeru identyfikacyjnego snapshota (snapshot ID).

Sygnatura czasowa:

// time travel to October 26, 1986 at 01:21:00 
spark.read 
     .option("as-of-timestamp","499162860000") 
     .format("iceberg") .load("path/to/table") 

Snapshot ID:

// time travel to snapshot with ID 10963874102873L 
spark.read 
     .option("snapshot-id",10963874102873L) 
     .format("iceberg") .load("path/to/table") 

Apache Hudi 

Ostatnie, ale nie mniej ważne rozwiązanie to Apache Hudi (wymawiane [hudi]). Jest ono zorientowane na usługi streamingowe w większym stopniu niż Iceberg lub Delta Lake i przypomina raczej dodatkową warstwę przetwarzania niż tylko format tabeli do wykorzystania w data lake. Główną właściwością Hudi jest architektura przyrostowa.  

“Podróże w czasie” są możliwe tylko w najnowszej wersji Hudi, tj. 0.9.0.   

Data Lakes

Więcej informacji o architekturze Apache Hudi można znaleźć tutaj:  

https://cwiki.apache.org/confluence/display/HUDI/Design+And+Architecture  

Prosty przykład 

“Podróże w czasie” to jedna z najnowszych funkcji Hudi. Wcześniej były możliwe tylko poprzez użycie kombinacji różnych zapytań. Teraz, od wersji 0.9.0, Hudi obsługuje osobną wygodną składnię dedykowaną podróżom w czasie. Obecnie stosować można trzy formaty zapisu czasu:  

spark.read
     .format("hudi")
     .option("as.of.instant", "20210728141108")
     .load(basePath) 
spark.read
     .format("hudi")
     .option("as.of.instant", "2021-07-28 14: 11: 08")
     .load(basePath)
// It is equal to "as.of.instant = 2021-07-28 00:00:00" 
spark.read
     .format("hudi")
     .option("as.of.instant", "2021-07-28")
     .load(basePath)  

Wnioski 

Inżynierowie rozwijający nowoczesne technologie data lakes dokładają starań, by podróże w czasie były łatwe i przystępne. Oprócz formatów tabel istnieją inne rozwiązania oferujące tę funkcję, np. lakefs lub hopsfs, które korzystają z możliwości wyżej wymienionych technologii.    

“Podróże w czasie” to przydatna funkcja dla każdego, kto zajmuje się przetwarzaniem potokowym (data pipelines). Naukowcy zajmujący się danymi mogą z łatwością uzyskać dostęp do modeli historycznych, a inżynierowie danych – szybko przywrócić kanały do poprzedniego stanu w przypadku błędów uszkadzających dane. Funkcja ta ułatwia i przyspiesza pracę wszędzie tam, gdzie danych przybywa i gdzie często ulegają zmianom.  

Autor

Łukasz Okrąglewski

Big Data Developer

Potrzebujesz więcej informacji?

Skontaktuj się z opiekunem handlowym.

Joanna Bartoszek

Account Manager

534 255 826

Joanna.Bartoszek@billennium.com

Skontaktuj się przez LinkedIn

Skontaktuj się z nami

Chcesz wiedzieć, jak możemy pomóc Tobie? Porozmawiajmy!

Kontakt