Asynchroniczne WebServisy czyli jak przyspieszyć SOAP

Ostatnio w zakładzie dostałem do rozpoznania wolne działanie webserwisu. Problem leżał w tym, iż aplikacje klienckie były w stanie szybciej strzelać pod webserwis niż ten nadążał z procesowaniem. I zasadniczo możnaby rozpocząć szukanie winnego w kodzie gdyby nie prosty fakt, że klasy odpowiadające za webserwis walidowały tylko żądanie po czym pchały obiekt do JMS. Co tutaj można przyspieszyć?

Odpaliłem SoapUIPro i z konkretną dawką testów obciążeniowych udałem się na poszukiwanie winnego. Co się okazało – webserwis był oparty o SOAPa. To jeszcze może nie jest samo w sobie tragiczne – tragicznym natomiast okazało się to, iż pod spodem nasz request potrafił zawierać naprawdę sporą ilość XMLa. Standardowe dane dla każdego requestu to dobre 5 elementów XMLa,  zaś szóstym była lista łańcuchów tekstowych. W 90% ta lista zawierała raptem jeden element – problemem było pozostałe 10%. Wówczas lista rozrastała się do dość solidnych rozmiarów i proces przesyłania tych danych, ich marshallingu, procesowania i takich tam troszkę trwał.  Trzeba było coś z tym fantem zrobić. Przepisanie na RESTa pozostawało w dalszych planach, zaś na szybko udało mi się zorganizować jedną rzecz – wbudowaną w JAX-WS adnotację @Oneway.

 The @Oneway annotation denotes a method as a Web service one-way operation that only has an input message and no output message. Apply this annotation to methods on a client or server Service Endpoint Interface (SEI) or a server endpoint implementation class for a JavaBeans endpoint.

Dodam jeszcze tylko, że adnotowane w ten sposób metody muszą spełniać następujące kryteria:

  • muszą zwracać void
  • nie mogą rzucać wyjątków

Może to być dość ograniczające, np. kiedy rzucony wyjątek w jakiś sposób służy nam do kontroli przepływu po stronie klienta. Jednakże jeśli przy strzelaniu do usługi sieciowej stosujemy metodę fire&forget wówczas jesteśmy w domu. Brak oczekiwania na odpowiedź ze strony serwera – w przypadku przeze mnie opisywanym wstępny przyrost wydajności to około 400%. Myślę zatem, że gra jest warta świeczki.

Advertisements

11 thoughts on “Asynchroniczne WebServisy czyli jak przyspieszyć SOAP

  1. Mariusz

    W moim odczuciu JMS i asynchroniczny webservice to jedność. Ostatnio coraz częściej stosujemy @Oneway i użytkownicy wyraźnie odczuwają przyspieszenie aplikacji.

    Pozdrawiam

  2. chlebik Post author

    Oczywiście ja nie twierdzę, że jest to lek na wszystkie bolączki świata z mgłą nad Smoleńskiem włącznie 😉 Jednakże w przypadku projektów, gdzie da się API bez uszczerbku zmienić to jest to rzecz warta przemyślenia. Zresztą w moim przypadku dodałem nową metodę do usługi bez usuwania starej i po prostu uaktualniono dokumentacje i poinformowano cały zespół. Wilk syty i babcia cała.

  3. Tomek

    Zapytam może nieco odmiennie – a czemu to SOAP jest taki zły, a REST taki dobry? 😉 Przecież JSON – który chyba najczęściej przewija się w przykładach z RESTa – także trzeba przetworzyć, więc argument, że SOAP to XML chyba nie jest taki zły. JSON może jest nieco czytelniejszy, ale na co dzień chyba nie będziesz czytał zapytań Web Service’u – robi to przecież maszynka. Pytanie może głupie, ale jestem ciekawy, jakie masz uzasadnienie na tą tezę. 🙂

  4. Tomek

    Errata – “więc argument, że SOAP to XML chyba nie jest taki zły” powinno być oczywiście “więc argument, że SOAP to XML chyba nie jest taki dobry (/mocny)”.

  5. Koziołek

    Tomku, parsowanie XMLa w porównaniu z parsowaniem JSONa jest znacznie trudniejsze. W dodatku sam protokół SOAP daje dość duży narzut na dokument (wysyłamy bit zgodności + całą kopertę) co też spowalnia. REST jest w takim przypadku znacznie bardziej elastyczny.
    Jedyną poważną zaletą SOAP jest standaryzowane zarządzanie bezpieczeństwem. W REST masz tylko HTTPS, w SOAP jest znacznie więcej możliwości.

  6. chlebik Post author

    @Tomek: Wspomniałem o ‘słabości’ SOAPa właśnie w kontekście narzutów XMLa, które wymusza. W przypadku opisywanym przy wysyłaniu listy np. 500 adresów email masz w JSONie 500 łańcuchów i separator. W XMLu… no jest tego cokolwiek więcej 😉

  7. Jan Bajerski (@jbajerski)

    Moje 3 grosze. W kontekście asychronicznych WS odpowiedź jest zwracana w oparciu o WS-Addressing (chyba, że nie ma żadnej odpowiedzi). W takim wypadku warto pamiętać kontekst adresu przy przesyłaniu dalej.
    Zamiast przesyłać całość danych jako XML część (czyli wspomnianą listę) można przesłać w załączniku jako np. csv. Możemy wówczas traktować te dane jako binarne i po prostu wrzucić w całości do JMS’a bez parsowania.

  8. Tomek

    Dzięki za odpowiedzi – tak się spodziewałem, że argumenty mogą być jednak trochę inne – jakby nie patrzeć, sensowniejsze. 🙂 Jestem niezbyt doświadczony z WS-ami, w pracy leciałem głównie SOAP, bo taki był interfejs.. Nie dostarczany przez nas. Przy okazji kolejna errata, “tę tezę” oczywiście. 😛

  9. Tomek N.

    @Mariusz: JMS i asynchroniczne (tak naprawdę: jednokierunkowe) web-servisy to nie to samo chociażby ze względu na gwarancję dostarczenia. Przynajmniej w przypadku Apache CXF jeśli coś się posypie przy przetwarzaniu żądania klient się o tym nie dowie.

    Inna sprawa, że można używać JMS jako transportu SOAP, ale to nieco egzotyczne podejście.

    @Koziołek: Jest to zmiana niekompatybilna wstecz. Dwukierunkowa (domyślna) metoda void zwraca pusty komunikat response. Metoda jednokierunkowa po prostu takiego komunikatu nie ma (operacja definiuje tylko request). WSDL się zmienia, chociaż wygenerowany kod kliencki może być kompatybilny.

    @chlebik: Gdy przesyłasz w XMLu 500 stringów czy identyfikatorów wcale nie jesteś skazany na 500 otwierających i zamykających tagów. Mało znany tag xsd:list w XML Schema na pomoc: http://msdn.microsoft.com/en-us/library/ms256162.aspx

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s