Redis 连接在 Vert.x 3.9.4 上丢失

Redis connection lost on Vert.x 3.9.4

根据Vert.x documentation

vertx-redis-client升级到版本3.9.4

需要更新连接代码以符合新版本。 代码基于上述文档中的示例,如下所示:

Redis.createClient(vertx, redisOptions).connect(onConnect -> {
    if (onConnect.succeeded()) {
        RedisConnection client = onConnect.result();
        RedisAPI redis = RedisAPI.api(client);
        vertx.getOrCreateContext().put("redis", redis);
    }
});

但一个小时后(或多或少),我的连接丢失并出现以下错误堆栈跟踪:

io.vertx.redis.client.impl.ConnectionManager lambda$static[=12=] - Unhandled Error
java.nio.channels.ClosedChannelException 
at io.netty.channel.AbstractChannel$AbstractUnsafe.newClosedChannelException(AbstractChannel.java:957)
at io.netty.channel.AbstractChannel$AbstractUnsafe.write(AbstractChannel.java:865) 
at io.netty.channel.DefaultChannelPipeline$HeadContext.write(DefaultChannelPipeline.java:1367) 
at io.netty.channel.AbstractChannelHandlerContext.invokeWrite0(AbstractChannelHandlerContext.java:717) 
at io.netty.channel.AbstractChannelHandlerContext.invokeWriteAndFlush(AbstractChannelHandlerContext.java:764) 
at io.netty.channel.AbstractChannelHandlerContext.write(AbstractChannelHandlerContext.java:790) 
at io.netty.channel.AbstractChannelHandlerContext.writeAndFlush(AbstractChannelHandlerContext.java:758) 
at io.vertx.core.net.impl.ConnectionBase.write(ConnectionBase.java:124) 
at io.vertx.core.net.impl.ConnectionBase.writeToChannel(ConnectionBase.java:205) 
at io.vertx.core.net.impl.NetSocketImpl.writeMessage(NetSocketImpl.java:130) 
at io.vertx.core.net.impl.NetSocketImpl.write(NetSocketImpl.java:174) 
at io.vertx.core.net.impl.NetSocketImpl.write(NetSocketImpl.java:168) 
at io.vertx.redis.client.impl.RedisConnectionImpl.lambda$send(RedisConnectionImpl.java:136) 
at io.vertx.core.impl.ContextImpl.executeTask(ContextImpl.java:366) 
at io.vertx.core.impl.EventLoopContext.lambda$executeAsync[=12=](EventLoopContext.java:38) 
at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:164) 
at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:472) 
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:497) 
at io.netty.util.concurrent.SingleThreadEventExecutor.run(SingleThreadEventExecutor.java:989) 
at io.netty.util.internal.ThreadExecutorMap.run(ThreadExecutorMap.java:74) 
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) 
at java.lang.Thread.run(Thread.java:748)

有谁知道为什么会这样? 或者知道如何解决这个问题?

如果您的连接长时间处于空闲状态,Redis 服务器可能会关闭连接。有几种方法可以解决这个问题。 issue

中解释了类似的内容
  1. 添加固定周期虚拟命令 (PING),这样连接就不会关闭。

    Redis.createClient(vertx, new RedisOptions()).connect(onConnect -> {
        if (onConnect.succeeded()) {
            RedisConnection client = onConnect.result();
            RedisAPI redis = RedisAPI.api(client);
            vertx.getOrCreateContext().put("redis", redis);
    
            vertx.setPeriodic(30 * 1000, handler -> {
                redis.ping(new ArrayList<>(), result -> {
                    if (result.failed()) {
                        System.out.println("Error " + result.cause().getMessage());
                    }
                });
            });
        }
    });
    
  2. 添加将获取和替换您的连接的周期性任务。

    final AtomicReference<RedisConnection> vertxConnection = new AtomicReference<>();
    private void refreshConnection(Redis client, RedisConnection fallback) {
        // get a connection
        client.connect()
          .onFailure(err -> {
            // maybe log, don't change the current connection
            System.out.println("connect failed: " + err.getMessage());
            vertx.setTimer(5000L, t -> refreshConnection(client, fallback));
          })
          .onSuccess(conn -> {
            // swap old with new
            System.out.println("connect swapped: " + (conn != null ? conn.hashCode() : null));
            final RedisConnection old = vertxConnection.getAndSet(conn);
            vertx.setTimer(5000L, t -> refreshConnection(client, old));
            // the fallback isn't needed anymore
            if (fallback != null) {
              fallback.close();
            }
          });
      }
    // create client
    Redis client = Redis.createClient(vertx, redisOptions);
    
    // get a connection
    refreshConnection(client, null);
    
  3. 发生这种情况时添加异常处理程序以刷新连接,可以在官方文档中找到很好的例子:https://vertx.io/docs/vertx-redis-client/java/#_implementing_reconnect_on_error