【Redis篇】为什么需要 Redis:从单机到分布式的架构演进之路

文章目录

    • [为什么需要 Redis:从单机到分布式的架构演进之路](#为什么需要 Redis:从单机到分布式的架构演进之路)
    • 一、前言
    • 二、基本概念
      • [2.1 应用、模块与组件](#2.1 应用、模块与组件)
      • [2.2 分布式与集群](#2.2 分布式与集群)
      • [2.3 主(Master)与从(Slave)](#2.3 主(Master)与从(Slave))
      • [2.4 中间件](#2.4 中间件)
      • [2.5 衡量系统好坏的三个指标](#2.5 衡量系统好坏的三个指标)
    • 三、阶段一:单机架构
      • [3.1 最开始的样子](#3.1 最开始的样子)
      • [3.2 单机架构的问题](#3.2 单机架构的问题)
    • 四、阶段二:应用与数据分离
      • [4.1 最低成本的第一步拆分](#4.1 最低成本的第一步拆分)
      • [4.2 新的瓶颈:单台应用服务器撑不住了](#4.2 新的瓶颈:单台应用服务器撑不住了)
    • [五、阶段三:应用集群 + 负载均衡](#五、阶段三:应用集群 + 负载均衡)
      • [5.1 多台应用服务器协同工作](#5.1 多台应用服务器协同工作)
      • [5.2 常见的负载均衡调度算法](#5.2 常见的负载均衡调度算法)
      • [5.3 新的瓶颈:数据库撑不住了](#5.3 新的瓶颈:数据库撑不住了)
    • 六、阶段四:读写分离
      • [6.1 主从分离的核心思路](#6.1 主从分离的核心思路)
      • [6.2 为什么读写分离有效](#6.2 为什么读写分离有效)
      • [6.3 新的瓶颈:热点数据反复查数据库](#6.3 新的瓶颈:热点数据反复查数据库)
    • [七、阶段五:引入缓存 ------ Redis 登场](#七、阶段五:引入缓存 —— Redis 登场)
      • [7.1 冷热数据的区别](#7.1 冷热数据的区别)
      • [7.2 引入缓存后的架构](#7.2 引入缓存后的架构)
      • [7.3 为什么选 Redis 而不是 Memcached](#7.3 为什么选 Redis 而不是 Memcached)
      • [7.4 引入缓存带来的新问题](#7.4 引入缓存带来的新问题)
    • 八、阶段六:数据库分库分表
      • [8.1 数据量继续爆炸](#8.1 数据量继续爆炸)
      • [8.2 分库分表的代价](#8.2 分库分表的代价)
    • 九、阶段七:微服务架构
      • [9.1 业务拆分的必要性](#9.1 业务拆分的必要性)
      • [9.2 Redis 在微服务里的位置](#9.2 Redis 在微服务里的位置)
    • 十、总结

为什么需要 Redis:从单机到分布式的架构演进之路

一、前言

💬 这一篇讲什么:在正式学习 Redis 之前,先搞清楚它是怎么"被逼出来"的

🚀 核心内容

  • 什么是分布式系统?常见概念有哪些?
  • 一个电商系统是如何从单机一步步演进到分布式架构的?
  • 每个阶段遇到了什么瓶颈,用什么方案解决?
  • Redis 究竟在哪个环节登场,解决了什么问题?

很多人学 Redis 上来就背命令、背数据类型,学了半天却不明白它为什么存在,用在哪,解决了什么问题。这一篇不写任何 Redis 命令,只讲一件事:一个真实的互联网系统,是如何一步步把 Redis 逼出来的。


二、基本概念

2.1 应用、模块与组件

应用(Application)/ 系统(System):为了完成一整套服务而搭建的程序或程序群。比如淘宝就是一个应用,它背后是无数个相互配合的程序在支撑运转。

模块(Module)/ 组件(Component):当应用复杂到一定程度,会把其中职责清晰、内聚性强的部分单独抽出来,方便理解和维护。就像一支军队会分为突击小组、后勤小组、通信小组------各司其职,互不干扰。

2.2 分布式与集群

分布式(Distributed):系统中的多个模块被部署在不同的服务器上,彼此通过网络通信配合完成任务。比如 Web 服务器和数据库分别跑在两台机器上,这就是分布式。

集群(Cluster):部署在多台服务器上的、为了完成同一个目标的一组组件,整体称为集群。比如三台机器都跑 MySQL,共同提供数据库服务,这就是数据库集群。

两者不用太严格区分:分布式强调物理形态 (运行在不同机器上),集群强调逻辑目标(为了同一个服务目标而协作)。

2.3 主(Master)与从(Slave)

集群里通常有一台机器承担更多职责,称为主节点 ;其他承担辅助职责的称为从节点。比如 MySQL 集群中,只有主库允许写入数据(增删改),从库的数据全部从主库同步过来,只对外提供读取。

2.4 中间件

中间件(Middleware):处于不同应用程序之间、提供通信桥梁的一类软件。打个比方,一家餐厅起初每天自己去菜市场买菜,规模大了之后成立专门的采购部,采购部就是厨房和菜市场之间的"中间件"。在软件里,Redis、Nginx、MyCat 等都属于中间件的范畴。

2.5 衡量系统好坏的三个指标

可用性(Availability):单位时间内系统能正常提供服务的概率。我们常说的"4个9"就是 99.99% 的可用性,换算下来一年中最多允许宕机约 52 分钟;"5个9"则只允许宕机约 5 分钟。

响应时长(Response Time,RT):用户发出请求到收到结果的时间。原则上越短越好,但很多场景下要根据实际情况权衡。

吞吐量 / 并发(Throughput / Concurrent):吞吐量是单位时间内成功处理的请求数;并发是系统同一时刻能承载的最高请求量。我们平时说的"高并发"就是追求这个指标。

好,概念铺垫完毕,下面进入正题。


三、阶段一:单机架构

3.1 最开始的样子

任何系统在刚起步时都是单机架构。假设我们要做一个电商网站,初期团队小、预算紧、用户少,整个系统就跑在一台服务器上:

text 复制代码
用户
 ↓
[单台服务器]
  ├── 应用服务(处理业务逻辑:用户、商品、交易)
  └── 数据库服务(存储所有数据)
       ├── 用户表
       ├── 商品表
       └── 交易表

用户在浏览器输入 www.shop.com,DNS 把域名解析成 IP 地址,浏览器访问那台服务器,服务器处理完业务逻辑后从数据库读写数据,最后把结果返回给用户。

这个阶段技术栈很简单:一个 Web 服务器软件(Tomcat、Nginx 等)加一个数据库(MySQL 等),搭起来就能跑。大多数同学在学校做的课程设计、毕业设计,基本都是这个阶段的架构。

3.2 单机架构的问题

单机的核心问题是:应用和数据库共享同一台机器的 CPU、内存、磁盘。随着访问量增加,两者会互相抢占资源。应用逻辑跑得慢,数据库也跑得慢,整体性能很快触顶,迟早需要升级。


四、阶段二:应用与数据分离

4.1 最低成本的第一步拆分

网站上线后逐渐积累了一批稳定用户,访问量开始上升,单机开始撑不住。此时预算依然有限,最低成本的优化方案是:把应用服务和数据库服务分开,分别部署到两台服务器上。

text 复制代码
用户
 ↓
[应用服务器]               [存储服务器]
  应用服务   ─── 网络 ───   数据库服务
(处理业务逻辑)              ├── 用户表
                           ├── 商品表
                           └── 交易表

两台机器各司其职,不再互相抢资源,系统的承载能力得到明显提升,而且改动成本很低,只需要把数据库迁移到另一台机器上即可。

4.2 新的瓶颈:单台应用服务器撑不住了

随着业务继续增长,出现了爆款商品,流量暴增,单台应用服务器又触顶了。这时候摆在面前的有两条路:

垂直扩展(Scale Up):花大钱换一台性能更强的服务器。优点是不需要改代码;缺点是硬件性能和价格不是线性关系------性能翻倍,价格可能翻四倍,而且硬件性能本身存在物理上限。

水平扩展(Scale Out):多加几台同等规格的普通服务器,把流量分摊开。优点是成本可控,扩展上限高;缺点是系统复杂度增加,需要解决"流量怎么分"的问题。

长期来看,水平扩展才是正确的路。


五、阶段三:应用集群 + 负载均衡

5.1 多台应用服务器协同工作

水平扩展之后有了多台应用服务器,但随之而来一个问题:用户的请求该发给哪台?这就需要一个负载均衡器来统一接收请求,再按照一定的策略分发出去。

text 复制代码
用户
 ↓
[负载均衡器]
 ├── [应用服务器 1]
 ├── [应用服务器 2]   ─── 网络 ───   [数据库服务器]
 └── [应用服务器 3]

5.2 常见的负载均衡调度算法

负载均衡器该怎么分发请求?常见的策略有以下几种:

轮询(Round-Robin):依次轮流,非常公平。请求1给服务器1,请求2给服务器2,请求3给服务器3,然后循环。

加权轮询(Weight-Round-Robin):给性能更强的服务器分配更高的权重,能者多劳。比如服务器1性能是服务器2的两倍,就让它处理两倍的请求量。

一致性哈希:根据用户特征(比如 IP 地址)计算哈希值,相同特征的用户总是被路由到同一台服务器。这就像银行的专属客户经理服务,你每次打电话都对接同一个人,状态和上下文可以延续。

这个阶段用到的技术:Nginx、HAProxy、LVS 等负载均衡软件。

5.3 新的瓶颈:数据库撑不住了

应用层通过水平扩展解决了流量问题,但无论加多少台应用服务器,所有请求最终都会落到那一台数据库上。数据库很快成为整个系统的新瓶颈。

那能不能像扩展应用服务器一样,直接加多台数据库来分摊压力?

不能。 数据库有特殊性------如果数据随意分散在多台服务器上,就无法保证数据的一致性。想象这个场景:用户 A 向用户 B 转账 100 元,A 的余额在数据库1上减了 100,但 B 的余额在数据库2上没有加上,这 100 元就凭空消失了。所以数据库的扩展需要更谨慎的设计。


六、阶段四:读写分离

6.1 主从分离的核心思路

解决数据库瓶颈的方案是读写分离 :保留一台主库 负责所有的写操作(增删改),其余的从库数据全部从主库同步过来,只负责响应读请求。

text 复制代码
用户
 ↓
[负载均衡器]
 ├── [应用服务器 1]
 ├── [应用服务器 2]
 └── [应用服务器 3]
          │
          ├── 写请求 ──→ [主数据库]
          │                  ↓ 数据同步
          └── 读请求 ──→ [从数据库 1]
                     ──→ [从数据库 2]
                     ──→ [从数据库 3]

6.2 为什么读写分离有效

绝大多数互联网系统的读写请求比例都是严重不对称的。以电商为例,可能 100 次操作里有 95 次是读(浏览商品、查订单),只有 5 次是写。把读压力分散到多台从库,主库只承担写入,整体压力就大幅降低了。

当然这个方案不是没有代价的:主库到从库的数据同步存在一定的时间延迟,也就是说从库的数据会短暂地落后于主库。大部分场景下这个延迟可以接受,但对于强一致性要求高的场景(比如支付结果查询)就需要额外处理。

这个阶段用到的技术:MyCat、TDDL、Amoeba 等数据库中间件,负责自动将读写请求路由到对应的库。

6.3 新的瓶颈:热点数据反复查数据库

读写分离之后系统又撑了一段时间,但新的问题浮现出来:有些数据被反复查询,每次都要走数据库,哪怕数据根本没有变化。

比如电商首页的爆款商品信息,每秒可能被查询几十万次,而这些数据几个小时都不会变一次。每次查询都打到数据库,既慢、又浪费,还在白白消耗数据库的连接资源。

这个问题靠继续加从库已经解决不了了,需要引入新的解决思路。


七、阶段五:引入缓存 ------ Redis 登场

7.1 冷热数据的区别

这时候我们意识到,数据可以按照访问频率分成两类:

热数据:被频繁读取、但不常变化的数据。比如商品基本信息、首页推荐列表、用户 Session。

冷数据:不常被访问的数据。比如用户几年前的历史订单、归档日志。

对于热数据,每次都去数据库查完全没必要。把它放进内存缓存起来,直接从内存读,速度比磁盘快几十倍乃至上百倍,同时数据库的压力也大幅降低。

7.2 引入缓存后的架构

text 复制代码
用户
 ↓
[负载均衡器]
 ├── [应用服务器 1]
 ├── [应用服务器 2]
 └── [应用服务器 3]
          │
          ├── 先查缓存 ──→ [Redis 缓存服务器]  ← 命中直接返回结果
          │                       ↑ 未命中时回填
          ├── 写请求   ──→ [主数据库]
          │                   ↓ 同步
          └── 读请求   ──→ [从数据库]

核心逻辑 很简单:应用处理读请求时,先去 Redis 查。如果 Redis 里有(缓存命中 ),直接返回,整个流程不碰数据库;如果 Redis 里没有(缓存未命中),再去数据库查,查完把结果写进 Redis,下次同样的请求就直接命中缓存了。

通过这种方式,绝大多数读请求在缓存层就被拦截掉了,真正打到数据库的请求大幅减少,系统的响应速度和承载能力都得到了质的提升。

7.3 为什么选 Redis 而不是 Memcached

缓存中间件的代表有两个:Memcached 和 Redis。Memcached 出现更早,但只支持简单的字符串类型。Redis 则支持字符串、哈希、列表、集合、有序集合等多种数据结构,还提供持久化、主从复制、高可用等能力。正因如此,Redis 逐渐成为分布式缓存的首选,Memcached 的使用场景越来越少。

7.4 引入缓存带来的新问题

引入 Redis 之后,随之而来也出现了一批新问题,后续文章会专门讲,这里先混个眼熟:

缓存穿透:请求的数据在缓存和数据库里都不存在(比如攻击者恶意查询不存在的 key),每次都绕过缓存直接打到数据库,缓存形同虚设。

缓存雪崩:大量缓存 key 在同一时刻集中过期,瞬间所有请求都涌向数据库,数据库可能被打垮。

缓存击穿:某个极热的 key 刚好过期,大量并发请求同时穿透缓存涌向数据库,造成数据库瞬间压力飙升。

这些都是使用缓存时必须面对和解决的经典问题。


八、阶段六:数据库分库分表

8.1 数据量继续爆炸

Redis 缓存挡住了大量读请求,但写请求和数据量本身仍在持续增长。当单张表积累到几千万、几亿行数据时,哪怕有索引,查询性能也会急剧下降,磁盘 IO 成为新的瓶颈。

解决方案是分库分表:把数据按照某种规则拆分到多个库、多张表中,让每张表的数据量都保持在可控范围内。

以电商为例:

  • 评论表按商品 ID 取模,哈希到不同的表中存储。
  • 支付记录按小时建表,同一小时内的记录存在一张表里。
  • 用户数据、商品数据、交易数据分别存在各自独立的数据库(垂直分库)。
text 复制代码
[应用服务器集群]
       │
       ├──→ [用户库(主库 + 从库)]
       ├──→ [商品库(主库 + 从库)]
       └──→ [交易库(主库 + 从库)]

这个阶段用到的技术:MyCat、TiDB、Greenplum 等分布式数据库或中间件。

8.2 分库分表的代价

分库分表显著增加了运维难度。跨库的联表查询变得非常复杂,事务保证也更加困难,对 DBA 的要求很高。这也是为什么很多中小型系统能不分库分表就尽量不分,能用缓存扛住就先用缓存扛。


九、阶段七:微服务架构

9.1 业务拆分的必要性

随着团队规模扩大、业务越来越复杂,把所有业务塞在一个应用里开始带来新的麻烦:

  • 任何一个模块出 bug,整个应用可能一起挂掉。
  • 不同团队同时修改同一份代码,互相踩脚。
  • 某个模块需要扩容,整个应用必须一起扩,资源浪费严重。

解决方案是微服务拆分:把用户系统、商品系统、交易系统拆成独立部署的微服务,每个团队负责自己的服务,独立迭代、独立部署、独立扩容。

text 复制代码
              [电商系统入口 / API 网关]
                         │
          ┌──────────────┼──────────────┐
          ↓              ↓              ↓
   [用户子系统]    [商品子系统]    [交易子系统]
    应用集群         应用集群        应用集群
    Redis缓存        Redis缓存       Redis缓存
    独立数据库       独立数据库      独立数据库

          [公共服务:安全中心、监控预警中心等]

9.2 Redis 在微服务里的位置

可以看到,在微服务阶段,每个子系统都配备了自己独立的 Redis 缓存。Redis 不再是整个系统的一个公共组件,而是渗透到了每一个微服务内部,成为不可或缺的基础设施。


十、总结

回顾整个演进过程,我们可以清晰地看到每个阶段遇到的瓶颈和对应的解决方案:

阶段 核心瓶颈 解决方案
单机架构 应用和数据库抢占同一台机器资源 应用与数据库分离部署
应用数据分离 单台应用服务器触顶 负载均衡 + 应用集群水平扩展
应用集群 单台数据库成为瓶颈 读写分离,主从复制
读写分离 热点数据反复查库,性能浪费 引入 Redis 缓存层
引入缓存 单库数据量过大,查询变慢 分库分表
分库分表 业务耦合、团队协作困难 微服务拆分

Redis 在读写分离之后的阶段登场,核心使命是把热数据放进内存,让绝大多数读请求在到达数据库之前就被拦截,既大幅提升了响应速度,又保护了数据库不被压垮。

但 Redis 能做的远不止缓存。排行榜、计数器、消息队列、分布式锁......这些场景我们都会在后续的文章中一一展开。现在最重要的是记住一件事:Redis 不是凭空出现的,它是被真实的业务压力一步步逼出来的。 理解了这个背景,后面学到的每一个 Redis 特性都会有更清晰的落地感。

下一篇预告:正式认识 Redis ------ 它究竟有哪些特性,能做什么,不能做什么,以及从 2.6 到 7.0 它经历了怎样的版本演进。

相关推荐
ID_180079054731 小时前
Taobao & 1688 Product API Technical Overview and JSON Response Reference
数据库
启山智软1 小时前
从零搭建商城系统前端:技术选型与核心架构实践
前端·架构
数据与后端架构提升之路1 小时前
论云原生层次架构在自动驾驶云控平台中的应用
云原生·架构·自动驾驶
June`1 小时前
多线程redis项目之aof
数据库·redis·缓存
marsh02061 小时前
51 openclaw自定义中间件:解决特定业务需求的扩展方案
中间件·ai编程
云游牧者1 小时前
K8S-Ingress流量治理全解-Traefik从入门到实战完全指南
云原生·中间件·容器·kubernetes·ingress·traefik
解局易否结局1 小时前
理解 ops-transformer 在昇腾NPU架构中的位置:把大模型算子放进厨房里讲
深度学习·架构·transformer
Peter-OK1 小时前
Redis从3.x到8.4的核心新特性深度解析与实战学习指南
数据库·redis·缓存
文青小兵1 小时前
云计算Linux——数据库MySQL读写分离、数据库备份、恢复(十八)
linux·运维·服务器·数据库·mysql·云计算