在本文中,我们将使用RocksDB来实现一个非常简单的客户端持久键值存储。其思想是将最简单的实现方式作为初始参考。
您可以在本文结尾的“参考”部分中找到包含此文章的完整源代码的链接。
来自RocksDB文档:RocksDB是一个用于快速存储环境的持久性和可嵌入的键值存储。它是开源的,由Facebook创建并维护,它针对快速、低延迟的存储进行了优化,如闪存驱动器和高速磁盘驱动器。
让我们创建一个示例,第一步是生成一个带有基本REST端点的初始SpringBoot应用程序,导航到start.spring.io并创建一个应用程序,选择Java 11将执行器和Web作为依赖项开始,如果您从未这样做过,请查看这篇文章,您将在最简单的步骤中找到如何做的方法。我们称这个程序为rocksdbBootApp
。
创建应用程序后,下一步就是将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