Redis cluster
μ€νλ§ λΆνΈ μ°κ²°π€μ€νλ§ λΆνΈμμ
redis cluster
λ₯Ό μ°κ²°νλ λ°©λ²μλ μ¬λ¬κ°μ§κ° μμ΅λλ€. μ¬κΈ°μλ κΈ°λ³Έμ μΈ λ°©μμΌλ‘ μ°κ²°ν΄λ³΄κ² μ΅λλ€.
π
redis
λ₯Ό μ°κ²°νκΈ° μν΄μ λ¨Όμ redis
μ κ΄ν μ 보λ₯Ό μ€νλ§ λΆνΈμ μ λ¬μ ν΄μ£Όμ΄μΌ ν©λλ€.
λ¨Όμ ymlμ ν΄λΉ μ 보λ€μ λ£μ΄μ£Όκ² μ΅λλ€.
spring:
data:
redis:
cluster:
max-redirects: 3
password: 1111
connect-ip: 172.17.0.1
nodes: 172.17.0.1:7000, 172.17.0.1:7001,172.17.0.1:7002,172.17.0.1:7003,172.17.0.1:7004,172.17.0.1:7005
π« μ¬κΈ°μ nodesμ κ²½μ° μμ μ΄ μ¬μ©νλ
redis
μ μ£Όμλ₯Ό λ£μ΄μ£Όλ©΄ λ©λλ€.(μ λ λ컀λ₯Ό νμ©νμ¬ λμ°κ³ μκΈ°μ μμ κ°μ μ£Όμλ₯Ό μ¬μ©νμμ΅λλ€.)μ΄μ RedisInfo classλ₯Ό λ§λ€μ΄μ ν΄λΉ μ 보λ€μ λ겨 μ£Όκ² μ΅λλ€.
@Getter
@Setter
@NoArgsConstructor
@ConfigurationProperties(prefix = "spring.data.redis.cluster")
@Configuration
public class RedisInfo {
private int maxRedirects;
private String password;
private String connectIp;
private List<String> nodes;
}
π§νλ‘νΌν° κ°λ€μ ν΄λΉ ν΄λμ€κ° λ°μ μ μλλ‘
@ConfigurationProperties(prefix = "spring.data.redis.cluster")
λ₯Ό μ¬μ©νμμ΅λλ€.
μ΄μ μ΄ κ°μ μ΄μ©νμ¬ config classλ₯Ό μμ±νκ² μ΅λλ€.
πμμμ λ°μμ¨ κ°λ€μ
redis
μ€μ κ°μΌλ‘ μ΄μ©ν μ μκ² ν΄λΉ κ°λ€μ λκ²¨μ£Όκ² μ΅λλ€.RedisClusterConfiguration
classλ₯Ό ν΅ν΄ ν΄λΉ κ°λ€μ λ겨주면 κΈ°λ³Έμ μΈ μ€μ μ΄ μλ£λ©λλ€.
@RequiredArgsConstructor
@Configuration
public class RedisProdConfig {
private final RedisInfo redisInfo;
@Bean
public RedisConnectionFactory redisConnectionFactory() {
RedisClusterConfiguration redisClusterConfiguration = new RedisClusterConfiguration(redisInfo.getNodes());
redisClusterConfiguration.setPassword(redisInfo.getPassword());
redisClusterConfiguration.setMaxRedirects(redisInfo.getMaxRedirects());
}
new RedisClusterConfiguration(redisInfo.getNodes());
λ₯Ό ν΅ν΄ ν΄λΉ redis nodesλ€μ μ£Όμλ₯Ό λ겨μ€λλ€.
setPassword()
λ₯Ό ν΅ν΄ passwordλ₯Ό μ€μ ν΄μ£Όλλ° passwordλ₯Ό μ€μ νμ§ μμλ€λ©΄ μμ±νμ§ μμΌμ λ λ©λλ€.redirectλ₯Ό μ€μ ν μ΄μ μ λν΄μλ λ¨Όμ
redis clsuter
μ λν΄μ μμ μΌ ν©λλ€.π₯³
redis clsuter
λ μλμΌλ‘ λ°μ΄ν°λ€μ λΆμ° μ μ₯νκ³ μλλ° λ§μ½ 1μ΄λΌλ κ°μ μ°ΎμΌλ €κ³ νλ κ²½μ° ν΄λΉ λ Έλμ κ°μ΄ μλ€λ©΄ redirectλ₯Ό ν΅ν΄ λ€λ₯Έ λ Έλμμ μ°ΎμμμΌ ν©λλ€. μ΄λ₯Ό μ€μ νμ§ μλλ€λ©΄ 무ν redirectκ° λμ΄ μ±λ₯μ μ μ’μ μν₯μ λ―ΈμΉκΈ°μ μ€μ ν΄μ£Όμμ΅λλ€.
κΈ°λ³Έκ°μ 3μΌλ‘ μ§μ λμ΄ μμ΅λλ€.
π«‘μ¬μ€ μμ κ³Όμ κΉμ§ μ§νλμλ€λ©΄ μ°κ²°μλ μ±κ³΅μ ν κ²μ λλ€. κ·Έλ¬λ
redis cluster
λ₯Ό μ¬μ©νλ μ΄μ μλ κ³ κ°μ©μ±μ ν보νκΈ° μν΄μμΈλ° μ€μ λ‘ μ€νλ§ λΆνΈλ₯Ό μ€νν΄ λ³΄κ³ λμ λ§μ€ν° λ Έλ μ€ νλλ₯Ό μ°κ²°μ λμ΄λ²λ¦°λ€λ©΄ κ°μκΈ° λͺ¨λ μ°κ²°μ΄ λμ΄μ§λ μν©μ΄ λ°μν©λλ€.μ΄λ₯Ό λ§κΈ° μν΄μλ
Topology
λ₯Ό μ€μ ν΄μ£Όμ΄μΌ ν©λλ€. λ μμΈν λ΄μ©μ μ΄λ³΄ κ°λ°μλ₯Ό μν Redis Cluster Migration κ°μ΄λλΌμΈλ₯Ό ν΅ν΄ νμΈ νμ€ μ μμ΅λλ€.λ¨Όμ μλμ κ°μ΄ μμ±ν΄μ€λλ€.
ClusterTopologyRefreshOptions clusterTopologyRefreshOptions = ClusterTopologyRefreshOptions.builder()
.enableAllAdaptiveRefreshTriggers()
.enablePeriodicRefresh(Duration.ofHours(1L))
.build();
ClientOptions clientOptions = ClusterClientOptions.builder()
.topologyRefreshOptions(clusterTopologyRefreshOptions)
.build();
ClusterTopologyRefreshOptions
λ λ³κ²½ μ¬νμ μ΄λ»κ² κ°μ§νκ³ λ°μν μ§λ₯Ό μ€μ νλ ν΄λμ€μ λλ€.
enableAllAdaptiveRefreshTriggers()
λ λ Έλλ€μ μν λ³νκ° λ°μνλ©΄ ν΄λΉ λ΄μ©μ λ°μνλ μ€μ μ λλ€.(μ½κ² λ§ν΄ λͺ¨λ λ³κ²½(μμ , μΆκ°...)μ λν΄μ μ ν΄λΉ μ΅μ μ μ€ννλ€λΌκ³ μ΄ν΄νμλ©΄ λ©λλ€.)
enablePeriodicRefresh()
λ μ£ΌκΈ°μ μΌλ‘ λ Έλλ€μ μνλ₯Ό νμΈνλ λ©μλμ λλ€.π₯³μμ κ°μ΄ μ€μ ν ν ν΄λΉ optionλ€μ
ClientOptions
μ λ£μ΄μ€λλ€.
π«
configuration
μ μ client optionμ λ£μ΄μ£Όλ©΄ ν΄λΉ μ€μ λ€μ΄ μ μ©λκ² λ©λλ€.
μ μ© λ°©λ²μ μλμ κ°μ΅λλ€.
LettuceClientConfiguration clientConfiguration = LettuceClientConfiguration.builder()
.clientOptions(clientOptions)
.readFrom(ReadFrom.REPLICA_PREFERRED)
.build();
Lettuce
λ springμμ μ§μνλ λΌμ΄λΈλ¬λ¦¬μ λλ€.π₯³μ΄μ μ κ°μ μ€μ ν factoryλ₯Ό λ°ννκ³ μ¬μ©ν΄μ£Όμλ©΄ λ©λλ€.
LettuceConnectionFactory connectionFactory =
new LettuceConnectionFactory(redisClusterConfiguration)
return connectionFactory;
π€μ
redisCluster
μ€μ μ λ§μΉμ ¨λ€λ©΄ localμμλ μ¬μ©ν μ μλ μνκ° λ©λλ€.
κ·Έλ¬λ ν΄λΉcluster
μ€μ μ κ·Έλλ‘ μ¬μ©νμ€ κ²½μ° cloud νκ²½μμ μλμ μνκ² λ©λλ€.κ·Έ μ΄μ λ‘λ redis host,port μ€μ μ ν΄μ£Όμ§ μμκΈ° λλ¬Έμ λλ€. Topology refresh trying to connect to 127.0.0.1 #1289 μμ ν΅ν΄ ν΄λΉ λ¬Έμ κ° λ°μν μ΄μ μ κ·Έ ν΄κ²° λ°©λ²μ νμΈ ν μ μμμ΅λλ€.
π§ν΄λΉ κΈμμλ μ€μ μ΄ μλͺ»λμ μκΈ΄ λ¬Έμ κ° μλλ©° ν΄λΉ μ£Όμλ₯Ό μ¬μ€μ ν΄μ£Όλ©΄ ν΄κ²° ν΄ μ€ μ μλ€κ³ μ°μ¬μμ΅λλ€.μ¬μ€μ νλ λ°©λ²μ μλμ κ°μ΄ κ°μ΅λλ€.
MappingSocketAddressResolver resolver = MappingSocketAddressResolver.create(DnsResolvers.UNRESOLVED,
hostAndPort -> {
HostAndPort andPort = HostAndPort.of(redisInfo.getConnectIp(), hostAndPort.getPort());
return andPort;
}
);
πλ§μ½ μ μ€μ μ ν΄μ£Όμ§ μμ κ²½μ° localhostλ‘ λμμ νκ² λλλ° μ μ κ²½μ° λμ»€λ‘ λμ΄ μν©μ΄μ¬μ localhostλ‘ νκ² λλ©΄ ν΅μ μλλ μν©μ΄μμ΅λλ€. κ·Έλμ μ΄λ₯Ό ν΄κ²° νκΈ° μν΄ docker.hostλ‘ μ°κ²°νλ λ°©μμ μ¬μ©νμμ΅λλ€.
π
MappingSocketAddressResolver
λ₯Ό λ§λ€μ΄ μ€ ν hostμ κ²½μ° λ컀 νΈμ€νΈλ‘ 보λ΄κ³ portμ κ²½μ°μλ μμ²ν κ° κ·Έλλ‘ λ°μμ μ ν΄μ£Όμμ΅λλ€.λ€μ μ μ€μ κ°μ
ClientResources
λ£μ΄μ€ νLettuceClientConfiguration
μ λ£μ΄μ£Όλ©΄ λ©λλ€.
ClientResources clientResources = ClientResources.builder()
.socketAddressResolver(resolver)
.build();
LettuceClientConfiguration clientConfiguration = LettuceClientConfiguration.builder()
.commandTimeout(Duration.of(10, ChronoUnit.SECONDS))
.clientOptions(clientOptions)
.clientResources(clientResources) <--- μΆκ°
.readFrom(ReadFrom.REPLICA_PREFERRED)
.build();
μ΄λ κ² λλ©΄
redis clsuter
μ°κ²°μ΄ μμ±λκ² λ©λλ€.
π₯³κ³ κ°μ©μ±μ ν보 νκΈ° μν΄
redis cluster
λ₯Ό μ¬μ©νμλλ° κ³ κ°μ©μ±μ ν보νλ λ°©λ²μλ λ€μν λ°©λ²μ΄ μμ΅λλ€.
aws, ncp, gcpμμredis cloud
λ₯Ό μ§μνλ©°redis
λ₯Όsentinel
λ‘ μ°κ²°νλ λ°©λ²λ μμ΅λλ€.
λ§μ½ μ¬μ κ° λμ λ€λ©΄ μμ λ°©μλ νλ² μλν΄ λ³΄μλ κ²λ μ’μ κ² κ°μ΅λλ€.
π₯springμμλ νΈλμμ μ μ¬μ©νκΈ° νΈνκ² νκΈ° μν΄
setEnableTransactionSupport()
λΌλ λ©μλλ₯Ό μ§μνλλ°redis cluster
λ₯Ό μ¬μ©νλ κ²½μ° ν΄λΉ λ©μλλ₯Ό μ΄μ©ν μ μκ² λ©λλ€.
redis clsuter
μμλmulit
μ°μ°μ μ§μνμ§ μκΈ° λλ¬ΈμΈλ° μ΄λ₯Ό ν΄κ²°νλ λ°©λ²μλ κ°μ nodeμ κ°λ€μ΄ μμΉνλ©΄ λλ€λλ° μ λ μ μλλλΌκ³ μ... νΉμ μμλ λΆμ΄ μμΌλ©΄ λκΈλ‘ μλ €μ£Όμλ©΄ κ°μ¬ν©λλ€.π
μ΄λ³΄ κ°λ°μλ₯Ό μν Redis Cluster Migration κ°μ΄λλΌμΈ
Topology refresh trying to connect to 127.0.0.1 #1289