spring-data-redis의 LettuceConnectionFactory에 setEnableTransactionSupport(boolean) 메서드가 있다.

 

기본값은 false인데, true로 설정하면 트랜잭션을 사용할 수 있게 된다. 그런데 이는 트랜잭션을 지원한다는 의미이지, JDBC처럼 트랜잭션 처리를 알아서 해준다는 의미가 아니다. 

 

레디스에서 트랜잭션을 처리는 MULTI-EXEC 를 사용하여 이루어지는데, 당연하게도 한 트랜잭션은 하나의 커넥션이 MULTI 에서 EXEC 까지 모두 수행해야 한다. setEnableTransactionSupport 는 그것을 돕는다.

 

이 값이 false 이면, MULTI-SET-EXEC 를 호출하면 다음과 같이 동작한다:

getConnection: 커넥션A 획득

MULTI

close

getConnection: 커넥션 B 획득

SET

close

getConnection: 커넥션 C 획득

EXEC

close

 

MULTI 를 포함하여 모든 오퍼레이션이 다른 커넥션에서 호출된다. 마지막 EXEC 에서는 'EXEC without MULTI' 에러가 떨어진다. MULTI 없이 EXEC를 호출했다는 의미이다. 다른 커넥션에서 호출했었으니 하나의 트랜잭션으로 이어지지 않는다.

 

setEnableTransactionSupport 이 true 이면 위 오퍼레이션은 다음과 같이 동작한다:

getConnection: 커넥션A 획득

MULTI

getConnection: 커넥션A 획득

SET

getConnection: 커넥션A 획득

EXEC

 

이와 같이 MULTI에서부터 EXEC 까지의 오퍼레이션을 한 커넥션에 묶어준다. 위 동작의 배경은 LettuceConnection을 가지고 있는 RedisConnectionHolder를 생성하여 스프링의 TransactionSynchronizationManager에 리소스로 바인딩하는 방식을 취한다. JDBC 트랜잭션 관리와 마찬가지로 쓰레드에 자신이 사용할 커넥션을 묶어두는 것이다.

'Redis' 카테고리의 다른 글

Spring-Lettuce 커넥션 풀링 시 shareNativeConnection  (3) 2020.09.02
Lettuce 센티넬 failover 테스트  (0) 2020.09.01

spring-data-redis, Lettuce 사용 시, non-blocking, non-transactional 오퍼레이션은 커넥션 풀을 설정해도 하나의 포트로만 통신한다.

 

이 동작은 LettuceConnectionFactory 의 shareNativeConnection 값에 따라 달라진다. 이 값은 네이티브 커넥션을 공유해서 사용할지 여부를 가리킨다. 기본값이 true 이기에 non-blocking, non-transactional 오퍼레이션은 하나의 커넥션으로만 통신한다. MULTI 를 통해 트랜잭션을 시작하면 새로운 dedicated 커넥션이 할당되어 이것으로 통신한다.

 

언뜻 보기에 이 값을 false로 두고 커넥션 풀을 사용하여 오퍼레이션에 사용되는 커넥션을 분산하면 레디스 처리량이 올라가 성능이 좋아질 것 같지만, 레디스 자체가 싱글 쓰레드로 작동하기 때문에 실제로는 그렇지 않다고 한다. 스프링 부트 github에 부트 레벨에서 이 값을 false 로 설정할 수 있도록 해달라는 issue가 있었는데, 이와 같은 이유로 거부되었다:

 

github.com/spring-projects/spring-boot/issues/14196

 

Allow the ability to set shareNativeConnection to false for LettuceConnectionFactory · Issue #14196 · spring-projects/spring-b

By default, the LettuceConnection will use the sharedConnection for almost all non-tx or non-blocking operations. I have found the exclusive use of the shared connection to not allow very high thro...

github.com

 

이런 이유로, 스탠드얼론 레디스를 사용할 때 트랜잭션을 사용하지 않는다면 커넥션 풀을 사용할 이유가 없다.

 

 

출처:

docs.spring.io/spring-data/data-redis/docs/current/reference/html/#reference

'Redis' 카테고리의 다른 글

Spring-Lettuce setEnableTransactionSupport  (0) 2020.09.02
Lettuce 센티넬 failover 테스트  (0) 2020.09.01

spring-data-redis 1.7.111RELEASE

lettuce-3.5.0.Final

Redis 5.0

 

1 master - port 6379

3 replicas - port 6380, 6381, 6382

3 sentinels - port 26379, 26380, 26381

 

빈 설정

 

첫 연결 수립

로그 상단을 보면 아래와 같이, 3 개의 센티넬 주소 중 하나로 접근한다고 하는데, 여러 번 시도했지만 항상 첫 번째 주소인 26379 포트로만 접근했다. 순서대로 접근 시도하면서 센티넬이 응답하지 않는 경우 다음 센티넬로 넘어간다. 정상적으로 응답하는 센티넬을 찾으면 나머지 센티넬로는 요청을 보내지 않았다.

Trying to get a Sentinel connection for one of: [RedisURI [host='127.0.0.1', port=26379], RedisURI [host='127.0.0.1', port=26380], RedisURI [host='127.0.0.1', port=26381]]

 

로그 하단에서는 SENTINEL 커맨드를 통해 마스터 호스트를 얻는다:

Decoded Command [type=SENTINEL, output=ValueListOutput [output=[127.0.0.1, 6379], error='null']] ...

 

마스터로의 연결 수립

 

마스터 fails

마스터와 연결이 끊어져도 failover가 수행되기 전까지는 계속 연결 시도한다.

 

마스터와 연결이 끊어지자, 다시 센티넬로 연결하여 새로운 마스터 정보를 조회하는데, failover가 완료되기 전까지는 기존 마스터 정보를 반환한다.

 

Failover 완료 후

센티넬이 failover를 완료하고 새로운 마스터 주소(포트 6381)를 반환한다.

 

새 마스터로의 연결 정상 수립.

 

 

NOTE:

- 센티넬이 죽으면 다음 센티넬로 연결한다.

- quorum 값을 2로 하여 3 개의 센티넬이 구동했다가 2 개의 센티넬이 죽으면 failover가 수행되지 못한다. 1 개의 센티넬만 죽으면 failover는 수행되었다. 센티넬의 상태와 상관없이 vote 수를 채우면 failover에는 문제가 없는 것 같다.

+ Recent posts