写点什么

H2 存储内核分析一

作者:陈飞
  • 2023-03-27
    四川
  • 本文字数:3261 字

    阅读完需:约 11 分钟

开篇说明

  1. 现在做数据库一般都才有 C/C++ 获取其它编译型的语言,为什么会选择 h2 这种基于 java 的语言?会不会影响效率?其实回答这个问题很简单,无论是用什么语言来实现数据库,其实都是在调用操作系统 IO 的函数。因此仅仅是作为存储的话差别其实是不大的。

  2. 现在大多数,涉及到存储内核的文章或者讲义,要么是一堆原理,要么就是玩具版本例子,根本无法应用到实际的工程上面去,就像马保国的闪电五连鞭一样。我们选择 h2 的一个重要原因就是,学习完后,可以直接应用到工程上。行不行直接在擂台上比一下就知道了。

MVStore 的基础方法

1、创建一个 MVStore 的对象时,如果 fileName 设置为空表示纯内存模式。也就是说 MVStore 可以作为 redis 使用,当然功能会比 redis 还强大。

1.1、纯内存模式

// 创建一个纯内存的 storeMVStore store = MVStore.open(null);
复制代码

1.2、磁盘模式

// 文件存储位置String fileName = "/Users/chenfei/temp/my_store.db";// 创建一个 storeMVStore store = new MVStore.Builder().fileName(fileName).pageSplitSize(1000).open();
复制代码

1.3、使用 MVStore.Builder() 生成 MVStore

MVStore.Builder() 常用方法


  1. 生成纯内存 store


        MVStore.Builder builder = new MVStore.Builder();        MVStore store = builder.open();
复制代码


  1. fileName(String fileName):设置存储 MVStore 数据的文件名


        String fileName = "/Users/chenfei/temp/my_store.db";        MVStore.Builder builder = new MVStore.Builder();        builder.fileName(fileName);        MVStore store = builder.open();
复制代码


  1. encryptionKey(char[] key):设置加密密钥,用于对 MVStore 的数据进行加密。如果不设置,则不进行加密。


        String fileName = "/Users/chenfei/temp/my_store.db";        MVStore.Builder builder = new MVStore.Builder();        builder.encryptionKey("my_h2".toCharArray());        builder.fileName(fileName);        MVStore store = builder.open();
复制代码


  1. compress():开启压缩选项,用于将 MVStore 的数据进行压缩,以减小存储空间。默认不开启。


        String fileName = "/Users/chenfei/temp/my_store.db";        MVStore.Builder builder = new MVStore.Builder();        builder.encryptionKey("my_h2".toCharArray());        /**         * 使用 LZF 算法在写入之前压缩数据。这将节省         * 大约 50% 的磁盘空间,但会减慢读写速度操作轻微         * */        builder.compress();        builder.fileName(fileName);        MVStore store = builder.open();
复制代码


  1. 禁用自动提交事务,需要手动提交。默认开启自动提交事务。


        String fileName = "/Users/chenfei/temp/my_store.db";        MVStore.Builder builder = new MVStore.Builder();        builder.encryptionKey("my_h2".toCharArray());        /**         * 使用 LZF 算法在写入之前压缩数据。这将节省         * 大约 50% 的磁盘空间,但会减慢读写速度操作轻微         * */        builder.compress();        // 禁用自动提交事务,需要手动提交。        builder.autoCommitDisabled();        builder.fileName(fileName);        MVStore store = builder.open();
复制代码


  1. 设置 MVStore 为只读模式,不能进行写操作。


        String fileName = "/Users/chenfei/temp/my_store.db";        MVStore.Builder builder = new MVStore.Builder();        builder.encryptionKey("my_h2".toCharArray());        /**         * 使用 LZF 算法在写入之前压缩数据。这将节省         * 大约 50% 的磁盘空间,但会减慢读写速度操作轻微         * */        builder.compress();        // 禁用自动提交事务,需要手动提交。        builder.autoCommitDisabled();        // 设置MVStore为只读模式,不能进行写操作。        builder.readOnly();        builder.fileName(fileName);        MVStore store = builder.open();
复制代码


  1. 设置 MVStore 的缓存大小,单位为 MB,默认为 16MB。


        String fileName = "/Users/chenfei/temp/my_store.db";        MVStore.Builder builder = new MVStore.Builder();        builder.encryptionKey("my_h2".toCharArray());        /**         * 使用 LZF 算法在写入之前压缩数据。这将节省         * 大约 50% 的磁盘空间,但会减慢读写速度操作轻微         * */        builder.compress();        // 禁用自动提交事务,需要手动提交。        builder.autoCommitDisabled();        // 设置MVStore为只读模式,不能进行写操作。        // builder.readOnly();        // 设置MVStore的缓存为 8MB,默认为16MB        builder.cacheSize(8);        builder.fileName(fileName);        MVStore store = builder.open();
复制代码


  1. pageSplitSize(int pageSplitSize):数据页的大小是通过 pageSplitSize 方法进行设置的,默认值为 4KB。MVStore 使用了数据页的概念来管理存储的数据,将较大的数据文件拆分成多个小的数据页,以提高性能。每个数据页的大小是通过 pageSplitSize 方法进行设置的,默认值为 4KB。当 MVStore 在写入数据时,首先会将数据写入内存缓存中,当缓存中的数据达到一定大小后,会将数据刷新到磁盘上,并拆分成多个数据页。如果数据大小超过了 pageSplitSize 的设置值,则会拆分成多个数据页。因此,pageSplitSize 的设置值会影响数据拆分的粒度,进而影响 MVStore 的性能。通常情况下,pageSplitSize 的默认值可以满足大部分应用的需要。如果需要调整 MVStore 的性能,可以根据实际情况适当调整 pageSplitSize 的值。需要注意的是,pageSplitSize 的值必须是 2 的幂次方。


        String fileName = "/Users/chenfei/temp/my_store.db";        MVStore.Builder builder = new MVStore.Builder();        builder.encryptionKey("my_h2".toCharArray());        /**         * 使用 LZF 算法在写入之前压缩数据。这将节省         * 大约 50% 的磁盘空间,但会减慢读写速度操作轻微         * */        builder.compress();        // 禁用自动提交事务,需要手动提交。        builder.autoCommitDisabled();        // 设置MVStore为只读模式,不能进行写操作。        // builder.readOnly();        builder.pageSplitSize(500);        builder.fileName(fileName);        MVStore store = builder.open();
复制代码


  1. open():使用 builder 中的配置选项创建 MVStore 实例。


        String fileName = "/Users/chenfei/temp/my_store.db";        MVStore.Builder builder = new MVStore.Builder();        MVStore store = builder.open();
复制代码

生成 MVStore 实例的过程

如果是纯内存模式,它的 file header 就为空。只有是磁盘模式的时候才有 file header。

1、生成 MVMap

// 生成一个名为 cache_data 的 MVMap 对象store.openMap("cache_data");
复制代码


MVStore 执行 openMap 方法的时候,如果 map 不存在就新建,存在就直接打开。如果是纯内存模式的,则是新建。


2、MVMap 保存或者删除数据的过程

3、MVStore 提交的过程

在 MVStore 中添加或者是删除数据,为了效率都是在内存中执行的,并没有刷到磁盘上,如果要刷到磁盘上需要调用 commite 方法。


4、MVMap 查询的过程


如果大家对存储内核有兴趣的话,可以加入 DawnSql 交流群,告诉我,我会继续写下去。DawnSql 交流群,在 https://docs.dawnsql.com/ 的首页可以查看(打开有点慢,稍等一下就可以了)


说明一点:有些朋友有疑问,为什么 DawnSql 选择 h2 的存储内核,而不是去重新做一个?这里主要是为了高用性!h2 作为成熟的数据库存储内核,已经在实际的项目中应用了多年,它是经得起考验的。如果新做存储内核,可能会给使用者带来高可用性上面的顾虑,所以我们再三权衡后选择更稳定可用性更高的方案。当然随着 DawnSql 的发展和根据企业方的要求,我们也可以对其进行修改和重构!

用户头像

陈飞

关注

DawnSql开源分布式数据库的作者 2020-02-13 加入

还未添加个人简介

评论

发布
暂无评论
H2存储内核分析一_分布式数据库_陈飞_InfoQ写作社区