Doskonałe pytanie. Walczę z tym pytaniem. Najczęstszą odpowiedzią na stackoverflow jest "To zależy..." dla praktycznie każdego problemu. Nienawidzę tego mówić, ale nigdzie nie jest to bardziej istotne niż podkręcanie puli połączeń. To naprawdę jest gra podaży i popytu, w której żądania połączenia to popyt, a podaż to liczba dostępnych połączeń MySQL. To naprawdę sprowadza się do tego, czy Twoim głównym problemem jest zapobieganie zwracaniu nieaktualnych połączeń z puli, czy też problemem jest upewnienie się, że MySQL nie jest przeładowany bezczynnymi połączeniami, ponieważ nie zabijasz ich wystarczająco szybko. Większość ludzi leży gdzieś pośrodku.
Jeśli naprawdę rozumiesz, dlaczego ktoś miałby wybrać dowolną konfigurację puli połączeń, uwierz mi, że przestaniesz szukać ustawienia „Rocket Solid”, ponieważ będziesz wiedział, że jest to jak szukanie w Google planu biznesowego dla Twojego sklepu; Jest to całkowicie zakorzenione w liczbie otrzymywanych żądań połączeń i liczbie trwałych połączeń, które chcesz udostępnić. Poniżej podaję przykłady, dlaczego warto korzystać z niektórych ustawień. Odnoszę się do zmiennych, które będziesz musiał zmienić w tagu „Resource” w tagu „Context” w twoim pliku Context.xml. Przykładową pełną konfigurację można zobaczyć na samym dole.
Mały ruch
W tej sytuacji masz niewiele żądań do swojej aplikacji, więc istnieje duża szansa, że WSZYSTKIE połączenia w Twojej puli połączeń staną się przestarzałe, a pierwsze żądanie Twojej aplikacji przez przestarzałe połączenie spowoduje błąd. (W zależności od sterownika MySQL, którego używasz, błąd może wyjaśniać, że ostatni pomyślnie odebrany pakiet przekroczył ustawienie wait_timeout bazy danych). Tak więc twoją strategią puli połączeń jest zapobieganie zwróceniu martwego połączenia. Poniższe dwie opcje mają niewielki efekt uboczny w przypadku witryny o małym natężeniu ruchu.
-
Poczekaj dłużej, zanim zabijesz połączenia - Zrobiłbyś to, zmieniając wartość
wait_timeout
w Twojej konfiguracji MySQL. W MYSQL workbench możesz łatwo znaleźć to ustawienie w Admnin> Plik konfiguracyjny> Sieć. W przypadku witryny o dużym natężeniu ruchu nie jest to często zalecane, ponieważ może prowadzić do tego, że pula zawsze będzie zapełniana dużą ilością nieaktywnych połączeń. Pamiętaj jednak, że jest to scenariusz małego ruchu. -
Przetestuj każde połączenie - Możesz to zrobić, ustawiając
testOnBorrow = true
ivalidationQuery= "SELECT 1"
. A co z wydajnością? W tej sytuacji masz mały ruch. Testowanie każdego połączenia zwróconego z puli nie stanowi problemu. Oznacza to jedynie, że do każdej transakcji MySQL, którą wykonujesz na pojedynczym połączeniu, zostanie dodane dodatkowe zapytanie. Czy na stronie o małym natężeniu ruchu naprawdę będziesz się martwić? Twoim głównym celem jest problem utraty połączeń w puli, ponieważ nie są one używane.
Średni ruch
- Sprawdzaj wszystkie połączenia okresowo - Jeśli nie chcesz testować każdego połączenia za każdym razem, gdy jest używane lub wydłużać czas oczekiwania, możesz okresowo testować wszystkie połączenia za pomocą domyślnego lub niestandardowego zapytania, które wybierzesz. Na przykład ustaw
validationQuery = "SELECT 1"
,testWhileIdle = "true"
itimeBetweenEvictionRunsMillis = "3600"
lub jakikolwiek interwał chcesz. W przypadku bardzo małego ruchu będzie to zdecydowanie wymagać więcej pracy. Pomyśl o tym. Jeśli masz 30 połączeń w puli i w ciągu godziny tylko 4 zostaną wywołane, możesz łatwo sprawdzić wszystkie 4 połączenia przy każdym żądaniu, używając poprzedniegotestOnBorrow
podejście z niewielkim uderzeniem w wydajność. Ale jeśli zamiast tego zastosujesz podejście „Sprawdź wszystko co godzinę”, wyślesz 30 żądań, aby sprawdzić wszystkie połączenia, gdy używane były tylko 4.
Duży ruch
- Zabij bezczynne połączenia wcześniej - Jest to sytuacja, w której wszyscy mówią, że nie należy przedłużać czasu oczekiwania i testować każdego połączenia. Nie jest to model idealny na każdą sytuację. Kiedy masz duży ruch, każde połączenie w puli zostanie wykorzystane, a Twoim rzeczywistym problemem będzie zwiększenie liczby dostępnych połączeń, podczas gdy w rzeczywistości skrócisz się
wait_time
więc nie kończysz wysyłania bezczynnych połączeń w DB. Oto przykład faceta opowiadającego o tym, że ma do 10 000 nieaktywnych połączeń dziennie dla ruchliwej witryny, więc chce obniżyć wait_timeout Skrócenie czasu oczekiwania na zajętą witrynę
Przykładowa konfiguracja Context.xml
<Context>
<Resource name="jdbc/TestDB"
auth="Container"
type="javax.sql.DataSource"
factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
testWhileIdle="true"
testOnBorrow="true"
testOnReturn="false"
validationQuery="SELECT 1"
validationInterval="30000"
timeBetweenEvictionRunsMillis="30000"
maxActive="100"
minIdle="10"
maxWait="10000"
initialSize="10"
removeAbandonedTimeout="60"
removeAbandoned="true"
logAbandoned="true"
minEvictableIdleTimeMillis="30000"
jmxEnabled="true"
jdbcInterceptors="org.apache.tomcat.jdbc.pool.interceptor.ConnectionState;
org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer"
username="root"
password="password"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3306/mysql"/>
</Context>
Przykładowa konfiguracja web.xml
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
version="2.4">
<description>MySQL Test App</description>
<resource-ref>
<description>DB Connection</description>
<res-ref-name>jdbc/TestDB</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
</web-app>
Dokumentacja dotycząca właściwości puli Tomcat, aby dostosować pulę Tomcat