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

算法基础——存储

引入

基础理论的进步,是推动技术实现重大突破,促使相关领域的技术达成跨越式发展的核心。

在发展日新月异的大数据领域,基础理论的核心无疑是算法。不管是技术设计,还是工程实践,都必须仰仗相关算法的支持,才能够真的落地应用。

下面我们就看看大数据相关领域有哪些核心的算法。

存储类算法

大数据存储相关的核心算法,主要是为了高效存储和管理海量数据,以及提升数据读写性能和存储利用率等。

以下我们来看看大数据领域最经典的存储类算法:

B树及其变种(B+树、B* 树)

原理

  • B树:是一种自平衡的多路搜索树,每个节点可以有多个子节点。它的所有叶子节点都在同一层,并且包含了所有的数据。
  • B+树:是 B树的一种变种,它的非叶子节点只存储索引信息,所有的数据都存储在叶子节点中,叶子节点之间通过指针相连,形成一个有序链表,便于范围查询。(最通用)
  • B*树:在 B+树的基础上,对节点的分裂规则进行了优化,提高了空间利用率。

应用场景:广泛应用于关系型数据库的索引结构,能够高效地支持点查询和范围查询。

优点:查询、插入和删除操作的时间复杂度都是 O (log n),性能稳定。

缺点:对于大规模数据的写入操作,可能会导致频繁的节点分裂和合并,影响性能。

B+树是一种平衡的、多叉的树形结构,能够支持O(logn)的插入和查询时间复杂度。B+树的整个结构是有序存储的,这使得B+树能够高效地支持范围查询;在空间放大维度,B+树能够达到70%的空间利用率。综上所述,B+树有较好的综合性能,在现代的诸多存储系统中,B+树索引很常见,例如关系数据库MySQL的默认存储引擎InnoDB。

在大数据领域是避免不了使用多线程与高并发场景的,所以需要对B+树索引进行并发控制。由于B+树的树形结构会不断动态调整,要实现一个正确的多线程B+树,存在着较大的设计挑战。

目前来说,实现B+树的并发,可以采用以下3种机制:

  1. 锁耦合
    锁耦合机制是B+树中应用最为广泛的一种加锁方式。锁耦合机制就是一种节点级别的加锁方式,但是路径上的节点的锁会更早地释放,同时能保证线程安全。在锁耦合机制中,每个线程同时最多拥有两个节点的锁,分别为父节点和孩子节点。父节点的节点可以在孩子节点的锁获取之后释放,这样可以充分减少每个节点加锁和释放的临界区大小,从而最大化多线程性能。
  2. 乐观锁机制
    采用锁耦合机制,每个读/写线程仍然是互相阻塞的,而乐观锁机制则是为了减少写线程对读线程的阻塞,并进一步减少加锁的数量。内部节点除节点内部的锁字段之外,还额外维护一个写版本号。每当写线程对节点完成修改之后,先对写版本号完成自增操作,随后释放写锁。每当读线程访问一个节点的时候,首先记录节点版本号,在完成对节点的访问之后检测节点版本号是否发生变化,如果节点写版本号发生变化,读线程重做对该节点的访问,否则意味着节点访问过程中该节点并未发生写操作,因此读节点操作成功执行。
  3. 无锁机制。
    通过无锁的方式来操作B+树,提升随机读和范围查询的性能。它的核心的思想是把B+树的页(page)通过page id(PID)映射到map,map的[key,value]变成[PID,page value]​,把直接对page的修改,变成一个修改的操作记录,加入到“page value”​。所以“page value”可能是一个“base page”​,即page原始的内容,和一串对page修改形成的记录的链表,而在修改记录链表中加入一个修改记录节点可以很容易变成一个无锁的方式来实现。另外,对B+树的split和merge操作也通过类似的原理,把具体的操作细化成好几个原子操作,避免传统的加锁方式。

SkipList(跳表)

原理

  • SkipList 是一种可以用来快速查找数据的数据结构,它基于有序链表,并通过在链表节点上增加多层索引来提高查找效率。在 SkipList 中,每个节点都可能有多个指针,这些指针指向不同层次的下一个节点,高层的指针可以跳过更多的节点,从而加快查找速度。
  • 构建 SkipList 时,会按照一定的概率随机决定每个节点在不同层次出现的概率。例如,一个节点可能以 50% 的概率出现在第一层,以 25% 的概率出现在第二层,以 12.5% 的概率出现在第三层,以此类推。这样就形成了一个类似金字塔形状的多层结构,使得查找操作可以在对数时间内完成。

应用场景:由于 SkipList 在插入、删除和查找操作上都具有较高的效率,适合在内存中存储和操作大量的有序数据,能够快速地根据分数对元素进行排序和查找;在分布式哈希表(DHT)等分布式数据结构中,SkipList 可以用于实现节点之间的快速路由和数据查找。通过在不同节点上构建 SkipList 结构,可以高效地定位数据所在的节点,提高分布式系统的性能和可扩展性。

优点:SkipList 的插入、删除和查找操作的平均时间复杂度为 O (log n),与平衡树(如红黑树)等数据结构相当,但 SkipList 的实现相对简单,代码复杂度较低,易于理解和维护。而且 SkipList 支持动态扩展和收缩,能够方便地适应数据量的变化。

缺点:SkipList 的空间复杂度相对较高,因为每个节点可能包含多个指针,需要额外的空间来存储这些指针。此外,由于 SkipList 的节点层数是随机生成的,在极端情况下可能会出现查找性能下降的情况,但这种情况发生的概率较低。

跳跃表(SkipList)是一种能高效实现插入、删除、查找的内存数据结构,这些操作的期望复杂度都是O(logN)。与红黑树以及其他的二分查找树相比,跳跃表的优势在于实现简单,而且在并发场景下加锁粒度更小,从而可以实现更高的并发性。正因为这些优点,跳跃表广泛使用于KV数据库中,诸如Redis、LevelDB、HBase都把跳跃表作为一种维护有序数据集合的基础数据结构。

LSM树(Log-Structured Merge Tree)

原理:将数据的写入操作先记录在内存中(通常是一个有序的数据结构,如跳表),当内存中的数据达到一定阈值后,再批量地将数据写入磁盘,形成一个有序的数据文件(SSTable,Sorted String Table)。磁盘上的数据会按层级进行组织,不同层级的数据会定期进行合并操作,以减少数据冗余和提高查询效率。

应用场景:适用于写多读少的场景,如日志存储、时间序列数据存储等。

优点:写入性能高,能够快速处理大量的写入请求;

缺点:读取时可能需要合并多个 SSTable,读取性能相对较低,并且在合并过程中会产生一定的 I/O 开销。

2000年年初,Google发表了Bigtable的论文,论文中的创新点之一就是它所使用的文件组织方式,即LSM树。

算法的核心也是基于硬件特性来,才能真正的解决落地的问题。对于磁盘读写来说,顺序读写要远比随机读写快,LSM树通过将随机写转化为顺序写,消去随机的本地更新操作来提高写入性能,但查询(包括点查询和范围查询)性能会有一定程度的下降,因为一次查询操作可能要遍历磁盘中的许多个不同的SST文件。针对查询性能问题,在不同应用实现时会有一些优化,比如在HBase中设计了异步的compaction来降低文件个数,来提高读取性能。

LSM树本质上和B+树一样,是一种磁盘数据的索引结构。但和B+树不同的是,LSM树的索引对写入请求更友好。因为无论是何种写入请求,LSM树都会将写入操作处理为一次顺序写。

LSM树的索引一般由两部分组成,一部分是内存部分,一部分是磁盘部分。内存部分一般采用跳跃表来维护一个有序的KeyValue集合。磁盘部分一般由多个内部KeyValue有序的文件组成。

哈希算法(Hash Tables)

原理:通过哈希函数将键映射到一个固定大小的数组中,数组中的每个位置称为一个槽(Slot)。当插入、查找或删除数据时,先计算键的哈希值,然后根据哈希值找到对应的槽。如果发生哈希冲突(即不同的键映射到了同一个槽),可以采用开放寻址法、链地址法等方法来解决。

应用场景:适用于快速查找和插入的场景,如缓存系统、分布式哈希表(DHT)等。在分布式系统中,一致性哈希算法是一种常用的哈希算法,用于实现数据的均匀分布和节点的动态扩展。

优点:平均查找、插入和删除操作的时间复杂度为 O (1),性能高效;

缺点:哈希函数的设计比较关键,如果哈希函数设计不当,可能会导致哈希冲突频繁,影响性能。并且哈希表不支持范围查询。

哈希表是一种无序的数据结构,它提供了快速的插入操作和查找操作。

一个好的哈希表能够保证插入和查找的时间复杂度为O(1),即插入和查询性能与哈希表中的数据量无关。这种设计可以实现高效的写性能和查询性能,但是它牺牲了范围查询性能。

哈希表结构设计中最关键的问题是:

  1. 如何选择合适的哈希函数;
  2. 如何选择合适的哈希冲突处理机制。

常见的哈希冲突解决机制有四种:

  1. 链地址法。
    在链地址法下,哈希表的每个桶由一个链表构成。链表中存储的是所有哈希值相同的键值对。因此在进行查询操作时,可以通过遍历该链表查询对应的键值对。
  2. 线性探测法。
    在线性探测法下,哈希表是一个连续的桶数组,对于任意一个哈希键,根据哈希函数定位到一个映射位置,插入和查找都基于该地址进行向后探测。当插入一个键值时,判断映射地址是否为空,如果该地址为空,则在映射地址插入键值对,否则向后探测直到找到空桶,并将该键值对放入该空桶。查询操作则从映射地址开始向后扫描所有键值对,直到找到待查询键值对或者遇到一个空桶。
  3. 双选择法。
    双选择法采用两个独立的哈希函数,对于每个键值对,都有两个可插入的桶。当执行插入的时候,根据两个哈希函数分别将哈希键映射到两个桶a和b中。根据桶a和桶b的填充度,选择填充度更低的桶插入键值对。同样,执行查询操作时,只需要遍历两个桶即可定位到查询键值。
  4. 布谷鸟探测法。
    布谷鸟探测法是双选择法的一种变种。它同样采用两个哈希函数。当执行键值对插入时,根据两个哈希函数分别将哈希键映射到两个桶a和b中。如果桶a和b存在空闲位置,则将键值对插入到空闲位置中;否则,随机挑选一个桶中的键值对,将其踢出该桶,并存入待插入键值对,被踢出的键值对则尝试插入到其对应的另一个桶中。

采用不同哈希冲突解决方式,在查询性能、插入性能、哈希表填充度三个维度会有不同的表现,解决哈希冲突的方案也是没有“银弹”。

链地址法的插入性能更优,并且对于空间的占用是逐渐增长的;线性探测法的填充度可以做到最优,但是这是以牺牲查询和插入性能为前提的;在查询性能上,布谷鸟和双选择法会比其他方法更优。在实际的键值数据库中,不同的设计会采用不同的哈希函数和哈希冲突解决机制。Redis采用的就是链地址法,这使得Redis的空间占用更为缓慢,空间管理也更为灵活。

LRU(Least Recently Used)和 LFU(Least Frequently Used)缓存算法

原理

  • LRU:基于 “最近最少使用” 的原则,当缓存空间满时,优先淘汰最近最少使用的数据。通常使用双向链表和哈希表来实现,双向链表用于维护数据的访问顺序,哈希表用于快速查找数据。
  • LFU:基于 “最不经常使用” 的原则,当缓存空间满时,优先淘汰使用频率最低的数据。可以使用多个链表和哈希表来实现,每个链表存储相同使用频率的数据。

应用场景:常用于缓存系统中,如数据库缓存、Web 服务器缓存等,以提高数据的访问速度。

优点

  • LRU:实现简单,能够较好地反映数据的访问局部性。
  • LFU:能够更好地适应数据的使用频率。

缺点

  • LRU:对于某些特殊的访问模式,可能会导致性能下降。
  • LFU:实现相对复杂,并且在数据访问模式发生变化时,需要一定的时间来调整。

总结

今天提到的都是存储相关最核心的算法,本文主要是抛砖引玉,后续在分享大数据相关组件底层实现原理时,有涉及到相关算法的时候,我们再深入看看。

相关文章:

算法基础——存储

引入 基础理论的进步,是推动技术实现重大突破,促使相关领域的技术达成跨越式发展的核心。 在发展日新月异的大数据领域,基础理论的核心无疑是算法。不管是技术设计,还是工程实践,都必须仰仗相关算法的支持&#xff0…...

动态规划 (环形)

在一个圆形操场的四周摆放着n堆石子,现要将石子有次序地合并成一堆。规定每次只能选相邻2堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的得分。试设计一个算法,计算出将n堆石子合并成一堆的最小得分和最大得分。 输入格式: n表示n…...

信号模块--simulink操作

位置simulink/sourses 常用的模块 功能:常数模块,提供一个常数 数据设置可以是一维或多维 一维数据设置 多维数据设置(例三维数据设置) 方波脉冲模块 模块用于按固定间隔生成方波脉冲信号 振幅就是方波的幅度,0到…...

Streamlit入门

1、Streamlit是什么 Streamlit 是一个用于快速构建数据应用的开源 Python 库,由 Streamlit 公司开发并维护。它极大地简化了从数据脚本到交互式 Web 应用的转化过程,让开发者无需具备前端开发的专业知识,就能轻松创建出美观、实用的交互式应…...

列表(列表是什么)

你将学习列表是什么以及如何使用列表元素。列表让你能够在一个地方存储成组的信息,其中可以只包含几个元素,也可以包含数百万个元素。 列表是新手可直接使用的最强大的Python功能之一,它融合了众多重要的编程概念。 列表是什么 列表 由一系列…...

笔记本搭配显示器

笔记本:2022款拯救者Y9000P,显卡RTX3060,分辨率2560*1600,刷新率:165Hz,无DP1.4口 显示器:2024款R27Q,27存,分辨率2560*1600,刷新率:165Hz &…...

基于排队理论的物联网发布/订阅通信系统建模与优化

论文标题 英文标题:Queuing Theory-Based Modeling and Optimization of a Publish/Subscribe IoT Communication System 中文标题:基于排队理论的物联网发布/订阅通信系统建模与优化 作者信息 Franc Pouhela Anthony Kiggundu Hans D. Schotten …...

指针(C语言)从0到1掌握指针,为后续学习c++打下基础

目录 一,指针 二,内存地址和指针 1,什么是内存地址 2,指针在不同系统下所占内存 三,指针的声明和初始化以及类型 1,指针的声明 2,指针 的初始化 1, 初始化方式优点及适用场景 4,指针的声明初始化类型…...

实验八 JSP访问数据库

实验八 JSP访问数据库 目的: 1、熟悉JDBC的数据库访问模式。 2、掌握使用My SQL数据库的使用 实验要求: 1、通过JDBC访问mysql数据,实现增删改查功能的实现 2、要求提交实验报告,将代码和实验结果页面截图放入报告中 实验过程&a…...

Day31-【AI思考】-关键支点识别与战略聚焦框架

文章目录 关键支点识别与战略聚焦框架**第一步:支点目标四维定位法****第二步:支点验证里程碑设计****第三步:目标网络重构方案****第四步:动态监控仪表盘** 执行工具箱核心心法 关键支点识别与战略聚焦框架 让思想碎片重焕生机的…...

DeepSeek与其他大模型相比

DeepSeek与其他大模型相比 与GPT-4对比 性能方面 推理速度:DeepSeek在解决复杂的数学、物理和逻辑推理问题方面速度惊人,是ChatGPT的两倍。“幻觉”现象:在处理需要网络信息检索的任务时,DeepSeek的“幻觉”现象似乎比ChatGPT更少。创意任务:ChatGPT在创意性任务,如创作…...

在深度Linux (Deepin) 20中安装Nvidia驱动

文章创作不易,麻烦大家点赞关注收藏一键三连。 在Deepin上面跑Tensorflow, pytorch等人工智能框架不是一件容易的事情。特别是如果你要使用GPU,就得有nvidia的驱动。默认情况下Deepin系统自带的是nouveau开源驱动。这是没办法用tensorflow的。下面内容是…...

“LoRA技术中参数初始化策略:为何A参数采用正态分布而B参数初始化为0”

在LoRA(Low-Rank Adaptation)中,参数A和B的初始化策略是经过精心设计的,以确保模型训练的稳定性和有效性。具体来说,参数A通常被初始化为正态分布,而参数B则初始化为0。这样的设计有以下几个优点&#xff1…...

C语言初阶力扣刷题——349. 两个数组的交集【难度:简单】

1. 题目描述 力扣在线OJ题目 给定两个数组,编写一个函数来计算它们的交集。 示例: 输入:nums1 [1,2,2,1], nums2 [2,2] 输出:[2] 输入:nums1 [4,9,5], nums2 [9,4,9,8,4] 输出:[9,4] 2. 思路 直接暴力…...

理解动手学深度学习的自编包d2l

跟着李沐的《动手学深度学习-PyTorch版》入门Python编程和Pytorch框架,以前是重度Matlab用户,对于Python里的各种包很不习惯。特别是,本书还自己做了一个名为d2l包,有几个问题很是困惑。今天终于弄明白了,写在这里&…...

RK3568使用opencv(使用摄像头捕获图像数据显示)

文章目录 一、opencv相关的类1. **cv::VideoCapture**2. **cv::Mat**3. **cv::cvtColor**4. **QImage**5. **QPixmap**总结 二、代码实现 一、opencv相关的类 1. cv::VideoCapture cv::VideoCapture 是 OpenCV 中用于视频捕捉的类,常用于从摄像头、视频文件、或者…...

OpenEuler学习笔记(十六):搭建postgresql高可用数据库环境

以下是在OpenEuler系统上搭建PostgreSQL高可用数据环境的一般步骤,通常可以使用流复制(Streaming Replication)或基于Patroni等工具来实现高可用,以下以流复制为例: 安装PostgreSQL 配置软件源:可以使用O…...

数学平均数应用

给定一个长度为 n 的数组 a。在一次操作中,你可以从索引 2 到 n−1中选择一个索引i,然后执行以下两个操作之一: 将 a[i−1] 减少 1,同时将 a[i1] 增加 1。 将 a[i1] 减少 1,同时将 a[i−1] 增加 1。 在每次操作后&…...

元旦和春节取名的历史变迁

在中国漫长的历史长河中的春节,真要追溯起来也只有一百多年历史——是从晚清时期才逐渐出现在国人的生活里的,而且那时不叫“春节”而叫“元旦”。只不过随着历史的发展过程,“过年”这个名词也一直在演变,直至1949年最终才定下来…...

USB鼠标的数据格式

USB鼠标的数据格式由HID&#xff08;Human Interface Device&#xff09;协议定义&#xff0c;通常包含3个字节的标准数据&#xff0c;具体格式如下&#xff1a; 字节内容描述第1字节按键状态Bit 0: 左键按下&#xff08;1&#xff09;<br>Bit 1: 右键按下&#xff08;1…...

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…...

uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖

在前面的练习中&#xff0c;每个页面需要使用ref&#xff0c;onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入&#xff0c;需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...

【算法训练营Day07】字符串part1

文章目录 反转字符串反转字符串II替换数字 反转字符串 题目链接&#xff1a;344. 反转字符串 双指针法&#xff0c;两个指针的元素直接调转即可 class Solution {public void reverseString(char[] s) {int head 0;int end s.length - 1;while(head < end) {char temp …...

新能源汽车智慧充电桩管理方案:新能源充电桩散热问题及消防安全监管方案

随着新能源汽车的快速普及&#xff0c;充电桩作为核心配套设施&#xff0c;其安全性与可靠性备受关注。然而&#xff0c;在高温、高负荷运行环境下&#xff0c;充电桩的散热问题与消防安全隐患日益凸显&#xff0c;成为制约行业发展的关键瓶颈。 如何通过智慧化管理手段优化散…...

Robots.txt 文件

什么是robots.txt&#xff1f; robots.txt 是一个位于网站根目录下的文本文件&#xff08;如&#xff1a;https://example.com/robots.txt&#xff09;&#xff0c;它用于指导网络爬虫&#xff08;如搜索引擎的蜘蛛程序&#xff09;如何抓取该网站的内容。这个文件遵循 Robots…...

Swagger和OpenApi的前世今生

Swagger与OpenAPI的关系演进是API标准化进程中的重要篇章&#xff0c;二者共同塑造了现代RESTful API的开发范式。 本期就扒一扒其技术演进的关键节点与核心逻辑&#xff1a; &#x1f504; 一、起源与初创期&#xff1a;Swagger的诞生&#xff08;2010-2014&#xff09; 核心…...

【开发技术】.Net使用FFmpeg视频特定帧上绘制内容

目录 一、目的 二、解决方案 2.1 什么是FFmpeg 2.2 FFmpeg主要功能 2.3 使用Xabe.FFmpeg调用FFmpeg功能 2.4 使用 FFmpeg 的 drawbox 滤镜来绘制 ROI 三、总结 一、目的 当前市场上有很多目标检测智能识别的相关算法&#xff0c;当前调用一个医疗行业的AI识别算法后返回…...

.Net Framework 4/C# 关键字(非常用,持续更新...)

一、is 关键字 is 关键字用于检查对象是否于给定类型兼容,如果兼容将返回 true,如果不兼容则返回 false,在进行类型转换前,可以先使用 is 关键字判断对象是否与指定类型兼容,如果兼容才进行转换,这样的转换是安全的。 例如有:首先创建一个字符串对象,然后将字符串对象隐…...

USB Over IP专用硬件的5个特点

USB over IP技术通过将USB协议数据封装在标准TCP/IP网络数据包中&#xff0c;从根本上改变了USB连接。这允许客户端通过局域网或广域网远程访问和控制物理连接到服务器的USB设备&#xff08;如专用硬件设备&#xff09;&#xff0c;从而消除了直接物理连接的需要。USB over IP的…...

解决:Android studio 编译后报错\app\src\main\cpp\CMakeLists.txt‘ to exist

现象&#xff1a; android studio报错&#xff1a; [CXX1409] D:\GitLab\xxxxx\app.cxx\Debug\3f3w4y1i\arm64-v8a\android_gradle_build.json : expected buildFiles file ‘D:\GitLab\xxxxx\app\src\main\cpp\CMakeLists.txt’ to exist 解决&#xff1a; 不要动CMakeLists.…...