1、架构

Rocksdb中引入了ColumnFamily(列族, CF)的概念,所谓列族也就是一系列kv组成的数据集。所有的读写操作都需要先指定列族。

写操作先预写日志(Write-Ahead Logging(WAL)),再写memtable,memtable达到一定阈值后切换为Immutable Memtable,只能读不能写。

后台Flush线程负责按照时间顺序将Immutable Memtable刷盘,生成level0层的有序文件(SST)。后台合并线程负责将上层的SST合并生成下层的SST。

Manifest负责记录系统某个时刻SST文件的视图,Current文件记录当前最新的Manifest文件名。
每个ColumnFamily有自己的Memtable,SST文件,所有ColumnFamily共享WAL、Current、Manifest文件。

架构分析

整个系统的设计思路很好理解,这种设计的优势很明显,主要有以下几点:

1.所有的刷盘操作都采用append方式,这种方式对磁盘和SSD是相当有诱惑力的;

2.写操作写完WAL和Memtable就立即返回,写效率非常高。

3.由于最终的数据是存储在离散的SST中,SST文件的大小可以根据kv的大小自由配置,因此很适合做变长存储。

但是这种设计也带来了很多其他的问题:

1.为了支持批量和事务以及上电恢复操作,WAL是多个CF共享的,导致了WAL的单线程写模式,不能充分发挥高速设备的性能优势(这是相对介质讲,相对B树等其他结构还是有优势);

2.读写操作都需要对Memtable进行互斥访问,在多线程并发写及读写混合的场景下容易形成瓶颈。

3.由于Level0层的文件是按照时间顺序刷盘的,而不是根据key的范围做划分,所以导致各个文件之间范围有重叠,再加上文件自上向下的合并,读的时候有可能需要查找level0层的多个文件及其他层的文件,这也造成了很大的读放大。尤其是当纯随机写入后,读几乎是要查询level0层的所有文件,导致了读操作的低效。

4.针对第三点问题,Rocksdb中依据level0层文件的个数来做前台写流控及后台合并触发,以此来平衡读写的性能。这又导致了性能抖动及不能发挥高速介质性能的问题。

5.合并流程难以控制,容易造成性能抖动及写放大。尤其是写放大问题,在笔者的使用过程中实际测试的写放大经常达到二十倍左右。这是不可接受的,当前我们也没有找到合适的解决办法,只是暂时采用大value分离存储的方式来将写放大尽量控制在小数据。

适用场景

1.对写性能要求很高,同时有较大内存来缓存SST块以提供快速读的场景;

2.SSD等对写放大比较敏感以及磁盘等对随机写比较敏感的场景;

3.需要变长kv存储的场景;

4.小规模元数据的存取;

不适合场景

1.大value的场景,需要做kv分离;

2.大规模数据的存取

2、rockdb的java读写api

package com.kk;import org.rocksdb.*;import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;public class RocksDBTest {private static final String dbPath   = "E:\\defaultCF";private static final String cfdbPath = "E:\\CertainCF";public static void main(String[] args) throws RocksDBException {RocksDBTest t=new RocksDBTest();t.testDefaultColumnFamily();t.testCertainColumnFamily();}static {RocksDB.loadLibrary();}// RocksDB.DEFAULT_COLUMN_FAMILY 默认列族public void testDefaultColumnFamily() throws RocksDBException {System.out.println("testDefaultColumnFamily begin...");// 文件不存在,则先创建文件final Options options = new Options().setCreateIfMissing(true);final RocksDB rocksDB = RocksDB.open(options, dbPath);// 简单key-valuebyte[] key = "FirstKey".getBytes();rocksDB.put(key, "FirstValue".getBytes());System.out.println(new String(rocksDB.get(key)));rocksDB.put("SecondKey".getBytes(), "SecondValue".getBytes());// 通过List做主键查询List<byte[]> keys = Arrays.asList(key, "SecondKey".getBytes(), "missKey".getBytes());Map<byte[], byte[]> values = rocksDB.multiGet(keys);for (int i = 0; i < keys.size(); i++) {System.out.println("multiGet " + new String(keys.get(i)) + ":" + (values.get(keys.get(i)) != null ? new String(values.get(keys.get(i))) : null));}// 打印全部[key - value]RocksIterator iter = rocksDB.newIterator();for (iter.seekToFirst(); iter.isValid(); iter.next()) {System.out.println(new String(iter.key()) + ":" + new String(iter.value()));}// 删除一个keyrocksDB.delete(key);System.out.println("after remove key:" + new String(key));iter = rocksDB.newIterator();for (iter.seekToFirst(); iter.isValid(); iter.next()) {System.out.println(new String(iter.key()) + ":" + new String(iter.value()));}}// 使用特定的列族打开数据库,可以把列族理解为关系型数据库中的表(table)public void testCertainColumnFamily() throws RocksDBException {System.out.println("\ntestCertainColumnFamily begin...");final ColumnFamilyOptions cfOpts = new ColumnFamilyOptions().optimizeUniversalStyleCompaction();String cfName = "my-first-columnfamily";// list of column family descriptors, first entry must always be default column familyfinal List<ColumnFamilyDescriptor> cfDescriptors = Arrays.asList(new ColumnFamilyDescriptor(RocksDB.DEFAULT_COLUMN_FAMILY, cfOpts),new ColumnFamilyDescriptor(cfName.getBytes(), cfOpts));List<ColumnFamilyHandle> cfHandles = new ArrayList<>();final DBOptions dbOptions = new DBOptions().setCreateIfMissing(true).setCreateMissingColumnFamilies(true);final RocksDB rocksDB = RocksDB.open(dbOptions, cfdbPath, cfDescriptors, cfHandles);ColumnFamilyHandle cfHandle = cfHandles.stream().filter(x -> {try {return (new String(x.getName())).equals(cfName);} catch (RocksDBException e) {return false;}}).collect(Collectors.toList()).get(0);// 写入key/valueString key = "FirstKey";rocksDB.put(cfHandle, key.getBytes(), "FirstValue".getBytes());// 查询单keybyte[] getValue = rocksDB.get(cfHandle, key.getBytes());System.out.println(new String(getValue));// 写入第2个key/valuerocksDB.put(cfHandle, "SecondKey".getBytes(), "SecondValue".getBytes());List<byte[]> keys = Arrays.asList(key.getBytes(), "SecondKey".getBytes());List<ColumnFamilyHandle> cfHandleList = Arrays.asList(cfHandle, cfHandle);// 查询多个keyMap<byte[], byte[]> values = rocksDB.multiGet(cfHandleList, keys);for (int i = 0; i < keys.size(); i++) {System.out.println("multiGet:" + new String(keys.get(i)) + ":" + (values.get(keys.get(i)) == null ? null : new String(values.get(keys.get(i)))));}// 删除单keyrocksDB.delete(cfHandle, key.getBytes());RocksIterator iter = rocksDB.newIterator(cfHandle);for (iter.seekToFirst(); iter.isValid(); iter.next()) {System.out.println(new String(iter.key()) + ":" + new String(iter.value()));}for (final ColumnFamilyHandle columnFamilyHandle : cfHandles) {columnFamilyHandle.close();}}
}

参考:https://www.cnblogs.com/cobbliu/articles/9553271.html

杂记一:rocksdb架构及其java读写api相关推荐

  1. php java 读取所有txt_paip.文件读写api php java python总结.txt

    paip.文件读写api php java python总结.txt 一.多种方式读文件内容. 1.按字节读取文件内容 以字节为单位读取文件,常用于读二进制文件,如图片.声音.影像等文件. 2.按字符 ...

  2. java读写分离_java同时读写

    jar-------- 包说明 1. dom4j是一个Java的XML API,类似于jdom,用来读写XML文件的.dom4j是一个非常非常优秀的Java XML API,具有性能优异.功能强大和极 ...

  3. Java Persistence API中的FetchType LAZY和EAGER之间的区别?

    我是Java Persistence API和Hibernate的新手. Java Persistence API中的FetchType.LAZY和FetchType.EAGER什么区别? #1楼 我 ...

  4. Nacos 1.0.0 GA,架构、功能与 API 设计全面重构

    Nacos 1.0.0 GA 版本发布了,此版本在架构.功能和 API 设计上进行了全方位的重构和升级. 此版本新特性包括: 注册实例支持 ephemeral 字段 Nacos 1.0.0 版本在 i ...

  5. Java 常用API的运用,效率及技巧

    1.     Java面向对象基本概念 2.     System 3.     String, StringBuffer 4.     数值,字符,布尔对象与简单类型的操作 5.     Class ...

  6. 【Android架构师java原理详解】二;反射原理及动态代理模式

    前言: 本篇为Android架构师java原理专题二:反射原理及动态代理模式 大公司面试都要求我们有扎实的Java语言基础.而很多Android开发朋友这一块并不是很熟练,甚至半路初级底子很薄,这给我 ...

  7. java nio详解,Java NIO API详解

    Java NIO API详解 在JDK 1.4以前,Java的IO操作集中在java.io这个包中,是基于流的阻塞(blocking)API.对于大多数应用来说,这样的API使用很方 便,然而,一些对 ...

  8. java平台脚本+java编译器API

    [0]README 0.1)本文文字描述转自 core java volume 2, 旨在学习  java平台脚本+java编译器API 的 基础知识: ----------------------- ...

  9. java读写注册表的两种方式,Preferences与jRegistry

    打开注册表方式:电脑上的windows键加r键打开运行程序->输入指令regedit->随即系统便会提示你是否要运行,选择"是"就行了 由于java程序是"w ...

最新文章

  1. Java解决递归栈溢出_方法递归调用中java栈溢出的问题 及 解答 | 学步园
  2. 如何用CSS制作横向菜单?
  3. Android中Fragment+ViewPager的配合使用
  4. 脑电分析系列[MNE-Python-2]| MNE中数据结构Epoch及其创建方法
  5. Jmeter连接到Mysql
  6. 2.2 矩阵基本运算
  7. .net Web网站转换成Web应用程序 备忘
  8. 互联网晚报 | 11月13日 星期六 | 腾讯、抖音商谈对等开放;荣耀电商平台粉丝破亿;碧桂园杨惠妍第九次成为中国女首富...
  9. python报错:Cannot run the event loop while another loop is running
  10. java简单单向链表_用java简单的实现单链表的基本操作
  11. Caffe(13)--(SSRNet模型)Keras转Caffe教程
  12. Java注解@PostConstruct使用及相关原理分析
  13. DELL戴尔开启/关闭触摸板方法
  14. android 8.0自定义全局对话框,Android 8.0如何完美适配全局dialog悬浮窗弹出
  15. 第十一个Java程序,计算QQ等级。
  16. [二级域名映射端口][Ngins端口映射]腾讯云二级域名映射端口
  17. 非递归、递归遍历二叉树!
  18. 用WWW::Mechanize来写twiki
  19. ThinkPad物理机安装Linux系统实战企业级项目之CentOS安装
  20. 疫情严重,潜伏期也有传染性?科技公司在行动

热门文章

  1. Classloader和线程
  2. 接线 科思模块怎么和plc_PLC与传感器的如何接线详解!
  3. MySQL适配达梦数据库注意事项
  4. nginx作用_实战文档:彻底搞懂SpringBoot+微服务+Nginx+Docker+Tomcat
  5. (附源码)计算机毕业设计ssm办公用品管理系统
  6. Java学习日记8:文件上传工具类的实现和服务器给客户端发送图片
  7. delphi7 正式中文_热点聚焦 | 食品科学技术名词正式公布
  8. 图形计算器(geogebra[5.0.278.0])使用QQ浏览器打开下载
  9. 六月福师计算机应用基础在线作业,福师计算机应用基础在线作业一.pdf
  10. Ubuntu16.4下安装ROS系统配置ROBOTIQ 3-Finger Adaptive Robot Gripper运行环境