简单的 RocksDB 与 Java

在本文中,我们将使用RocksDB来实现一个非常简单的客户端持久键值存储。其思想是将最简单的实现方式作为初始参考。

您可以在本文结尾的“参考”部分中找到包含此文章的完整源代码的链接。

来自RocksDB文档:RocksDB是一个用于快速存储环境的持久性和可嵌入的键值存储。它是开源的,由Facebook创建并维护,它针对快速、低延迟的存储进行了优化,如闪存驱动器和高速磁盘驱动器。

让我们创建一个示例,第一步是生成一个带有基本REST端点的初始SpringBoot应用程序,导航到start.spring.io并创建一个应用程序,选择Java 11将执行器和Web作为依赖项开始,如果您从未这样做过,请查看这篇文章,您将在最简单的步骤中找到如何做的方法。我们称这个程序为rocksdbBootApp

简单的 RocksDB 与 Java_第1张图片

创建应用程序后,下一步就是将Rocksjava添加为依赖项,在这里您将看到有关如何使用maven进行操作的摘要。


  11
  5.5.1


  org.rocksdb
  rocksdbjni
  ${rocksdb.version}


现在让我们创建一个带有所需基本操作签名的接口KeyValueRepository

package io.stockgeeks.repository;

public interface KeyValueRepository<K, V> {
  void save(K key, V value);
  V find(K key);
  void delete(K key);
}

好的,我们有基本的初始操作来保存、查找和删除条目,让我们实现这些基本操作,在以下代码片段中要注意的最重要的一点是,RocksDB使用字节,因此在交互时它们都被转换为字节数组并返回使用它的API,因为在这个简单的示例中我们在这里使用Strings,所以我们可以简单地使用getBytes来将String转换为字节数组,然后使用String​(byte[] bytes)构造函数将其重新构建。如果需要序列化对象,则可以使用spring,SerializationUtils或者如果不使用Spring SerializationUtils,则可以使用apache-commons API中的一个类。

首先,我们实现接口,并声明一个带有本地存储名称的常量,该常量将反映在文件系统的一个目录中,其中RocksDB将保留数据结构,我们还定义了File指向最终文件夹结构的Java 引用和该RocksDB引用我们将要使用的是,我们将类标记为@Repository带有Spring注释,并使用lombok @Slf4j注释添加日志记录:

@Slf4j
@Repository
public class RocksDBRepositoryImpl implements KeyValueRepository<String, String> {

  private final static String NAME = "first-db";
  File dbDir;
  RocksDB db;

现在我们来创建一个初始化方法,该方法将初始化RocksDB文件系统结构及其配置,并为进行交互做好准备。

我们使用@PostConstruct注释,以便在应用程序启动后执行此片段。然后,我们确保创建了所需的文件系统目录结构,并RocksDB在初始化后打开,如果您按照此处的代码进行操作,因为它将在以下位置维护文件系统结构:/tmp/rocks-db/first-db,您可能需要调整如果您使用的是Windows环境,则代码的路径会有些许变化。

注意:Java具有通用路径

  @PostConstruct
  void initialize() {
    RocksDB.loadLibrary();
    final Options options = new Options();
    options.setCreateIfMissing(true);
    dbDir = new File("/tmp/rocks-db", NAME);
    try {
      Files.createDirectories(dbDir.getParentFile().toPath());
      Files.createDirectories(dbDir.getAbsoluteFile().toPath());
      db = RocksDB.open(options, dbDir.getAbsolutePath());
    } catch(IOException | RocksDBException ex) {
      log.error("Error initializng RocksDB, check configurations and permissions, exception: {}, message: {}, stackTrace: {}",
        ex.getCause(), ex.getMessage(), ex.getStackTrace());
    }
    log.info("RocksDB initialized and ready to use");
  }

准备好应用程序之后,我们现在可以实现基本的操作方法,从要保存的操作开始,没有什么特别的,只是一个简单直接的实现,我们记录该方法调用,并使用该RocksDB.save方法将传递的Strings转换为前面提到的,如果有任何例外情况,我们只记录这种情况下的错误:

    @Override
  public synchronized void save(String key, String value) {
    log.info("save");
    try {
      db.put(key.getBytes(), value.getBytes());
    } catch (RocksDBException e) {
      log.error("Error saving entry in RocksDB, cause: {}, message: {}", e.getCause(), e.getMessage());
    }
  }

find操作也很简单,要注意的唯一重要的事情是,我们检查结果是否为null,避免NullpointerException在运行时出现,以防传入的键不存在以及上述从字节数组到String使用String构造函数的转换。

  @Override
  public String find(String key) {
    log.info("find");
    String result = null;
    try {
      byte[] bytes = db.get(key.getBytes());
      if(bytes == null) return null;
      result = new String(bytes);
    } catch (RocksDBException e) {
            log.error("Error retrieving the entry in RocksDB from key: {}, cause: {}, message: {}", key, e.getCause(), e.getMessage());
    }
    return result;
  }

删除遵循相同的模式,其实现非常简单。

  @Override
  public void delete(String key) {
    log.info("delete");
    try {
      db.delete(key.getBytes());
    } catch (RocksDBException e) {
            log.error("Error deleting entry in RocksDB, cause: {}, message: {}", e.getCause(), e.getMessage());
    }
  }
}

现在我们已经有了基本的实现,现在可以创建一个API来以更具交互性的方式完成示例了,因此让我们使用Spring REST创建简单的API,该API只是将接收到的值传递给RocksDB实现使用基本的HTTP方法调用公开它,并在适用时处理返回200或204的结果,如果您感觉需要更多参考,请查看Spring Boot Crash Course了解更多详细信息,说明以及有关使用SpringBoot构建基本API的链接:

public class RocksApi {

  private final KeyValueRepository<String, String> rocksDB;

  public RocksApi(KeyValueRepository<String, String> rocksDB) {
    this.rocksDB = rocksDB;
  }

  @PostMapping("/{key}")
  public ResponseEntity<String> save(@PathVariable("key") String key, @RequestBody String value) {
    log.info("RocksApi.save");
    rocksDB.save(key, value);
    return ResponseEntity.ok(value);
  }

  @GetMapping("/{key}")
  public ResponseEntity<String> find(@PathVariable("key") String key) {
    log.info("RocksApi.find");
    String result = rocksDB.find(key);
    if(result == null) return ResponseEntity.noContent().build();
    return ResponseEntity.ok(result);
  }

  @DeleteMapping("/{key}")
  public ResponseEntity<String> delete(@PathVariable("key") String key) {
    log.info("RocksApi.delete");
    rocksDB.delete(key);
    return ResponseEntity.ok(key);
  }

现在,在准备好应用程序之后,您可以使用maven构建项目mvn clean package,然后运行mvn spring-boot:run,一旦应用程序启动,您就可以使用我们刚刚使用curl创建的API测试基本操作,下面curl命令中使用的选项是打印标题和请求中的有效负载,因此您可以更好地了解发生了什么:

添加条目:curl -v -H "Content-Type: text/plain" -X POST http://localhost:8080/api/rocks/1 -d mypersistedvalue,如果您添加一个具有相同键(路径中的1)的新条目,它将自动覆盖上一个条目,请注意,在此简单实现中,键可以是任何字符串,这里我们只使用1作为键对于被解析为字符串的示例。

获取条目: curl -iv -X GET -H "Content-Type: text/plain" http://localhost:8080/api/rocks/1

删除条目: curl -X DELETE http://localhost:8080/api/rocks/1

做完了!这是一个非常简单的初始参考,旨在帮助您入门,如果您需要使用客户端持久性缓存并确定RocksDB是一个不错的选择,那么这肯定只是它的提示,当您需要使用RocksDB时,RocksDB可以为您提供许多其他选择您需要自定义缓存,可以设置过滤器(例如BloomFilter),可以配置LRU缓存,还有许多其他选项可用,请查看其完整文档和有关以下参考部分的参考。

注意:默认情况下,在执行Streams以及使用KTables或GlobalKTables时,Kafka默认使用RocksDB。

参考文献

从github rockdbBootApp克隆源代码:git clone [email protected]:stockgeeks/rocksdbBootApp.git

RocksJava文档和项目

Christopher Gower在Unsplash上​​的标题照片

原文链接:https://dev.to//thegroo/simple-rocksdb-with-java-crash-course-20o7

你可能感兴趣的:(简单的 RocksDB 与 Java)