Rozszerzone zdarzenia (Extended Events) w praktyce
Opublikowano: 19 lutego 2009
Autor: Damian Widera
Zawartość strony
Krótki wstęp | |
Przykłady | |
Wydajność mechanizmu rozszerzonych zdarzeń | |
Podsumowanie |
SQL Server 2008 udostępnił administratorom baz danych doskonałe narzędzie służące do monitorowania systemów serwerowych. Tym narzędziem jest mechanizm rozszerzonych zdarzeń (ang. Extended events - XE), którego architektura pozwala na korelowanie informacji nie tylko pochodzących z serwera SQL, ale także – pod pewnymi warunkami – na korelowanie informacji pochodzących z systemu operacyjnego czy innych aplikacji.
Idea rozszerzonych zdarzeń została już omówiona w artykule opublikowanym na stronach TechNet (https://www.microsoft.com/poland/technet/article/art0121.mspx), a także w ramach Akademii SQL (https://www.microsoft.com/poland/technet/article/art0131.mspx) . W artykule nie zostaną więc ponownie poruszone kwestie architektury tego rozwiązania, a główny nacisk zostanie położony na zaprezentowanie kilku praktycznych przykładów obrazujących możliwości systemu.
Krótki wstęp
Zarówno wcześniejsze wersje serwera SQL Server, jak i obecna, posiadają wbudowane mechanizmy pozwalające na przechwytywanie i analizowanie zdarzeń, które miały miejsce podczas pracy systemu.
Jednym z najstarszych mechanizmów jest mechanizm śledzenia (ang. trace), który do tej pory bywa najczęściej używanym podczas analizy pracy serwera, szybkiego znajdowania zakleszczeń i blokad, dostrajania zapytań czy rozwiązywania problemów z wydajnością. Liczba dostepnych zdarzeń w procesie śledzenia wynosi:
SELECT COUNT(*) FROM sys.trace_events
GO
180
(1 row(s) affected)
W poprzedniej wersji SQL Servera zaimplementowany został mechnizm powiadamiania o zdarzeniach (ang. Event Notification), który pozwala przechytywać m.in. zdarzenia pochodzące z audytu baz danych, tworzenia, usuwania kluczy i certyfikatów, wyzwalaczy definiowanych na poziomie serwera, tworzenia grup i pul zarządcy zasobów i wiele innych. Liczba zdarzeń dostępna w mechaniźmie powiadamiania o zdarzeniach wynosi:
SELECT COUNT(*) FROM sys.event_notification_event_types
GO
364
(1 row(s) affected)
SQL Server udostepnia również informacje pochodzące z liczników wydajności używanych w monitorze wydajności a teraz także w nowej funkcjonalności wchodzącej w skład serwera SQL w wersji Enterprise – w studio monitoringu (ang. Performance Studio). Obecnie liczników tych jest 334:
SELECT COUNT(*)
FROM(
SELECT DISTINCT object_name, counter_name
FROM sys.dm_os_performance_counters
)D
334
(1 row(s) affected)
Mechanizm XE na pierwszy rzut oka nie dostracza imponującej liczby zdarzeń:
SELECT COUNT(*) FROM sys.dm_xe_objects
WHERE object_type='event'
GO
254
(1 row(s) affected)
Pytanie nasuwa się natychmiast – dlaczego używać informacji pochodzących z nowego mechanizmu, skoro liczba dostępnych zdarzeń jest prawie o połowę mniejsza niż ma to miejsce w przypadku mechanizmu powiadamiania o zdarzeniach?
Odpowiedź na to pytanie wymaga dokładniejszego przeanalizowania zdarzeń dostępnych w mechaniźmie XE. Okazuje się, że można otrzymać informacje niedostępne do tej pory, a odnoszące się do wewnętrzych struktur serwera SQL, na których zbudowano np. widoki dynamiczne; można uzyskać także dużo dokładniejsze informacje dotyczące usługi Broker niż ma to miejsce podczas śledzenia przy pomocy narzędzia Profiler.
Spójrzmy więc, jakie grupy zdarzeń są dostępne w mechaniźmie XE:
SELECT DISTINCT xem.map_value as [Lista obszarow XE]
FROM sys.dm_xe_map_values xem
JOIN sys.dm_xe_packages xep
ON xep.guid = xem.object_package_guid
WHERE xem.name = 'keyword_map'
ORDER BY xem.map_value
Lista obszarow XE
access_methods
broker
cdc_logscan
change_tracking
clr
cursor
database
deadlock_monitor
errors
exception
execution
io
latch
lock
memory
process
replication
scheduling
server
synchronization
transactions
(21 row(s) affected)
W kolejnych wersjach serwera SQL, a może także przy okazji pojawiania się kolejnych uaktualnień (SP czy CU) będą pojawiały się kolejne zdarzenia w kolekcji XE, więc obszar zastosowań tego mechanizmu napewno się rozszerzy.
Do początku strony
Przykłady
Pora przedstawić praktyczne zastosowanie mechanizmu rozszerzonych zdarzeń na kilku przykładach.
Przykład nr 1
W tym przykładzie pokazałem, w jaki sposób można wykorzystać informacje przekazywane przez sesję rozszerzonych zdarzeń, która pozwala monitorować procesy odłączania i podłaczania baz danych.
Nie jest to przykład skomplikowany, również dla wielu administratorów może nie mieć znaczenia praktycznego, wszak odłączanie i przyłączanie baz danych w warunkach produkcyjnych nie jest wykonywane codziennie. W tym przykładzie chciałem dokładniej pokazać, w jaki sposób korzystać z bloków wchodzących w skład architektury mechanizmu XE, czyli także z odbiorców oraz akcji.
Utworzyłem sesję rozszerzonych zdarzeń:
CREATE EVENT SESSION database_stuff ON SERVER
ADD EVENT sqlserver.database_attached
(
ACTION
(
sqlserver.session_id
,sqlos.task_time
)
),
ADD EVENT sqlserver.database_detached
(
ACTION
(
sqlserver.session_id
,sqlos.task_time
)
)
ADD TARGET package0.asynchronous_file_target
(SET FILENAME=N'c:\temp\db_stuff.xel', metadatafile=N'c:\temp\db_stuff.xem');
go
Sesja db_stuff zawierała 2 zdarzenia (dołączenie i odłączenie bazy danych) i do każdego z nich dostarczała takich informacji, jak identyfikator sesji (session_id) oraz czas trwania zadania (task_time). Informacje o zdarzeniach zapisywne były w plikach db_stuff.xel oraz db_stuff.xem w katalogu C:\Temp. Pierwszy z plików db_stuff.xel — przechowuje informacje o zdarzeniu w formacie XML, a drugi plik przechowuje informacje o metadanych związanych ze zdarzeniem.
Po zdefiniowaniu sesji należało ją uruchomić:
ALTER EVENT SESSION database_stuff ON SERVER STATE = START;
Każda operacja odłaczenia lub podłączenia bazy danych spowodowała zapis informacji o tym zdarzeniu do pliku.
W momencie, w którym chcemy zaprzestać przechytywania informacji należy zatrzymać sesję rozszerzonych zdarzeń:
ALTER EVENT SESSION database_stuff ON SERVER STATE = stop;
Usunięcie sesji za pomocą polecenia DROP EVENT SESSION spowoduje całkowite usunięcie metadanych zwiazanych z tą sesją, a więc nie będzie jej można uruchomić ponownie przed wykonaniem nowej definicji.
DROP EVENT SESSION database_stuff ON SERVER
Odczytanie informacji pochodzących z sesji rozszerzonych zdarzeń nie jest specjalnie trudne, ale należy samodzielnie zadbać, aby informacja ta dostarczona była w formacie tabelarycznym. W przypadku odczytywania informacji zapisanych w plikach mozna posłużyć się wbudowaną funkcją sys.fn_xe_file_target_read_file podając jako jej paramtery obydwa zapisane pliki:
SELECT object_name AS [Zdarzenie] , CONVERT(xml, event_data) as [Dane]
from sys.fn_xe_file_target_read_file
('c:\temp\db_stuff*.xel', 'c:\temp\db_stuff*.xem', null, null)
Wynik operacji odłaczenia bazy danych został zapisany w kolumnie Dane następująco:
<event name="database_detached" package="sqlserver" id="95" version="1" timestamp="2009-01-23T03:22:19.566Z">
<data name="database_id">
<value>7</value>
<text />
</data>
<action name="session_id" package="sqlserver">
<value>70</value>
<text />
</action>
<action name="task_time" package="sqlos">
<value>46552749</value>
<text />
</action>
</event>
Dla przypomnienia — listę wszystkich dostępnych zdarzeń można uzyskać wykonując zapytanie:
SELECT
xo.name as [Nazwa zdarzenia]
,xo.description as [Opis zdarzenia]
,xp.name as [Nazwa paczki]
FROM sys.dm_xe_objects xo join sys.dm_xe_packages xp
ON xo.package_guid=xp.guid
WHERE xo.object_type = 'event'
ORDER BY xo.name
Zdarzenie database_attached dostarcza informacji pokazanych pokazanych poniżej, z których najistotniejszą jest identyfikator bazy danych, która została przyłączona:
SELECT xc.name AS [Nazwa kolumny]
,xc.description AS [Opis kolumny]
,xp.name AS [Nazwa paczki]
FROM sys.dm_xe_object_columns xc
JOIN sys.dm_xe_packages xp
ON xc.object_package_guid = xp.guid
WHERE xc.object_name='database_attached'
Nazwa kolumny Opis kolumny Nazwa paczki
ID Numeric ID sqlserver
UUID Globally Unique ID sqlserver
VERSION Event schema version sqlserver
CHANNEL ETW Channel sqlserver
KEYWORD Associated Keyword sqlserver
database_id NULL sqlserver
(6 row(s) affected)
Każde zdarzenie może otrzymać dodatkowe informacje — dane, które mogą być istotne podczas późniejszej analizy tego zdarzenia. Należy pamiętać, że do każdego zdarzenia można wstawić dowolną akcję, których lista jest dostępna po wykonaniu zapytania:
SELECT xo.name AS [Nazwa akcji]
,xo.description AS [Opis akcji]
,xp.name AS [Nazwa paczki]
FROM sys.dm_xe_objects xo
JOIN sys.dm_xe_packages xp
ON xo.package_guid=xp.guid
WHERE object_type='action'
ORDER BY xo.name
Informacje o sesji rozszerzonych zdarzeń mogą być przesłane do jednego z siedmiu odbiorców. Wybór odbiorcy ma fundamentalne znaczenie z punktu widzenia wydajności całego mechanizmu, o czym bardziej szczegółowo napisałem w sekcji Wydajność:
SELECT xo.name AS [Nazwa odbiorcy]
,xo.description AS [Opis odbiorcy]
,xp.name AS [Nazwa paczki]
FROM sys.dm_xe_objects xo
JOIN sys.dm_xe_packages xp
ON xo.package_guid = xp.guid
WHERE object_type='target'
AND xp.name <>'SecAudit'
ORDER BY xo.name
Przy konstruowaniu sesji rozszerzonych zdarzeń należało wiedzieć, jakie parametry są konieczne do odpowieniego skonstruwania odbiorcy zdarzenia. Poniższe zapytanie wyświetla listę parametrów dla odbiorcy asynchronous_file_target, który pozwala na zapisanie informacji we wskazanym miesjcu na dysku. Ten typ odbiorcy ma bardzo istotną przewagę nad odbiorcami przechowującymi informacje w pamięci, ponieważ wszystkie informacje zapisane w pliku dostępne są także po zatrzymaniu sesji a także po jej usunięciu.
SELECT xc.name AS [Nazwa kolumny]
,xc.description AS [Opis kolumny]
,xp.name AS [Nazwa paczki]
FROM sys.dm_xe_object_columns xc
JOIN sys.dm_xe_packages xp
ON xc.object_package_guid = xp.guid
WHERE xc.object_name='asynchronous_file_target'
Przykład nr 2
W przykładzie drugim, który jest kontynuacją poprzedniego przykladu, dodałem do sesji db_stuff (teraz nazwanej db_stuff_ext) kilka interesujacych zdarzeń związanych z odczytywaniem, zapisywaniem oraz zmianą rozmiaru pliku danych.
Wykorzystując te informacje administrator może precyzyjnie okreslić kiedy następowało fizyczne powiększanie pliku danych oraz uzyskać wiedzę na temat operacji zapisu i odczytu danych z dysku. Wiadomo, że dostęp do danych zapisanych na dysku jest zdecydowanie najwolniejszym dostępem, porównując go np. z dostepem do danych trzymanych w buforach pamięci. Dla zdarzeń związanych z zapisem i odczytem danych udostepniłem także informację o czasie trwania takiego zdania, identyfikatorze procesora, który wykonywał to zadanie oraz identyfikatorze wątka. Warto jednak we własnym zakresie dodać i przetestwoać także inne akcje:
CREATE EVENT SESSION db_stuff_ext ON SERVER
ADD EVENT sqlserver.database_attached
(
ACTION
(
sqlserver.session_id
)
),
ADD EVENT sqlserver.database_detached
(
ACTION
(
sqlserver.session_id
)
),
ADD EVENT sqlserver.file_read
(
ACTION
(
sqlos.task_time
,sqlos.system_thread_id
,sqlos.cpu_id
)
),
ADD EVENT sqlserver.file_read_completed
(
ACTION
(
sqlos.task_time
,sqlos.system_thread_id
,sqlos.cpu_id
)
),
ADD EVENT sqlserver.file_write_completed
(
ACTION
(
sqlos.task_time
,sqlos.system_thread_id
,sqlos.cpu_id
)
),
ADD EVENT sqlserver.file_written
(
ACTION
(
sqlos.task_time
,sqlos.system_thread_id
,sqlos.cpu_id
)
),
ADD EVENT sqlserver.databases_data_file_size_changed
(
ACTION
(
sqlos.task_time
,sqlos.system_thread_id
,sqlos.cpu_id
)
)
ADD TARGET package0.asynchronous_file_target
(SET FILENAME =N'c:\temp\db_stuff.xel', metadatafile=N'c:\temp\db_stuff.xem');
Podobnie jak miało to miejsce w pierwszym przykładzie, użyłem asynchronicznej metody zapisu informacji o zdarzeniach do plików nie decydując wprost, jaki jest maksymalny czas pozostawania informacji w buforze.
Przykład 3
Kończąc wątek związany z plikami warto poświęcić trochę czasu dla dziennika transakcji, dla którego można znaleźć wartościowe informacje w mechanizmie rozszerzonych zdarzeń, takie jak:
- Zmiana rozmiaru pliku dziennika transakcji (databases_log_file_size_changed),
- Zmniejszenie pliku (databases_log_shrink),
- Obcięcie pliku (databases_log_truncation).
Definicja sesji rozszerzonych zdarzeń, która miałaby dostarczać powyższych informacji mogłaby wyglądać następująco:
CREATE EVENT SESSION logs_stuff ON SERVER
ADD EVENT sqlserver.databases_log_file_size_changed
(
ACTION
(
sqlos.task_time
)
),
ADD EVENT sqlserver.databases_log_shrink
(
ACTION
(
sqlos.task_time
)
),
ADD EVENT sqlserver.databases_log_truncation
(
ACTION
(
sqlos.task_time
)
)
ADD TARGET package0.ring_buffer
GO;
Zwróć uwagę, że użyłem w tym przykładzie innego odbiorcę zdarzenia, a mianowicie bufor okrężny (ang. ring buffer), który pozostawia informacje o zarejestrowanych zdarzeniach w pamięci serwera. Informacja ta jest dostępna tylko w trakcie uruchomionej sesji rozszerzonych zdarzeń. Po wykonaniu polecenia ALTER EVENT SESSION ... STOP lub DROP EVENT SESSION informacja o zdarzeniach jest usuwana z pamięci. Domyślnie, bufor w pamięci ma 4MB, ale jest to wielkość, którą mozna skonfigurować nie tylko na etapie tworzenia sesji, ale także później.
ALTER EVENT SESSION logs_stuff ON SERVER STATE = START
--WYKONYWANE SĄ NORMALNE OPERACJE
--CO DZIEJE SIĘ Z DZIENNIKIEM TRANSAKCJI????
Po włączeniu sesji można za pomocą poniższego zapytania odczytywać informacje dotyczące dziennika transakcji. Informacje zapisane są w formacie XML i póki co należy je ręcznie parsować:
SELECT
T.Event.value('@name', 'nvarchar(max)') as [Nazwa zdarzenia]
,T.Event.value ('(data/.)[1]', 'int') AS Wartosc
,T.Event.value ('(data/.)[2]', 'int') AS Inkrementacja
,T2.Event.value ('.', 'nvarchar(MAX)') AS [Czas (ticks)]
FROM
(
SELECT CAST(xet.target_data as xml) as [Dane]
FROM sys.dm_xe_session_targets xet
JOIN sys.dm_xe_sessions xe
ON (xe.address = xet.event_session_address)
WHERE xe.name = 'logs_stuff'
) [Events]
CROSS APPLY [Dane].nodes ('//RingBufferTarget/event') AS [T] (Event)
CROSS APPLY T.Event.nodes('(action[@name="task_time"]/value)[1]') AS [T2] (Event)
Po zakończeniu monitorowania serwera należy sesję zatrzymać oraz w razie potrzeby usunąć pamiętając, że po zatrzymaniu sesji można ją ponownie uruchomić, natomiast po usunięciu należy od nowa ją zdefiniować.
--ZATRZYMANIE I USUNIĘCIE SESJI
ALTER EVENT SESSION logs_stuff ON SERVER STATE = STOP
DROP EVENT SESSION logs_stuff ON SERVER
Przykład 4
Jednym z najprzydatniejszych praktycznych zastosowań mechanizmu rozszerzonych zdarzeń jest możliwość użycia odbiorcy, który dopasowuje zdarzenia, łącząc je w pary. Zastosowaniem tego faktu, które natychmiast przychodzi na myśl, jest odnajdywanie tych założonych blokad dla wybranej bazy danych (zdarzenie lock_acquired), dla których nie odnaleziono potem operacji ich zdjęcia (zdarzenie lock_released).
Można przyjąć następujący scenariusz, który polega na okresowym sprawdzaniu, czy są dla wybranej bazy danych aktywne blokady. Dodatkowo na poniższym przykładzie pokazałem, że można uzyskać identyfikator sesji (session_id), identyfikator transakcji (transaction_id) oraz tekst zapytania, które spowodowało blokadę (sql_text):
CREATE EVENT SESSION Blokady ON SERVER
ADD EVENT sqlserver.lock_acquired
(
ACTION
(
sqlserver.sql_text,
sqlserver.session_id,
sqlos.transaction_id
)
WHERE sqlserver.database_id=10
),
ADD EVENT sqlserver.lock_released
(
WHERE sqlserver.database_id=10
)
ADD TARGET package0.pair_matching
(
SET
begin_event='sqlserver.lock_acquired',
begin_matching_columns=database_id, resource_0, resource_1, resource_2, transaction_id, mode',
end_event='sqlserver.lock_released',
end_matching_columns='database_id, resource_0, resource_1, resource_2, transaction_id, mode'
)
WITH (max_dispatch_latency = 1 seconds)
Warto w tym momencie skomentować definicję odbiorcy pair_matching. Odbiorca ten przyjmuje szereg parametrów, ale najważniejsze z nich są 4:
- begin_eventoraz end_event pozwalają na skojarzenie ze sobą konkretnych zdarzeń,
- begin_matching_columns oraz end_matching_columns, które łączą ze sobą specyficzne informacje charakterystyczne dla każdego zdarzenia, np identyfikator transakcji czy bazy danych
Zwróć również uwagę, że w definicji obydwu zdarzeń tworzących tę sesję wstawiłem filtr pozwalajacy ograniczać liczbę przechytywanych zdarzeń do tych, które pochodzą z bazy danych o identyfikatorze 10.
Po włączeniu sesji Blokady można na bieżąco analizować informacje:
ALTER EVENT SESSION Blokady ON SERVER STATE = START
GO
Dane z odbiorcy pair_matching dostepne są w formacie XML. Poniższy kod wyświetla te informacje i umożliwia ich dalszą obróbkę:
SELECT CAST(xest.target_data AS xml) Blokady
FROM sys.dm_xe_session_targets xest
JOIN sys.dm_xe_sessions xes
ON xes.address = xest.event_session_address
WHERE xest.target_name = 'pair_matching'
AND xes.name = 'Blokady'
--zakończenie i ewentualnie usunięcie sesji
ALTER EVENT SESSION Blokady ON SERVER STATE = STOP
DROP EVENT SESSION Blokady ON SERVER
Przykład 5
Mechanizm rozszeronych zdarzeń dostarcza w wielu przypadkach pełniejszej informacji, niż uzyskujemy z widoków dynamicznych. Można na przykład skonstruować sesję rozszerszonych zdarzeń, która przechwyci informacje o stanach oczekiwania związanych z określoną sesją użytkownika.
W tym przykładzie skorzystałem z dwóch zdarzeń znajdujących się w paczce sqlos – ze zdarzenia wait_info oraz zdarzenia wait_info_external, które dają pełen obraz stanów oczekiwania na werwerze. W każdym z tych zdarzeń uwzględniłem filtr w postaci identyfikatora sesji oraz czasu trwania stanu oczekiwania.
CREATE EVENT SESSION oczekiwania ON SERVER
ADD EVENT sqlos.wait_info
(
WHERE sqlserver.session_id=66 and duration>0
)
,
ADD EVENT sqlos.wait_info_external
(
WHERE sqlserver.session_id=66 and duration>0
)
ADD TARGET package0.asynchronous_file_target
(SET FILENAME=N'c:\temp\wait_stats.xel', metadatafile=N'c:\temp\wait_stats.xem');
Po uruchomieniu sesji informacje zostaną zapisane do wskazanych plików. Przykładowy sposób uzyskania informacji z plików opisałem w przykładzie nr 1 i 2.
Przykład 6
Na pokazanym poniżej przykładzie omówiłem, w jaki sposób można dynamicznie zdefiniować sesję rozszerzonych zdarzeń. Chciałem sprawdzić, ile trwa wykonanie punktu konrolnego (ang. checkpoint) dla wybranej bazy danych.
Punkt kontrolny polega na zapisaniu na dysku wszystkich stron będących w pamięci, które zostały zmienione od ostatniego punktu kontrolnego. Strony takie nazywane są „brudnymi" (and. dirty pages). Za wskazywanie stron do zapisu podczas kolejnego puktu kontrolnego odpowiada proces LAZY_WRITER. Dzięki mechanizmowi XE można naprawdę łatwo stwierdzić ile trwa proces wykonania punktu kontrolnego oraz z jaką częstotliwości serwer go wykonuje:
DECLARE @DBID smallint = DB_ID('AdventureWorks2008')
DECLARE @event_session varchar(max)
SET @event_session = '
CREATE EVENT SESSION CheckpointEvent ON SERVER
ADD EVENT sqlserver.checkpoint_begin
(
WHERE sqlserver.database_id='+CAST(@DBID as varchar)
SET @event_session +='
)
,ADD EVENT sqlserver.checkpoint_end
(
WHERE sqlserver.database_id='+CAST(@DBID as varchar)
SET @event_session +='
)
ADD TARGET package0.ring_buffer'
EXEC(@event_session)
Po wykonaniu polecenia EXEC(@event_session) definicja sesji rozszerzonych zdarzeń została zapisana w tablicy metadanych (). Sesję można uruchomić w taki sam sposób, w jaki uruchamialiśmy sesje definiowane statycznie:
ALTER EVENT SESSION CheckpointEvent ON SERVER STATE=START
Przechwycone zdarzenia można odczytać wykonując poniższe zapytanie:
SELECT
T.Event.value('@name', 'nvarchar(max)') as [Nazwa zdarzenia]
,T.Event.value('@timestamp', 'datetime') as [Czas zdarzenia]
FROM
(
SELECT CAST(xet.target_data as xml) as [Dane]
FROM sys.dm_xe_session_targets xet
JOIN sys.dm_xe_sessions xe
ON (xe.address = xet.event_session_address)
WHERE xe.name = 'CheckpointEvent'
) [Events]
CROSS APPLY [Dane].nodes ('//RingBufferTarget/event') AS [T] (Event)
Po zakończeniu przechytywania zdarzeń związanych z punktami kontrolnymi, ich sesję można zatrzymać i usunąć:
ALTER EVENT SESSION CheckpointEvent ON SERVER STATE= STOP
DROP EVENT SESSION CheckpointEvent ON SERVER
Przykład 7
W kolejnym przykładzie zaprezentowałem, w jaki sposób wykorzystać liczniki zdarzeń. Sesja rozszerzonych zdarzeń zaprezentowana na przykładzie poniżej pozwala przechwycić informację o co piątym zdarzeniu związnym ze zdarzeniem sql_statement_completed .
W ramach tego zdarzenia otrzymujemy także informację o identyfikatorze sesji oraz zapytaniu , które zostało zakończone. Wyniki uzyskane w ramach sesji przechowane są w pamięci i pojawią się w buforze z maksymalnie jednosekundowym opóźnieniem:
CREATE EVENT SESSION CoPiateZdarzenie ON SERVER
ADD EVENT sqlserver.sql_statement_completed
(
ACTION
(
sqlserver.session_id
, sqlserver.sql_text
)
WHERE package0.divides_by_uint64 (package0.counter, 5)
)
ADD TARGET package0.ring_buffer
WITH (max_dispatch_latency = 1 seconds)
Przykład 8
Ostatni przykład jest pewną modyfikacją poprzednio omówionego przykładu, w którym zmieniłem tylko warunek licznika zdarzeń. Teraz sesja rozszerzonych zdarzeń przechwyci ich tylko 5 związnych ze zdarzeniem sql_statement_completed:
CREATE EVENT SESSION PierwszePiecZdarzen ON SERVER
ADD EVENT sqlserver.sql_statement_completed
(
ACTION
(
sqlserver.session_id
, sqlserver.sql_text
)
WHERE package0.counter <= 5
)
ADD TARGET package0.ring_buffer
WITH (max_dispatch_latency = 1 seconds)
Do początku strony
Wydajność mechanizmu rozszerzonych zdarzeń
Kluczowym pytaniem w przypadku rozszerzonych zdarzeń staje się pytanie o wydajność tego mechanizmu. W tym przypadku nie jest inaczej niż w każdym innym, w którym mierzymy wydajność, ponieważ nieumiejętne skonfigurowanie sesji rozszerzonych zdarzeń skończy się z całą pewnością pogorszeniem wydajności całego serwera.
Te problemy nie są obce również wspomnianym na początku artykułu starszym sposobom monitorowania serwera SQL. Nie wynikają ze złego zaprojektowania mechanizmów, ale z faktu, że ich nieumiejętne użycie może tak znacznie obciążyć monitorowany obiekt, że zaciemniony zostanie zupełnie jego faktyczny obraz.
Dobrą analogią może być próba zmierzenia temperatury szpilki za pomocą lekarskiego termometru rtęciowego — nawet, jeśli szpilka będzie rozgrzana do czerwoności, to przykładając do niej taki termometr stwierdzimy, że jej temperatura nie przekracza trzydziestu stopni. Dokadnie taki sam efekt da nieumiejętne użycie sesji rozszerzonych zdarzeń czy niedpowiednia konfiguracja sesji śledzenia w narzedziu Profiler.
Jak skonfigurować odpowiednio sesje śledzenia?
Należy pamiętać, że predykaty są wywoływane synchronicznie zawsze przed przesłaniem zdarzenia do odbiorców. Skomplikowana logika zawarta w predykatach z całą pewnością wpłynie na wydajność sesji rozszeronych zdarzeń.
Jednkaże głównym powodem do niepokoju może byc konieczność użycia synchronicznych odbiorców zdarzenia (ang. synchronous targets). W takim przypadku kod, który wygenerował zdarzenie zostaje wstrzymany aż do momentu, w którym zakończone zostaną wszystkie operacje związane z obsługą tego zdarzenia.
Alternatywą dla takiego rozwiązania jest użycie asynchronicznych odbiorców zdarzeń, które jednak wymagają zbuforowania zdarzeń w pamięci serwera. W tym celu w pamięci zakładany jest 4MB bufor dla przechowania zdarzeń przed ich wysłaniem do odbiorców. Domyślnie, zdarzenia będa przechowywane w buforze tak długo, jak to możliwe chyba, że bufor zostanie zapełniony. Zarówno wielkośc bufora, jak i czas, przez który zdarzenia będą w nim pozostawały są konfigurowalne, co będzie miało fundamentale znaczenie dla systemów generujących wiele zdarzeń.
Ostatnią ważną opcją mająca bezpośredni wpływ na wydajność sesji rozszezronych zdarzeń jest opcja EVENT_RETENTION_MODE, która określa zachowanie podczas buforowania czy przetwarzania przechwyconych zdarzeń. Opcja może przyjąć jeden z podanych poniżej parametrów:
EVENT_RETENTION_MODE = { ALLOW_SINGLE_EVENT_LOSS | ALLOW_MULTIPLE_EVENT_LOSS | NO_EVENT_LOSS }
Domyślnym ustawieniem tej opcji jest ALLOW_SINGLE_EVENT_LOSS, które zezwala na odrzucenie zarejestrowanego zdarzenia w sytuacji, kiedy bufor jest już pełny i nie ma możliwości jego opróżnienia. Ta opcja ustanawia pewien kompromis pomiędzy dużą wydajnością mechanizmu rozszerzonych zdarzeń a faktem, że pojedyncze zdarzenia mogą zostać utracone bez żadnej szkody. Ustawienie opcji EVENT_RETENTION_MODE z wartością ALLOW_MULTIPLE_EVENT_LOSS oznacza, że może zostać utracony cały bufor przechowujący informacje o przechwyconych zdarzeniach. W takiej sytuacji wydajność jest największa i można ją stosować w sytuacjach, kiedy bufory zostają ponownie szybko napełnione informacjami. Najbardziej restrykcyjnym sposóród omawianych parametrów jest NO_EVENT_LOSS, który nie zezwala na utratę żadnego zdarzenia. Powoduje to jednak konieczność wstrzymania wykonywania kodu, który wywołał zdarzenie aż do momentu, w którym znajdzie się miejsce w buforze, w które można to zdarzenie zapisać.
Skonfigurowanie sesji rozszerszonych zdarzeń tak, aby była maksymalnie wydajna i nieobciążająca serwera będzie wymagało przeanalizowania działania serwera oraz podjęcia decyzji o wyborze predykatów, odbiorców oraz konfiguracji opcji EVENT_RETENTION_MODE .
Do początku strony
Podsumowanie
W artykule przedstawiłem niektóre, według mnie najciekawsze, aspekty praktycznego zastosowania mechanizmu rozszerzonych zdarzeń. Pokazałem, w jaki sposób efektywnie wykorzystać naprawdę spore możliwości oferowane przez XE, zwłaszcza te niedostepne innymi metodami śledzenia czy monitorowania aktywności serwera.
Mechanizm rozszerzonych zdarzeń oferuje ciekawą gamę predykatów, dzięki czemu można konstruowac dużo bardziej rozbudowane filtry niż w przypadku narzędzia SQL Profiler. Można również wybierać, gdzie zostaną zapisane informacje o przechwyconych zdarzeniach.
Jedynym mankamentem jest brak zintegrowanego z konsolą SSMS wygodnego parsera lub edytora zdarzeń i konieczności pisania wszystkiego "na piechotę".
Damian Widera, Project Manager & Team Lead (MCT, MCITP – DBA, MCSD.NET) Od 8 lat zajmuje się projektowaniem, tworzeniem i wdrażaniem aplikacji wykorzystujących platformę .NET, SQL Server oraz Oracle. Obecnie pracuje jako project manager dla LGBS Polska. Pracował także jako trener, programista, administrator baz danych, twórca domumentacji oraz analityk biznesowy. Aktywnie współpracuje z polskim oddziałem Microsoft publikując atykuły, webcasty oraz porady z zakresu SQL Server na stronach TechNet. Jest współautorem książki „Serwer SQL 2008. Administracja i programowanie”. Speaker na wielu konferencjach, m.in. Microsoft Heroes Happen Here, C2C, European PASS Conference, Microsoft Technology Summit, Energy Launch, TechED. Od 2004 r. posiada certyfikaty firmy Microsoft: MCT, MCITP–DBA oraz MCSD.NET. Jest współtwórcą oraz liderem jednej z najwiekszych grup pasjonatów SQL Server w Polsce – Śląskiej Regionalnej Grupy Microsoft (PLSSUG Katowice). Od listopada 2008 jest prezesem Polish SQL Server Users Group (PLSSUG) w Polsce. W styczniu 2009 nagrodzony tytułem MVP w kategorii SQL Server. |
Do początku strony |