存储方案作为产品——Midgard探索

news2025/1/9 14:39:49

作者 | greatstone94

导读

互联网业务大多是围绕数据展开,获取、生产数据,投入到产品中为用户服务。百度的搜索业务正是典型的数据密集业务,数据规模大,使用方式多样,极为关注如何构建高效低成本的存储系统。

然而软硬件技术升级、业务增长与变迁从未停止,一个久经验证的方案可能在短短半年后就偏离了设计之初的最佳状态。Midgard是搜索场景下提出的智能化的数据存储方案管理器,本文简要介绍了Midgard如何有效利用数据自身提供的信息,如何利用存储系统的先进特性,始终保持数据服务的高效低廉。

全文3733字,预计阅读时间10分钟。

01 存储需求如何变动

为了说明业务和技术同时驱动着存储方案的变化,此处举一个较为容易理解的例子:网页的倒排索引构建。
假设我们要经营一个叫做tendu的检索服务,业务就是接受一批网页集合,并对这些网页提供检索服务,当网页集合或者网页内容发生变化时,也将这些变化更新到检索结果中。

1.1业务起步——方案 1.0

tendu业务初起步的时候需求是非常简单明了的,因为规模和性能并非瓶颈,需求说明往往是流程性的。我们给出下面这样一个模型来示意这批网页的检索服务应该如何构建:

在这里插入图片描述

为了说明清楚,上图中完整表述了离在线的结构,但是在本文中,我们只关注离线的部分。除去网页数据库之外(假设这个数据库在我们的目标之外,并且极为稳定),最为主要的数据组件就是”正排计算结果存储“这个数据库,这个数据库有两个主要作用:

在这里插入图片描述

这时我们可以看到这个数据系统的需求是明了简单的:

1、根据key和数据名随机读写数据。

2、全量扫描所有数据。

那么一个简单的类Big-Table表格存储系统就可以解决上述问题,此时我们的方案是1.0版本,计算系统面对唯一一个数据库,使用Get/Put接口来计算网页正排数据,使用Scan接口来扫描数据全集组装倒排。

1.2 快速更新 —— 方案 2.0

随着tendu的用户越来越多,用户也发现了产品有一些问题:更新非常慢,一个已经更新到第10话的漫画,在检索结果中,依然显示为一周前的第2话。面对这些用户反馈,业务很快总结出了这个阶段的新目标:提升更新速度。
在1.0方案当中,整个系统的需求都是流程性的,在这个目标下,只要正排对应的网页特征以及倒排索引被正确的产出,这就是一个合格的方案。为了完成更新速度提升的目标,业务需求补充了一些量化描述:

在这里插入图片描述

我们在1.0当中采取的类表格存储很快遇到了瓶颈:计算过程中需要从数据库当中Get一些列,而1.0方案中采用了HDD介质的数据库来存储所有数据,HDD介质的随机IO能力非常低,要提升随机Get的吞吐量则需要非常高的成本,为此,我们重新修改上述的架构。

在这里插入图片描述

经过业务的一番分析发现,有频繁Get需求的只是一部分非常少的数据列,大约只占数据库整体的5%,因此需要一个支持对小体积数据进行高频查询的存储服务。我们在这里增加了一个redis作为这个类型数据的缓存,正排计算服务的随机Get请求发送给Redis,写入请求同时发送给Redis和我们的表格存储。
至此,使用HDD和内存混合存储的方案基本满足了业务的快速更新需求。

1.3大范围收录 —— 方案3.0

随着更新速度越来越快,用户在检索服务上可以得到的结果越发精准、有效,业务效果广受好评,但是也迎来了新的产品需求:有一些小众的需求不是大多数人的需要,但是恰好有一些网页可以满足这部分需求,这部分网页的数量是非常巨大,但是往往更新并不频繁。
此时需求中出现了两组数据集合:

优质集合

在这里插入图片描述

广泛集合

在这里插入图片描述

为满足分别的扫描需求,做出分库分表的方案,一个库存储优质集合,另外一个库存储广泛集合。

在这里插入图片描述

02 引入存储方案层

2.1 精细化存储方案的问题

如上,我们讲述了一个检索服务的演变,为了不断适应新的业务需求,不停变换存储方案。带来的结果是:

1、存储效果——到达了较为理想的状态。

2、存储后端数量翻倍(1到2)再翻倍(2到4)。

3、不同存储之间的数据存在关系,这些关系需要所有业务计算模块知晓,管理成本上升。

在这里插入图片描述

2.2 Midgard——存储方案管理

开篇的例子很好的说明了存储方案调整的方式,根据数据使用需求、结合存储介质特性,反复迭代。Midgard是基于这一思路做出来的数据层,让业务脱离对具体存储的管理和维护。用户可以使用变更需求描述的方式表达业务变化,而代码和各种设施层面则不需变动,因为Midgard提供了稳定的接口。

核心结构——按名访问数据

Midgard的核心可以看作以下几个部分:

1、Meta模块,元信息管理,存放了各种数据的基础配置信息,比如某字段是否拥有Cache,存储在何处。

2、Server模块接口层,处理用户请求,将用户请求根据元信息加载进来并进行预处理。

3、算子/执行器层,接口层会将用户请求编译成多个算子,并组织成一定结构交给执行器执行。

在这里插入图片描述

通过较为简单的分层结构满足了数据名与接口实现分离的要求,算子和执行器通过从Meta模块获取的编排信息就可以知道有哪些步骤需要执行,接口层面则对用户完全屏蔽掉这些细节。并且修改Meta当中的信息就可以修改一个数据列的具体行为,实现了数据存储方案的灵活管理。

按需调整能力

1、用户向Midgard注册数据接口的需求量

  • 例如数据PAGE_SCORE需要get接口供给1000QPS的服务能力

2、根据业务需求,修改存储方案的元信息

  • 一般来说业务会有两类需求:新增添加数据,定期更新存储方案重新调优

3、稳定使用

4、Midgard根据从执行器和存储服务上采集到的数据反过来优化存储方案

在这里插入图片描述

从上面的示意图来看,Midgard是数据需求与存储方案之间的桥梁,接受各种需求,落地成各种存储方案,后续再根据从执行层获取到的后验信息积极的调整存储方案。
在我们一开始举的例子当中,那些嵌在各个业务代码里的存储间处理逻辑,对业务就可以简化成一步:对Midgard更新数据需求描述,并且业务无需管理这些具体的存储组件,当我们要开展一个新的业务时也可以复用我们现有的技术方案。

组合计算能力

此外,得益于执行器的结构,每个操作都是由若干个独立的算子组合形成的,Midgard因此具备一定的组合计算能力。
举一个例子:现有两张表,表A包含了网页的主要信息,表B是一个用户评分系统,记录了用户对网页的打分,其中有一项sham_score标记了用户是否认为网页有虚假信息,并且这一列加载了cache。
我们现在想要组装一个任务,从表A中定期扫描所有的网页,将sham_score>5的数据全部清除。一般来说这可能需要一些复杂的代码来同时读取三个存储:a) 表A b) 表B c) sham_score的缓存,但是Midgard的组合计算能力,可以将细节隐藏在冰山之下。
用户传递给Midgard的可能是一个简单的原语序列:

Scan(A).Join(B.sham_score).Filter(sham_score > 5).Delete(A)

首先Midgard会把它拆解为一个命令序列:

Scan A
Join sham_score
Filter sham_score > 5
Delete A

然后Midgard会从元信息中得出sham_score有可用缓存的信息,拆解为:

Scan A
Join sham_score.cache     // 尝试读取缓存
FallbackJoin sham_score   // 如果缓存获取失败则退回到原数据
Filter sham_score > 5
Delete A

考虑到这样一个任务,对存储的主要压力有:A的扫描压力,cache读取压力,原数据读取压力,从A中删除数据压力。还可以在Midgard中插入几个限流算子,由于使用了惰性求值,所以在限流策略不触发数据消费时,限流算子之前的算子的IO就可以暂时挂起。

Scan A
Limit xx M/s              // 插入限流算子通过执行器反压
Join sham_score.cache     // 尝试读取缓存
FallbackJoin sham_score   // 如果缓存获取失败则退回到原数据
Filter sham_score > 5
Limit xx M/s              // 插入限流算子进行反压
Delete A

这样一套逻辑如果由各个业务单独实现可能会非常繁琐,但是得益于Midgard算子的原子化拆分,很容易通过简单组装完成数据的功能组合。

03 结语

整体来说,Midgard是搜索的数据系统在智能化方面的尝试。很多数据业务都是人工了解业务诉求、分析合适的方案,方案一经制定极少变动,只有在极少数大规模架构变革时顺带修改。
这种运营模式依赖人工经验,缺少持续维护的途径,并且在产生新的技术突破时很难惠及存量业务,而且会随着时间推移,需求的变动使得最初的方案设计逐渐腐化。
Midgard希望提供一个对业务稳定的数据接口层,让存储方案变更对业务屏蔽,并且具有长久的可维护性。例子当中的分表和缓存也不是Midgard仅有的能力,未来可能会接入更多的功能和方案选择,让存储系统面向数据使用者,持续迭代。

——END——

推荐阅读

百度垂类离线计算系统发展历程

度加剪辑App的MMKV应用优化实践

百度工程师浅析解码策略

百度工程师浅析强化学

浅谈统一权限管理服务的设计与开发

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/953664.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

算法工程题(非递减顺序 排列)

* 题意说明: * 给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n , * 分别表示 nums1 和 nums2 中的元素数目。 * 请你 合并 nums2 到 nums1 中,使合并后的数组同样按 非递减顺序 排列。…

flex实现瀑布流布局可用于uniapp项目和vue项目

flex布局实现瀑布流 介绍 flex实现瀑布流布局,可用于vue项目,uniapp项目。 实现方式 将列表分为两列或者多列,在循环时分别处理列表数据显示。 预览地址 http://diy.hsycms.com/waterfall/index.htmlhttps://gitee.com/link?targethttp%3A%2F%2Fd…

gitlab升级

1.下载需要的版本 wget -c https://mirrors.tuna.tsinghua.edu.cn/gitlab-ce/yum/el7/gitlab-ce-15.7.6-ce.0.el7.x86_64.rpm --no-check-certificate gitlab-ce-15.4.6-ce.0.el7.x86_64.rpm gitlab-ce-15.7.6-ce.0.el7.x86_64.rpm gitlab-ce-15.9.7-ce.0.el7.x86_64.rpm g…

node 如何下载任意版本

开门见山啦 第一步:打开node官网 Node.js 第二步:点击下载 进入下面的页面,然后往下滑,点击 All download options 查看以往所有的版本号: 这样就可以按自己的需求下载对应的node版本啦 或者 : 最简单…

【Cortex-M3权威指南】学习笔记4 - 异常

目录 实现 CM3流水线CM3 详细框图CM3 总线接口总线连接模板 异常异常类型优先级定义优先级组 向量表中断输入于挂起NMI中断挂起 Fault 类异常总线 faults存储器管理 faults用法 faults SVC 与 PendSV 实现 CM3 流水线 CM3 处理器使用 3 级流水线,分别是:…

Elasticsearch 7.6 - Springboot应用基础操作篇

ES 7.6 - JAVA应用基础操作篇 环境准备依赖配置 实体类准备使用说明索引/映射操作创建索引和映射索引和映射相关查询删除索引 文档操作插入数据更新数据删除数据批量操作 文档查询根据ID查询根据字段精准查询根据字段分词查询控制返回字段范围查询组合查询排序分页高亮搜索聚合…

C#---第21: partial修饰类的特性及应用

0.知识背景 局部类型适用于以下情况: 类型特别大,不宜放在一个文件中实现。一个类型中的一部分代码为自动化工具生成的代码,不宜与我们自己编写的代码混合在一起。需要多人合作编写一个类 局部类型的限制: 局部类型只适用于类、接口、结构&am…

MySQL之脏读,不可重复读与幻读的概念及区别

MySQL是一款常用的关系型数据库,但在使用过程中,可能会遇到一些问题,比如脏读、不可重复读和幻读。这些问题可能会导致数据的不一致性,因此需要了解它们的概念及区别。 1. 脏读 首先是脏读。脏读是指在一个事务中读取了另一个事…

软件UI工程师工作的岗位职责(合集)

软件UI工程师工作的岗位职责1 职责: 1.负责产品的UI视觉设计(手机软件界面 网站界面 图标设计产品广告及 企业文化的创意设计等); 2.负责公司各种客户端软件客户端的UE/UI界面及相关图标制作; 3.设定产品界面的整体视觉风格; 4.参与产品规划构思和创意过程&…

java JUC并发编程 第三章 中断机制

系列文章目录 第一章 java JUC并发编程 Future: link 第二章 java JUC并发编程 多线程锁: link 第三章 java JUC并发编程 中断机制: link 文章目录 系列文章目录1 LockSupport前言1.1 如何停止中断运行中的线程1.1.1 通过volatile变量实现1.1.2 通过AtomicBoolean实现1.1.3 通…

智慧工地源码带开发手册文档 app 数据大屏、硬件对接、萤石云

智慧工地解决方案依托计算机技术、物联网、云计算、大数据、人工智能、VR、AR等技术相结合,为工程项目管理提供先进技术手段,构建工地现场智能监控和控制体系,弥补传统方法在监管中的缺陷,最终实现项目对人、机、料、法、环的全方…

Verilog基础:延时模型

相关阅读 Verilog基础专栏https://blog.csdn.net/weixin_45791458/category_12263729.html?spm1001.2014.3001.5482 目录 1、连续赋值延时 1.1、赋值内嵌延时 1.2、线网声明延时 1.3、门延迟 2、过程赋值延时 2.1、过程语句前置时序控制 2.2、过程赋值语句内嵌时序控制…

记录--解决前端内存泄漏:问题概览与实用解决方案

这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 内存泄漏是前端开发中的一个常见问题,可能导致项目变得缓慢、不稳定甚至崩溃。在本文中,我们将深入探讨在JavaScript、Vue和React项目中可能导致内存泄漏的情况,并提…

现代C++中的从头开始深度学习:【6/8】成本函数

现代C中的从头开始深度学习:成本函数 一、说明 在机器学习中,我们通常将问题建模为函数。因此,我们的大部分工作都包括寻找使用已知模型近似函数的方法。在这种情况下,成本函数起着核心作用。 这个故事是我们之前关于卷积的讨论的…

【python爬虫】7.爬到的数据存到哪里?

文章目录 前言存储数据的方式存储数据的基础知识基础知识:Excel写入与读取基础知识:csv写入与读取项目:存储周杰伦的歌曲信息 复习 前言 上一关我们以QQ音乐为例,主要学习了如何带参数地请求数据(get请求)…

软件测试/测试开发丨Pytest和Allure报告 学习笔记

点此获取更多相关资料 本文为霍格沃兹测试开发学社学员学习笔记分享 原文链接:https://ceshiren.com/t/topic/26755 Pytest 命名规则 类型规则文件test_开头 或者 _test 结尾类Test 开头方法/函数test_开头注意:测试类中不可以添加__init__构造函数 注…

IP基本原理(上)

文章目录 一、IP的定义二、IP的作用1.标识节点和链路2.寻址和转发3.适应各种数据链路 三、IP头部封装格式四、MTU五、IP地址1.定义2.格式2.1 点分十进制和二进制关系与转换2.2 由网络位主机位组成2.3 网络位长度决定网段 3.分类3.1 A类3.2 B类3.3 C类3.4 D类3.5 E类 4.特殊地址…

Linux虚拟机磁盘扩容

Linux虚拟机磁盘扩容 问题起源 在使用linux系统开发时遇到文件无法创建的问题,根据提示发现是磁盘空间不足。 使用df -h查看具体磁盘使用情况。 针对这个问题,有两种解决方案: 使用du -sh ./*可以查看当前工作目录下各文件的占用空间大小…

【USRP】Ettus USRP X440 (USRP软件无线电设备)

Ettus USRP X440 30 MHz至4 GHz,1.6 GHz 带宽,基于GPS的OCXO,USRP软件无线电设备 - Ettus USRP X440是一款USRP软件无线电(SDR)设备,可帮助您集成硬件和软件,对高性能、多通道、宽带信号生成和分析系统进行原型验证。…

InnoDB的Buffer

一、Buffer内存结构 MySQL 服务器启动的时候就向操作系统申请了一片连续的内存,默认128M,可通过从参数修改。 [server] innodb_buffer_pool_size 268435456 1.1 控制块 控制块包括该页所属的 表空间编号、页号、缓存页在 Buffer Pool 中的地址、链表…