Na pewno nie raz się spotkałeś albo spotkałaś z nazwą HikariCP przy uruchamianiu swojego projektu opartego o Spring Boota. Widnieje ona w logach podczas uruchamiania aplikacji. Ale czy zastanawiałaś bądź zastanawiałeś się czym to narzędzie właściwie jest? Żeby się tego dowiedzieć na początku trzeba jednak zapoznać się z definicją puli połączeń.

Czym jest pula połączeń?

Starałem się wymyślić jakieś zobrazowanie tego zagadnienia i jedyne na co wpadłem to przykład z obsługą kolejki ludzi w barze szybkiej obsługi. Wyobraźmy sobie, że mamy do dyspozycji tylko jednego pracownika. Musi on przyjąć zamówienie, pobrać opłatę, przekazać je klientowi i zaprosić następnego. Przez to, że jest sam to może zająć się obsługą tylko jednego kupującego na raz. Taki sposób nie jest wydajny, a ludzie mogą zacząć się niecierpliwić z racji na długie oczekiwanie. W przypadku, gdybyśmy jednak mieli 3 pracowników wykonaliby oni pracę trzykrotnie szybciej! Oczywiście pochłonęłaby więcej zasobów, czyli np. pieniędzy, ale zysk czasowy byłby nieporównywalny.


Obsługa kolejki w kontekście jednego połączenia a puli połączeń

Przenosząc powyższe porównanie na świat komputerów. Połączenie reprezentuje pracownika, który ma do wykonania określone zadanie. Gdybyśmy jednak wykorzystali ich większą pulę to byłaby to właśnie taka ekipa pracownicza. Mogłaby ona pracować równolegle zużywając oczywiście więcej zasobów naszego komputera kosztem wydajniejszej pracy. Sztuką natomiast jest takie zorganizowanie pracy, aby nikt nikomu nie przeszkadzał. Najlepiej jakby każdy miał swoje niezależne zadanie do wykonania. Nie chciałabyś albo chciałbyś, aby jeden z pracowników zabiegł drugiemu drogę, aby ten się wywrócił. Albo aby wszyscy korzystali z tego samego miejsca poboru wydawania zamówień. Spowodowałoby to kolejną kolejkę, “wąskie gardło”, przez co prace znacznie by się opóźniały. Ale nie o tym dzisiaj mowa. Po więcej wiedzy na pokrewny temat puli wątków zapraszam Cię do artykułu Darka Mydlarza.

Jednak co ma wspólnego pula połączeń z HikariCP? HikariCP to właśnie narzędzie, które zarządza pulą połączeń z bazą danych.

HikariCP - framework połączeń JDBC

Nazwa Hikari jak można się domyślić pochodzi z języka japońskiego i oznacza jasność albo promień. Sam projekt powstał dzięki inicjatywie Brett Wooldridge w 2012. HikariCP określany jest przez twórców jako szybki, prosty i niezawodny. Bez problemu na GitHub możemy sprawdzić w jaki sposób waga tego narzędzia osiągnęła niską wartość 130kB. Nie bez powodu Spring Boot wybrał go jako konkretną implementację DataSource. Aby skonfigurować Hikari trzeba podać wartości dla trzech z czterech obligatoryjnych parametrów. Reszta jest opcjonalna i ich domyślne wartości wystarczają w większości systemów. Na wstępie warto jeszcze zaznaczyć, że wszystkie czasowe parametry zapisywane są w postaci milisekund.

Obligatoryjne parametry

Pierwszym z obligatoryjnych parametrów jest dataSourceClassName. Dla niego należy podać nazwę klasy pozwalającej na łączenie się z konkretną bazą danych np. Oracle. Można sprawdzić w dokumentacji jaka klasa jest do tego odpowiednia albo oprzeć się na tej tabelce. Dla użytkowników MySQL twórcy podają, aby nie korzystali z tego parametru z racji na “zepsute” wsparcie sieciowego timeoutu. Dodatkowo użytkownicy Spring Boota polegający na jego autokonfiguracji także nie powinni brać pod uwagę dataSourceClassName. Zatem jaka jest alternatywa do tego rozwiązania?

Jeśli nie chcemy lub nie możemy zdecydować się na pierwszy parametr to do wyboru mamy jeszcze jeden. Nosi on nazwę jdbcUrl i opera się o menadżera sterowników. Jednak twórcy i tak bardziej promują powyższe rozwiązanie, ale są powody (takie jak wymienione wcześniej), które nam na to nie pozwalają. Czasami może się zdarzyć, że korzystając ze starych sterowników trzeba będzie jeszcze dodatkowo ustawić driverClassName. Natomiast na początku i tak lepiej spróbować bez niego. Podawanie parametrów sterownika w URL jest jednak mniej polecane niż robienie tego za pośrednictwem DataSource.

Oczywiście, aby połączyć się z bazą danych należy podać dane do autoryzacji. Do tego posłużą nam parametry username oraz password. Dzięki nim jesteśmy w stanie otworzyć połączenia do bazy danych i umieścić je w puli. Aby tego dokonać dane zostaną przekazywane do DataSource.getConnection(username, password). Jeśli połączenie oprzemy na konfiguracji sterownika to HikariCP użyje w zamian następującej linijki DriverManager.getConnection(jdbcUrl, props) do ustawienia wszystkich przekazanych parametrów.

Często wykorzystywane parametry

Przejdziemy jeszcze szybko po kilku parametrach, które są często wykorzystywane przez deweloperów. Po więcej zapraszam na stronę twórców znajdującą się na GitHubie. Pierwszym z nich jest prosty parametr autoCommit. Jego rolą jest decydowanie o tym czy chcemy mieć autocommit dla połączeń wracających z puli czy też nie. Domyślną wartością jest true.

connectionTimeout to bardzo ważny parametr. To on ustala ile maksymalnie klient będzie czekał na dostępne połączenie w puli. W przypadku jego przekroczenia zostanie rzucony wyjątek SQLException. Najmniejszą możliwą wartością jest 250 milisekund, a domyślnie wynosi ona 30000, czyli 30 sekund.

Następny w kolejce jest idleTimeout. Jego wartość mówi nam o tym jaka jest górna granica czasu jaką dane połączenie może przebywać bezczynnie w puli. To ustawienie jednak ma sens tylko, gdy parametr minimumIdle ma niższą wartość niż maximumPoolSize. Czyli minimalna liczba bezczynnych połączeń musi być niższa niż maksymalna liczba połączeń w puli. Bezczynne połączenia zajmują porty, więc warto, aby housekeeper HikariCP je zamykał i zwalniał. Minimalną wartością jest 10 sekund, a domyślną 10 minut. Natomiast w przypadku ustawienia 0 bezczynne połączenia nigdy nie znikną z puli.

Podtrzymywanie istniejących połączeń

Jeśli chcemy możemy poinstruować HikariCP, aby starało się trzymać połączenia jako “żywe”. W tym celu musimy ustawić parametr keepaliveTime, aby zapobiec timeoutowi połączenia z bazą danych albo z infrastrukturą sieciową. HikariCP co zdefiniowany czas będzie pingowało bezczynne połączenia, aby ich nie utracić. Oczywiście wartość parametru musi być niższa niż ta zdefiniowana w maxLifetime. Najmniejsza dopuszczalna wartość dla keepaliveTime wynosi 30000ms natomiast bardziej zalecany jest sekundowy rząd wielkości. Ta wartość domyślnie przyjmuje wartość zero (jest nieaktywna).

Dochodzimy do parametru maxLifetime. To on decyduje ile tak naprawdę wynosi cykl życia dla połączeń. Zalecane jest, aby jego wartość wynosiła o kilka sekund mniej niż obecny limit czasu dla danej bazy danych albo innej zależnej infrastruktury. W ten sposób zabezpieczamy się przed masowym “wymieraniem” połączeń w puli. Jeśli przyjmiemy wartość 0 to cykl życia będzie nieskończony (oczywiście zewnętrzne czynniki wpłyną na niego). Dozwolone minimum to 30 sekund, a domyślne ustawienie to 30 minut. Oczywiście przy jego dobieraniu trzeba pamiętać o idleTimeout.

Testowanie zapytanie i rozmiary

Dla sterowników nie obsługujących JDBC4 powstał parametr connectionTestQuery. W innych przypadkach nie warto go stosować. Dzięki niemu możemy wysłać testowe zapytanie, aby zweryfikować czy połączenie jest ciągle aktywne. Twórcy jednak polecają, aby najpierw uruchomić pulę bez tego parametru. Jeśli wsparcie dla JDBC4 nie jest obecne to HikariCP poinformuje nas o tym w konsoli.

minimumIdle służy do ustalenia minimalnej liczby bezczynnych połączeń w puli, które HikariCP będzie starało się utrzymać. Jeśli liczba takich połączeń spadnie poniżej tej wartości to nastąpi ich automatyczne dodanie w sposób jak najszybszy i najefektywniejszy. Twórcy natomiast zalecają, aby nie ustawiać minimumIdle i pozwolić HikariCP, aby zachowywał się jak pula o stałej wielkości. Z tego powodu jego wartość wynosi tyle co maximumPoolSize.

Przechodząc płynnie do maximumPoolSize. Jest to maksymalny rozmiar puli jaki chcemy mieć do dyspozycji. W ten sposób określamy maksymalną liczbę połączeń z bazą danych. W jej skład wchodzą aktywne oraz bezczynne połączenia. Jeśli ten rozmiar zostanie osiągnięty, a nie ma dostępnych żadnych bezczynnych połączeń to będzie następowała próba połączenia przez klienta aż do momentu uzyskania timeoutu określonego przez connectionTimeout. Warto zapoznać się z tym wpisem dotyczącym wielkości puli. Domyślnie wartość wynosi 10.

Podsumowanie

Mam nadzieję, że ten artykuł przybliżył Ci ideę stojącą za Hikari oraz dał pogląd na istotne parametry konfiguracyjne. Moim zdaniem naprawdę warto zagłębiać się w takie aspekty, aby wiedzieć co tak naprawdę wykorzystujemy do swojej pracy.

Try to learn something about everything and everything about something.

Thomas Huxley