WCF kompresja serwer

Jakiś czas temu zacząłem otrzymywać sygnały, że jeden z naszych programów bardzo długo się włącza, ściąganie niezbędnych danych podczas uruchamiania trwa bardzo długo. Zacząłem przyglądać się problemowi i moje podejrzenie padło na rozmiar przesyłanych danych. W środowisku developerskim tego nie odczuwałem – jesteśmy blisko serwerów, przepustowość łącza, inaczej niż na stacjach klienckich, wynosi kilkadziesiąt MB/s. Podczas startu programu pobieramy pewne stałe, które opakowane w kopertę soap rozrastają się do naprawdę dużych rozmiarów – zacząłem podglądać przesyłany ruch za pomocą narzędzia Fiddler i zauważyłem, że dane, które pobieramy (listy obiektów) i potem zapisujemy do plików – jako koperta soapowa są 4, 5 razy większe niż ich rzeczywisty rozmiar (czyli dane o wielkości 1MB są przesyłane w soapie jako 4,5 razy większy plik). Całkiem spory narzut..Tak na marginesie, to Fiddler był mi pomocny jedynie gdy podglądałem środowisko developerskie, na którym nie mamy włączonego ssl. W środowisku produkcyjnym, gdzie do zabezpieczania danych i przykrycia warstwy transportowej jest użyty ssl z certyfikatami klienta nie dało się podglądać ruchu. Na szczęście udało się znaleźć narzędzie, które do tego się nadaje – był to web debugger Charles. Te narzędzie ma opcję śledzenia ruchu ssl, co w moim przypadku było tym, czego potrzebuje.

Po odkryciu przyczyny powolnego startu programu zacząłem myśleć nad kompresją – do głowy przychodziły mi pomysły wydzielenia tych dużych danych, umieszczeniu ich na osobnym serwerze np. ftp w postaci spakowanych plików i pobieranie ich do aplikacji już nie jako soap’y. Problem stanowiło wymyślenie mechanizmu synchronizacji tzn. potrzebna byłaby jakaś usługa która uaktualni te pliki w przypadku zmiany danych w bazie danych – wszystko to jest do zrobienia, ale oczywiście wymaga pracy i ryzyko błędu jest na pewno spore.

Do głowy przyszedł mi następnie pomysł, który uznałem, że będzie dobry – w protokole http jest przecież wbudowana obsługa kompresji gzip..Zacząłem poszukiwać odpowiedzi na stackoverflow i wreszcie natrafiłem na bloga jednego z guru .net’u, który w tym poście opisuje, jak uruchomić automatyczną kompresję gzip dla odpowiedzi serwera iis. Po wykonaniu tych kroków (w skrócie włączenie dynamicznej kompresji i ustalenie typów odpowiedzi, dla których ma być stosowana) odpaliłem nieocenionego Charlesa i zacząłem podglądać ruch – zauważyłem, że tylko część ruchu jest kompresowana i niestety nie są to komunikaty, na których najbardziej mi zależy, te największe..Ale dzięki Charlesowi zauważyłem, że dla bindingu wshttpbinding, którego używam, w nagłówku soap jest jakiś dziwny typ danych i jest to multipart-related. Po dodaniu tego typu do obsługiwanych przez kompresję typów zacząłem oglądać ruch. No i rezultaty były bardzo bardzo zadowalające Charles wskazywał stopień kompresji rzędu 85-90% – rezultat był zdecydowanie zauważalny.

Co jest bardzo ważne dla tej metody – jeżeli używasz .net 4 i klienta wcf w tej wersji żadne modyfikacje kodu źródłowego nie są potrzebne – jeżeli klient widzi w nagłówku http, że wiadomość jest zakodowana gzipem, to .net automatycznie ją odkoduje i dla programisty jest to transparentne – wszystko robi iis i .net.

No dobrze, a co w przypadku wysyłania na serwer dużych komunikatów..Tu niestety nie jest tak różowo i jest to dla mnie niezrozumiałe – dlaczego jeżeli klient wcf jest w stanie odkodować wiadomość gzip, to nie ma możliwości kodowania tych wiadomości gzipem z pudełka i wysyłania ich na serwer? Dziwne, ale tak nie jest. Są pewne możliwości, o których napisze prawdopodobie później – niecierpliwi mogą zerknąć do sdk wcf, do katalogu extensibility i compression, ale nie było to rozwiązanie, które zastosowałem, bo wymaga ona zastosowania bindingu typu custom, a ja nie chciałbym rezygnować z wshttpbinding.