1. 程式人生 > 程式設計 >Redis Java Lettuce驅動框架原理解析

Redis Java Lettuce驅動框架原理解析

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",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",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。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。