-
Notifications
You must be signed in to change notification settings - Fork 6
SidePlugin Java Binding
只需要 Bind SidePluginRepo
,并且只需要 bind 极少的方法(此处仅列出声明):
class SidePluginRepo extends RocksObject {
public SidePluginRepo(); // constructor
public void importAutoFile(String fname) throws RocksDBException;
public RocksDB openDB(String js) throws RocksDBException;
public RocksDB openDB(String js, List<ColumnFamilyHandle> out_cfhs) throws RocksDBException;
public RocksDB openDB() throws RocksDBException;
public RocksDB openDB(List<ColumnFamilyHandle> out_cfhs) throws RocksDBException;
public void startHttpServer() throws RocksDBException;
public void closeHttpServer();
public void closeAllDB(); // conform to C++ native name CloseAllDB
public void close(); // synonym to closeAllDB
public void put(String name, String spec, Options opt); // rarely used
public void put(String name, String spec, DBOptions dbo); // rarely used
public void put(String name, String spec, ColumnFamilyOptions cfo); // rarely used
}
这么小的工作量,我已经多年没碰过 java,jni 更是从来没用过,实现这个 Binding,现学现卖,从头至尾,也只花了不到一天的时间。所以,良好的架构设计,可以极大地减小工作量,如果按照 SidePlugin 的架构,rocksdbjava 中的代码(java 代码与 c++ 各约 4 万行)至少可以缩减 90%。
参考 C++ 版的 101,Java 版的写法没啥大的不同;再参考实际的例子 SideGetBenchmarks,相信大家很容易使用 java 调用 ToplingDB。
其中的 put
方法是为了兼容已有代码:如果现存代码对各种 Option 进行了一些设置,并且这些设置无法通过配置文件进行配置(例如自定义了 java 版的 CompactionFilter),就先把 option put 到 SidePluginRepo
,然后再调用 importAutoFile —— importAutoFile 会补充 put option 中的缺失选项,并覆盖同名选项!
将这个 Binding 再精简归纳总结:
void importAutoFile(String fname) throws RocksDBException;
RocksDB openDB(4 个重载) throws RocksDBException;
void startHttpServer() throws RocksDBException;
void close();
void put(String name, String spec, 三种 option); // 很少使用
openDB
的四个重载中:
-
js
参数一般是 json/yaml 中定义的 dbname,极少数情况下可以是 db 的 json 定义- 没有该参数的 openDB 指的是打开 json 中
open
对象指定的 db, 这是多数情况
- 没有该参数的 openDB 指的是打开 json 中
-
out_cfhs
指的是打开包含多个 ColumnFamily 的 db- 没有该参数的 openDB 指的是打开仅使用 default cf 的 db
一般情况下,在 openDB ... startHttpServer ... closeHttpServer ... closeAllDB 中,closeHttpServer 可以省略,因为 http 会在 closeAllDB 中自动关闭,同时,close 是 closeAllDB 的同义词,从而,可以简化为 openDB ... startHttpServer ... close,在使用了 try (...) {} 的情况下,close 也可以省略。
仍然提供 closeHttpServer 的原因在于,用户可能并不想在 db 的整个生存期内一直开启 http
sudo yum -y install git gcc-c++ jemalloc-devel
sudo yum -y install java-latest-openjdk java-latest-openjdk-devel maven
sudo yum -y install libaio-devel gflags-devel zlib-devel bzip2-devel libcurl-devel liburing-devel
git clone https://github.com/topling/toplingdb.git --depth 1
cd toplingdb
git submodule update --init --recursive
ssh-keyscan -t rsa github.com >> ~/.ssh/known_hosts # silent git
make -j`nproc` DEBUG_LEVEL=0 shared_lib
sudo make install-shared PREFIX=/opt
# 务必设置正确的环境变量 JAVA_HOME, 这里设置的是 open jdk 的默认路径
export JAVA_HOME=/usr/lib/jvm/jre-openjdk
make rocksdbjava -j`nproc` DEBUG_LEVEL=0
你现在应该位于 toplingdb 仓库的根目录
cd java/target
cp rocksdbjni-7.10.0-linux64.jar rocksdbjni-7.10.0-SNAPSHOT-linux64.jar
mvn install:install-file -Dfile=rocksdbjni-7.10.0-SNAPSHOT-linux64.jar -DgroupId=org.rocksdb -DartifactId=rocksdbjni -Dversion=7.10.0-SNAPSHOT -Dpackaging=jar
假定你现在位于 toplingdb 仓库的根目录
cd java/jmh
mvn clean package
假定你现在已经位于 toplingdb/java/jmh
mkdir -p /dev/shm/db_bench_enterprise
cp ../../sideplugin/rockside/src/topling/web/{style.css,index.html} /dev/shm/db_bench_enterprise
export LD_LIBRARY_PATH=/opt/lib:$LD_LIBRARY_PATH # for libterark-*
export LD_PRELOAD=libterark-zbs-g++-12.1-r.so:libterark-fsa-g++-12.1-r.so:libjemalloc.so
java -jar target/rocksdbjni-jmh-1.0-SNAPSHOT-benchmarks.jar \
-p keyCount=1000 -p keySize=128 -p valueSize=32768 \
-p sideConf=../../sideplugin/rockside/sample-conf/db_bench_enterprise.yaml SideGetBenchmarks
运行起来之后,可以访问 http://127.0.0.1:2011 观测 db 状态。
说明 1:社区版用户请将 db_bench_enterprise.yaml 替换为 db_bench_community.yaml,这两个文件都在 toplingdb
/sideplugin/rockside/sample-conf 中, sideplugin/rockside 是 ToplingDB 的 submodule。
社区版强行使用 db_bench_enterprise.yaml 也可以正常工作,只是 compact 中不会创建 ToplingZipTable 的 SST,与 yaml 中 level_writers 定义的不一致。
说明 2:设置 LD_PRELOAD 是因为 toplingdb 和 jemalloc 动态库使用了 init exec 类型的 TLS(线程局部存储),这种 TLS 访问速度最快,但使用了这种 TLS 的动态库必须预先加载,或者由可执行文件显式链接。而 java 加载 jni 是由 jvm 动态加载的,如果不用 LD_PRELOAD,会导致动态库中的这种 TLS 初始化失败。
目前使用 Java 实现的组件无法用 Java 代码注册到 SidePlugin 的插件库中,一般情况下这并不是什么严重问题,唯一的问题在于:无法使用分布式 Compact。
例如在 Java 中实现了自定义的 CompactionFilter/MergeOperator ,因为无法注册到 SidePlugin 的插件库中,所以无法为 dcompact_worker 预加载相应的动态库以运行分布式 Compact。除非(1)实现专门的动态库,在其中用 jni 创建 JVM 并调用 Java 代码,并创建 C++ 包装类,把相应的组件注册到 SidePlugin 中。或者(2)使用 C++ 实现相同功能的插件并注册到 SidePlugin 中,例如数据都是 protobuf 格式,用 C++ 实现相应插件并不困难,而且性能还更高。
例如 flink rocksdb state backend 就是用 C++ 实现的 CompactionFilter,用 jni 包装后再通过 java 来管理