Hintergrund: Ich habe kürzlich einen Stresstest auf einem neu entwickelten Springboot-System durchgeführt. Als ich den Stresstest zum ersten Mal startete, konnte ich jedoch nach ein paar Minuten Pause normal darauf zugreifen Ich habe jmeter weiterhin verwendet, um den Stresstest durchzuführen. Plötzlich tauchte wie verrückt eine ungewöhnliche Meldung auf: Befehl ist nach 6 Sekunden abgelaufen ...
1 Caused by: io.lettuce.core.RedisCommandTimeoutException: Command timed out after 6 second(s) 2 at io.lettuce.core.ExceptionFactory.createTimeoutException(ExceptionFactory.java:51) 3 at io.lettuce.core.LettuceFutures.awaitOrCancel(LettuceFutures.java:114) 4 at io.lettuce.core.cluster.ClusterFutureSyncInvocationHandler.handleInvocation(ClusterFutureSyncInvocationHandler.java:123) 5 at io.lettuce.core.internal.AbstractInvocationHandler.invoke(AbstractInvocationHandler.java:80) 6 at com.sun.proxy.$Proxy134.mget(Unknown Source) 7 at org.springframework.data.redis.connection.lettuce.LettuceStringCommands.mGet(LettuceStringCommands.java:119) 8 ... 15 common frames omitted
Ich habe eilig den Redis-Cluster überprüft und festgestellt dass alle Knoten im Cluster normal waren und die CPU- und Speicherauslastung weniger als 100 % betrug. Als ich mir das alles ansah, geriet ich plötzlich in eine lange Überlegung, was genau das Problem ist ... Nach der Suche auf Baidu, Ich habe festgestellt, dass viele Leute ähnliche Situationen erlebt haben. Einige Leute sagten, dass das Setzen des Timeouts auf einen größeren Wert das Problem lösen kann. Ich habe diese Lösung befolgt und den Timeout-Wert auf einen größeren Wert gesetzt, aber das Timeout-Problem wurde immer noch nicht gelöst.
Unter diesen ist das Abhängigkeitspaket für Springboot zum Betrieb von Redis –
1 <dependency> 2 <groupId>org.springframework.boot</groupId> 3 <artifactId>spring-boot-starter-data-redis</artifactId> 4 </dependency>
Cluster-Konfiguration – –
1 redis: 2 timeout: 6000ms 3 cluster: 4 nodes: 5 - xxx.xxx.x.xxx:6379 6 - xxx.xxx.x.xxx:6379 7 - xxx.xxx.x.xxx:6379 8 jedis: 9 pool: 10 max-active: 1000 11 max-idle: 10 12 min-idle: 5 13 max-wait: -1
Klicken Sie auf Spring-Boot-Starter-Data-Redis und stellen Sie fest, dass es die Abhängigkeit von Salat enthält:
springboot1 .x verwendet standardmäßig jedis und Springboot2.x verwendet standardmäßig Salat. Wir können einfach überprüfen, ob in der Redis-Treiberladekonfigurationsklasse die RedisConnectionFactory-Informationen ausgegeben werden:
1 @Configuration 2 @AutoConfigureAfter(RedisAutoConfiguration.class) 3 public class Configuration { 4 @Bean 5 public StringRedisTemplate redisTemplate(RedisConnectionFactory factory) { 6 log.info("测试打印驱动类型:"+factory); 7 }
Druckausgabe -
测试打印驱动类型:org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory@74ee761e
Es ist ersichtlich, dass hier die Salattreiberverbindung verwendet wird, also beim Ersetzen durch die vorherige Wenn Wenn mehr Jedis-Treiber angeschlossen sind, ist dieser Befehl nach 6 Sekunden abgelaufen. Das Problem tritt nicht mehr auf.
1 <dependency> 2 <groupId>org.springframework.boot</groupId> 3 <artifactId>spring-boot-starter-data-redis</artifactId> 4 <exclusions> 5 <exclusion> 6 <groupId>io.lettuce</groupId> 7 <artifactId>lettuce-core</artifactId> 8 </exclusion> 9 </exclusions> 10 </dependency> 11 <dependency> 12 <groupId>redis.clients</groupId> 13 <artifactId>jedis</artifactId> 14 </dependency>
Dann ist die Frage, wie Springboot2.x standardmäßig Salat verwendet. Wir müssen einen Teil des darin enthaltenen Codes studieren. Wir können den Redis-Teil von Springboot2 eingeben. Dies bedeutet, dass bei Verwendung der Spring-Boot-Starter-Data-Redis-Abhängigkeit sowohl Salat- als auch Jedis-Treiber automatisch importiert werden können , was wenig Sinn ergibt. Daher ist die Reihenfolge hier sehr wichtig. Warum sagen Sie das?
Geben Sie LettuceConnectionConfiguration.class bzw. JedisConnectionConfiguration.class ein und jeder zeigt den für diesen Artikel erforderlichen Kerncode an:
1 @Configuration( 2 proxyBeanMethods = false 3 ) 4 @ConditionalOnClass({RedisOperations.class}) 5 @EnableConfigurationProperties({RedisProperties.class}) 6 @Import({LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class}) 7 public class RedisAutoConfiguration { 8 public RedisAutoConfiguration() { 9 } 10 ......省略 11 }
Es ist ersichtlich, dass LettuceConnectionConfiguration.class und JedisConnectionConfiguration.class dieselbe Annotation haben @ConditionalOnMissingBean({RedisConnectionFactory.class } ), bedeutet dies, dass, wenn die RedisConnectionFactory-Bean im Container registriert wurde, andere ähnliche Beans nicht mehr geladen und registriert werden. Einfach ausgedrückt: Fügen Sie die Annotation @ConditionalOnMissingBean({RedisConnectionFactory. class}) hinzu, nur eine davon Zwei können in den Container geladen und registriert werden, der andere wird nicht erneut geladen und registriert.
Dann stellt sich die Frage: Wer wird zuerst registriert?
Dies geht auf den oben genannten Satz zurück, die Reihenfolge im Satz @Import({LettuceConnectionConfiguration.class}) ist entscheidend, was bedeutet, dass LettuceConnectionConfiguration registriert wird.
Es ist ersichtlich, dass Springboot standardmäßig Salat verwendet, um eine Verbindung zu Redis herzustellen.
Wenn wir das Spring-Boot-Starter-Data-Redis-Abhängigkeitspaket einführen, entspricht dies tatsächlich der Einführung des Salatpakets. Zu diesem Zeitpunkt wird der Salattreiber verwendet. Wenn Sie nicht den Standardsalattreiber verwenden möchten , können Sie die Salatabhängigkeit direkt ausschließen.
1 2 @Import({LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class}) 3
Führen Sie dann die Jedis-Abhängigkeit ein –
1 //LettuceConnectionConfiguration 2 @ConditionalOnClass({RedisClient.class}) 3 class LettuceConnectionConfiguration extends RedisConnectionConfiguration { 4 ......省略 5 @Bean 6 @ConditionalOnMissingBean({RedisConnectionFactory.class}) 7 LettuceConnectionFactory redisConnectionFactory(ObjectProvider<LettuceClientConfigurationBuilderCustomizer> builderCustomizers, ClientResources clientResources) throws UnknownHostException { 8 LettuceClientConfiguration clientConfig = this.getLettuceClientConfiguration(builderCustomizers, clientResources, this.getProperties().getLettuce().getPool()); 9 return this.createLettuceConnectionFactory(clientConfig); 10 } 11 } 12 //JedisConnectionConfiguration 13 @ConditionalOnClass({GenericObjectPool.class, JedisConnection.class, Jedis.class}) 14 class JedisConnectionConfiguration extends RedisConnectionConfiguration { 15 ......省略 16 @Bean 17 @ConditionalOnMissingBean({RedisConnectionFactory.class}) 18 JedisConnectionFactory redisConnectionFactory(ObjectProvider<JedisClientConfigurationBuilderCustomizer> builderCustomizers) throws UnknownHostException { 19 return this.createJedisConnectionFactory(builderCustomizers); 20 } 21 } 22
Was ist der Unterschied zwischen Salat und Jedis? Salat: Die unterste Ebene ist in Netty implementiert, threadsicher und verfügt standardmäßig nur über eine Instanz.
jedis: Kann direkt mit dem Redis-Server verbunden und mit dem Verbindungspool verwendet werden, um physische Verbindungen zu erhöhen.
Suchen Sie die Fehlermethode gemäß der Ausnahmeaufforderung. Im folgenden Code soll LettuceConverters.toBoolean(this.getConnection().zadd(key, score, value))——
1 <dependency> 2 <groupId>org.springframework.boot</groupId> 3 <artifactId>spring-boot-starter-data-redis</artifactId> 4 <exclusions> 5 <exclusion> 6 <groupId>io.lettuce</groupId> 7 <artifactId>lettuce-core</artifactId> 8 </exclusion> 9 </exclusions> 10 </dependency>
Das obige ist der detaillierte Inhalt vonSo lösen Sie die Timeout-Ausnahme, wenn Springboot2.x Salat integriert und eine Verbindung zum Redis-Cluster herstellt. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!