
很多人在学习 Java 后端的时候,都会遇到这样一张技术栈地图:
Spring Boot → Nginx → Gateway → Nacos → Redis → MQ → MySQL → Elasticsearch → 分布式事务 → 微服务 → 监控 → 链路追踪......
问题是,为什么会有这么多东西?
如果只是一个个去学习,很容易变成:
- Nginx 是负载均衡;
- Redis 是缓存;
- MQ 是消息队列;
- Nacos 是注册中心;
- Gateway 是网关;
- Elasticsearch 是搜索引擎......
每个知识点似乎都懂,但把它们放在一起,却不知道它们为什么同时存在。
其实,互联网架构并不是一堆技术名词的堆砌。
它更像是一部由问题推动的系统演进史。
- 今天我们有 Redis,是因为数据库扛不住了。
- 今天我们有 MQ,是因为请求洪峰把系统打爆了。
- 今天我们有微服务,是因为单体系统越来越难以维护。
- 今天我们有 Nacos,是因为微服务越来越多以后,服务之间不知道彼此在哪里。
- 今天我们有链路追踪,是因为系统越来越复杂以后,出了问题不知道到底是哪一环出了问题。
所以,理解互联网架构最重要的不是记住:
"这个组件有什么功能?"
而是建立一个更底层的问题意识:
"系统遇到了什么问题,所以才需要这个组件?"
一、互联网架构到底在解决什么问题?
在学习 Spring Boot 的时候,我们接触到的通常是一个单体应用。
如果把它比作一家小餐厅,那么整个系统可以理解成:
顾客
↓
服务员 Controller
↓
厨师 Service
↓
仓库管理员 / Mapper
↓
数据库 MySQL
- 一家小餐厅只有几个人的时候,这套结构非常简单,也非常好管理。
- 但是,当这家餐厅突然火了起来,事情就开始变得复杂。
- 一天来了几千个顾客。
于是出现了第一个问题:
一家店坐不下了怎么办?
开分店。
分店越来越多以后,又出现:
顾客应该去哪一家?
于是需要统一调度。
客人突然同时涌入,又出现:
厨房做不过来了怎么办?
于是需要排队和缓冲。
订单越来越多,又出现:
一个仓库放不下所有东西怎么办?
于是需要拆分仓库。
最后店铺遍布全国:
哪家店坏了?哪个环节出了问题?
于是需要监控、日志和链路追踪。
这就是互联网架构演进的本质。
我们可以把所有问题归纳成三个最核心的目标:
| 问题 | 餐厅里的表现 | 互联网系统里的表现 |
|---|---|---|
| 高并发 | 突然来了几万名顾客 | 大量请求同时访问系统 |
| 高可用 | 一家店着火,不能让全国都关门 | 某台服务器故障不能导致整个系统不可用 |
| 海量数据 | 仓库装不下所有食材 | 数据量越来越大,单库性能达到瓶颈 |
所以可以得到一个非常重要的结论:
互联网架构,本质上就是系统面对规模增长之后,不断解决新的问题。
二、从一家小餐厅开始
最开始,我们甚至不需要复杂的互联网架构。
假设只有一家餐厅:
餐厅
┌─────────────┐
│ 顾客 │
└──────┬──────┘
↓
┌─────────────┐
│ 服务员 │
│ Controller │
└──────┬──────┘
↓
┌─────────────┐
│ 厨师 │
│ Service │
└──────┬──────┘
↓
┌─────────────┐
│ 仓库 │
│ MySQL │
└─────────────┘
这就是我们学习 Spring Boot 时最容易理解的三层架构。
顾客 → 服务员 → 厨师 → 仓库。
简单、清晰,而且完全够用。
但是问题来了:
如果顾客突然从 100 人变成 10 万人呢?
三、第 1 步:人多了,开分店------集群 + 负载均衡
一家店只能容纳 100 人。
现在突然来了 10000 人。
最直接的办法是什么?
开分店。
于是:
顾客
↓
总服务台
↓
┌──────────┼──────────┐
↓ ↓ ↓
分店A 分店B 分店C
在互联网系统里,就是:
用户
↓
Nginx
↓
┌──────────┼──────────┐
↓ ↓ ↓
Server1 Server2 Server3
这就是集群 + 负载均衡。
Nginx 可以根据负载均衡策略,把请求分发给不同服务器。
例如:
请求1 → Server1
请求2 → Server2
请求3 → Server3
请求4 → Server1
...
这样原来一台服务器承担的压力,就被分摊到了多台服务器上。
解决的问题
单台机器性能不够怎么办?
答案:
横向扩展。
也就是:
一台机器不够
↓
复制更多机器
↓
组成集群
↓
负载均衡
这也是互联网架构中非常重要的思想:
Scale Out(横向扩展)
四、第 2 步:厨房太慢,提前备菜------Redis
虽然我们已经有很多家分店,但新的问题又出现了。
假设餐厅最热门的一道菜是:
鱼香肉丝。
每天有 10000 个顾客点这道菜。
如果每一次都:
顾客
↓
服务员
↓
厨师
↓
仓库
↓
找食材
↓
现做
效率非常低。
于是餐厅想出了一个办法:
热门菜提前做好,放到保温柜里。
顾客来了:
顾客
↓
保温柜
↓
有 → 直接拿
只有保温柜没有的时候,才:
保温柜没有
↓
去仓库取食材
↓
现做
↓
放回保温柜
互联网系统中的这个"保温柜",就是:
Redis
典型缓存流程:
请求
↓
Redis
↙ ↘
命中 未命中
↓ ↓
直接返回 MySQL
↓
写入 Redis
↓
返回
Redis 的核心思想其实非常简单:
把访问频率高的数据放进速度更快的内存中。
所以 Redis 并不是为了"替代 MySQL"。
两者承担的角色不同:
Redis
↓
速度快
↓
缓存热点数据
MySQL
↓
可靠持久化
↓
保存核心业务数据
于是我们得到第二个重要思想:
用空间和内存换时间。
五、第 3 步:客人太多,厨房爆炸------MQ 削峰填谷
现在餐厅又遇到一个非常严重的问题。
平时每秒只有 100 个订单。
厨房刚好可以处理。
但是晚上 8 点突然发生促销:
1 秒钟
↓
10000 个订单
可是厨房:
1 秒钟
↓
只能处理 100 个订单
怎么办?
如果让 10000 个订单直接冲进厨房:
10000 请求
↓
厨房
↓
💥
系统可能直接被打爆。
于是餐厅设置了一个:
接单箱。
顾客先把订单放进接单箱。
厨房按照自己的处理能力:
订单
↓
接单箱
↓
厨房
↓
一个一个处理
互联网系统里的这个"接单箱",就是:
消息队列 MQ。
例如 Kafka、RocketMQ、RabbitMQ。
整个过程:
用户
↓
订单服务
↓
MQ
↓
消费者
↓
业务处理
MQ 的三个核心价值:
1. 异步
不需要所有事情都立即做完。
2. 削峰
把瞬间的流量洪峰变成平稳的处理流量。
请求流量
/\
/ \
/ \ → 洪峰
处理能力
────────────── → 平稳
3. 解耦
订单服务不需要知道:
"到底有多少个其他服务需要处理这个订单?"
只需要:
订单服务
↓
发送消息
↓
MQ
其他服务自己消费:
MQ
├── 积分服务
├── 优惠券服务
├── 通知服务
└── 数据统计服务
因此:
MQ 不只是一个"异步工具",它实际上是在帮助系统隔离流量和业务之间的耦合。
六、第 4 步:一家店什么都做太乱------微服务
随着餐厅越来越大,又出现一个新的问题。
最开始:
一家餐厅
├── 用户
├── 订单
├── 支付
├── 商品
├── 库存
└── 营销
所有东西都在一个系统里。
这就是单体架构 。
一开始没问题。
但当代码越来越多:
订单代码
用户代码
支付代码
商品代码
库存代码
营销代码
...
所有代码耦合在一起。
于是:
改支付功能,可能影响订单。
改订单功能,可能影响库存。
一个模块出现问题,整个系统都可能受到影响。
于是餐厅开始拆分。
总部
│
┌──────────┼──────────┐
↓ ↓ ↓
川菜馆 粤菜馆 甜品店
↓ ↓ ↓
独立经营 独立经营 独立经营
互联网系统也是一样:
Gateway
↓
┌──────────┼──────────┐
↓ ↓ ↓
订单服务 用户服务 支付服务
这就是:
微服务架构。
按照业务领域,把一个庞大的系统拆成多个相对独立的服务。
例如:
订单服务
├── 创建订单
├── 查询订单
└── 修改订单
用户服务
├── 用户注册
├── 用户登录
└── 用户信息
支付服务
├── 创建支付
├── 支付回调
└── 支付查询
微服务解决的核心问题之一就是:
复杂度。
它不是"为了高级而拆分",而是因为系统规模增长以后,单体系统的复杂度已经超过了人能够舒服管理的范围。
七、第 5 步:分店太多,不知道去哪------Nacos + Gateway
微服务拆出来以后,新的问题马上出现:
订单服务怎么找到用户服务?
假设用户服务现在有:
User Service 1
192.168.1.10:8080
User Service 2
192.168.1.11:8080
User Service 3
192.168.1.12:8080
订单服务不可能把这些 IP 地址全部写死。
因为:
- 服务可能扩容;
- 服务可能缩容;
- IP 可能变化;
- 某个实例可能挂掉。
于是需要一个"总部通讯录"。
这就是:
注册中心。
在 Spring Cloud Alibaba 体系中经常使用:
Nacos
服务启动的时候:
User Service
↓
"我来了,这是我的地址"
↓
Nacos
订单服务需要调用用户服务:
Order Service
↓
"User Service 在哪里?"
↓
Nacos
↓
返回可用实例
↓
RPC
↓
User Service
所以 Nacos 解决的是:
服务在哪里?
而 Gateway 解决的是:
用户的请求应该去哪里?
整个结构可以理解为:
用户
↓
Gateway
↓
┌──────┴──────┐
↓ ↓
订单服务 用户服务
↑ ↑
└──── Nacos ──┘
Gateway 是用户进入微服务系统的统一入口。
它可以统一处理:
- 路由
- JWT 鉴权
- 限流
- 跨域
- 请求日志
而 Nacos 更像是微服务内部的"通讯录"。
八、第 6 步:仓库扛不住了------MySQL 主从、读写分离、分库分表
系统继续增长。
这次轮到数据库出现瓶颈。
最开始:
所有请求
↓
MySQL
但是数据越来越多,请求越来越多。
于是可以先做:
主从复制。
MySQL 主库
/ \
↓ ↓
从库1 从库2
主库主要负责写:
INSERT
UPDATE
DELETE
从库负责读:
SELECT
于是:
写请求
↓
主库
读请求
↓
从库
这就是:
读写分离。
但是,如果数据规模继续增长呢?
一个数据库真的可能放不下所有数据。
于是继续拆:
数据库
↓
┌─────────┴─────────┐
↓ ↓
用户库 订单库
↓ ↓
用户表 订单表
↓
订单表1 / 订单表2 / ...
这就是
分库分表。
它背后的思想依然是:
单个节点扛不住,就把压力分散到多个节点。
你会发现:
服务器扛不住
↓
集群
数据库读太多
↓
读写分离
数据库数据太多
↓
分库分表
其实都是同一个思想:
分而治之。
九、第 7 步:系统越来越复杂------Elasticsearch
数据库解决了数据存储问题,但又出现了新的需求:
搜索。
例如电商网站搜索:
"黑色 男士 运动鞋 42码"
用户希望:
- 全文搜索;
- 模糊搜索;
- 分词;
- 相关性排序;
- 高亮;
- 聚合分析。
这并不是传统 MySQL 最擅长的事情。
于是可以引入:
Elasticsearch。
整个系统形成:
MySQL
│
核心业务数据
│
↓
Elasticsearch
│
搜索索引
这里需要建立一个重要认识:
Elasticsearch 通常不是为了替代 MySQL,而是补充 MySQL 的搜索能力。
MySQL 更关注:
数据可靠地存下来。
Elasticsearch 更关注:
数据快速地搜索出来。
这就是典型的:
不同组件解决不同问题。
十、最后一个问题:系统出问题了怎么办?
到这里,我们的系统已经变得非常复杂:
用户
↓
Nginx
↓
Gateway
↓
订单服务
↓
用户服务
↓
Redis
↓
MySQL
↓
MQ
↓
支付服务
↓
...
这时候,如果用户突然告诉你:
"我的订单怎么一直加载?"
你打开代码可能会发现:
每个服务看起来都没问题。
那么到底哪里出了问题?
于是我们需要三个东西:
1. 日志
日志回答:
系统刚才发生了什么?
例如:
Order Service
16:20:01 请求进入
User Service
16:20:02 查询用户
MySQL
16:20:10 SQL 执行完成
2. 监控
监控回答:
系统现在怎么样?
例如:
CPU:90%
内存:85%
QPS:12000
响应时间:3.5s
错误率:8%
当指标超过阈值:
监控
↓
告警
↓
开发人员
3. 链路追踪
链路追踪回答:
一次请求到底经过了哪些服务?每一步花了多长时间?
例如
用户请求
↓ 10ms
Gateway
↓ 20ms
Order Service
↓ 50ms
User Service
↓ 3000ms
MySQL
于是你终于发现:
原来不是订单服务慢,而是用户服务查询数据库用了 3 秒。
这就是:
SkyWalking / Zipkin 等链路追踪系统的价值。
十一、于是,一张完整的互联网架构图出现了
经过前面的不断演进,我们最终得到的系统大致变成:
用户
浏览器 / APP
│
↓
CDN
图片 / 视频缓存
│
↓
DNS
域名解析
│
↓
Nginx
负载均衡 / 限流 / 反向代理
│
↓
Gateway
路由 / 鉴权 / 限流
│
↓
┌─────────────┐
│ Nacos │
│ 服务注册发现 │
│ 配置管理 │
└──────┬──────┘
│
┌───────────┼───────────┐
↓ ↓ ↓
订单服务 用户服务 支付服务
↕ ↕ ↕
└─────── RPC 调用 ──────┘
│ │ │
┌─────┴─────┐ │ ┌─────┴─────┐
↓ ↓ ↓ ↓ ↓
Redis MQ MySQL Elasticsearch
│ │ │ │
↓ ↓ ↓ ↓
缓存 异步 持久化 搜索
削峰
↓
┌─────────────────┐
│ 可观测性体系 │
├─────────────────┤
│ 日志 │
│ 监控告警 │
│ 链路追踪 │
└─────────────────┘