Przyspieszamy ASP.NET - kompresja HTTP
Wyobraźmy sobie rozwiązanie, które:
- pozwala na zmniejszenie transferu wykorzystywanego przez witrynę,
- umożliwia szybsze dostarczenie treści użytkownikowi,
- wymaga bardzo małego nakładu pracy przy wdrożeniu,
- w niedużym stopniu wpływa na wydajność serwera oraz
- jest od dawna wspierane przez wszystkie przeglądarki…
Zbyt piękne, żeby było prawdziwe? Nieprawda – takie rozwiązanie istnieje i nazywa się kompresja HTTP! Idea polega w skrócie, żeby odpowiedź na żądanie klienta skompresować przed wysłaniem, ograniczając jej rozmiar i czas przesyłania przez sieć. Efekt: wilk syty, owca cała – zmniejszamy transfer witryny (nasze koszty) i czas ładowania stron (lepszy odbiór przez użytkowników).
Jak to działa?
Przeglądarka wysyła do serwera żądanie, którego nagłówek wygląda mniej więcej tak:
W tym nagłówku ważny jest nagłówek Accept-Encoding, w którym przeglądarka chwali się jakie rodzaje kodowania (czyt. kompresji) obsługuje. Dostępne są dwie standardowe metody: GZip oraz Deflate. Wówczas serwer wie, że może skompresować przesyłaną zawartość i że klient go zrozumie. Nagłówek odpowiedzi może wyglądać mniej więcej tak:
Jak widać nagłówek Content-Encoding informuje klienta, jaka metoda kodowania (kompresji) została zastosowana do przesłania treści odpowiedzi.
A teraz rzecz najważniejsza. Kompresja HTTP oraz metody GZip i Deflate są częścią standardu HTTP/1.1 (opublikowanego w 1999r.) i wspierają je wszystkie współczesne przeglądarki – począwszy od IE 4.0 i Netscape 4.0.
Oczywiście, nie wszystko warto kompresować. O ile zawartość tekstowa (ASPX, HTML, JS, CSS) w wyniku kompresji zmniejsza swój rozmiar średnio o 75% (staje się 4 razy mniejsza!), to w przypadku plików już skompresowanych (grafika, wideo, docx, itd.) zwykle uzyskamy efekt zerowy.
Nie ma róży bez kolców? Niekoniecznie. Jedyną wadą kompresji HTTP jest trochę większe zużycie procesora, potrzebne do skompresowania wysyłanej treści. Jednakże w większości rozwiązań webowych wąskie gardło stanowi szybkość dysków lub ilość pamięci operacyjnej, podczas gdy czasu procesora mamy pod dostatkiem (oczywiście są wyjątki).
Kompresja HTTP z punktu widzenia serwera
Wyróżniamy dwa rodzaje kompresji z punktu widzenia serwera:
- Kompresja statyczna, która dotyczy statycznych plików serwowanych bezpośrednio przez serwer (np. pliki HTML, JS, CSS). Ponieważ ich zawartość nie zmienia się w czasie, to serwer może raz skompresowany plik zachować w swoim cache’u, dzięki czemu przy następnym żądaniu nie musi przeprowadzać kompresji na nowo.
- Kompresja dynamiczna, dotycząca zawartości generowanej dynamicznie (ASPX, ASMX, ASHX, AXD, itp.). W tej sytuacji każda odpowiedź jest inna i serwer musi za każdym razem przeprowadzać kompresję.
Kompresja HTTP na IIS 6
Uruchomienie kompresji w II 6 możliwe jest albo z poziomu konsoli administracyjnej albo wykorzystując odpowiedni skrypt. Wyczerpująco opisuje to artykuł “Enabling HTTP Compression (IIS 6.0)”, więc nie ma sensu, żebym go tutaj przepisywał. Natomiast jeśli chodzi o konfigurację to polecam tekst “Using HTTP Compression for Faster Downloads (IIS 6.0)”.
Z ważnych informacji – IIS 6 pozwala na wybór, kiedy stosowana jest kompresja. Niestety, to rozróżnienie bazuje tylko i wyłącznie na rozszerzeniach plików. W przypadku zawartości statycznej nie stanowi to problemu. Natomiast w przypadku treści generowanej dynamicznie jest to spore ograniczenie. Najlepszym przykładem mogą być tutaj HTTP Handlers (rozszerzenie ASHX), w przypadku których typ dostarczanej zawartości zależy tylko i wyłącznie od konkretnego handlera.
Kompresja HTTP na IIS 7
W przypadku IIS 7 uruchomienie kompresji wymaga dwóch kroków. Po pierwsze musimy upewnić się, iż mamy zainstalowane odpowiednie składniki serwera (“Kompresja zawartości statycznej” i “Kompresja zawartości dynamicznej”). Po drugie musimy włączyć kompresję w pliku web.config lub z poziomu konsoli IIS Manager. Uruchomienie i konfigurację kompresji HTTP na IIS 7 bardzo dobrze opisuje artykuł “HTTP Compression ”.
IIS 7, w odróżnieniu od poprzedniej wersji, pozwala decydować o stosowaniu kompresji w oparciu o typ MIME zawartości (nagłówek Content-Type odpowiedzi). Dzięki temu, zwłaszcza w przypadku zawartości dynamicznej mamy dostępne znacznie precyzyjniejsze narzędzie.
Z ciekawych możliwości wprowadzonych w IIS 7 jest możliwość określenia progów zużycia procesora, dla których wyłączana jest kompresja oraz włączana jest ponownie (jeśli taka możliwość istniała w IIS 6, to poprawcie mnie).
Kompresja HTTP ręcznie
Czasami może zdarzyć się, iż nie możemy włączyć kompresji bezpośrednio na serwerze. Najczęściej bywa tak w przypadku hostingu aplikacji ASP.NET (shared hosting). Wówczas w interesie hostingodawcy (wg GIODO takie słowo istnieje ;)) jest abyśmy z kompresji nie korzystali, gdyż za transfer płacimy, a za czas procesora zwykle nie. Istnieje jednak programistyczne obejście pozwalające włączyć kompresję przynajmniej w tych sytuacjach, gdy żądanie nie jest obsługiwane bezpośrednio przez serwer i dociera do silnika ASP.NET (w przypadku IIS 6 jest to tylko zawartość dynamiczna; w przypadki IIS 7 zależy to od konfiguracji).
Oto przykładowy fragment pliku Global.asax.cs uruchamiający kompresję HTTP ręcznie dla stron ASP.NET:
1: protected void Application_BeginRequest(object sender, EventArgs e)
2: {
3: if (this.Request.Headers["Accept-Encoding"] != null
4: && this.Request.Headers["Accept-Encoding"].Contains("gzip")
5: && this.Request.Path.ToLower().EndsWith(".aspx"))
6: {
7: this.Response.Filter = new System.IO.Compression.GZipStream(this.Response.Filter, System.IO.Compression.CompressionMode.Compress, true);
8: this.Response.AddHeader("Content-encoding", "gzip");
9: }
10: }
Podsumowanie
Kompresja HTTP:
- wchodzi w skład standardu HTTP/1.1,
- jest wpierana przez praktycznie wszystkie współczesne przeglądarki,
- wymaga bardzo małego nakładu pracy do uruchomienia,
- zmniejsza transfer wykorzystywany przez witrynę,
- skraca czas ładowania stron,
- ale zwiększa zużycie procesora.
Czy warto? A czy szybciej biega się z pięćdziesięciokilogramowym workiem na plecach czy bez?