当前位置: 首页 > news >正文

LSM-Tree (日志结构合并树)

     LSM-Tree(日志结构合并树)是一种高效处理写操作的存储结构,广泛应用于NoSQL数据库如LevelDB和RocksDB。其核心思想是将随机写入转换为顺序写入,提升吞吐量。以下是其原理及Java实现示例:

### **LSM-Tree 原理**
1. **结构组成**:
   - **MemTable**:内存中的有序结构(如跳表),用于快速写入。
   - **Immutable MemTable**:MemTable写满后转为只读,准备刷盘。
   - **SSTable(Sorted String Table)**:磁盘上的有序文件,由MemTable刷入生成,多个SSTable分层存储。

2. **写入流程**:
   - 数据先写入MemTable。
   - MemTable满后转为Immutable MemTable,异步刷入磁盘生成SSTable。
   - 磁盘SSTable按层级组织,通过合并(Compaction)消除冗余数据。

3. **读取流程**:
   - 依次查找MemTable、Immutable MemTable和各层SSTable。
   - 使用布隆过滤器减少无效磁盘访问。

4. **合并(Compaction)**:
   - 合并多个SSTable,保留最新数据,减少文件数量,提升读取效率。

---

### **Java 示例代码**
```java
import java.io.*;
import java.util.*;
import java.util.concurrent.ConcurrentSkipListMap;

public class LSMTree {
    private ConcurrentSkipListMap<String, String> memTable = new ConcurrentSkipListMap<>();
    private ConcurrentSkipListMap<String, String> immutableMemTable = null;
    private List<File> sstables = new ArrayList<>();
    private static final int MAX_MEMTABLE_SIZE = 1000;

    // 写入数据
    public synchronized void put(String key, String value) {
        memTable.put(key, value);
        if (memTable.size() >= MAX_MEMTABLE_SIZE) {
            switchMemTable();
        }
    }

    // 切换MemTable并刷盘
    private void switchMemTable() {
        immutableMemTable = memTable;
        memTable = new ConcurrentSkipListMap<>();
        flushToSSTable(immutableMemTable);
        immutableMemTable = null;
    }

    // 将数据写入SSTable文件
    private void flushToSSTable(ConcurrentSkipListMap<String, String> data) {
        String filename = "sstable_" + System.currentTimeMillis() + ".txt";
        File file = new File(filename);
        try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) {
            for (Map.Entry<String, String> entry : data.entrySet()) {
                writer.write(entry.getKey() + "," + entry.getValue());
                writer.newLine();
            }
            sstables.add(file);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    // 读取数据
    public String get(String key) {
        String value = memTable.get(key);
        if (value != null) return value;

        if (immutableMemTable != null) {
            value = immutableMemTable.get(key);
            if (value != null) return value;
        }

        // 从最新SSTable开始查找
        for (int i = sstables.size() - 1; i >= 0; i--) {
            value = searchInSSTable(sstables.get(i), key);
            if (value != null) return value;
        }
        return null;
    }

    // 在SSTable中查找键
    private String searchInSSTable(File file, String key) {
        try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
            String line;
            while ((line = reader.readLine()) != null) {
                String[] parts = line.split(",", 2);
                if (parts[0].equals(key)) {
                    return parts.length > 1 ? parts[1] : null;
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    // 合并SSTable文件
    public void compact() {
        if (sstables.size() < 2) return;

        List<File> oldFiles = new ArrayList<>(sstables);
        sstables.clear();
        TreeMap<String, String> mergedData = new TreeMap<>();

        // 按旧到新顺序合并,保留最新值
        for (File file : oldFiles) {
            try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
                String line;
                while ((line = reader.readLine()) != null) {
                    String[] parts = line.split(",", 2);
                    String key = parts[0];
                    String value = parts.length > 1 ? parts[1] : null;
                    mergedData.put(key, value);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        // 写入新文件并清理旧文件
        String filename = "sstable_merged_" + System.currentTimeMillis() + ".txt";
        File mergedFile = new File(filename);
        try (BufferedWriter writer = new BufferedWriter(new FileWriter(mergedFile))) {
            for (Map.Entry<String, String> entry : mergedData.entrySet()) {
                writer.write(entry.getKey() + "," + entry.getValue());
                writer.newLine();
            }
            sstables.add(mergedFile);
            for (File f : oldFiles) {
                f.delete();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        LSMTree lsm = new LSMTree();
        // 示例操作
        lsm.put("key1", "value1");
        lsm.put("key2", "value2");
        System.out.println(lsm.get("key1")); // 输出 value1
    }
}
```

### **代码说明**
1. **写入优化**:使用跳表(`ConcurrentSkipListMap`)作为MemTable,写满后转为Immutable并刷盘。
2. **读取流程**:依次检查内存表和SSTable文件,确保获取最新数据。
3. **合并策略**:简单合并所有SSTable,生成新文件并删除旧文件,保留最新键值。

### **优化方向**
- **分层存储**:引入层级结构,每层数据量逐层递增,合并策略更精细。
- **布隆过滤器**:快速判断键是否存在于SSTable,减少IO。
- **索引优化**:为SSTable维护内存索引,加速查找。

LSM-Tree通过顺序写入和定期合并,在高写入场景下表现优异,适合日志系统、时序数据库等应用。

相关文章:

LSM-Tree (日志结构合并树)

LSM-Tree&#xff08;日志结构合并树&#xff09;是一种高效处理写操作的存储结构&#xff0c;广泛应用于NoSQL数据库如LevelDB和RocksDB。其核心思想是将随机写入转换为顺序写入&#xff0c;提升吞吐量。以下是其原理及Java实现示例&#xff1a; ### **LSM-Tree 原理** 1. **…...

【深入理解JWT】从认证授权到网关安全

最近的项目学习中&#xff0c;在进行登陆模块的用户信息验证这一部分又用到了JWT的一些概念和相关知识&#xff0c;特在此写了这篇文章、方便各位笔者理解JWT相关概念 目录 先来理解JWT是什么&#xff1f; 区分有状态认证和无状态认证 有状态认证 VS 无状态认证 JWT令牌的…...

利用 Open3D 保存并载入相机视角的简单示例

1. 前言 在使用 Open3D 进行三维可视化和点云处理时&#xff0c;有时需要将当前的视角&#xff08;Camera Viewpoint&#xff09;保存下来&#xff0c;以便下次再次打开时能够还原到同样的视角。本文将演示如何在最新的 Open3D GUI 界面&#xff08;o3d.visualization.gui / o…...

智绘教:Windows平台上的高效悬浮窗画笔工具深度解析

在Windows平台上,一款高效、实用的悬浮窗画笔工具对于提升工作效率和演示效果至关重要。今天,我要为大家介绍一款备受好评的悬浮窗画笔程序——智绘教。这款软件以其丰富的功能和便捷的操作,成为了众多用户心中的首选。接下来,让我们一起深入了解智绘教的各项特性。 一、体…...

从“Switch-case“到“智能模式“:C#模式匹配的终极进化指南

当代码开始"思考" 你是否厌倦了层层嵌套的if-else地狱&#xff1f;是否想过让代码像侦探推理一样优雅地解构数据&#xff1f;C#的模式匹配正是这样一把瑞士军刀&#xff0c;从C# 7.0到C# 12&#xff0c;它已悄然进化成改变编程范式的利器。 一、模式匹配的三重境界…...

【Linux】进程优先级 | 进程调度(三)

目录 前言&#xff1a; 一、进程优先级&#xff1a; 1.通过nice值修改优先级&#xff1a; 二、进程切换&#xff1a; 三、上下文数据 四、Linux真实调度算法&#xff1a; 五、bitmap位图&#xff1a; 六、命令总结&#xff1a; 总结&#xff1a; 前言&#xff1a; 我…...

wordpress按不同页调用不同的标题3种形式

在WordPress中&#xff0c;可以通过多种方式根据不同的页面调用不同的标题。这通常用于实现SEO优化、自定义页面标题或根据页面类型显示不同的标题内容。 使用wp_title函数 wp_title函数用于在HTML的title标签中输出页面标题。你可以通过修改主题的header.php文件来实现自定义…...

音频进阶学习十六——LTI系统的差分方程与频域分析一(频率响应)

文章目录 前言一、差分方程的有理式1.差分方程的有理分式2.因果系统和ROC3.稳定性与ROC 二、频率响应1.定义2.幅频响应3.相频响应4.群延迟 总结 前言 本篇文章会先复习Z变换的有理分式&#xff0c;这是之前文章中提过的内容&#xff0c;这里会将差分方程和有理分式进行结合来看…...

css实现左右切换平滑效果

2025.02.25今天我学习了如何用css实现平滑效果 一、html相关代码 &#xff08;1&#xff09;设置往左、往右的动画属性&#xff0c;样式可以放在同一级。 &#xff08;2&#xff09;必须设置唯一key进行刷新数据&#xff0c;使用v-show来展示每次渲染的组件数量。 <tran…...

详解Tomcat下载安装以及IDEA配置Tomcat(2023最新)

目录 步骤一&#xff1a;首先确认自己是否已经安装JDK步骤二&#xff1a;下载安装Tomcat步骤三&#xff1a;Tomcat配置环境变量步骤四&#xff1a;验证Tomcat配置是否成功步骤五&#xff1a;为IDEA配置Tomcat 步骤一&#xff1a;首先确认自己是否已经安装JDK jdk各版本通用安…...

Docker快速使用指南

docker pull ubuntu:22.04 //先拉取一个基础镜像&#xff0c;一般是操作系统创建一个Dockerfile&#xff0c;放在任意目录下&#xff0c;内容如下 # 使用 Ubuntu 22.04 作为基础镜像 FROM ubuntu:22.04# 设置环境变量&#xff0c;避免安装过程中出现交互提示 ENV DEBIAN_FRONT…...

【Project】基于Prometheus监控docker平台

一、设计背景 1.1项目简介 本项目旨在创建一个全面的容器化应用程序监控解决方案&#xff0c;基于Prometheus监控Docker平台上的各种服务。在当今的软件开发环境中&#xff0c;容器化技术已成为一种关键的工具&#xff0c;使应用程序能够更快速、可靠地交付和扩展。然而&…...

Binder通信协议

目录 一,整体架构 二,Binder通信协议 三&#xff0c;binder驱动返回协议 四&#xff0c;请求binder驱动协议 一,整体架构 二,Binder通信协议 三&#xff0c;binder驱动返回协议 binder_driver_return_protocol共包含18个命令&#xff0c;分别是&#xff1a; 四&#xff0c…...

使用 Postman 访问 Keycloak 端点

1. 引言 在本教程中&#xff0c;我们将首先快速回顾 OAuth 2.0、OpenID 和 Keycloak。然后&#xff0c;我们将了解 Keycloak REST API 以及如何在 Postman 中调用它们。 2. OAuth 2.0 OAuth 2.0 是一个授权框架&#xff0c;它允许经过身份验证的用户通过令牌向第三方授予访问…...

uniapp-X 对象动态取值

有个对象&#xff0c;例如 const data{age:12,list:[1,2,3,4]} 有个函数如下 export function getValueByPath(obj:UTSJSONObject, path:string):any {const current obj.getAny(path) as any;// 返回最终的值return current; } 期待 通过执行getValueByPath("xx.xx…...

建模软件Blender与Blender GIS插件安装教程

Blender&#xff08;blender.org - Home of the Blender project - Free and Open 3D Creation Software&#xff09;是一款功能强大的开源3D创作套件&#xff0c;它支持整个3D管道—建模、渲染、动画制作、模拟、渲染、合成和运动跟踪&#xff0c;甚至视频编辑和游戏制作&…...

数据解析与处理

数据解析与处理是数据科学、分析或开发中的核心步骤&#xff0c;涉及从原始数据中提取、清洗、转换和存储有效信息的过程。 一、数据解析 数据解析就是将原始数据&#xff08;如文本、二进制、日志、API响应等&#xff09;转换为结构化格式&#xff08;如表格、字典、JSON等&…...

强化学习概览

强化学习的目标 智能体&#xff08;Agent&#xff09;通过与环境&#xff08;Environment&#xff09;交互&#xff0c;学习最大化累积奖励&#xff08;Cumulative Reward&#xff09;​的策略。 数学抽象 马尔科夫决策过程&#xff08;MDP&#xff09; 收益 由于马尔科夫决…...

如何在netlify一键部署静态网站

1. 准备你的项目 确保你的静态网站文件&#xff08;如 HTML、CSS、JavaScript、图片等&#xff09;都在一个文件夹中。通常&#xff0c;项目结构如下&#xff1a; my-static-site/ ├── index.html ├── styles/ │ └── styles.css └── scripts/└── script.js…...

2024中国信通院“集智”蓝皮书合集(附下载)

【目 录】 1. 数字政府一体化建设蓝皮书&#xff08;2024年&#xff09; 2. 数字乡村发展实践蓝皮书&#xff08;2023年&#xff09; 3. 中国工业互联网发展成效评估报告&#xff08;2024年&#xff09; 4. 云计算蓝皮书&#xff08;2024年&#xff09; 5. 具身智能发展报告…...

Xshell远程连接Kali(默认 | 私钥)Note版

前言:xshell远程连接&#xff0c;私钥连接和常规默认连接 任务一 开启ssh服务 service ssh status //查看ssh服务状态 service ssh start //开启ssh服务 update-rc.d ssh enable //开启自启动ssh服务 任务二 修改配置文件 vi /etc/ssh/ssh_config //第一…...

智慧工地云平台源码,基于微服务架构+Java+Spring Cloud +UniApp +MySql

智慧工地管理云平台系统&#xff0c;智慧工地全套源码&#xff0c;java版智慧工地源码&#xff0c;支持PC端、大屏端、移动端。 智慧工地聚焦建筑行业的市场需求&#xff0c;提供“平台网络终端”的整体解决方案&#xff0c;提供劳务管理、视频管理、智能监测、绿色施工、安全管…...

AtCoder 第409​场初级竞赛 A~E题解

A Conflict 【题目链接】 原题链接&#xff1a;A - Conflict 【考点】 枚举 【题目大意】 找到是否有两人都想要的物品。 【解析】 遍历两端字符串&#xff0c;只有在同时为 o 时输出 Yes 并结束程序&#xff0c;否则输出 No。 【难度】 GESP三级 【代码参考】 #i…...

在Ubuntu中设置开机自动运行(sudo)指令的指南

在Ubuntu系统中&#xff0c;有时需要在系统启动时自动执行某些命令&#xff0c;特别是需要 sudo权限的指令。为了实现这一功能&#xff0c;可以使用多种方法&#xff0c;包括编写Systemd服务、配置 rc.local文件或使用 cron任务计划。本文将详细介绍这些方法&#xff0c;并提供…...

实现弹窗随键盘上移居中

实现弹窗随键盘上移的核心思路 在Android中&#xff0c;可以通过监听键盘的显示和隐藏事件&#xff0c;动态调整弹窗的位置。关键点在于获取键盘高度&#xff0c;并计算剩余屏幕空间以重新定位弹窗。 // 在Activity或Fragment中设置键盘监听 val rootView findViewById<V…...

【HarmonyOS 5 开发速记】如何获取用户信息(头像/昵称/手机号)

1.获取 authorizationCode&#xff1a; 2.利用 authorizationCode 获取 accessToken&#xff1a;文档中心 3.获取手机&#xff1a;文档中心 4.获取昵称头像&#xff1a;文档中心 首先创建 request 若要获取手机号&#xff0c;scope必填 phone&#xff0c;permissions 必填 …...

在Ubuntu24上采用Wine打开SourceInsight

1. 安装wine sudo apt install wine 2. 安装32位库支持,SourceInsight是32位程序 sudo dpkg --add-architecture i386 sudo apt update sudo apt install wine32:i386 3. 验证安装 wine --version 4. 安装必要的字体和库(解决显示问题) sudo apt install fonts-wqy…...

基于SpringBoot在线拍卖系统的设计和实现

摘 要 随着社会的发展&#xff0c;社会的各行各业都在利用信息化时代的优势。计算机的优势和普及使得各种信息系统的开发成为必需。 在线拍卖系统&#xff0c;主要的模块包括管理员&#xff1b;首页、个人中心、用户管理、商品类型管理、拍卖商品管理、历史竞拍管理、竞拍订单…...

虚拟电厂发展三大趋势:市场化、技术主导、车网互联

市场化&#xff1a;从政策驱动到多元盈利 政策全面赋能 2025年4月&#xff0c;国家发改委、能源局发布《关于加快推进虚拟电厂发展的指导意见》&#xff0c;首次明确虚拟电厂为“独立市场主体”&#xff0c;提出硬性目标&#xff1a;2027年全国调节能力≥2000万千瓦&#xff0…...

CSS | transition 和 transform的用处和区别

省流总结&#xff1a; transform用于变换/变形&#xff0c;transition是动画控制器 transform 用来对元素进行变形&#xff0c;常见的操作如下&#xff0c;它是立即生效的样式变形属性。 旋转 rotate(角度deg)、平移 translateX(像素px)、缩放 scale(倍数)、倾斜 skewX(角度…...