Jeśli jesteś administratorem serwera WWW, to prawdopodobnie wiesz, czym jest ETag. Nie wszyscy jednak wiedzą, jak dokładnie ten mechanizm działa i czasem warto sprawdzić, czy aby w naszym środowisku działa zgodnie z przeznaczeniem - zdarza się, że drobne przeoczenie zmusza klientów do niepotrzebnego pobierania tony grafik i plików CSS, co wydłuża czas dostępu do strony i generuje niepotrzebny ruch sieciowy. Przez pewien moment sami mieliśmy z ETagiem do czynienia, co skłoniło nas do głębszej analizy, a przy okazji poznaliśmy kilka ciekawych faktów.
W skrócie, czym jest ETag? Jest to nagłówek HTTP wysyłany w odpowiedzi przez serwer WWW, który zawiera pewien ciąg znaków unikalny dla danej wersji konkretnego pliku. Kiedy pobieramy plik z serwera po raz pierwszy, zapisujemy razem z nim w pamięci podręcznej ten właśnie ETag i przy następnym wywołaniu tego pliku pytamy, czy na serwerze jest plik o innym ETagu niż posiadany przez nas. Jeśli tak (czyli jeśli plik się zmienił), to go pobieramy ponownie. Jeśli nie, to serwer odpowiada komunikatem 304 Not Modified i na tym wywołanie się kończy, a przeglądarka wie, że może śmiało użyć swojej kopii pliku.
No dobrze, to jak się liczy taki ETag? Jednoznacznej odpowiedzi na to pytanie nie ma :-) Każdy producent serwerów WWW robi to po swojemu, nie każdy jednak chętnie chce się nim dzielić ze światem. Ogólnie jednak oczywiście wiadomo, że wpływ na wartość tego parametru ma między innymi data modyfikacji pliku. W serwerach IIS, których używamy, dodatkowo po znaku ":" serwer umieszcza obliczaną przez siebie "wersję pliku". Trochę na ten temat można przeczytać w artykule KB922703, ale Microsoft nie publikuje szczegółów na temat swojego algorytmu ETagów.
Już na tym etapie administratorzy klastrów WWW mają mały problem - jeśli jest kilka frontendów, a każdy oblicza sobie samodzielnie i niezależnie ETag (przynajmniej jego drugą część), to przy założeniu, że klienci wpadają w losowy węzeł klastra mogą za każdy razem dostawać inne ETagi i w nieskończoność pobierać niepotrzebnie te same pliki. Ten problem jest dość dobrze znany, na blogu IIS.net został opisany jeszcze trzy lata temu i tak naprawdę w wersji 7.0 już nie istnieje. Domyślnie IIS 7.0 wpisuje bowiem "0" jako numer wersji, co eliminuje losowość i pozwala ujednolicić ETag na wszystkich węzłach. W starszych wersjach IIS numer "0" możemy natomiast wymusić (warto jednak zapoznać się wcześniej z linkowanym już przeze mnie wcześniej artykułem KB922703 oraz KB900245).
Do hostingu dobrychprogramów, TechIT, Gamikaze i wszystkich usług towarzyszących używamy Windows Server 2008, więc i IIS 7.0. Pomimo tego w pewnym momencie zauważyliśmy, że w przypadku niektórych plików z każdym wywołaniem ETag jest inny, a zapisując jego wartości doszliśmy do wniosku, że jest ich tyle, ile węzłów w klastrze NLB. Co się stało? Powód był oczywisty - te same pliki na różnych serwerach (tak, replikujemy zawartość WWW pomiędzy frontendami, co ma szereg naszym zdaniem dużych zalet i małych wad, o czym może kiedy indziej) mają różne daty. Jak to się jednak stało? Odpowiedź na to pytanie nie była już taka oczywista.
Ostatecznie okazało się, że w procesie kopiowania kolejnych wersji witryny z serwera deweloperskiego na produkcyjne wykorzystywany był protokół FTP, który kopiując plik zamienia datę modyfikacji na bieżącą. Dodając do tego fakt, że ostatecznym miejscem docelowym jest przestrzeń DFS (czyli kopiowane pliki wpadają na losowy węzeł) i to, że usługa DFSR nie replikuje metadanych plików takich jak daty, mieliśmy już kompletne rozwiązanie. Po kilku cyklach kopiowania część plików, na przykład style CSS, na każdym serwerze miała inną datę.
Rozwiązanie? Na początek trzeba ujednolicić daty na wszystkich serwerach. Później rozwiązań jest kilka. Najlepiej nie kopiować w ogóle niezmienionych plików, ale nie zawsze jest to rozwiązanie najprostsze. My pilnujemy po prostu, by wszystkie pliki kopiowane były przy pomocy SMB, który zachowuje daty modyfikacji (dla przyspieszenia procesu na wąskich łączach można całość wcześniej spakować). I życie stało się prostsze - także dla Waszych przeglądarek ;-)