ASP.NET MVC, kontrolery a sesje: test wydajności

W ostatnim wpisie wyjaśniłem jak bardzo sesja wpływa na wydajność i skalowalność aplikacji. Dzisiaj chciałbym pokazać przykład i konkretne liczby, które pozwolą nam oszacować skalę problemu.

Zacznijmy od ASP.NET MVC. Stworzymy trzy kontrolery:

  1. SessionlessCotroller – kontroler będzie miał zablokowaną sesję.
  2. SessionController – kontroler zapisuje dane do sesji.
  3. SessionReadOnlyController – kontroler ma dostęp tylko do odczytu.

Kod:

[SessionState(SessionStateBehavior.Required)]
public class SessionController : Controller
{        
public ActionResult Index()
{
  Session["Test"] = "test";
  Thread.Sleep(1000);
  return new HttpStatusCodeResult(200);
}
}
[SessionState(SessionStateBehavior.Disabled)]
public class SessionLessController : Controller
{     
   public ActionResult Index()
   {
       Thread.Sleep(1000);
       return new HttpStatusCodeResult(200);
   }
}
[SessionState(SessionStateBehavior.ReadOnly)]
public class SessionReadOnlyController : Controller
{
   public ActionResult Index()
   {
       var value = Session["Test"];
       Thread.Sleep(1000);
       return new HttpStatusCodeResult(200);
   }
}

Następnie napiszemy prostą aplikację konsolową, która będzie po prostu wywoływać powyższe metody z różnych wątków:

class Program
{
private static void Main(string[] args)
{
  RunTests(@"http://localhost/Session");
  RunTests(@"http://localhost/Sessionless");
  RunTests(@"http://localhost/SessionReadOnly");
}

private static void RunTests(string url,int tests=3)
{
  Console.WriteLine(url);

  for (int test = 0; test < tests; test++)
  {
      var cookieContainer = new CookieContainer();
      SendRequest(url, cookieContainer); 

      var stopwatch = Stopwatch.StartNew();

      const int requestNumber = 20;                            
      Parallel.For(0,requestNumber, (i) => SendRequest(url, cookieContainer));
  
      Console.WriteLine(stopwatch.ElapsedMilliseconds);
  }

  Console.WriteLine();
}

static void SendRequest(string sourceURL,CookieContainer cookies)
{
  var webRequest = (HttpWebRequest) WebRequest.Create(sourceURL);
  webRequest.CookieContainer = cookies;
  
  var response = (HttpWebResponse)webRequest.GetResponse();            
}
}

Kolejne wywołania dzielą te same ciasteczka, aby przekazywać id sesji.

Wyniki są następujące:

image

Wyraźnie widać, że zapis do sesji jest najwolniejszy ponieważ wtedy ASP.NET MVC (patrz poprzedni post), musi kolejkować zapytania. Ze względu na to, że korzystamy tutaj z wielowątkowej pętli, zapytania mogłyby być wykonywane po kilka naraz. W przypadku zapisu do sesji jest to niemożliwe –  kod jest wykonywany sekwencyjnie. Odczyt sesji nie spowoduje żadnych problemów (jest thread-safe) więc nie musi być kolejkowany – stąd wydajność taka sama jak w przypadku zablokowanej sesji.

Ktoś może zadać pytanie, że to sam zapis jest po prostu wolniejszy ponieważ trzeba modyfikować dane. Zmodyfikujmy powyższy kod tak, aby wykonywał się sekwencyjnie:

Parallel.For(0,requestNumber,new ParallelOptions{MaxDegreeOfParallelism = 1}, (i) => SendRequest(url, cookieContainer));

Wynik:

image

Przykład wyraźnie pokazuje, że to kwestia szeregowania zapytań a nie faktu, że zapis jest wolniejszy sam w sobie. Z tego inny wniosek nasuwa się – im więcej wątków z puli po stronie ASP.NET MVC tym bardziej obniżamy przepustowość kontrolera poprzez wprowadzenie sesji. Jeśli mamy np. 30 wątków w ASP.NET MVC wtedy moglibyśmy aż tyle zapytań obsłużyć w tym samym czasie gdyby nie sesja i jej implementacja w ASP.NET MVC.

One thought on “ASP.NET MVC, kontrolery a sesje: test wydajności”

  1. Bardzo ciekawy wpis obrazujący problem który wcześniej lub później pojawia się w złożonych AJAX-owych aplikacjach. Zakładam że sesja była InProc. Proponuje pójść o krok dalej i zbadać opóźnienia gdy sesja jest przechowywana poza serwerem IIS np. w bazie danych. Wówczas odczyt powinien być już wolniejszy ponieważ sesję trzeba pobrać i odserializować. Zapis dodatkowo bedzię musiał zserializować i wysłać sesję do bazy. Oczywiście sesja powinna trochę “ważyć” aby te czasy były zauważalne. Przy okazji można nakreślić kolejny problem jakim jest nadmierna ilość danych przechowywanych często niepotrzebnie w sesji.

Leave a Reply

Your email address will not be published.