欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Redis Java Lettuce驱动框架原理解析

程序员文章站 2022-03-10 15:33:49
lettuce是一个高性能基于java编写的redis驱动框架,底层集成了project reactor提供天然的反应式编程,通信框架集成了netty使用了非阻塞io,5.x版本之后融合了jdk1.8...

lettuce是一个高性能基于java编写的redis驱动框架,底层集成了project reactor提供天然的反应式编程,通信框架集成了netty使用了非阻塞io,5.x版本之后融合了jdk1.8的异步编程特性,在保证高性能的同时提供了十分丰富易用的api,5.1版本的新特性如下:

  • 支持redis的新增命令zpopmin, zpopmax, bzpopmin, bzpopmax。
  • 支持通过brave模块跟踪redis命令执行。
  • 支持redis streams。
  • 支持异步的主从连接。
  • 支持异步连接池。
  • 新增命令最多执行一次模式(禁止自动重连)。
  • 全局命令超时设置(对异步和反应式命令也有效)。
  • ......等等

注意一点:redis的版本至少需要2.6,当然越高越好,api的兼容性比较强大。

引入依赖项:

<dependency>
<groupid>io.lettuce</groupid>
<artifactid>lettuce-core</artifactid>
<version>5.3.4.release</version>
</dependency>

一、连接redis

单机、哨兵、集群模式下连接redis需要一个统一的标准去表示连接的细节信息,在lettuce中这个统一的标准是redisuri。可以通过三种方式构造一个redisuri实例:

定制的字符串uri语法:

redisuri uri = redisuri.create("redis://localhost/");

使用建造器(redisuri.builder):

redisuri uri = redisuri.builder().withhost("localhost").withport(6379).build();

直接通过构造函数实例化:

redisuri uri = new redisuri("localhost", 6379, 60, timeunit.seconds);

二、基本使用

lettuce使用的时候依赖于四个主要组件:

  • redisuri:连接信息。
  • redisclient:redis客户端,特殊地,集群连接有一个定制的redisclusterclient。
  • connection:redis连接,主要是statefulconnection或者statefulredisconnection的子类,连接的类型主要由连接的具体方式(单机、哨兵、集群、订阅发布等等)选定,比较重要。
  • rediscommands:redis命令api接口,基本上覆盖了redis发行版本的所有命令,提供了同步(sync)、异步(async)、反应式(reative)的调用方式,对于使用者而言,会经常跟rediscommands系列接口打交道。

一个基本使用例子如下:

redisuri redisuri = redisuri.builder()          // <1> 创建单机连接的连接信息
    .withhost("localhost")
    .withport(6379)
    .withtimeout(duration.of(10, chronounit.seconds))
    .build();
redisclient redisclient = redisclient.create(redisuri);  // <2> 创建客户端
statefulredisconnection<string, string> connection = redisclient.connect();   // <3> 创建线程安全的连接
rediscommands<string, string> rediscommands = connection.sync();        // <4> 创建同步命令
setargs setargs = setargs.builder.nx().ex(5);
string result = rediscommands.set("name", "throwable", setargs);
result = rediscommands.get("name");
system.out.println(result);
// ... 其他操作
connection.close();  // <5> 关闭连接
redisclient.shutdown(); // <6> 关闭客户端

关闭连接一般在应用程序停止之前操作,一个应用程序中的一个redis驱动实例不需要太多的连接(一般情况下只需要一个连接实例就可以,如果有多个连接的需要可以考虑使用连接池,其实redis目前处理命令的模块是单线程,在客户端多个连接多线程调用理论上没有效果)。

关闭客户端一般应用程序停止之前操作,如果条件允许的话,基于后开先闭原则,客户端关闭应该在连接关闭之后操作。

三、lettuce api

  • 同步(sync):rediscommands。
  • 异步(async):redisasynccommands。
  • 反应式(reactive):redisreactivecommands。
redisuri redisuri = redisuri.builder()
    .withhost("localhost")
    .withport(6379)
    .withtimeout(duration.of(10, chronounit.seconds))
    .build();
redisclient client = redisclient.create(redisuri);
statefulredisconnection<string, string> connection = client.connect();

redis命令api的具体实现可以直接从statefulredisconnection实例获取,见其接口定义:

public interface statefulredisconnection<k, v> extends statefulconnection<k, v> {
  boolean ismulti();
  rediscommands<k, v> sync();
  redisasynccommands<k, v> async();
  redisreactivecommands<k, v> reactive();
} 

值得注意的是,在不指定编码解码器rediscodec的前提下,redisclient创建的statefulredisconnection实例一般是泛型实例statefulredisconnection<string,string>,也就是所有命令api的key和value都是string类型,这种使用方式能满足大部分的使用场景。当然,必要的时候可以定制编码解码器rediscodec<k,v>。

同步api

先构建rediscommands实例

rediscommands<string, string> rediscommands= connection.sync();
string pong = rediscommands.ping();
// 返回pong
system.out.println("pong:" + pong);

setargs setargs = setargs.builder.nx().ex(5);
rediscommands.set("name", "throwable", setargs);
string value = rediscommands.get("name");
system.out.println("name:" + value);

同步api在所有命令调用之后会立即返回结果。如果熟悉jedis的话,rediscommands的用法其实和它相差不大。

异步api

先构建redisasynccommands实例:

redisasynccommands<string, string> rediscommands = connection.async();

基本使用:

redisasynccommands<string, string> rediscommands = connection.async();
redisfuture<string> redisfuture = rediscommands.ping();
// 返回pong
system.out.println("pong:" + redisfuture.get());

setargs setargs = setargs.builder.nx().ex(5);
redisfuture<string> future = rediscommands.set("name", "throwable", setargs);
system.out.println("name:" + future.get());

redisasynccommands所有方法执行返回结果都是redisfuture实例,而redisfuture接口的定义如下:

public interface redisfuture<v> extends completionstage<v>, future<v> {
  string geterror();
  boolean await(long timeout, timeunit unit) throws interruptedexception;
}  

也就是,redisfuture可以无缝使用future或者jdk1.8中引入的completablefuture提供的方法。

反应式api

lettuce引入的反应式编程框架是project reactor,如果没有反应式编程经验可以先自行了解一下project reactor。

构建redisreactivecommands实例:

redisreactivecommands<string, string> rediscommands = connection.reactive();

根据project reactor,redisreactivecommands的方法如果返回的结果只包含0或1个元素,那么返回值类型是mono,如果返回的结果包含0到n(n大于0)个元素,那么返回值是flux。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。