美团大规模KV存储挑战与架构实践--图文分析

美团大规模KV存储挑战与架构实践–图文分析

原作者:美团技术团队

原文链接:https://tech.meituan.com/2024/03/15/kv-squirrel-cellar.html

1 美团 KV 存储发展历程

第一代:使用Memcached

img

什么是一致性哈希?

哈希:hash,可以通过Key存储Value,也可以通过Key取得Value. 简单说就是Value存储的位置是通过Hash算法计算出来的

(实现,如HashMap)。

随着客户端发起的请求数量越来越高,为了加快响应速度,在客户端与数据库之间增加了缓存层,把数据库中的热点数据存入缓存,这样客户端可以直接从缓存取得热点数据,无需每次都访问数据库,即加快了响应时间,又降低了数据库层的压力。

在这里插入图片描述

hash取模运算

随着业务规模不断扩大,数据量也跟着增大,缓存数量飙增,这样就需要考据搭建缓存集群,把大量的缓存分散到多台缓存服务器中进行存储

取模算法hash(key)%N,即:对缓存数据的key进行hash运算后取模,N是机器的数量;运算后的结果映射对应集群中的节点。具体如下图所示:

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=F%3A%2FBaiduNetdiskDownload%2FDevOps%E7%AC%94%E8%AE%B0-MarkDown%E5%8E%9F%E7%89%88%2FDevOps%2FPictures%2Fimage-20240607182832191.png&pos_id=img-VgEmEbVn-1717929022871在这里插入图片描述

问题,如上图,三个node,所以N为3,此时key通过公式hash(key)%3存入指定节点,之后扩容成4个节点,N为4,公式也变成了hash(key)%4,之前n为3的值取不出来了。

一致性哈希

一致性哈希算法将整个哈希值空间映射成一个虚拟的圆环。整个哈希空间的取值范围为02^32-1,按顺时针方向开始从0232-1排列,最后的节点232-1在0开始位置重合,形成一个虚拟的圆环。

对服务器IP地址进行哈希计算,哈希计算后的结果对232取模,结果一定是一个0到232-1之间的整数。最后将这个整数映射在哈希环上,整数的值就代表了一个服务器节点的在哈希环上的位置。即:hash(服务器ip)% 2^32。

当服务器接收到数据请求时,首先需要计算请求Key的哈希值;然后将计算的哈希值映射到哈希环上的具体位置;接下来,从这个位置沿着哈希环顺时针查找,遇到的第一个节点就是key对应的节点

在这里插入图片描述

服务器扩容

D数据本来应该会落在node1中,由于扩容节点node4,D数据落在了node4中

在这里插入图片描述

服务器缩容

node4节点宕机或者移除后,数据D继续顺时针找到node1节点存储。

在这里插入图片描述

数据倾斜与虚拟节点

数据abcd都落在node1中,node2,node3没事干,node1压力山大。

在这里插入图片描述

解决方案,使用虚拟节点

hash(服务器ip)% 2^32 变更为 hash(服务器ip+随机数)% 2^32

例如:Hash(“114.211.11.141”);

变更为:

Hash(“114.211.11.141#1”);

Hash(“114.211.11.141#2”);

注意,虚拟节点只是帮助真实节点扩大获取数据的范围,并不会保存数据,所获取的数据最终还是要存储在真实节点中。

在这里插入图片描述

memcached的问题

传统的memcached是不支持内存数据的持久化操作,因为它将数据存储在内存当中的,当服务器宕机重启,数据会丢失。

不适合存储1M以上的数据。

适用场景:缓存一些很小但是被频繁访问的,即便你丢失也不会影响系统以及系统业务正常执行的数据。如:新闻热点缓存,即便日后数据丢失,热点已经降温,数据不重要。

第二代:使用Redis

img

优点:支持持久化,服务宕机后数据不会丢失,可以通过哨兵机制进行故障恢复(failover)

宕机数据不丢失策略

RDB每5分钟一次生成快照,AOF每秒通过一个后台的线程持久化操作,最多丢一秒的数据。单独用RDB会丢失很多数据,单独用AOF数据恢复没RDB快,所以解决方案是第一时间用RDB恢复,然后AOF做数据补全

缺点:扩缩容丢失数据。

一致性hash只是用来减少扩缩容时数据迁移量,无法对整个集群进行统一管理(缺乏类似提供心跳检测等服务的中心管理层,数据迁徙的时候,节点无法感知整个集群的状态,数据从A节点中迁徙出去了,但接收的B节点处于网络卡顿状态导致无法接受全部迁徙数据等问题)

第三代:阿里巴巴的 Tair

Tair 开源版本的架构主要是三部分:最下边的是存储节点,存储节点会上报心跳到它的中心节点,中心节点内部设有两个配置管理节点,会监控所有的存储节点。如果有任何存储节点宕机或者扩容之类的行为,它会做集群拓扑的重新构建,拥有数据迁移机制来保证数据的完整性。

img

缺点:

1.中心节点是高可用的,但是会发生脑裂。

脑裂:选举bug,多个leader,多个从节点被选举成了主节点,不干从节点的活了导致数据丢失。

2.和redis的数据类型不兼容

第四代:

基于Tair的Cellar ,基于Redis Cluster的Squirrel

img

这两个存储其实都是 KV 存储领域的解决方案。实际应用上,如果业务的数据量小,对延迟敏感,建议用 Squirrel ;如果数据量大,对延迟不是特别敏感,我们建议用成本更低的 Cellar 。

2 大规模 KV 存储的挑战

1.集群的规模越来越大,节点增加困难(比如带宽饱和)

2.部分业务场景带来的木桶效应以及长尾延迟(例如:mget

3.如何保证集群可用性不会随着规模的变大而有所降低

名词解释:

mget:

可以一次性读取redis中多个值:

redis 127.0.0.1:6379> SET key1 "hello"
OK
redis 127.0.0.1:6379> SET key2 "world"
OK
redis 127.0.0.1:6379> MGET key1 key2 someOtherKey
1) "Hello"
2) "World"
3) (nil)

长尾效应:

红色区域量大响应时间短,黄色区域量小耗时长。比如使用了上面的mget批量读取就有大概率造成此类问题。

在这里插入图片描述

3 内存 KV Squirrel 挑战和架构实践

img

上图是美团的 Squirrel 架构。中间部分跟 Redis 社区集群是一致的。它有主从的结构,Redis 实例之间通过 Gossip 协议去通信。右边添加了一个集群调度平台管理整个集群,把管理结果作为元数据更新到 ZooKeeper。我们的客户端会订阅 ZooKeeper 上的元数据变更,实时获取到集群的拓扑状态,直接对 Redis 集群节点进行读写操作。

难点补充:

Gossip 原理:

节点1更新数据,告知了相邻节点2,4,7;相邻节点再去告诉自己的相邻节点。

在这里插入图片描述

优点:去中心化(多个缓存中间件采用,区块链采用)

缺点:当节点特别多的时候消耗性能,节点更新后相邻节点可能会重复更新,非常损耗性能。

3.2 Gossip优化

为了解决上述的扩展性问题,我们对社区的 Gossip 方案进行了优化。首先针对 Gossip 传输的消息,我们通过 Merkle Tree 对其做了一个摘要,把集群 Gossip 通信的数据量减少了90%以上。服务端节点仅需要对比 Hash 值即可判断元数据是否有更新对于存在更新的情况也能快速判断出更新的部分并仅对此部分元数据进行获取、更新,大幅降低了 Gossip 消息处理的资源消耗

原文中的默克尔树(Merkle Tree)

img

补全图:

在这里插入图片描述

类似平衡二叉树,通过对比上层节点的hash是否一致即可得知是否已经更新,可双向判断:判断更新以及找到更新位置。难度:之前为O(N)现在为O Log(N)

3.3 Squirrel 垂直扩展的挑战

节点过大,Fork生成RDB影响性能。(执行RDB的主要三种场景:save,bgsave,主从复制)

Redis备份数据做持久化操作有AOF和RDB两种,为了不影响主线程,会通过内置的Fork系统启动一个子线程执行,但Fork子进程过程中如果节点过大,依然会占用大量资源导致阻塞。可以简单理解为,Redis会在数据增长到一定程度或者执行主从复制的时候,备份自己的数据,生成一个RDB文件(快照),保存当时Redis中的所有数据用于以后的数据恢复,但这个RDB文件尽管通过子线程生成,但每次生成一个大文件在保存还是耗费资源。

3.4 forkless RDB

解决方案就是采用复制队列的方式,由原来的一次拷贝一个大的(越大越慢,会造成阻塞),改成一个key一个key的往队列拷贝生成的方式。

拷贝期间数据变化怎么办:把变化过程也拷贝到队列里。

拷贝期间发生rehash导致里面的key顺序重排怎么办:暂停rehash.

img

这里的rehash 又是什么意思呢?

redis中有一个全局Hash表(HashTable),表里有一个一个的哈希桶(Bucket),桶里装着Entry(存放key,value的指针),数据量特别大的时候会发生Hash冲突行成链表,如下图的Bucket2.

在这里插入图片描述

解决方案:rehash,扩容。

创建一个比原来还大的HashTable,向其中传递原来HashTable的数据,并对存在Hash冲突的地方进行哈希桶的重新分配。

在这里插入图片描述

这就是为什么美团的forkless RDB执行的时候需要停止rehash了,因为要一个一个的拷贝key,并且有游标指向key的位置,但rehash发生后,key的位置就会发生变化。

3.5 工作多线程

原生Redis:IO多线程,工作线程为单线程。

修改为:IO多线程,工作线程也是多线程,通过加锁解决线程安全问题。

img

3.6 Squirrel可用性的挑战

只有两个机房,A选B,B选A,选不出主或者造成脑裂,必须部署3机房,但通常两个副本足够用了,没必要部署3个副本。

3.7 两机房容灾

img

参考 Google Spanner(可伸缩分布式数据库)的见证者投票方式。

简单说就是:

还是三个机房,但保存两个副本就行了,另外一个只投票,不保存副本。

3.8 跨地域容灾

img

3.9 双向同步冲突自动解决

img

简单说就是谁的时间新就保存谁的。

服务器发生了时间回退怎么办:保存数据时使用时间戳,发生回退了依然使用时间戳来防止数据跟着回退。

两个值的更新时间一样怎么办:比较集群ID,保存集群ID大的那一个。(个人理解类似足球比赛积分净胜球等都相同,靠抽签决定谁进入下一轮)

由复制操作改为复制变更后的数据:只考虑操作后的数据,而不是复制操作。

链图片转存中…(img-qMRzytbP-1717929022879)]

3.9 双向同步冲突自动解决

[外链图片转存中…(img-CDljEhDy-1717929022880)]

简单说就是谁的时间新就保存谁的。

服务器发生了时间回退怎么办:保存数据时使用时间戳,发生回退了依然使用时间戳来防止数据跟着回退。

两个值的更新时间一样怎么办:比较集群ID,保存集群ID大的那一个。(个人理解类似足球比赛积分净胜球等都相同,靠抽签决定谁进入下一轮)

由复制操作改为复制变更后的数据:只考虑操作后的数据,而不是复制操作。

保存最近删除的 Key:简单说就是B集群同步复制A集群数据的时候,对于复制过来一个已经不存在的数据,先不要创建,而是到删除库中看一看这个数据是不是已经被删除了。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Elasticsearch 认证模拟题 - 17

这两道题目非常具有代表性,分别是跨集群复制和跨集群检索,需要相应的 许可 这里在虚拟机上搭建集群完成这两道题目,这里补充一下 elasticsearch 和 kibana 的配置文件 # elasticsearch.yml cluster.name: cluster2 node.name: cluster2-node…

【python解决】查询报%d format: a number is required, not str问题

【Python解决】查询报%d format: a number is required, not str问题 在Python中,字符串格式化是一种常见的操作,用于创建包含变量的字符串。如果你在使用%操作符进行格式化时遇到了%d format: a number is required, not str的错误,这意味着…

Java Web学习笔记20——Ajax-Axios

Axios: 介绍:Axios对原生的Ajax进行封装,简化书写,快速开发。 官网:https://www.axios-http.cn Axios 入门: {}是Js的对象。 get的请求参数是在URL后面?和相关参数值。 post的请求参数是在请…

素颜个人引导页源码

源码介绍 素颜个人引导页源码,源码由HTMLCSSJS组成,记事本打开源码文件可以进行内容文字之类的修改,双击html文件可以本地运行效果,也可以上传到服务器里面,重定向这个界面 效果预览 源码下载 素颜个人引导页源码

IIS7整合Tomcat9服务器,并搭建ASP+PHP+JSP完整运行环境

本文以Windows Vista系统为例,详细讲解IIS7整合Tomcat服务器,同时支持ASPPHPJSP三种Web动态网页技术的方法。 Vista系统自带的IIS版本为7.0,能安装的IE浏览器的最高版本为IE9。IE9也是Vue2前端框架支持的最低浏览器版本。 【准备工作】 去微…

k8s——pod控制器

一、pod控制器定义 Pod控制器,又称之为工作负载(workload),是用于实现管理pod的中间层,确保pod资源符合预期的状态,pod的资源出现故障时,会尝试进行重启,当根据重启策略无效&#xf…

「动态规划」打家劫舍的变形题,你会做吗?

213. 打家劫舍 IIhttps://leetcode.cn/problems/house-robber-ii/description/ 你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。这个地方所有的房屋都围成一圈,这意味着第一个房屋和最后一个房屋是紧挨着的。同时&#x…

QT Udp广播实现设备发现

测试环境 本文选用pc1作为客户端,pc2,以及一台虚拟机作为服务端。 pc1,pc2(客户端): 虚拟机(服务端): 客户端 原理:客户端通过发送广播消息信息到ip:255.255.255.255(QHostAddress::Broadcast),局域网…

Tensorflow入门实战 P03-天气识别

目录 1、完整代码 2、运行结果 2.1 查看20张图片 2.2 程序运行 2.3 运行结果 3、小结 ① 代码运行过程中有报错: ② 修改代码如下: ③ 分析原因: 本文为🔗365天深度学习训练营 中的学习记录博客🍖 原作者&…

STM32H750启动和内存优化(分散加载修改)

前些日子有个朋友一直给我推荐STM32H750这款芯片,说它的性价比,说它多么多么好。于是乎,这两天试了试,嚯,真香!我们先看看基本配置 这里简单总结下,cortex-m7内核,128k片内flash …

k8s挂载配置文件(通过ConfigMap方式)

一、ConfigMap简介 K8s中的ConfigMap是一种用于存储配置数据的API对象,属于Kubernetes中的核心对象。它用于将应用程序的配置信息与容器镜像分离,以便在不重新构建镜像的情况下进行配置的修改和更新。ConfigMap可以存储键值对、文本文件或者以特定格式组…

[Vue-常见错误]浏览器显示Uncaught runtime errors

文章目录 错误描述正确写法具体如下 错误描述 当前端代码发生错误时,浏览器中出现以下错误提示。 正确写法 显然这不是我们所期望的,在vue.config.js中配置如下设置关闭Uncaught runtime errors显示 devServer: {client: {overlay: false}具体如下 …

UltraEditUEStudio软件最新版下载及详细安装教程

UEStudio简介: UEStudio建立在上文本编辑器UltraEdit的功能基础上,并为团队和开发人员提供了其他功能,例如深度Git集成。您可以直接在UEStudio中克隆,签出,更新,提交,推入/拉入等操作&#xff…

【WEB前端2024】3D智体编程:乔布斯3D纪念馆-第37课-自动切换纹理

【WEB前端2024】3D智体编程:乔布斯3D纪念馆-第37课-自动切换纹理 使用dtns.network德塔世界(开源的智体世界引擎),策划和设计《乔布斯超大型的开源3D纪念馆》的系列教程。dtns.network是一款主要由JavaScript编写的智体世界引擎&…

后台管理系统排序混乱,分页出现重复条例

检查了接口和请求参数都没有问题。 查询数据库发现是排序字段create_time 都相同导致的。没有区分度。 解决方案 按照唯一id排序 避免create_time 大批量相同 order by create_time ,xxx 两个排序字段

Python第二语言(五、Python文件相关操作)

目录 1. 文件编码的概念 2. 文件的读取操作 2.1 什么是文件 2.2 open()打开函数 2.3 mode常用的三种基础访问模式 2.4 文件操作及案例 3. 文件的写入操作及刷新文件:write与flush 4. 文件的追加操作 5. 文件操作的综合案例(文件备份操作&#x…

推荐4个好用有趣的软件

MyComic——漫画聚合软件 MyComic是一款界面简洁、分类详尽的漫画阅读软件,专为动漫爱好者设计。它提供了丰富的高清漫画资源,支持在线免费阅读,并且可以一键下载到书架,方便随时离线观看,节省流量。用户可以轻松找到喜…

Java多线程-初阶1

博主主页: 码农派大星. 数据结构专栏:Java数据结构 数据库专栏:MySQL数据库 JavaEE专栏:JavaEE 关注博主带你了解更多数据结构知识 1. 认识线程(Thread) 1.线程是什么 ⼀个线程就是⼀个 "执⾏流". 每个线程之间都可以按照顺序执⾏⾃⼰的代…

Linux——信号

目录 一关于信号 二信号概念 三信号产生 四信号处理 1核心转储 2信号的其它常见概念 3函数实现 五信号捕捉 1捕捉流程 2内核态与用户态 2.1再谈地址空间 2.2键盘输入数据 2.3OS的运行过程 3函数实现 六其它问题 1可重入函数 2.volatile 3SIGCHLD 一关于信号 …