Natyrny silnik wykonawczy dla Data Fabric Engineering

Silnik wykonawczy to przełomowe usprawnienie dla wykonywania zadań w Apache Spark w usłudze Microsoft Fabric. Ten wektoryzowany aparat optymalizuje wydajność i efektywność zapytań Spark, uruchamiając je bezpośrednio w infrastrukturze lakehouse. Płynna integracja silnika oznacza, że nie wymaga modyfikacji kodu i unika uzależnienia od dostawcy. Obsługuje ona interfejsy API platformy Apache Spark i jest zgodna ze środowiskiem Uruchomieniowym 1.3 (Apache Spark 3.5) i środowiskiem uruchomieniowym 2.0 (Apache Spark 4.1) oraz współpracuje z formatami Parquet, Delta i CSV. Niezależnie od lokalizacji danych w usłudze OneLake, czy uzyskujesz dostęp do danych za pomocą skrótów, natywne środowisko wykonawcze maksymalizuje efektywność i sprawność.

Silnik wykonywania natywnego znacznie podnosi wydajność zapytań przy jednoczesnym obniżeniu kosztów operacyjnych. Rzeczywiste wyniki różnią się w zależności od charakterystyk obciążeń i konfiguracji. Silnik jest biegły w zarządzaniu szeroką gamą scenariuszy przetwarzania danych, począwszy od rutynowego wczytywania danych, zadań wsadowych i zadań ETL (ekstrakcja, transformacja, ładowanie) do złożonych analiz danych i interaktywnych zapytań. Użytkownicy korzystają z przyspieszonego czasu przetwarzania, zwiększonej przepływności i zoptymalizowanego wykorzystania zasobów.

Aparat wykonywania natywnego opiera się na dwóch kluczowych składnikach OSS: Velox, bibliotece przyspieszającej bazę danych C++ wprowadzonej przez Meta, oraz Apache Gluten (inkubowanie) — warstwie pośredniej odpowiedzialnej za przekazywanie wykonania silników SQL opartych na JVM do natywnych silników wprowadzonych przez Intel.

Obsługiwane operatory są przenoszone z Spark działającego na JVM do wektoryzowanej ścieżki wykonywania C++, zapewniając kolumnowe, przyspieszone przez SIMD przetwarzanie z natywną obsługą formatów Parquet i Delta. Rodzimy silnik zachowuje kluczowe optymalizacje zapytań w Fabric Spark, w tym adaptacyjne wykonywanie zapytań (AQE), przekształcenia oparte na analizie kosztów, przycinanie kolumn i przesuwanie predykatów, dzięki czemu te zachowania optymalizatora pozostają w pełni aktywne po odciążeniu operatorów. Silnik obsługuje również równoległe ładowanie migawek Delta i przyspiesza operacje, które korzystają z Z-ordering i Liquid Clustering w tabelach Delta, zapewniając dalsze wzrosty wydajności dla zorganizowanych układów danych.

Kiedy należy używać natywnego silnika wykonawczego

Silnik natywnej egzekucji oferuje rozwiązanie do uruchamiania zapytań na dużą skalę w zestawach danych; optymalizuje wydajność, wykorzystując natywne możliwości bazowych źródeł danych, minimalizując narzut typowo związany z przenoszeniem i serializacją danych w tradycyjnych środowiskach Spark. Silnik obsługuje różne operatory i typy danych, w tym agregację przez funkcję skrótu, łączenie przez zagnieżdżoną pętlę transmisji (BNLJ) i dokładne formaty znacznika czasu. Jednak aby w pełni korzystać z możliwości silnika, należy wziąć pod uwagę jego optymalne przypadki użycia:

  • Silnik jest skuteczny podczas pracy z danymi w formatach Parquet i Delta, które przetwarza natywnie i wydajnie.
  • Zapytania obejmujące skomplikowane przekształcenia i agregacje znacznie korzystają z możliwości przetwarzania kolumnowego i wektoryzacji silnika.
  • Zwiększenie wydajności jest najbardziej istotne w scenariuszach, w których zapytania nie wyzwalają mechanizmu rezerwowego, unikając nieobsługiwanych funkcji lub wyrażeń.
  • Silnik jest dobrze dopasowany do zapytań, które są intensywnie obliczeniowe, a nie prostych lub związanych z operacjami wejścia-wyjścia.

Aby uzyskać informacje na temat operatorów i funkcji obsługiwanych przez aparat wykonywania natywnego, zobacz dokumentację Apache Gluten.

Włącz aparat wykonywania natywnego

Aby korzystać z pełnych możliwości natywnego aparatu wykonawczego w fazie zapoznawczej, niezbędne są określone konfiguracje. Poniższe procedury pokazują, jak aktywować tę funkcję dla notesów, definicji zadań platformy Spark i całych środowisk.

Włącz na poziomie środowiska

Aby zapewnić jednolite zwiększenie wydajności, włącz natywny silnik wykonywania we wszystkich zadaniach i notesach związanych z twoim środowiskiem.

  1. Przejdź do obszaru roboczego zawierającego Twoje środowisko i wybierz to środowisko. Jeśli nie masz utworzonego środowiska, zobacz Tworzenie, konfigurowanie i używanie środowiska w Fabric.

  2. W obszarze Obliczenia platformy Spark wybierz pozycję Przyspieszanie.

  3. Zaznacz pole wyboru z etykietą Włącz natywny silnik wykonywania.

  4. Zapisz i opublikuj zmiany.

    Zrzut ekranu przedstawiający sposób włączania natywnego silnika wykonawczego w elemencie środowiska.

Po włączeniu na poziomie środowiska wszystkie kolejne zadania i notesy przejmują ustawienie. Dziedziczenie gwarantuje, że wszystkie nowe sesje lub zasoby utworzone w środowisku automatycznie korzystają z ulepszonych możliwości wykonywania operacji.

Ważne

Wcześniej natywny silnik wykonawczy był włączany poprzez ustawienia Spark w konfiguracji środowiska. Silnik wykonawczy natywny można teraz łatwiej włączyć za pomocą przełącznika na karcie Akceleracja ustawień środowiska. Aby kontynuować korzystanie z niego, przejdź do karty Przyspieszanie i włącz przełącznik. Można ją również włączyć za pomocą właściwości platformy Spark, jeśli jest to preferowane.

Włącz dla notesu lub definicji zadania Spark

Możesz włączyć mechanizm wykonawczy natywny dla pojedynczego notesu lub definicji zadania Spark, musisz uwzględnić niezbędne konfiguracje na początku skryptu wykonywania:

%%configure 
{ 
   "conf": {
       "spark.native.enabled": "true", 
   } 
} 

W przypadku notebooków wstaw wymagane polecenia konfiguracji w pierwszej komórce. W przypadku definicji zadań platformy Spark uwzględnij konfiguracje w pierwszej linii definicji zadania platformy Spark. Silnik wykonywania natywnego jest zintegrowany z pulami na żywo, więc po włączeniu tej funkcji działa ona natychmiast, nie trzeba inicjować nowej sesji.

Kontrola na poziomie zapytania

Mechanizmy umożliwiające włączenie natywnego aparatu wykonawczego na poziomie najemcy, w obszarze roboczym i środowisku, są bezproblemowo zintegrowane z interfejsem użytkownika i są aktywnie opracowywane. W międzyczasie można wyłączyć wbudowany silnik wykonawczy dla określonych zapytań, szczególnie w przypadku operatorów, które nie są obecnie obsługiwane (zobacz ograniczenia). Aby wyłączyć, ustaw w konfiguracji Spark opcję spark.native.enabled na false dla określonej komórki zawierającej zapytanie.

%%sql 
SET spark.native.enabled=FALSE; 

Zrzut ekranu przedstawiający sposób wyłączania natywnego aparatu wykonywania wewnątrz notatnika.

Po wykonaniu zapytania, w którym natywny silnik wykonywania jest wyłączony, należy ponownie go włączyć dla kolejnych komórek, ustawiając opcję spark.native.enabled na wartość true. Ten krok jest niezbędny, ponieważ platforma Spark wykonuje sekwencyjnie komórki kodu.

%%sql 
SET spark.native.enabled=TRUE; 

Identyfikowanie operacji wykonywanych przez aparat

Istnieje kilka metod, aby określić, czy operator w zadaniu Apache Spark został przetworzony przy użyciu silnika natywnego wykonania.

Interfejs użytkownika platformy Spark i serwer historii platformy Spark

Uzyskaj dostęp do serwera historii platformy Spark lub interfejsu użytkownika platformy Spark, aby zlokalizować zapytanie, które należy sprawdzić. Aby uzyskać dostęp do interfejsu webowego Sparka, przejdź do definicji zadania Spark i uruchom ją. Na zakładce Uruchomienia wybierz ... obok nazwy aplikacji i wybierz Otwórz internetowy interfejs użytkownika platformy Spark. Możesz także uzyskać dostęp do interfejsu Spark z zakładki Monitor w obszarze roboczym. Wybierz notatnik lub potok, na stronie monitorującej znajduje się bezpośredni link do interfejsu użytkownika platformy Spark dla aktywnych zadań.

Zrzut ekranu przedstawiający sposób przechodzenia do internetowego interfejsu użytkownika platformy Spark.

W planie zapytania wyświetlanym w interfejsie interfejsu użytkownika platformy Spark wyszukaj nazwy węzłów, które kończą się sufiksem Transformer, *NativeFileScan lub VeloxColumnarToRowExec. Sufiks oznacza, że silnik wykonawczy natywnego wykonania przeprowadził operację. Na przykład węzły mogą być oznaczone jako RollUpHashAggregateTransformer, ProjectExecTransformer, BroadcastHashJoinExecTransformer, ShuffledHashJoinExecTransformer lub BroadcastNestedLoopJoinExecTransformer. W przypadku źródeł danych CSV natywne skany mogą być wyświetlane jako natywne węzły skanowania plików lub transformacji w interfejsie użytkownika Spark, podobnie jak węzły skanowania Parquet i Delta.

Zrzut ekranu przedstawiający sposób sprawdzania wizualizacji języka DAG kończącej się sufiksem Transformer.

Wyjaśnienie DataFrame

Alternatywnie możesz wykonać df.explain() polecenie w notesie, aby wyświetlić plan wykonania. W danych wyjściowych wyszukaj te same sufiksy Transformer, *NativeFileScan lub VeloxColumnarToRowExec. Ta metoda zapewnia szybki sposób potwierdzenia, czy określone operacje są obsługiwane przez natywny aparat wykonywania.

Zrzut ekranu przedstawiający sposób sprawdzania planu fizycznego zapytania oraz czy zapytanie zostało wykonane przez natywny silnik wykonawczy.

Alerty usługi Fabric Spark Advisor

Usługa Fabric Spark Advisor zapewnia widoczność awaryjną w czasie rzeczywistym podczas wykonywania komórek notatnika. Gdy operator lub segment planu wraca do platformy Spark opartej na maszynie JVM zamiast ścieżki natywnej, usługa Advisor wyświetla alert bezpośrednio w danych wyjściowych komórki notesu, pomagając szybko identyfikować nieobsługiwane operatory lub konfiguracje bez opuszczania notesu. Za pomocą tych alertów można zdiagnozować, kiedy nie zastosowano odciążania natywnego i zdecydować, czy dostosować zapytanie, czy konfigurację.

Mechanizm rezerwowy

W niektórych przypadkach natywny silnik wykonawczy może nie być w stanie wykonać zapytania z takich powodów jak nieobsługiwane funkcje. W takich przypadkach operacja wraca do tradycyjnego silnika Spark. Ten automatyczny mechanizm zapasowy gwarantuje, że przepływ pracy nie będzie przerywany.

Zrzut ekranu przedstawiający mechanizm powrotu.

Zrzut ekranu przedstawiający sposób sprawdzania dzienników skojarzonych z mechanizmem rezerwowym.

Monitoruj zapytania i ramki danych wykonywane przez silnik

Aby lepiej zrozumieć, jak silnik natywnego wykonania jest stosowany do zapytań SQL i operacji na DataFrame'ach, a także aby szczegółowo zbadać poziomy etapów i operatorów, możesz skorzystać z Spark UI oraz Spark History Server, aby uzyskać bardziej szczegółowe informacje na temat wykonywania tego silnika.

Karta Silnik wykonywania natywnego

Możesz przejść do nowej karty "Gluten SQL / DataFrame", aby wyświetlić informacje o kompilacji Gluten i szczegóły wykonywania zapytań. Tabela Zapytania dostarcza informacji o liczbie węzłów uruchomionych na silniku natywnym i tych, które wracają do JVM dla każdego zapytania.

Zrzut ekranu przedstawiający kartę silnika wykonywania natywnego.

Wykres wykonywania zapytań

Możesz również wybrać opis zapytania dla wizualizacji planu wykonywania zapytań platformy Apache Spark. Wykres wykonywania zawiera natywne szczegóły wykonywania na różnych etapach i ich odpowiednich operacjach. Kolory tła odróżniają silniki wykonawcze: zielony reprezentuje Natywny Silnik Wykonawczy, a jasnoniebieski wskazuje, że operacja jest uruchomiona na domyślnej maszynie JVM.

Zrzut ekranu przedstawiający wykres wykonywania zapytania.

Ograniczenia

Chociaż natywny silnik wykonawczy (NEE) w Fabric znacząco zwiększa wydajność zadań Apache Spark, obecnie ma następujące ograniczenia. Kilka elementów związanych z poprawnością, które dotyczyły Runtime 1.3 (Apache Spark 3.5), jest rozwiązywanych w Runtime 2.0 (Apache Spark 4.1); Każdy element notuje czas działania, do którego się odnosi.

Istniejące ograniczenia

  • Niekompatybilne funkcje Spark (wszystkie runtime): Natywny silnik wykonawczy obecnie nie obsługuje strumieniowania strukturalnego. Jeśli korzystasz z nieobsługiwanych funkcji bezpośrednio lub przez importowane biblioteki, Spark wraca do domyślnego silnika. Natywny silnik wykonawczy obsługuje teraz Python UDF, UDF-y Scala oraz złożone typy danych (tablice, mapy, struktury). Aby uzyskać więcej informacji, zobacz funkcje UDF języka Python, funkcje UDF języka Scala i złożone typy danych w natywnym silniku wykonywania.

  • Nieobsługiwane formaty plików (wszystkie runtime): Natywny silnik wykonawczy nie przyspiesza zapytań względem JSON formatów i XML formatów. Te formaty domyślnie wracają do standardowego silnika Spark JVM do wykonania. Wektoryzowany parser CSV obsługuje teraz CSV.

  • Tryb ANSI (tylko Runtime 1.3): W Runtime 1.3 (Apache Spark 3.5) natywny silnik wykonawczy nie obsługuje trybu ANSI SQL. Jeśli włączysz tryb ANSI SQL, wykonanie wraca do silnika Spark z podstawowym systemem. W Runtime 2.0 (Apache Spark 4.1) obsługiwany jest tryb ANSI SQL: operatorzy przesuwają się do natywnego silnika, a semantyka błędów ANSI (np. dzielenie przez zero i nieprawidłowe casty) jest konsekwentnie wymuszana w JVM Spark.

  • Niedopasowania typów filtrów dat (wszystkie runtime): Aby skorzystać z przyspieszenia natywnego silnika wykonawczego, upewnij się, że obie strony porównania dat są zgodne pod względem typu danych. Na przykład, zamiast porównywać kolumnę DATETIME z literałem tekstowym, jawnie zrzutuj ją, jak pokazano:

    CAST(order_date AS DATE) = '2024-05-20'
    

Inne zagadnienia i ograniczenia

Note

Dziesiętne castowanie, strefa czasowa, round(), duplikat klucza orazcollect_set()/collect_list() elementy w tej sekcji dotyczą Runtime 1.3 (Apache Spark 3.5) i są rozwiązywane w Runtime 2.0 (Apache Spark 4.1).map() Są one zachowywane dla użytkowników nadal korzystających z Runtime 1.3.

  • Niedopasowanie castingu dziesiętnego do pływającego (Runtime 1.3; rozwiązane w Runtime 2.0): Podczas przelewania z DECIMAL do FLOAT, Spark zachowuje precyzję, konwertując na ciąg i analizując go. W Runtime 1.3 NEE (za pośrednictwem Velox) wykonuje bezpośrednie odlewanie z wewnętrznej reprezentacji int128_t , co może skutkować rozbieżnościami zaokrąglenia.

  • Błędy konfiguracji strefy czasowej (Runtime 1.3; rozwiązane w Runtime 2.0): W Runtime 1.3 ustawienie nierozpoznanej strefy czasowej w Spark powoduje niepowodzenie zadania w NEE, podczas gdy Spark JVM obsługuje to bez zgrań. Przykład:

    "spark.sql.session.timeZone": "-08:00"  // May cause failure under NEE on Runtime 1.3
    
  • Niespójne zachowanie zaokrągleń (Runtime 1.3; rozwiązane w Runtime 2.0): W Runtime 1.3 round() funkcja zachowuje się inaczej w NEE ze względu na poleganie na std::round, które nie odtwarza logiki zaokrągleń Spark. Ta różnica może prowadzić do niespójności liczbowych w wynikach zaokrągleń.

  • Brak funkcji sprawdzania map() duplikatów klucza (Runtime 1.3; rozwiązane w Runtime 2.0): Gdy spark.sql.mapKeyDedupPolicy jest ustawiony na EXCEPTION, Spark wyświetla błąd dotyczący duplikatów kluczy. W runtime 1.3 NEE pomija tę kontrolę i pozwala na błędne zakończenie zapytania. W Runtime 2.0 NEE podnosi DUPLICATED_MAP_KEY się konsekwentnie razem z JVM Spark.
    Przykład:

    SELECT map(1, 'a', 1, 'b'); -- Should fail with duplicate keys
    
  • Wariancja kolejności w przy collect_list() sortowaniu (Runtime 1.3; rozstrzygnięcie w Runtime 2.0): Gdy używamy DISTRIBUTE BY i SORT BY, Spark zachowuje kolejność elementów w collect_list(). W Runtime 1.3 NEE może zwracać wartości w innej kolejności z powodu różnic w tasowaniu, co może prowadzić do niezgodnych oczekiwań dotyczących logiki wrażliwej na kolejność.

  • Niedopasowanie typu pośredniego dla collect_list() / collect_set() (Runtime 1.3; rozwiązane w Runtime 2.0): W runtime 1.3 Spark używa BINARY jako pośredniego typu dla tych agregacji, natomiast NEE używa ARRAY. Ta niezgodność może prowadzić do problemów ze zgodnością podczas planowania lub wykonywania zapytań.

  • Zarządzane prywatne punkty końcowe wymagane do dostępu do pamięci masowej (wszystkie runtime): Gdy Native Execution Engine (NEE) jest włączony, a zadania spark próbują uzyskać dostęp do konta pamięci masowej za pomocą zarządzanego prywatnego endpointu, musisz skonfigurować oddzielne zarządzane prywatne endpointy zarówno dla Blob (blob.core.windows.net), jak i DFS / File System (dfs.core.windows.net), nawet jeśli wskazują na to samo konto pamięci. Nie możesz ponownie użyć jednego endpointa dla obu. To ograniczenie może wymagać dodatkowej konfiguracji sieci przy włączaniu natywnego silnika wykonawczego w przestrzeni roboczej, która zarządza prywatnymi punktami końcowymi do kont pamięci masowej.