Jak „rozgrzać” Entity Framework? Kiedy robi się „zimno”?

118

Nie, odpowiedzią na moje drugie pytanie nie jest zima.

Przedmowa:

Ostatnio dużo badałem Entity Framework i coś, co mnie niepokoi, to jego wydajność, gdy zapytania nie są rozgrzane, tak zwane zimne zapytania.

Zapoznałem się z artykułem dotyczącym wydajności dla Entity Framework 5.0. Autorzy przedstawili koncepcję zapytań Warm and Cold i ich różnice, co również zauważyłem, nie wiedząc o ich istnieniu. W tym miejscu chyba warto wspomnieć, że mam za plecami zaledwie pół roku doświadczenia.

Teraz wiem, jakie tematy mogę dodatkowo zbadać, jeśli chcę lepiej zrozumieć ramy pod kątem wydajności. Niestety większość informacji w Internecie jest nieaktualna lub nadęta z subiektywnością, stąd nie mogę znaleźć żadnych dodatkowych informacji na temat zapytań Warm vs Cold .

Zasadniczo zauważyłem do tej pory, że za każdym razem, gdy muszę ponownie skompilować lub odzyskać trafienia, moje początkowe zapytania stają się bardzo wolne. Każdy kolejny odczyt danych jest szybki ( subiektywny ), zgodnie z oczekiwaniami.

Będziemy migrować do Windows Server 2012, IIS8 i SQL Server 2012 i jako Junior faktycznie zyskałem możliwość przetestowania ich przed resztą. Bardzo się cieszę, że wprowadzili moduł rozgrzewający, który przygotuje moją aplikację na to pierwsze żądanie. Jednak nie jestem pewien, jak kontynuować rozgrzewanie mojego Entity Framework.

Co już wiem, warto zrobić:

  • Wygeneruj moje widoki z wyprzedzeniem, zgodnie z sugestią.
  • W końcu przenieś moje modele do oddzielnego zespołu.

To, co uważam za zrobienie, kierując się zdrowym rozsądkiem, prawdopodobnie jest złym podejściem :

  • Wykonywanie fikcyjnych odczytów danych podczas uruchamiania aplikacji w celu rozgrzania, wygenerowania i zweryfikowania modeli.

Pytania:

  • Jakie byłoby najlepsze podejście do zapewnienia wysokiej dostępności w mojej Entity Framework w dowolnym momencie?
  • W jakich przypadkach Entity Framework znów się „stygnie”? (Rekompilacja, recykling, ponowne uruchomienie usług IIS itp.)
Piotr
źródło
Dowiedz się, czy jest to generowanie widoku lub kompilacja zapytań, która uderza Cię najbardziej. Jeśli jest to gen widoku, użyj widoków prekompilowanych. Jeśli to są zapytania - czy masz dużą skomplikowaną hierarchię? Zwróć uwagę, że drogie rzeczy zwykle zdarzają się raz na domenę aplikacji i są zapisywane w pamięci podręcznej, dlatego pojawiają się tego rodzaju problemy, gdy domena aplikacji jest rozładowywana i tworzona jest nowa.
Paweł
Wspomniałem już o generowaniu widoków @Pawel, hierarchia nie jest skomplikowana, ani trochę. Ale problem jest również zasadniczy. Zgodnie z tym, co powiedziałeś, zbadam, kiedy domena aplikacji jest rozładowywana. Jednak to nadal nie pomaga w innym problemie, który rozgrzewa Entity Framework w przypadku, jak powiedziałeś, domena aplikacji zostanie zwolniona. W tym momencie wydaje się, że domena aplikacji jest wyładowywana bardziej niż powinna i nie jestem pewien dlaczego, recykling odbywa się tylko w nocy, bieg jałowy jest ustawiony na 0.
Peter
4
Jak myślisz, dlaczego wykonywanie fikcyjnych odczytów danych jest złym podejściem?
Josh Heitzman
5
Po prostu nie czuję się dobrze, pomyślałem, że może być coś bardziej eleganckiego, czego nie jestem świadomy. Ale jeśli to jedyne rozwiązanie i ktoś z dobrą wiedzą może potwierdzić, że nie ma innego sposobu, po prostu się na to zdecyduję.
Peter
1
Jednym z problemów, które napotkałem podczas zamykania puli aplikacji po pewnym okresie braku aktywności (z powodu małego ruchu), jest utworzenie usługi, która wysyła żądanie w ustalonych odstępach czasu do jednej z Twoich stron. Zapobiega to długiemu opóźnieniu przed ponownym uruchomieniem puli aplikacji przy pierwszym żądaniu. Możesz też skorzystać z bezpłatnej usługi, takiej jak www.pingalive.com, aby wysłać ping do domeny / adresu IP. Pomaga to również zapobiegać wyczyszczeniu buforowanych obiektów przed ich wygaśnięciem.
hatsrumandcode

Odpowiedzi:

55
  • Jakie byłoby najlepsze podejście do zapewnienia wysokiej dostępności w mojej Entity Framework w dowolnym momencie?

Możesz wybrać połączenie wstępnie wygenerowanych widoków i statycznych skompilowanych zapytań.

Statyczne CompiledQuerys są dobre, ponieważ są szybkie i łatwe do napisania i pomagają zwiększyć wydajność. Jednak w przypadku EF5 nie jest konieczne kompilowanie wszystkich zapytań, ponieważ EF sam skompiluje zapytania. Jedynym problemem jest to, że te zapytania mogą zostać utracone, gdy pamięć podręczna zostanie wyczyszczona. Dlatego nadal chcesz przechowywać odwołania do własnych skompilowanych zapytań dla tych, które występują bardzo rzadko, ale są drogie. Jeśli umieścisz te zapytania w klasach statycznych, zostaną one skompilowane, gdy będą wymagane. W przypadku niektórych zapytań może być za późno, dlatego warto wymusić kompilację tych zapytań podczas uruchamiania aplikacji.

Inną możliwością, o której wspomniałeś, jest pregenerowanie widoków. Szczególnie w przypadku zapytań, których kompilacja zajmuje bardzo dużo czasu i które się nie zmieniają. W ten sposób przenosisz narzut wydajności z czasu wykonywania na czas kompilacji. Nie spowoduje to również żadnego opóźnienia. Ale oczywiście ta zmiana przechodzi do bazy danych, więc nie jest to łatwe. Kod jest bardziej elastyczny.

Nie używaj dużo dziedziczenia TPT (jest to ogólny problem z wydajnością w EF). Nie buduj swojej hierarchii dziedziczenia zbyt głębokiej ani zbyt szerokiej. Tylko 2-3 właściwości specyficzne dla niektórych klas mogą nie wystarczyć, aby wymagać własnego typu, ale mogą być obsługiwane jako właściwości opcjonalne (dopuszczające wartość null) dla istniejącego typu.

Nie trzymaj się jednego kontekstu przez długi czas. Każda instancja kontekstu ma własną pamięć podręczną pierwszego poziomu, która spowalnia wydajność, gdy rośnie. Tworzenie kontekstu jest tanie, ale zarządzanie stanem wewnątrz buforowanych jednostek kontekstu może stać się kosztowne. Inne pamięci podręczne (plan kwerend i metadane) są współdzielone między kontekstami i znikną wraz z domeną AppDomain.

Podsumowując, należy często alokować konteksty i używać ich tylko przez krótki czas, aby można było szybko uruchomić aplikację, kompilować rzadko używane zapytania i udostępniać wstępnie wygenerowane widoki dla zapytań, które są krytyczne dla wydajności i często używane.

  • W jakich przypadkach Entity Framework znów się „stygnie”? (Rekompilacja, recykling, ponowne uruchomienie usług IIS itp.)

Zasadniczo za każdym razem, gdy tracisz AppDomain. Usługi IIS są uruchamiane ponownie co 29 godzin , więc nigdy nie możesz zagwarantować, że będziesz mieć swoje wystąpienia w pobliżu. Również po pewnym czasie braku aktywności AppDomain jest wyłączany. Powinieneś spróbować szybko podnieść się. Może możesz wykonać część inicjalizacji asynchronicznie (ale uważaj na problemy z wielowątkowością). Możesz używać zaplanowanych zadań, które wywołują fałszywe strony w aplikacji w czasie, gdy nie ma żądań, aby zapobiec śmierci AppDomain, ale w końcu tak się stanie.

Zakładam również, że gdy zmienisz plik konfiguracyjny lub zmienisz zestawy, nastąpi ponowne uruchomienie.

Andreas
źródło
Dziękuję Andre, tego potrzebowałem.
Peter
@Andreas Właściwie nawet przy statycznych skompilowanych zapytaniach pierwsze uruchomienie jest zbyt długie. Czy jest jakiś sposób, aby je rozgrzać, oprócz: wykonywania fikcyjnych odczytów danych podczas uruchamiania aplikacji w celu rozgrzania, wygenerowania i zweryfikowania modeli.
manishKungwani,
@Andreas Więc Entity framework5 potrzebuje tego czy nie? co się zmieni, jeśli użyjesz go na ef5 (mam na myśli wciąż powolny lub mały
pałka,
„Statyczne zapytania CompiledQuery są dobre, ponieważ są szybkie i łatwe do napisania oraz pomagają zmniejszyć wydajność”. Zmniejszona wydajność?
Mathemats
9

Jeśli szukasz maksymalnej wydajności we wszystkich wywołaniach, powinieneś dokładnie rozważyć swoją architekturę. Na przykład sensowne może być wstępne buforowanie często używanych wyszukiwań w pamięci RAM serwera podczas ładowania aplikacji zamiast używania wywołań bazy danych przy każdym żądaniu. Ta technika zapewni minimalne czasy odpowiedzi aplikacji w przypadku powszechnie używanych danych. Musisz jednak mieć pewność, że masz dobrze działające zasady wygasania lub zawsze czyść pamięć podręczną po wprowadzeniu zmian, które mają wpływ na dane w pamięci podręcznej, aby uniknąć problemów ze współbieżnością.

Ogólnie rzecz biorąc, należy dążyć do projektowania rozproszonych architektur tak, aby wymagały żądań danych opartych na we / wy tylko wtedy, gdy informacje przechowywane lokalnie w pamięci podręcznej stają się nieaktualne lub muszą być transakcyjne. Każde żądanie danych „over the wire” trwa zwykle 10–1000 razy dłużej niż pobieranie danych lokalnych w pamięci podręcznej. Już sam ten fakt sprawia, że ​​dyskusje na temat „danych zimnych i ciepłych” są nieistotne w porównaniu z kwestią danych „lokalnych i zdalnych”.

mcstar
źródło
Jest to dobry punkt, który często ignoruję, gdy jestem podekscytowany surową wydajnością struktury encji. Przyjrzę się temu dokładniej i zbadam zasady buforowania. Jednak „zimno kontra ciepło” w odniesieniu do EF jest nadal czymś, co chcę lepiej zrozumieć.
Peter
2
„Już sam ten fakt sprawia, że ​​dyskusje na temat„ danych zimnych i ciepłych ”są nieistotne w porównaniu z kwestią danych„ lokalnych i zdalnych ”. Nie całkiem. Jeśli nie masz go w pamięci podręcznej lokalnie (czego początkowo nie zrobisz), nadal będziesz musiał nacisnąć EF i cierpieć z powodu bólu inicjalizacji, aby przygotować pamięć podręczną. W tych samych miejscach, w których pamięć podręczna jest niezainicjalizowana, EF będzie niezainicjowany. Więc dodanie warstwy buforowania może nie pomóc, jeśli jedynym problemem jest czas inicjalizacji EF, ale doda kolejną warstwę złożoności ...
MikeJansen
8

Ogólne wskazówki.

  • Wykonuj rygorystyczne rejestrowanie, w tym informacje o tym, do czego uzyskano dostęp i czas żądania .
  • Wykonuj fałszywe żądania podczas inicjowania aplikacji w celu wykonania gorącego rozruchu bardzo powolne żądania , które zostały odebrane z poprzedniego kroku.
  • Nie przejmuj się optymalizacją, chyba że jest to prawdziwy problem, komunikuj się z konsumentem aplikacji i pytaj. Poczuj się komfortowo, mając ciągłą pętlę sprzężenia zwrotnego, jeśli tylko chcesz dowiedzieć się, co wymaga optymalizacji .

Teraz wyjaśnij, dlaczego fałszywe żądania nie są złym podejściem .

  • Mniejsza złożoność - Rozgrzewasz aplikację w sposób, który będzie działał niezależnie od zmian w frameworku i nie musisz wymyślać prawdopodobnie funky API / frameworków, aby to zrobić we właściwy sposób .
  • Większy zasięg - rozgrzewasz jednocześnie wszystkie warstwy buforowania związane z wolnym żądaniem.

Wyjaśnienie, kiedy pamięć podręczna staje się „zimna”.

Dzieje się tak na każdej warstwie twojego frameworka, która stosuje pamięć podręczną. Dobry opis znajduje się na górze strony wydajności .

  • Kiedy kiedykolwiek pamięć podręczna musi zostać zweryfikowana po potencjalnej zmianie, która powoduje, że pamięć podręczna jest przestarzała, może to być przekroczenie limitu czasu lub bardziej inteligentne (tj. Zmiana w pozycji w pamięci podręcznej).
  • Kiedy element pamięci podręcznej jest eksmitowany, algorytm służący do tego jest opisany w sekcji „Algorytm eksmisji z pamięci podręcznej” w artykule dotyczącym wydajności, do którego został odsyłany , ale w skrócie.
    • LFRU (Najrzadziej - ostatnio używana) pamięć podręczna licznika trafień i wieku z limitem 800 elementów.

Inne rzeczy, o których wspomniałeś, w szczególności ponowna kompilacja i ponowne uruchomienie usług IIS, powodują wyczyszczenie części lub wszystkich pamięci podręcznych.

udoprog
źródło
To kolejna pomocna odpowiedź, bardzo ceniona.
Peter
3

Jak już powiedziałeś, użyj „wstępnie wygenerowanych widoków”, to naprawdę wszystko, co musisz zrobić.

Wyodrębniono z linku : „Kiedy generowane są widoki, są one również weryfikowane. Z punktu widzenia wydajności ogromna większość kosztów generowania widoku to w rzeczywistości walidacja widoków”

Oznacza to, że podczas budowania złożenia modelu nastąpi spadek wydajności. Twój obiekt kontekstu pominie wtedy „zimne zapytanie” i pozostanie responsywny przez czas trwania cyklu życia obiektu kontekstu, jak również przez kolejne nowe konteksty obiektu.

Wykonywanie nieistotnych zapytań nie będzie służyło żadnym innym celom poza zużywaniem zasobów systemowych.

Skrót ...

  1. Pomiń całą dodatkową pracę związaną z wstępnie wygenerowanymi widokami
  2. Utwórz kontekst obiektu
  3. Odpal to słodkie, nieistotne pytanie
  4. Następnie po prostu zachowaj odniesienie do kontekstu obiektu na czas trwania procesu (niezalecane).
hotpie
źródło
2

Nie mam doświadczenia w tych ramach. Ale w innych kontekstach, np. W Solr, całkowicie fałszywe odczyty nie będą zbyt użyteczne, chyba że możesz buforować całą bazę danych (lub indeks).

Lepszym podejściem byłoby rejestrowanie zapytań, wyodrębnianie najczęstszych z dzienników i używanie ich do rozgrzewki. Tylko pamiętaj, aby nie rejestrować zapytań rozgrzewkowych ani nie usuwać ich z dzienników przed kontynuowaniem.

estani
źródło