Czy JEE Java Web Application z EclipseLink jest dużo szybsze od ASP.NET MVC z EF (testy)

0

Przeprowadziłem testy porównawcze dwóch internetowych aplikacji bazodanowych. Aplikacji JEE z EclipseLink i ASP.NET z EntityFramework ( aplikacja składa się z modułu Web MVC i trzech modułów bibliotecznych języka C#, odpowiednio danych z modelem encji, repozytoriów i service zawierające klasy obsługi biznesowej).

Obie tworzą dokument PZ przyjęcia towaru do magazynu. By sprawdzić wydajność przeprowadziłem testy. Testy przeprowadziłem w trzech bazach danych.

Test był testem w którym wyszukiwane były pojedynczo rekordy 4 tabel bazy danych. Encja Magazyny 10 rekordów, encja Dostawcy 1000 rekordów, encja Towary 1000 rekordów, encja Naglowki_Pz 1000 rekordów. Rekordy encji były wyszukiwane według klucza głównego (była nim liczba od 1 do np. 1000) . Test miał na celu sprawdzić szybkość wyszukania pojedynczych danych. Czas podany w ms.

................................Ap. JEE.......Ap. ASP.NET...czas o (%)
PostgreSQL 10..................4907.......42976............776

MS SQL Server 2017.........3198.......37978..........1088

Oracle Database 12c.........3750.......32022............754

Ponieważ wynik był szokujący przeprowadziłem testy uzupełniające tym razem w połączeniu z bazą Oracle Database, zmniejszyłem liczbę rekordów.

Test uzupełniający pierwszy polegał na wyszukaniu 100 rekordów tabeli Towary.

Wynik osiągnięty przez aplikację JEE w połączeniu z bazą Oracle Database wyniósł : 1516 ms

Wynik osiągnięty przez aplikację ASP.NET w połączeniu z bazą Oracle Database wyniósł: 2647 ms.

Aplikacja JEE była szybsza od aplikacji ASP.NET o 75 % przy wyszukiwaniu rekordów encji.

Test uzupełniający drugi, polegał na dodaniu 100 nagłówków dokumentu PZ, bez procesu wyszukiwania dostawcy i magazynu, których rekordy zostały wyszukane przed rozpoczęciem pomiaru czasu, wszystkie 100 dokumentów zostało wystawionych w tym samym magazynie, dla tego samego dostawcy.

Wynik osiągnięty przez aplikację JEE w połączeniu z bazą Oracle Database wyniósł: 193 ms

Wynik osiągnięty przez aplikację ASP.NET w połączeniu z bazą Oracle Database wyniósł: 346 ms.

Aplikacja JEE była szybsza od aplikacji ASP.NET o 79 % przy dodawaniu nowych rekordów encji.

Czy spotkaliście się z taką różnicą ?

0
  1. Nie ma sensu testowanie jednokrotnego wywoływania operacji, robi się np. kilkaset prób i liczy średnią.
  2. Testuje się po uruchomieniu aplikacji i wywołaniu kodu, który ma być testowany, aby nie wliczać do czasu pomiaru kompilacji JIT.
  3. Jaką mamy gwarancję, że kod jest poprawny?
  4. Czemu pytasz o to samo drugi raz?
0
somekind napisał(a):
  1. Nie ma sensu testowanie jednokrotnego wywoływania operacji, robi się np. kilkaset prób i liczy średnią.
  2. Testuje się po uruchomieniu aplikacji i wywołaniu kodu, który ma być testowany, aby nie wliczać do czasu pomiaru kompilacji JIT.
  3. Jaką mamy gwarancję, że kod jest poprawny?
  4. Czemu pytasz o to samo drugi raz? Co jest szybsze ASP.NET MVC z EF 6 czy JAVA WEB APPLICATION i JPA

Testowałem po wdrożeniu aplikacji odpowiednio na GlassFish i IIS. Test był wywoływany po uruchomieniu aplikacji z menu aplikacji. Pomiar czasu obejmował tylko instrukcje odczytu.
To są wyniki.

To dotyczyło tworzenia to odczyt.

1

Nie ma sensu ten test.

  • Jakie parametry ma HW użyty do testów
  • Jak wygląda konfiguracja użytych komponentów
  • Jak rozkłada się czas odpowiedzi na poszczególne warstwy, aplikacja + ORM + baza.
  • Jak wygląda rozkład czasów odpowiedzi ? (7 zapytań w czasie <50ms, 15 zapytań w czasie < 100ms, .... itd).
  • Jak wygląda utylizacja zasobów podczas testów
  • Jak zmieniają się czasy odpowiedzi przy wzroście obciążenia

I masa innych pytań. Szkoda Twojego czasu na mierzenie czasu odpowiedzi, bo nic z tego nie wynika .

0

Pytałem czy dostrzegliście takie różnice wydajności lub podobne w waszej pracy, to działanie aplikacji od strony końcowego użytkownika w pewnym sensie. I użytkownicy muszą widzieć różnicę w szybkości wyraźną, w swoich aplikacjach zrobionych na obie platformy.

0

No ja nie widziałem, bo nie tworzę softu na dwie konkurencyjne platformy. I generalnie nikt nie rozwija równolegle dwóch wersji tej samej aplikacji na róznych platformach, więc użytkownicy też nie mają szans tego zobaczyć.
W każdym razie, rozbieżności w Twoich wynikach każą sądzić, że coś jest nie tak z architekturą, kodem albo testami. Nie udowodnisz większej wydajności jednej wersji nad drugą bez pokazania kodu.

0

Test inny obejmował wczytanie 4 list, wszystkich wierszy wybranych tabel : Magazyny, Dostawcy, Towary, Naglowki_Pz.

To było bardzo ciekawe biblioteki Oracle zdziałały cuda ?

...............................Ap. JEE.......Ap. ASP.NET...czas o (%)
PostgreSQL 10..................1969.......3373...............71

MS SQL Server 2017.........1474.......2488...............69

Oracle Database 12c.........2541........2734..............7,6

1

Trudno porównać jedną aplikację na różnych platformach, a co dopiero różne aplikacje na różnych platformach :-)

Zobaczy prosty przykład, czysta analityka, bez uruchamiana jakiejkolwiek appki. (Jak temat Cię interesuję to polecam lekturę książek Neila Gunthera).

Czas odpowiedzi można modelować tak:

ResponseTime = WaitTime + ServiceTime * 1/(1-Utilization)

WaitTime - to tyle trzeba czekać w kolejce do okienka na poczcie (kolejce do dysku, kolejce do puli wątków, ... )
ServiceTime - tyle średnio trwa obsługa interesanta (lub jak wolisz zapytania)
Utilization - tak bardzo są zajęte zasoby realizujące usługę

Teraz jak robisz sobie testy odczytów i nie mówisz nic na temat utylizacji maszyny, to prosty przykłady:

  • średnio odczyt trwa 50ms
  • Twoja appka czeka, aż dysk zrealizuje operację odczytu (dyski mają takie kolejki requestów, czasem kolejka sięga do drzwi i trzeba poczekać na zewnątrz)
  • maszynka na której rezyduje Twoja appka jest używana przez coś innego i utylizacja zmienia się w czasie

Przykład1) maszyna nic nie robi - utylizacja 0%

ResponseTime = 10 + 50* 1/(1-0) = 60 (ms)

Przykład2) maszyna zajęta w 50%
ResponseTime = 10 + 50*(1-0.5) = 110 (ms)

Przykład3) maszyna zajęta w 75%
ResponseTime = 10 + 50*(1-0.75) = 210 (ms)

Przykład4) maszynka zajęta w 100%
...

Jak widzisz czasy odpowiedzi appki zmieniają się drastycznie i jeśli patrzysz tylko na czasy, to wyniki będą bez sensu i nie trzeba tu nic uruchamiać by się o tym przekonać.

2

Wrzuć pełny kod zarówno c# i javy, to aż z ciekawości wrzucę na azura i zobaczymy jakie będę wyniki ;).

0

dysk SSD, maszyna z Windows 10 Education na Oracle Linux 7 z VMware Workstation Player for Linux

po każdym teście restart całej maszyny, każdy test trzy razy wykonany dla każdej bazy

0

To testy ASP.NET puszczałeś na wirtualce, a Javy na gołym sprzęcie?

0
somekind napisał(a):

To testy ASP.NET puszczałeś na wirtualce, a Javy na gołym sprzęcie?

Wszystkie testy na maszynie pod Windowsem który restartowałem po każdym teście bez względu na aplikację.

0

Jeżeli ktoś z Was programuje w obu platformach nie dostrzegł tej różnicy ?

0

aplikacja to wersja wcześniejsza ASP.NET MVC 5

czyli nie jest to ASP.NET Core

0
Pawel412 napisał(a):

Wszystkie testy na maszynie pod Windowsem który restartowałem po każdym teście bez względu na aplikację.

Czyli zarówno aplikacja w ASP.NET jak i Javie pracowała na Windowsie, tak?
A po restarcie uruchamiałeś aplikację i wykonywałeś operację, a potem dopiero puszczałeś testy?
Jakiego softu używałeś do testów? JMeter?

0
somekind napisał(a):
Pawel412 napisał(a):

Wszystkie testy na maszynie pod Windowsem który restartowałem po każdym teście bez względu na aplikację.

Czyli zarówno aplikacja w ASP.NET jak i Javie pracowała na Windowsie, tak?
A po restarcie uruchamiałeś aplikację i wykonywałeś operację, a potem dopiero puszczałeś testy?
Jakiego softu używałeś do testów? JMeter?

Tak obie pod Windows dla Javy startowałem dodatkowo GlassFish, potem otwierałem FireFox, uruchamiałem aplikacje i z menu wybierałem test i uruchamiałem go, pomiar czasu był w kodzie a wynik zapisywany był w bazie danych w tabeli

0
Pawel412 napisał(a):
somekind napisał(a):
Pawel412 napisał(a):

Wszystkie testy na maszynie pod Windowsem który restartowałem po każdym teście bez względu na aplikację.

Czyli zarówno aplikacja w ASP.NET jak i Javie pracowała na Windowsie, tak?
A po restarcie uruchamiałeś aplikację i wykonywałeś operację, a potem dopiero puszczałeś testy?
Jakiego softu używałeś do testów? JMeter?

Tak obie pod Windows dla Javy startowałem dodatkowo GlassFish, potem otwierałem FireFox, uruchamiałem aplikacje i z menu wybierałem test i uruchamiałem go, pomiar czasu był w kodzie a wynik zapisywany był w bazie danych w tabeli

Test list kod jest roboczy i nazwy niestety też ASP.NET

public void TestWczytajListy()
    {

        HurtowniaData.HurtowniaEntities.daneContext Context = new daneContext();

        NaglowkiDokumentowPZObslugaDanych mNaglowkiDokumentowPZObsluga = new NaglowkiDokumentowPZObslugaDanych(Context);
        ObslugaDanych<MAGAZYNY> mObslugaMagazynow = new ObslugaDanych<MAGAZYNY>(Context);
        ObslugaDanych<DOSTAWCY> mObslugaDostawcow = new ObslugaDanych<DOSTAWCY>(Context);

        ObslugaDanych<TOWARY> mObslugaTowarow = new ObslugaDanych<TOWARY>(Context);

        ObslugaDanych<TESTY> TestyFacade = new ObslugaDanych<TESTY>(Context);



        System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch();
        watch.Start();

        List<MAGAZYNY> magazynyLista = mObslugaMagazynow.getListeWierszy();
        List<DOSTAWCY> dostawcyLista = mObslugaDostawcow.getListeWierszy();
        List<TOWARY> towaryLista = mObslugaTowarow.getListeWierszy();
        List<NAGLOWKI_PZ> naglowkiPzLista = mNaglowkiDokumentowPZObsluga.getListeWierszy();




        watch.Stop();
        TESTY test = new TESTY();
        test.TYP_TESTU = "CZYT_LISTY_ENCJI_NET";
        test.CZAS = watch.ElapsedMilliseconds;
        test.CZAS_TAKTOWANIE = watch.ElapsedTicks;
        TestyFacade.dodajWiersz(test);
        TestyFacade.zapiszZmiany();

    }

0

JEE ten sam test

 public void testWczytajListy() {

        long start = System.currentTimeMillis();

        List<Magazyny> magazynyLista = MagazynyFacade.findAll();
        List<Dostawcy> dostawcyLista = DostawcyFacade.findAll();
        List<Towary> towaryLista = TowaryFacade.findAll();
        List<NaglowkiPz> naglowkiPzLista = NaglowkiDokumentowPZFacade.findAll();

        long stop = System.currentTimeMillis();

        TestyObsluga.dodajNowyTest("CZYT_LISTY_ENCJI", BigDecimal.valueOf(stop - start));

    }
0

No, ale nadal nie wiemy jak wygląda ObslugaDanych, w szczególności getListeWierszy().

0
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data.Entity;
using System.Linq.Expressions;
using HurtowniaData.HurtowniaEntities;
using System.Data.Entity.Migrations;


namespace HurtowniaRepositories
{
    public class ObslugaDanych<TEncja> : IObslugaDanych<TEncja> where TEncja : class

    {
        protected DbContext Context;

        public ObslugaDanych(DbContext context)
        {
            Context = context;
        }

        public TEncja getWiersz(decimal id)
        {
            return Context.Set<TEncja>().Find(id);
        }


        public TEncja getWierszWedlugWarunku(Expression<Func<TEncja, bool>> predicate)
        {
            return Context.Set<TEncja>().Where(predicate).FirstOrDefault();
        }

        public List<TEncja> getListeWierszy()
        {
            return Context.Set<TEncja>().ToList();
        }

        public List<TEncja> getWierszeWedlugWarunku(Expression<Func<TEncja, bool>> predicate)
        {
            return Context.Set<TEncja>().Where(predicate).ToList();
        }

        public List<TEncja> getWierszeWedlugWarunkuPosortowane(Expression<Func<TEncja, bool>> predicate, Expression<Func<TEncja, object>> predicate2)
        {
            return Context.Set<TEncja>().Where(predicate).OrderBy(predicate2).ToList();
        }

        public void dodajWiersz(TEncja entity)
        {
            Context.Set<TEncja>().Add(entity);
        }

        public TEncja dodajWierszIZwroc(TEncja entity)
        {
            Context.Set<TEncja>().Add(entity);
            Context.SaveChanges();
            return entity;
        }

        public void dodajWiersze(IEnumerable<TEncja> entities)
        {
            Context.Set<TEncja>().AddRange(entities);
        }


        public void edytujWiersz(TEncja entity)
        {
            Context.Set<TEncja>().AddOrUpdate(entity);
        }

        public void usunWiersz(TEncja entity)
        {
            Context.Set<TEncja>().Remove(entity);
        }
        public void usunWiersze(IEnumerable<TEncja> entities)
        {
            Context.Set<TEncja>().RemoveRange(entities);
        }

        public void zwolnijContext()
        {
            Context.Dispose();
        }

        public void zapiszZmiany()
        {
            Context.SaveChanges();
        }
    }
}

0
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using System.Data.Entity;

namespace HurtowniaData.HurtowniaEntities
{
    public class daneContext : DbContext
    {

        public daneContext()
           : base("name=Entities")
        {
         //  this.Configuration.LazyLoadingEnabled = false;
        }
        public DbSet<DOSTAWCY> Dostawcy { get; set; }
        public DbSet<KLIENCI> Klienci { get; set; }
        public DbSet<MAGAZYNY> Magazyny { get; set; }
        public DbSet<NAGLOWKI_MM> Naglowki_Mm { get; set; }
        public DbSet<NAGLOWKI_PZ> Naglowki_Pz { get; set; }
        public DbSet<NAGLOWKI_WZ> Naglowki_Wz { get; set; }
        public DbSet<POZYCJE_MM> Pozycje_Mm { get; set; }
        public DbSet<POZYCJE_PZ> Pozycje_Pz { get; set; }
        public DbSet<POZYCJE_WZ> Pozycje_Wz { get; set; }
        public DbSet<STANY> Stany { get; set; }
        public DbSet<TOWARY> Towary { get; set; }
        public DbSet<TESTY> Testy { get; set; }

    }
}

aplikacja JEE ustawione w encjach na LAZY
0

W przypadku

  1. Ten microbenchmark to trochę katastrofa. Nic sensownego nie mierzy. Nie bierze pod uwage cache, rozgrzewania jvm, ani potencjalnego escape analysis. Nie ma też kyszytyny sensu biznesowego i nie jest podobny do typowych aplikacji biznesowych. Tak jakbyś mierzył przydatność samochodów ciężarowych do przewozu materiałów budowlanych, puszczając je na 5 okrążeń, bez paki, na tor formuły 1.
  2. JEE???( to się już od dawna tak nie nazywa - Java EE, teraz Jakarta EE ) to stara, nudna platforma. Od dawna jej nie używam (jeśli nie muszę), bo jest strasznie upierdliwa i powolna w developmencie i zbyt błędogenna w użyciu. Testowanie dużo gorsze niż w Spring (a Spring wcale nie jest fajny). Na produkcjach aplikacje Java EE na ogół nie powalają wydajnością, ale dramatu zwykle nie ma.
    Edit
  3. Strzelam, że twój test może być kompletnie zafałszowany przez paging i lazy loading na listach. Może porównujesz ile czasu jee wczytuje pierwsze 20 rekordów, vs wszystkie 100 on .Net. Kij wie, to zależy od wielu parmetrów.
  4. Gdzie się tak spieszysz?

(To kyszytyny to zamierzone, sorry).8

0

rozumiem pewnie słuszne uwagi jednak czytałem w testach pojedyncze encje i wartości z nich i podobne wyniki odczytu to pewność że jednak odczytał je

lazy ustawiłem w encjach aplikacji JEE bo EclipseLink ma eager standardowo ustawione

pomijając to

pytanie do programistów czy dostrzegli różnicę bo moim zdaniem jest wyraźna w wydajności przy przetwarzaniu większej liczby rekordów encji ?

1

Jak chcesz żeby ktoś to sprawdził (o ile w ogóle komuś będzie się chciało) to umieść gdzieś gotową aplikację (fragment na którym testowałeś), która działa i można ją uruchomić, żeby zweryfikować co się dzieje, że różnica to jest aż 10x...

0

ja się nie upieram przy swoim teście przy małej ilości danych jest to różnica około 70 % procent taka różnica występuję między narzędziami ORM w różnych testach np. dla platformy .NET

jednak czy ktoś może zauważył że wydajność spada wraz wzrostem liczby przetwarzanych rekordów w swoich aplikacjach ASP.NET

3
Pawel412 napisał(a):

pytanie do programistów czy dostrzegli różnicę bo moim zdaniem jest wyraźna w wydajności przy przetwarzaniu większej liczby rekordów encji ?

Nie wiadomo co mierzysz, nadal.
Między dwoma aplikacjami Java EE , robiącymi dokładnie to samo biznesowo, mogą być różnice 20krotne w wydajnośći. To wręcz normalka, jak usuniesz typową zwałkę na produkcji.

Wystaw pełny kod obu testów na githubie czy gdzieś. Razem z danymi do bazy danych.
Wtedy np. będę Ci mógł powiedzieć dlaczego twój test części Java EE jest bez sensu i co dokładnie on mierzy, dlaczego jest nierealistycznie wolny (strzelam, że jest). Pewnie to samo, będą mogli zrobić koledzy z .NET.
Dyskutowanie z benchmarkami, których nie możemy odtworzyć i sprawdzić, jest zupełnie pozbawione sensu.

Edit:
Dawno temu była dokładnie odwrotna akcja.
Chłopaki zwiazani z MS zrobili w .NET aplikację Pet store i wyszło im, że są prawie 30 razy szybsi od wersji Java EE, a do tego mają mniej linii kodu:)
Było wielki oburzenie wśród javowców ( obraza majestatu).
Nie chce mi się teraz przez to przebijać, bo jest za dużo śmiecia w temacie, ale mniej więcej chodziło, że java ee petstore był typowo enterprise odjechanym przykładem kodu z ilomaś warstwami i architekturą na przyszłość/ na wypasie/ na pewno jeszcze jedna warstwa się przyda/ czy mamy już AbstractFafctoryBuilderImpl?. .NETowcy pojechali po bandzie, procedury składowane, kod w stylu raczej YAGNI (to nie jest zarzut, wręcz przeciwnie). Benchmark był z pewnością nie fair, porównywanie się z refernce implementacją przykładową było zagraniem poniżej pasa, ale też sprowokowało dyskusje w JavaEE... czy my naprawdę musimy to wszystko tak rozdmuchiwać?. To pomogło IMO Springowi wypłynąć.
Tu jakiś fragment z tej wojenki:
https://www.techrepublic.com/article/creator-of-net-pet-shop-defends-implementation/

2

Tutaj są bardziej wiarygodne testy: https://www.techempower.com/benchmarks/#section=data-r16&hw=ph&test=query
Można porównać "aspcore-mvc-ef-pg" vs "wildfly-ee7"
Oba działają na ORMach.

Mimo wszystko "bardziej wiarygodne" test w tym przypadku to dalej niewiele znacząca metryka, bo w 95%+ korpo-krów biznesowych problemem będą prozaiczne rzeczy typu mocno nieoptymalne zapytania bazodanowe (bądź problem N+1 zapytań), niepotrzebne przepychanie danych po HTTP w różne strony, obciążanie garbage collectora przez produkowanie masy śmiecia i/ lub wycieki pamięci, niepotrzebnie wysoka złożoność obliczeniowa, itp itd

Ważniejsze od tego co można osiągnąć w nierealistycznym benchmarku są zwykle promowane przez framework lub jego społeczność rozwiązania. Dla przykładu, jeśli w danym frameworku bardzo łatwo jest osiągnąć wiele rzeczy przy jednoczesnym rozepchaniu sesji użytkownika do rozmiaru wielu megabajtów, a trudno jest robić te rzeczy bez rozpychania sesji, to taki framework jest o kant tyłka rozbić. Ciężka sesja użytkownika ogranicza skalowanie aplikacji - jeśli zaloguje się wielu użytkowników naraz, a każdy będzie miał wielomegabajtową sesję na serwerze to pamięć na serwerze szybko się skończy, a garbage collector będzie szalał i zjadał cenne cykle procesora.

  • przez sesję użytkownika mam na myśli także pamięć zajmowaną przez ORMa, serializery (JSON, XML, itd) i inne zajmujące RAM procesy potrzebne do obsługi żądań konkretnego użytkownika
0

rozumiem jest tu tak dużo możliwości że porównanie jest możliwe tylko w przypadku działających gotowych aplikacji i to razem z ich konfiguracją i środowiskiem

jednak jest rzeczywistość tylko czy ktoś ją ocenił

1 użytkowników online, w tym zalogowanych: 0, gości: 1