Thenusan Santhirakumar
Thenusan SanthirakumarSoftware Engineer Intern

Jedis, czyli pule połączeń Redisa w Javie

Sprawdź, jak komunikować się z Redisem z wielu wątków w tym samym czasie na konkretnych przykładach.
4.11.20214 min
Jedis, czyli pule połączeń Redisa w Javie

Pula połączeń oznacza, że połączenia są ponownie wykorzystywane, a nie tworzone za każdym razem, gdy połączenie jest żądane. Aby ułatwić ponowne wykorzystanie połączeń, pamięć podręczna połączeń z baz danych, zwana pulą połączeń, jest utrzymywana przez moduł puli połączeń jako osobna warstwa. Nawiązywanie połączenia jest wykonywane w tle i nie ma wpływu na sposób kodowania aplikacji.

Jedis

Nauczymy się tworzyć pule połączeń Redis poprzez klienta Redisa w Javie o nazwie Jedis.

Istnieją pewne obawy związane z używaniem Redisa w środowisku wielowątkowym. Instancja połączenia Redis jest jednowątkowa. Jeśli ponownie użyjemy jednowątkowego połączenia Redis pomiędzy wieloma wątkami, będzie to blokować inne wątki do czasu, aż jeden z nich zakończy połączenie. Jeśli utworzymy osobne połączenie Redis dla wątku, będzie to stanowiło obciążenie dla serwera Redis.

Musimy mieć pulę połączeń w środowiskach wielowątkowych, aby sprostać tym wyzwaniom. Pozwala to komunikować się z Redisem z wielu wątków, jednocześnie uzyskując korzyści płynące z ponownego użycia połączeń. Obiekt JedisPool jest thread-safe i może być używany z wielu wątków w tym samym czasie. Chodzi o to, żeby pobrać połączenie z puli i zwolnić je z powrotem do puli, gdy już skończymy. Pula ta powinna być skonfigurowana raz i może być wielokrotnie używana.

Konfiguracja puli Jedis

Przed użyciem puli, musimy skonfigurować początkowe ustawienia odpowiednio do naszych potrzeb. Po kolei wyjaśnię właściwości konfiguracji początkowej.

  1. maxTotal: ta właściwość zarządza maksymalną liczbą połączeń, które mogą być wykorzystywane w danym czasie. Ponieważ połączenia Jedis nie mogą być współdzielone pomiędzy wątkami, to ustawienie wpływa na poziom współbieżności, jaki może mieć Twoja aplikacja podczas interakcji z Redis. Zauważ, że każde połączenie ma pewien koszt pamięci i procesora, więc ustawienie tej wartości na bardzo wysoką może mieć negatywne konsekwencje. Jeśli nie jest ustawiona, domyślną wartością jest 8, która jest zbyt niska dla większości aplikacji. Przy wyborze wartości należy rozważyć ile równoczesnych wywołań do Redisa może być możliwych przy dużym obciążeniu.
  2. maxIdle: jest to maksymalna liczba połączeń, które mogą być bezczynne w puli i pozostać otwarte. Jeśli nie jest ustawiona, domyślną wartością jest 8. Sugerowana wartość jest taka sama jak dla maxTotal, w celu uniknięcia niepotrzebnego otwierania i zamykania połączeń. Jeśli połączenie jest bezczynne przez dłuższy czas, zostanie ono eksmitowane, jeśli liczba bezczynnych połączeń nie osiągnie minIdle, które wyjaśniam poniżej.
  3. minIdle: jest to liczba połączeń, które są gotowe do natychmiastowego użycia. Pozostają one w puli nawet po zmniejszeniu poziomu obciążenia. Jeśli nie jest ustawiona, domyślną wartością jest 0. Wybierając wartość należy wziąć pod uwagę jednoczesne żądania do Redisa w stanie ustalonym. Na przykład, jeśli Twoja aplikacja wywołuje do Redis z 10 wątków jednocześnie, powinieneś ustawić tę wartość na co najmniej 10 (trochę wyższą, aby mieć jeszcze trochę miejsca).
  4. blockWhenExhausted: to ustawienie kontroluje zachowanie, gdy wątek prosi o połączenie, ale nie ma żadnych wolnych, i pula nie może utworzyć więcej (z powodu konfiguracji maxTotal). Jeśli ustawione na true, wątek wywołujący zablokuje się na maxWaitMillis przed rzuceniem wyjątku. Domyślnie jest to true i naprawdę polecam taką wartość dla środowisk produkcyjnych. Możesz ustawić ją na false w środowiskach testowych, aby łatwiej było Ci odkryć, jakiej wartości użyć dla maxTotal.
  5. maxWaitMillis: czas oczekiwania w milisekundach jeśli wywołanie JedisPool.getResource() się zablokuje. Domyślnie -1, co oznacza blokowanie na czas nieokreślony.
  6. TestOnBorrow: kontroluje czy połączenie jest testowane przed zwróceniem go z puli. Domyślnie ustawiona jest wartość false. Ustawienie na true może zwiększyć odporność na nagłe zmiany połączeń, ale może mieć także swój koszt wydajnościowy przy pobieraniu połączeń z puli.

Zastanówmy się więc dwa razy, zanim ustawimy te parametry w konfiguracji połączeń puli.

Przykładowy kod konfiguracji puli

private JedisPool getJedisInstance() throws JedisConnectionException {

        try {
            if (pool == null) {
                synchronized (RedisStore.class) {
                    if (pool == null) {
                        pool = new JedisPool(getPoolConfig(), HOST, PORT);
                    }
                }
            }
            return pool;
        } catch (JedisConnectionException e) {
            log.error(e);
        }
        return null;
    }

    private GenericObjectPoolConfig getPoolConfig() {

        GenericObjectPoolConfig jedisPoolConfig = new GenericObjectPoolConfig();
        jedisPoolConfig.setMaxTotal(100);
        jedisPoolConfig.setMaxIdle(100);
        jedisPoolConfig.setMinIdle(10);
        jedisPoolConfig.setMaxWaitMillis(2000);
        jedisPoolConfig.setBlockWhenExhausted(true);
        jedisPoolConfig.setTestOnBorrow(true);
        

        return jedisPoolConfig;
    }


Możemy pozostawić niektóre konfiguracje, jeśli nie chcemy zmieniać ich wartości domyślnych. Poprzez wywołanie poniższego kodu uzyskamy instancję Jedis.

jedisInstance = getJedisInstance().getResource()


Nasze przechowywanie i pobieranie możemy kontynuować za pomocą obiektu jedisInstance.

Mam nadzieję, że zrozumieliście dzisiejszy temat. Jeśli macie jakieś wątpliwości lub chcielibyście cokolwiek dopowiedzieć, nie wahajcie się skontaktować ze mną poprzez sekcję odpowiedzi. Dzięki za poświęcony czas! Cześć!

Oryginał tekstu w języku angielskim przeczytasz tutaj.

<p>Loading...</p>