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

Redis【有与无】【Lettuce】L10.编解码器

程序员文章站 2022-05-01 08:02:21
...

本文章基于Redis 6.0.9版本,Lettuce 6.0.1.RELEASE版本

目录

1.编解码器

1.1.为什么用ByteBuffer 而不是byte[]

1.2.编解码器中的多样性

1.3.多线程

1.4.压缩

例子1.压缩编解码器的用法

1.5.例子

例子2. BitString编解码器

例子3. JDK序列化器


1.编解码器

编解码器是一种可插入的机制,用于在应用程序和Redis之间对键和值进行代码转换。默认编解码器支持UTF-8编码的字符串键和值。

每个连接都可以将其编解码器传递给扩展的RedisClient.connect方法:

StatefulRedisConnection<K, V> connect(RedisCodec<K, V> codec)
StatefulRedisPubSubConnection<K, V> connectPubSub(RedisCodec<K, V> codec)

Lettuce带有预定义的编解码器:

  • io.lettuce.core.codec.ByteArrayCodec - 使用byte[]作为键和值
  • io.lettuce.core.codec.StringCodec - 使用字符串作为键和值。 使用默认字符集或指定的Charset,并改进了对US_ASCIIUTF-8的支持。
  • io.lettuce.core.codec.CipherCodec - 用于值的透明加密。
  • io.lettuce.core.codec.CompressionCodec - 将GZIPDEFLATE压缩应用于值。

Publish/Subscribe连接使用通道名称和键模式; 消息被视为值。

键和值可以彼此独立地编码,这意味着键可以是java.lang.String,而值是byte[]。 许多其他星座也是可能的,例如:

  • 如果你的数据映射到特定的Java类型,则将数据表示为JSON。 由于编解码器适用于所有操作,因此很难映射不同的类型。
  • 使用Java序列化器(ObjectInputStream/ObjectOutputStream)序列化数据。 允许类型安全的转换,但与其他语言的互操作性较低

  • 使用Kryo序列化数据,以改善类型安全的序列化。
  • 任何专门的编解码器,例如BitStringCodec(请参见下文)

1.1.为什么用ByteBuffer 而不是byte[]

RedisCodec接口接受并返回ByteBuffer以进行数据交换。 ByteBuffer不考虑基础字节的来源。 Lettuce 3.x的byte[]接口要求用户为数组提供准确的数据以进行交换。 因此,如果你有一个只想使用一个子集的数组,则需要创建一个字节数组的新实例并复制数据。 如果你使用其他字节源(例如netty的ByteBuffer或NIO ByteBuffer),则同样适用。 用于解码的ByteBuffer是指向基础数据的指针。 用于编码数据的ByteBuffer可以是纯指针或已分配的内存。 生菜不会释放任何内存(例如池缓冲)。

1.2.编解码器中的多样性

就像在技术的其他每个领域一样,在编解码器方面也没有一个万能的解决方案。 Redis数据结构提供了多种方式。编解码器的关键和价值限制是有意的,在便利性和简单性之间取得了平衡。 Redis API在编码和解码特定数据元素时允许更多差异。 一个很好的例子是Redis哈希。 哈希由其键标识,但存储另一个key/value对。 可以使用与哈希键不同的方法来对键值对的键进行编码。 另一种不同的方法可能是在列表和集合之间使用不同的编码。 使用基本编解码器(例如UTF-8或字节数组)并在基本编解码器之上执行自己的转换通常是更好的主意。

1.3.多线程

编解码器中的一个关键点是编解码器是共享资源,可以被多个线程使用。 你的编解码器需要是线程安全的(无共享,共享或同步)。 每个逻辑Lettuce连接都使用其编解码器实例。 一旦有多个线程发出命令或使用Redis Cluster,便会共享编解码器实例。

1.4.压缩

在Redis中存储更大的数据块时,压缩可能是一个好主意。 任何文本数据结构(例如JSON或XML)都适合压缩。 压缩是在编解码器级别处理的,这意味着你不必更改应用程序即可应用压缩。 CompressionCodec使用GZIP或Deflate压缩为值提供基本和透明的压缩:

例子1.压缩编解码器的用法

StatefulRedisConnection<String, Object> connection = client.connect(
                CompressionCodec.valueCompressor(new SerializedObjectCodec(), CompressionCodec.CompressionType.GZIP)).sync();

StatefulRedisConnection<String, String> connection = client.connect(
                CompressionCodec.valueCompressor(StringCodec.UTF8, CompressionCodec.CompressionType.DEFLATE)).sync();

压缩可以与任何编解码器一起使用,压缩器仅包装内部RedisCodec并压缩/解压缩(compresses/decompresses)交换的数据。 你可以使用提供自己的编解码器的相同方式来构建自己的压缩器。

1.5.例子

例子2. BitString编解码器

public class BitStringCodec extends StringCodec {
    @Override
    public String decodeValue(ByteBuffer bytes) {
        StringBuilder bits = new StringBuilder(bytes.remaining() * 8);
        while (bytes.remaining() > 0) {
            byte b = bytes.get();
            for (int i = 0; i < 8; i++) {
                bits.append(Integer.valueOf(b >>> i & 1));
            }
        }
        return bits.toString();
    }
}

StatefulRedisConnection<String, String> connection = client.connect(new BitStringCodec());
RedisCommands<String, String> redis = connection.sync();

redis.setbit(key, 0, 1);
redis.setbit(key, 1, 1);
redis.setbit(key, 2, 0);
redis.setbit(key, 3, 0);
redis.setbit(key, 4, 0);
redis.setbit(key, 5, 1);

redis.get(key) == "00100011"

例子3. JDK序列化器

public class SerializedObjectCodec implements RedisCodec<String, Object> {
    private Charset charset = Charset.forName("UTF-8");

    @Override
    public String decodeKey(ByteBuffer bytes) {
        return charset.decode(bytes).toString();
    }

    @Override
    public Object decodeValue(ByteBuffer bytes) {
        try {
            byte[] array = new byte[bytes.remaining()];
            bytes.get(array);
            ObjectInputStream is = new ObjectInputStream(new ByteArrayInputStream(array));
            return is.readObject();
        } catch (Exception e) {
            return null;
        }
    }

    @Override
    public ByteBuffer encodeKey(String key) {
        return charset.encode(key);
    }

    @Override
    public ByteBuffer encodeValue(Object value) {
        try {
            ByteArrayOutputStream bytes = new ByteArrayOutputStream();
            ObjectOutputStream os = new ObjectOutputStream(bytes);
            os.writeObject(value);
            return ByteBuffer.wrap(bytes.toByteArray());
        } catch (IOException e) {
            return null;
        }
    }
}