W wielu usługach, nad którymi pracuję, jest dużo rejestrowania. Usługi są usługami WCF (głównie), które korzystają z klasy .NET EventLogger.
Jestem w trakcie poprawiania wydajności tych usług i pomyślałem, że asynchroniczne logowanie poprawiłoby wydajność.
Nie jestem świadomy tego, co się dzieje, gdy wiele wątków prosi o zalogowanie się, a jeśli tworzy to wąskie gardło, ale nawet jeśli tak nie jest, nadal uważam, że nie powinno to zakłócać rzeczywistego wykonywanego procesu.
Myślę, że powinienem wywołać tę samą metodę dziennika, którą teraz wywołuję, ale robię to przy użyciu nowego wątku, kontynuując rzeczywisty proces.
Kilka pytań na ten temat:
Czy to jest w porządku?
Czy są jakieś wady?
Czy należy to zrobić w inny sposób?
Może jest tak szybki, że nawet nie jest wart wysiłku?
Odpowiedzi:
Osobny wątek dla operacji we / wy brzmi rozsądnie.
Na przykład nie byłoby dobrze logować, które przyciski użytkownik nacisnął w tym samym wątku interfejsu użytkownika. Taki interfejs użytkownika zawiesza się losowo i ma powolną postrzeganą wydajność .
Rozwiązaniem jest oddzielenie zdarzenia od jego przetworzenia.
Oto wiele informacji o problemach producenta i konsumenta oraz kolejce zdarzeń ze świata tworzenia gier
Często jest taki kod
Takie podejście doprowadzi do rywalizacji wątków. Wszystkie wątki przetwarzania będą walczyć o możliwość uzyskania blokady i zapisu do tego samego pliku na raz.
Niektórzy mogą próbować usunąć blokady.
Nie można przewidzieć wyniku, jeśli 2 wątki wejdą do metody w tym samym czasie.
W końcu programiści w ogóle wyłączą rejestrowanie ...
Czy można to naprawić?
Tak.
Powiedzmy, że mamy interfejs:
Zamiast czekać na blokadę i wykonywać operacje blokowania plików za każdym razem, gdy
ILogger
zostanie wywołane, dodamy nowy LogMessage do kolejki komunikatów Penging i wrócimy do ważniejszych rzeczy:Zrobiliśmy to za pomocą tego prostego rejestratora asynchronicznego .
Następnym krokiem jest przetwarzanie wiadomości przychodzących.
Dla uproszczenia, zacznijmy nowy wątek i poczekaj wiecznie, aż aplikacja zakończy działanie, lub Asynchronous Logger doda nową wiadomość do kolejki oczekującej .
Mijam łańcuch niestandardowych słuchaczy. Prawdopodobnie możesz po prostu wysłać ramę rejestrowania połączeń (
log4net
itp.)Oto reszta kodu:
Punkt wejścia:
źródło
Kluczowymi czynnikami, które należy wziąć pod uwagę, jest potrzeba niezawodności plików dziennika i potrzeba wydajności. Patrz wady. Myślę, że to świetna strategia w sytuacjach wymagających dużej wydajności.
Czy to w porządku - tak
Czy są jakieś wady - tak - w zależności od krytyczności rejestrowania i implementacji może wystąpić dowolna z poniższych sytuacji - dzienniki zapisywane poza kolejnością, akcje wątku dziennika nie są zakończone przed zakończeniem akcji zdarzenia. (Wyobraź sobie scenariusz, w którym logujesz „zaczyna się łączyć z DB”, a następnie psujesz serwer, zdarzenie dziennika może nigdy nie zostać zapisane, nawet jeśli zdarzenie miało miejsce (!))
Powinno to zostać zrobione w inny sposób - możesz spojrzeć na model Disruptor, ponieważ jest on prawie idealny do tego scenariusza
Może jest tak szybki, że nawet nie jest wart wysiłku - nie zgadzam się. Jeśli twoja jest logiką „aplikacji”, a jedyne, co robisz, to zapisywanie dzienników aktywności - wtedy będziesz o rząd wielkości mniejszy opóźnienie poprzez odciążenie rejestrowania. Jeśli jednak powrócisz do wywołania SQL SQL trwającego 5 sekund przed zarejestrowaniem 1-2 instrukcji, korzyści będą mieszane.
źródło
Myślę, że rejestrowanie jest z natury operacją synchroniczną. Chcesz rejestrować rzeczy, jeśli się zdarzają lub nie zależą od twojej logiki, więc aby coś zalogować, należy to najpierw ocenić.
Powiedziawszy to, możesz poprawić wydajność aplikacji, buforując dzienniki, a następnie tworząc wątek i zapisując je w plikach, gdy masz operacje związane z procesorem.
Musisz sprytnie zidentyfikować punkty kontrolne, aby nie stracić ważnych informacji rejestracyjnych podczas tego okresu buforowania.
Jeśli chcesz zwiększyć wydajność wątków, musisz zrównoważyć operacje IO i operacje CPU.
Jeśli utworzysz 10 wątków, z których wszystkie wykonują operacje we / wy, nie zwiększysz wydajności.
źródło
Logowanie asynchroniczne to jedyny sposób, jeśli potrzebujesz wątków w wątkach rejestrowania. Aby osiągnąć maksymalną wydajność, należy zastosować wzorzec przerywacza dla komunikacji wątkowej bez blokowania i bez śmieci. Teraz, jeśli chcesz pozwolić na jednoczesne logowanie wielu wątków do tego samego pliku, musisz albo zsynchronizować wywołania dziennika i zapłacić cenę w rywalizacji o blokadę, albo użyć multipleksera bez blokady. Na przykład CoralQueue zapewnia prostą kolejkę multipleksowania, jak opisano poniżej:
Możesz spojrzeć na CoralLog, który wykorzystuje te strategie do rejestrowania asynchronicznego.
Oświadczenie: Jestem jednym z twórców CoralQueue i CoralLog.
źródło