2009/01/13

Wielkości bloków, a wydajność

Od kilku tygodni w wolnych chwilach pracuję nad wynikami testów wydajnościowych macierzy 3PAR. Głównie to zajęcie polega na wyliczeniu maksymalnych możliwych do osiągnięcia rezultatów testowanej konfiguracji. Wartości te będę chciał potem porównać z faktycznymi wynikami.  Stworzyłem formułę, która wylicza potrzebne mi dane. Okazało się jednak, że jest ona niekompletna. Nie uwzględniała ona bowiem faktu, że pojedyncza operacja I/O może wykonać się na więcej niż jednym dysku.

Wbrew pozorom nie jest to sytuacja bardzo rzadka. Zdarza się bowiem tak, że operacja IO dotyczy bloku danych, który leży na dwóch, a nawet większej ilości dysków. Koszt wykonania takiej operacji na backend'zie macierzy będzie przez to odpowiednio większy. 

Prawdopodobieństwo wystąpienia tej sytuacji zależy od dwóch parametrów - wielkości bloku jakim operuje aplikacja (block size) i  wielkości bloku jakim operuje macierz dyskowa (stripe size).  Napisałem wzór, który wylicza jaka jest szansa na trafienie jednym blokiem w więcej niż jeden dysk:

((block size * 2) - 1) / (stripe size * 2)

Jest to wzór uproszczony, w którym założyłem, że aplikacja wybiera bloki z dokładnością co do 512 bajtów. W ten sposób działa narzędzie vdbench>, którego używałem do testowania 3PAR'a.

Po dodaniu do wyniku 1, otrzymujemy średnią ilość dysków jakie zastaną zaangażowane do obsłużenia operacji IO:



Dopasowanie bloków aplikacji i macierzy jak widać jest bardzo istotnym elementem strojenia podsystemu dyskowego i warto o tym pamiętać.

2 komentarze:

Unknown pisze...

Maro, ale jak zinterpretować ten wzór i tabelkę, bo trochę się pogubiłem?

Unknown pisze...

Pisałem to późno w nocy i rzeczywiście nie wydaje się jasne. Postaram się to więc lepiej wyjaśnić. Wzór ma na celu wyliczenie prawdopodobieństwa sytuacji gdy jedna operacja I/O nie "zmieści się" na jednym dysku. Sytuacja taka występuje, gdy blok danych, który jej dotyczy zaczyna się na jednym dysku, a kończy na innym. Dyski w macierzy są sformatowane z określoną wielkością stripe'a wyrażoną w kB. (stripe size * 2) to całkowita ilość 512 bloków, na które może być zaadresowana operacja I/O. (block size * 2 - 1) to z kolei ilość 512 bloków tego stripe'a, na które zaadresowana operacja I/O o wielkości block size nie zmieści się na tym stripe'ie. Stosunek tych dwóch ilości adresów stanowi szukane prawdopodobieństwo. Przykład: stripe size = 256 kB, block size = 16kB. Całkowita ilość adresów w stripe'ie to 512 ( 256 * 2 ). Jeżeli zaadresujemy nasze I/O na ostatnie 31 bloków (16 * 2 -1 ) to nie zmieścimy się z naszym 16 kB blokiem w tym 256 kB stripe'ie. Czyli prawdopodobieństwo takiej sytuacji wynosi 31/512 = 0,06. Na 100 % taka operacja trafi w 1 dysk, tak więc średnio taka operacja obejmie 1,06 dysku. Tabelka pokazuje wyniki tych kalkulacji dla różnych kombinacji stripe size i block size. Widać z niej na przykład, że przy block size = stripe size niemal w każdym przypadku jedna operacja I/O trafi na dwa dyski, co przy losowych operacjach znacznie obniży wydajność całej macierzy. Tabelka pokazuje też, że ogólnie im większy stripe size tym lepiej. Ne można jednak na tą sprawę patrzeć jednostronnie, bowiem większy stripe powoduje gorsze wykorzystanie cache macierzy (spada hit ratio).