一、数据库的"中年危机"
想象一下数据库MySQL是个勤勤恳恳的会计大叔,今年刚满35岁的他,每次Tomcat服务(好比年轻的前台接待员)收到客户端请求,都要让大叔翻找厚重的账本(磁盘IO)。当客流量激增时,前台不断喊话:"大叔快查XX数据!",大叔逐渐手忙脚乱。随着客流不断激增,以及前台的不断喊话,大叔走向了崩溃的边缘。------这就是数据库瓶颈的经典场景。
此时我们请来了最强大脑"记忆大师Redis"(缓存),这位记忆大师能把热点数据记在大脑里(内存存储)。80%的常见问题都能秒答,只有疑难杂症才需要唤醒会计大叔。这种"内存缓冲层"的机制,让系统响应速度直线提升。
解释:客户端的请求首先查到经过Redis缓存层,Redis以其惊人的内存读写速度,迅速响应大部分热点数据的查询。如果Redis中不存在所需数据,这时才会将请求转发给MySQL数据库,进行磁盘IO操作。通过这种方式,大大减轻了MySQL的负担,使其能够专注于处理那些真正复杂的数据查询,从而有效缓解了数据库的"中年危机"。
二、记忆大师Redis团队
2.1主从复制:职场师徒制
三年后,Redis大师的咨询室门庭若市。客户端们举着号码牌排到云服务器走廊: "大师!查我的购物车!" "大师!先查我的秒杀资格!" 由于Redis记忆大师出色的表现,深受客户端们的好评。 此时门口有3个学生慕名而来要拜师学艺。从今往后,大徒弟处理写请求,二徒弟三徒弟接读请求,只见徒弟们手持binlog秘籍开始实时同步数据。 某日机房地震,大徒弟突然宕机。二徒弟瞬间掏出偏移量日记本:"别慌!我有全量备份+增量日志,马上顶上主节点!
解释:主从复制机制在Redis中扮演着重要的角色,它允许Redis实现数据的读写分离和负载均衡。在这种机制下,主节点负责处理写操作,即接收新的数据或更新现有数据。而从节点则负责处理读操作,它们通过复制主节点的数据来保持数据的一致性。当客户端发送读请求时,可以被路由到从节点上,从而减轻主节点的负担,提高系统的整体吞吐量。 这种读写分离的策略使得Redis能够更高效地处理大量的客户端请求。主节点可以专注于处理复杂的写操作,而从节点则可以分担读操作的负担。这样,整个团队(Redis集群)的工作效率得到了提升,同时也提高了系统的可用性和容错性。即使某个从节点出现故障,其他从节点仍然可以提供读服务,确保系统的稳定运行。
2.2数据分片:分布式文件柜
随着大量客户端们的热情拜访。数据量暴涨让师徒们陷入"存储焦虑"。记忆大师Redis灵机一动,祭出哈希取模分片大法,将文件(数据)分到三个文件柜。直到某天老板塞进第四个文件柜... (数据迁移现场) 三徒弟抱着硬盘哀嚎:"为什么新增1个节点要搬动75%的数据?!我的发际线啊!"
由于增加了节点,导致哈希后取模算法由原来的%3变为了%4,所有的数据存储以及检索功能发生了变更,老的数据需要进行迁移才能适应最新的检索机制。
解释:单个Redis实例在面对高并发读写时可能会成为性能瓶颈。通过将数据分散到多个节点,可以充分利用多个服务器的资源,从而提升系统的整体性能和吞吐量。同时,随着数据量的增长,单个Redis实例的内存可能无法满足存储需求。 数据分片允许通过添加更多的节点来扩展存储容量,从而突破单机的内存限制。数据分片可以采用多种形式,上面通过计算哈希值,然后取模后进行存储的方式,就是哈希分片。 它要求我们在增加或减少存储节点时,必须重新计算并分配所有数据,这无疑是一项庞大而繁琐的工作。 这种全量数据迁移不仅耗时耗力,还可能导致服务中断,影响系统的稳定性和用户体验。因此,我们需要一种更为灵活和高效的数据分片策略,以应对数据规模的不断变化。
三、哈希环:让数据找到回家的路
3.1 哈希分片的"搬家噩梦"
还记得第二章的分布式文件柜吗? "老板,新增的004号文件柜到了!" "太好了!现在把4/8/12号标签的文件全搬过去!,原来的文件搬出来重新分配一遍" ------全体人员卒。 这时候老板发现:服务器不是文件柜,搬家是要掉头发的!
3.2 哈希环登场
聪明的记忆大师灵机又动:"为什么不让数据自己找下家?" 想象一个刻着0~2³²-1数字的魔法转盘(哈希环)。我们这样玩转数据: 具体操作:
- 把每个Redis服务器(文件柜)比如"redis-01:192.168.1.1"哈希后钉在转盘上
- 把数据(文件)的key(比如"user:1001")也哈希后甩到转盘
- 数据顺着时针方向滑行,遇到的第一个服务器就是它的家
如图所示: 文件A、文件B按照顺时针归属在节点1,文件C归属在节点2,文件D归属在节点3。
假设此时如果要新增节点4,哈希后落在了节点2和节点3之间。
那么按照顺时针数据归属的规则,在节点3到节点4之间的数据,之前是归属在节点2的,之后归属在节点4。那么数据迁移也只需要迁移节点3到节点4之间的数据,从节点2迁移到节点4,其他节点中的数据不用迁移。这样的方式叫一致性哈希分片。采用一致性哈希分片,节点新增或者删除,能很大程度减少数据迁移的成本。
3.3 数据倾斜:相亲市场的残酷现实
某天魔法转盘(哈希环)上出现了这样的对话: Redis(大徒弟):"为什么80%的数据都往我这挤?" Redis(二徒弟):"可能因为...你长得像吴彦祖?" Redis(三徒弟):"而我像岳云鹏?"
这就是数据倾斜:
对于存储框架来说:数据切斜就是大部分的数据存储在少量服务器上。少量的数据存储在大部分服务器上。 对于计算框架来说:数据切斜就是大部分数据由少量的服务器计算。少量的数据由大部分服务器计算。
就像在相亲市场某些节点成为"高富帅节点",而其他节点沦为"单身狗节点"。
这时候单身的朋友们急了,应该怎么解决数据倾斜呢?
**解决方案:**虚拟分身术 可以让每个服务器在环上创建N个影分身(虚拟节点)。 就像相亲时: 1.吴彦祖分身成100个普通男生 2.岳云鹏也分身成100个普通男生 3.数据随机选择任意分身,最终均匀分配
解释:数据倾斜现象的出现,其根本原因在于哈希算法本身所具有的随机性特点。当系统中的节点数量相对较少时,这种随机性可能导致大量的数据不均匀地分布到少数几个节点上。为了解决这一问题,可以采取一种策略,即让原本数量有限的节点在系统中虚拟地表现为更多的节点。通过这种方式,可以有效地分散数据,减少单个节点上的数据压力,从而缓解数据倾斜带来的负面影响。
3.4竞争对手的攻击
自从记忆大师Redisl来后,会计大叔MySQL终于闲下心来。因为只有疑难杂症才需要他来处理。 此时传来暗悄悄地对话:
竞争对手A:"听说客户端们最近都跑去对面访问,怎么把我们的生意全抢光了" 竞争对手B:"是的,听说他们请了记忆大师,还是使用了独家绝技哈希环。" 竞争对手A:"哈希环?" 竞争对手B:"没关系,我用十万个不存在的文件(key)发起攻击!" MySQL会计大叔:"我...我裂开了..."
缓存穿透攻击:
- 查询不存在的数据(如id=-1)
- Redis查不到→穿透到MySQL
- 高并发时大量请求直接击穿数据库
就在MySQL会计大叔快扛不住时,他想起了他的发小保安大叔(过滤器),于是请求帮忙来进行安全守卫。
缓存穿透防御: 1.布隆过滤器:就像保安大叔,快速拦截可疑人物。
2.空值缓存:给"不存在的key"的结果发个临时身份证(短期缓存)。
3.限流熔断:当MySQL会计大叔开始崩溃时,暂时拒绝部分请求。
3.5 保安大叔的自我介绍
由于大伙上次的防御非常成功,尤其是上次来协助的保安大叔(过滤器) 这次可是立了大功。在庆功宴上,这位保安大叔开始了自我介绍,大家好,我的真名叫布隆过滤器...
解释:这里说一下布隆过滤器算法的原理:
- 假设存在一个ID为234的请求,它访问了布隆过滤器。
- 布隆过滤器内部维护着一个长度为7的数组,其值仅包含0和1
- 该请求通过哈希函数处理后取模,得到的值为2,随后将数组中位置2的值设置为1。
- 接着,ID为555的请求经过哈希函数取模,得到的值为5,并将数组中位置5的值设置为1。
- 然后,ID为678的请求也通过哈希函数取模,得到的值为2,并将数组中位置2的值再次设置为1。
- 此时,数组下标为2的位置可能对应ID为234或678的请求,而下标为5的位置则对应ID为555的请求。
- 当有客户访问时,ID为888的请求经过哈希函数取模后得到数组下标为2,这表明数据存在。而ID为999的请求经过哈希函数取模后得到数组下标为3,该位置的值为0,这表明数据不存在。
- 因此,使用布隆过滤器时,如果请求的ID存在,仍有可能出现误判,因为所有请求都经过哈希函数处理并取模。如果请求的ID不存在,则可以确定它确实不存在。由于数组长度为7,误判的概率相对较高。
那么,我们如何减少误判呢?
- 由于哈希碰撞主要由于数组长度有限而发生,我们可以通过增加数组长度来降低碰撞概率,进而减少误判。例如,将数组长度从7增加到10,哈希碰撞的概率将从1/7降低到1/10。
- 使用多个哈希函数。如果选择三个哈希函数,每个函数发生碰撞的概率为1/10,那么三个函数同时发生碰撞的概率仅为1/1000。
四、灵魂三问
Q1:哈希环比传统哈希强在哪?
就像搬家时不用重新打包所有行李,只需移动部分物品到新家!
Q2:虚拟节点为什么能治数据倾斜?
相当于把吴彦祖拆分成100个普通男生,让每个女生都有平等选择机会~
Q3:缓存穿透怎么预防最有效?
三步走:布隆过滤器当门卫 + 给空数据发临时通行证 + 流量过大时启动应急预案!