RocksDB Java基本操作、乐观锁、事务及性能测试

RocksDB

rocksdb是一款由Facebook使用C/C++开发的嵌入式的持久化的KV数据库

基于Google的LevelDB改进而来,redis是基于内存的会存在丢失情况,而RocksDB不会丢失且性能极好(硬盘和SSD)。

属于单机数据库,且同一库只可被一个进程读取写入。(线程安全需要用事务)

适用场景

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

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

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

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

不适合场景

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

​ 2.大规模数据的存取

  • 项目环境 maven jdk1.8 windows10

  • 项目类型 maven项目

  • 依赖

    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.54</version>
    </dependency>
    <dependency>
        <groupId>org.kevoree.mwg.plugins</groupId>
        <artifactId>rocksdb</artifactId>
        <version>6</version>
    </dependency>
    
    <dependency>
        <groupId>org.rocksdb</groupId>
        <artifactId>rocksdbjni</artifactId>
        <version>6.6.4</version>
    </dependency>
    
    • 还需要手动下载一个jar包引入

      rockssdb-6.jar

      https://www.mvnjar.com/org.kevoree.mwg.plugins/rocksdb/6/detail.html

  • 基本操作示范类

    步骤

    建立连接

    调用get put delete close方法即可

    import org.rocksdb.Options;
    import org.rocksdb.RocksDB;
    import org.rocksdb.RocksDBException;
    
    /**
     * RocksDB基本操作类
     * 由于默认操作要传入的是bytes所以做了一层封装,直接传入string操作。
     */
    public class RocksDBOps {
        //数据库路径(文件夹)
        private String path;
        //rocksdb连接
        private RocksDB rocksDB;
        static {
            //加载库
            RocksDB.loadLibrary();
        }
        public RocksDBOps(String path) throws RocksDBException {
            this.path=path;
            rocksDB=RocksDB.open(path);
        }
    
        /**
         * 写入数据
         * @param key 键
         * @param value 值
         * @return boolean 成功与否
         */
        public boolean put(String key,String value){
            try {
                rocksDB.put(key.getBytes(),value.getBytes());
                return true;
            }catch (RocksDBException e){
                return false;
            }
        }
    
        /**
         * 获取数据
         * @param key 键
         * @return string 值
         */
        public String  get(String key){
            try {
                byte[] bytes=rocksDB.get(key.getBytes());
                if(bytes!=null){
                    return new String(bytes);
                }
            }catch (RocksDBException e){
                e.printStackTrace();
            }
            return  null;
        }
    
        /**
         * 删除数据
         * @param key 键
         * @return boolean 成功与否
         */
        public boolean delete(String key){
            try {
                rocksDB.delete(key.getBytes());
                return true;
            }catch (RocksDBException e){
                e.printStackTrace();
            }
            return false;
        }
    
        /**
         * 关闭连接
         */
        public void close(){
            if(rocksDB!=null){
                rocksDB.close();
            }
        }
        public static void main(String[] args) {
            String path="C:\\rocksdb_test.db";
            try {
                //创建连接
                RocksDBOps rocksDBOps=new RocksDBOps(path);
                String key="chen";
                //写入
                rocksDBOps.put(key,"programmer");
                //获取
                String job=rocksDBOps.get(key);
                System.out.println("job:"+job);
                //删除
                boolean ret=rocksDBOps.delete(key);
                if(ret){
                    System.out.println("deleted");
                }else {
                    System.err.println("delete failed");
                }
                //关闭连接
                rocksDBOps.close();
            }catch (Exception e){
                e.printStackTrace();
            }
    
        }
    }
    
    
  • 乐观事务操作

    操作步骤

    建立连接,创建事务,对事务操作,提交事务,失败时回滚,最终关闭

    写同一个两个事务只成功一个。

    import org.rocksdb.*;
    
    public class OptimisticTransactionTest {
        private static OptimisticTransactionDB db;
        private static final String path="C:\\rocksdb_test.db";
        private static final String key="test";
    
        static {
            try {
                //加载库
                RocksDB.loadLibrary();
                //创建连接
                db= OptimisticTransactionDB.open(new Options().setCreateIfMissing(true),path);
                //设置初始值(由于多次运行该程序测试,做一个初始化操作)
                db.put(key.getBytes(),"C".getBytes());
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    
        /**
         * 修改某个key的乐观锁测试
         */
        public class TestThread extends Thread{
            private String name;
            private int sleep;
            public TestThread(String name,int sleep){
                super(name);
                this.name=name;
                this.sleep=sleep;
            }
            @Override
            public void run() {
                Transaction transaction=db.beginTransaction(new WriteOptions());
                try {
                    transaction.put(key.getBytes(),name.getBytes());
    //                Thread.sleep(sleep);
                    transaction.commit();
                    System.out.println(name+" success");
                }catch (Exception e){
                    System.err.println(name+" failed");
                    try {
                        transaction.rollback();
                    }catch (Exception e1){
                        e1.printStackTrace();
                    }
                    e.printStackTrace();
                }
            }
        }
        public void test(){
            TestThread t1=new TestThread("A",500);
            TestThread t2=new TestThread("B",1000);
            t1.start();
            t2.start();
        }
        public static void main(String[] args) {
            new OptimisticTransactionTest().test();
        }
    }
    
  • 读写测速(不考虑线程安全情况)

    测试类

    package bean;
    
    import com.alibaba.fastjson.JSONObject;
    
    import java.math.BigDecimal;
    import java.util.Random;
    
    public class User {
        private Long uid;
        private String username;
        private String password;
        private Integer age;
        private BigDecimal balance;
    
        public Long getUid() {
            return uid;
        }
    
        public void setUid(Long uid) {
            this.uid = uid;
        }
        public String getUsername() {
            return username;
        }
    
        public void setUsername(String username) {
            this.username = username;
        }
    
        public String getPassword() {
            return password;
        }
    
        public void setPassword(String password) {
            this.password = password;
        }
    
        public Integer getAge() {
            return age;
        }
    
        public void setAge(Integer age) {
            this.age = age;
        }
    
        public BigDecimal getBalance() {
            return balance;
        }
    
        public void setBalance(BigDecimal balance) {
            this.balance = balance;
        }
    
        @Override
        public String toString() {
            return JSONObject.toJSONString(this);
        }
        public static User randomUser(){
            Random random=new Random();
            int n=random.nextInt(10);
            User user=new User();
            user.setUid(123004545L*n);
            user.setAge(n);
            user.setBalance(new BigDecimal(n*1000000));
            user.setPassword("123123"+n);
            user.setUsername("hello"+n);
            return user;
        }
    }
    
    

    机器:i5 9500 @ 3.00GHz 6核心 16GB内存 windows (还开着挺多开发软件,但是这个单进程读写应该不会受到太多影响)

    测试50万次读取写入带有5个不同类型的实例

    bean概貌:

    public class User {
        private Long uid;
        private String username;
        private String password;
        private Integer age;
        private BigDecimal balance;
    }
    

    结果:

    读取 50万次/秒

    写入 10万次/秒

    测试3000万次读取写入带有5个不同类型的实例

    结果:

    读取26.万次/秒

    写入12万次/秒

  • 性能测试(使用乐观锁的事务)

    六核机器

    单线程写入3万次每秒(数据量少就更快)

    双线程写入4万次

    四线程写入5万次

    六线程写入5万次

    十二线程写入4.5万次

  • 性能测试结论:建议使用与核心数相同的线程来操作RocksDB可发挥最优性能

posted @ 2020-12-09 18:33  HumorChen99  阅读(22)  评论(0编辑  收藏  举报  来源