Vert.x-Redis

Vert.x-Redis

Scroll Down

Vert.x-Redis是Vertx官方提供的一个Redis的无阻塞异步调用库,本文基于3.8.1版本来介绍Vert.x-Redis的核心API

RedisOptions

用于指定创建redis连接的配置,这里使用的是io.vertx.redis.client包下的而非io.vertx.redis包下的RedisOptions,后者包装的是vertx 基本网络连接的配置,可以设置为前者的netClientOptions字段

重要字段

  • endpoints: Redis的地址和端口
  • type: Redis的连接类型(STANDALONE,SENTINEL,CLUSTER)
  • netClientOptions:基本网络配置,不设置会使用默认构造器创建

Redis

所有RedisClient实现的抽象接口,提供了默认静态构造方法创建具体RedisClient,默认为STANDALONE,带RedisOptions的构造方法会根据RedisOptions中的type来决定具体实例化RedisClient的类型

创建Redis对象的默认静态构造方法源码

    static Redis createClient(Vertx vertx, RedisOptions options) {
switch (options.getType()) {
  case STANDALONE:
    return RedisClient.create(vertx, options);
  case SENTINEL:
    return RedisSentinelClient.create(vertx, options);
  case CLUSTER:
    return RedisClusterClient.create(vertx, options);
  default:
    throw new IllegalStateException("Unknown Redis Client type: " + options.getType());
        }
    }

初始化连接

在执行命令之前必须先调用connect()方法来建立连接,使用连接未建立的client执行命令时返回的response为空

一个完整的从定义到调用的示例

Redis.createClient(
    vertx,
    new RedisOptions()
.setType(RedisClientType.SENTINEL)
.addEndpoint(SocketAddress.inetSocketAddress(5000, "127.0.0.1"))
.addEndpoint(SocketAddress.inetSocketAddress(5001, "127.0.0.1"))
.addEndpoint(SocketAddress.inetSocketAddress(5002, "127.0.0.1"))
.setMasterName("sentinel7000")
.setRole(RedisRole.MASTER))
 .connect(onConnect -> {
// assuming we got a connection to the master node
// query the info for the node
onConnect.result()
  .send(Request.cmd(Command.INFO), info -> {
    // do something...
     });
 });

RedisAPI

RedisAPI接口中定义了redis中所有常见命令方法,它的默认静态构造方法接收一个Redis的实例,创建并返回一个RedisAPIImpl对象,RedisAPIImpl持有传入的Redis实例,并实现了所有命令方法都要调用的send方法

使用RedisAPI执行命令示例

     RedisAPI api =  RedisAPI.api(redisClient);
     
  api.keys("*",info -> {
        // do something...
  });

Result类型

执行Redis命令异步返回Future:AsyncResult 中包装的result的类型为Response,该类型有五种实现,各自代表了Redis返回结果的数据结构,它们分别是

  • SimpleStringType: 简易字符串类型,默认值为OK,一般无具体返回结果的命令(例如set)的结果就会用此类型包装
  • IntegerType 数字类型,一般返回结果一定是数字的命令(例如incr)结果会用此类型包装
  • BulkType 基本对象类型,一般有具体单一返回结果的命令(例如get)都会用此类型包装
  • MultiType 数组类型,有多个返回结果的命令(例如list)都会用此类型包装,也是唯一可迭代的类型
  • ErrorType异常类型,该类型包装的是Vertx Redis工具类所抛出的异常而非Redis本身返回的异常,Redis本身返回的异常将会被封装在AsyncResult的throwable中

Response接口继承了Iterable,但这并不意味着所有的Response实现类都是可迭代的,事实上,只有MultiType是可迭代的,其它实现的迭代相关方法都在Response中default实现成抛出UnsupportedOperationException异常

哨兵实现

Vertx Redis哨兵客户端的实现实际是使用了装饰模式加强了单节点的redis客户端,哨兵客户端持有一个单节点客户端和一个哨兵客户端,哨兵客户端订阅哨兵消息,当收到消息后会通过redisClient的fail()方法传入消息触发注册在redisClient上的OnException函数处理消息从而完成响应哨兵消息,核心代码如下:

      sentinel
    .handler(msg -> {
      if (msg.type() == ResponseType.MULTI) {
        if ("MESSAGE".equalsIgnoreCase(msg.get(0).toString())) {
          // we don't care about the payload
          if (redis != null) {
            redis.fail(ErrorType.create("SWITCH-MASTER Received +switch-master message from Redis Sentinel."));
          } else {
            LOG.warn("Received +switch-master message from Redis Sentinel.");
          }
        }
      }
    });