一、“技术思考六问”
- 它是什么?
- 它解决什么问题?
- 为什么需要它?
- 它是怎么实现的?
- 它有什么代价和局限?
- 什么情况下应该用它,什么情况下不应该用?
例如学 Redis。
不要停留在:
Redis 是一个内存数据库,速度很快。
继续问:
① 它是什么?
Redis是什么?
→ 一个内存型数据存储系统。
② 它解决什么问题?
→ 数据库访问太慢、重复查询太多。
③ 为什么需要它?
→ 如果每次请求都查MySQL,大量重复请求会造成数据库压力。
④ 它怎么实现?
→ 数据主要放在内存中,通过数据结构和高效网络模型处理请求。
⑤ 代价是什么?
→ 内存成本高;数据持久化、数据一致性、缓存失效等都会带来复杂性。
⑥ 什么情况下使用?
→ 高频读取、变化相对较慢的数据。
什么时候不适合?
→ 不能因为“Redis快”就所有数据都放Redis。
二、继续问“如果……”
不断给系统增加约束。
形成一个非常重要的思考习惯:
正常情况 ↓ 如果用户变多呢? ↓ 如果数据变多呢? ↓ 如果某个组件挂了呢? ↓ 如果网络断了呢? ↓ 如果请求重复了呢? ↓ 如果突然流量暴增呢? ↓ 如果需求改变了呢?
三、举一个完整例子:学 MySQL 索引后怎么思考
假设你刚学完:
B+Tree 索引。
很多人到这里就结束了。
但是你应该开始问:
第一层:为什么
为什么数据库需要索引?
如果没有索引:
1 2 3 4 … 1000000
查一个用户,需要大量扫描。
有索引之后:
Root / \ / \ Node Node / \ / \ Data Data Data可以更快定位。
第二层:为什么是 B+Tree?
为什么不是普通二叉树?
为什么不是 Hash?
为什么 MySQL 常用 B+Tree?
这时候你开始比较:
B+Tree Hash AVL 红黑树
然后发现:
数据库不仅要:
id = 100
还经常需要:
id > 100 ORDER BY id BETWEEN 100 AND 500
于是你开始理解:
数据库索引不仅追求单点查询,还要支持范围查询和磁盘访问效率。
这就是“为什么”。
四、接下来思考“极端情况”
例如:
SELECT * FROM user WHERE name = ‘Tom’;
加索引以后很快。
那么继续问:
如果有1000万条数据呢?
如果有1亿条呢?
如果这个字段重复率非常高呢?
如果查询条件是:
WHERE name LIKE ‘%Tom%’
还快吗?
如果:
WHERE age = 20 AND city = ‘Shanghai’
两个字段都有索引,数据库怎么选?
你开始发现:
技术不是“用了就快”,而是存在边界条件。
五、再进一步:思考“代价”
这是很多初学者最缺的一步。
例如:
建索引可以提高查询速度。
听起来是好东西。
但继续问:
索引有没有代价?
有。
索引 ↓ 查询更快
同时:
占用磁盘 + 占用内存 + 写入变慢 + 更新成本增加
于是你得到真正的工程结论:
不是索引越多越好,而是在查询性能和写入成本之间进行权衡。
这就是架构。
六、以后遇到任何技术,都可以强行从“正反两面”想
给你一个非常实用的模板:
使用它的好处是什么? 不用它的坏处是什么?
使用它的坏处是什么? 不用它的好处是什么?
比如 Redis。
使用 Redis:
优点:
快 减少数据库压力
缺点:
增加系统复杂度 存在一致性问题 占用内存
于是你再问:
为什么不是所有数据都直接放 MySQL?
这时候你的理解就开始深入了。
七、再建立一个特别重要的思考维度:对比
技术学习特别适合比较。
例如学:
ArrayList
不要只学:
ArrayList 是动态数组。
而是比较:
ArrayList vs LinkedList
思考:
问题
ArrayList
LinkedList
随机访问
强
弱
中间插入
一般
一般/特定场景有优势
内存连续性
较好
较差
实际使用
很常见
更少
然后继续问:
为什么实际开发中 ArrayList 经常比 LinkedList 更常用?
这就会把你引向:
CPU Cache
内存局部性
对象开销
最终又回到了计算机系统。
一个知识点会自然牵出另一个知识点。
八、另一个非常强的思考方法:反过来想
例如你学:
Redis缓存。
你应该故意问:
如果没有 Redis,我怎么办?
可能:
MySQL ↓ 增加索引 ↓ 读写分离 ↓ 数据库集群
然后继续:
如果 Redis 也不够呢?
Redis ↓ 集群 ↓ 分片
继续:
如果服务器挂了呢?
主从 + 哨兵 + 集群
继续:
如果缓存和数据库数据不一致呢?
然后出现:
Cache Aside Write Through Write Back
你会发现:
架构知识不是一堆孤立的技术,而是一连串“如果……怎么办?”
九、最值得培养的是“故障思维”
你以后学后端,一定要养成这个习惯:
任何组件,我都要问:它坏了怎么办?
比如:
MySQL挂了怎么办?
Redis挂了怎么办?
Kafka挂了怎么办?
网络断了怎么办?
一个服务实例挂了怎么办?
一个机房挂了怎么办?
一个请求发送两次怎么办?
一个消息消费两次怎么办?
数据库突然慢100倍怎么办?
这时候你学到的就不再只是:
“Redis是什么。”
而是:
“如何设计一个即使 Redis 出问题也不会直接把整个系统搞崩的系统。”
这已经是架构思维了。
十、再往上:从“技术问题”思考到“业务问题”
这是非常重要的一层。
比如:
为什么需要消息队列?
初学者答案:
Kafka可以异步。
更好的答案:
某些任务不需要用户实时等待,所以把它异步化,可以降低接口延迟并削峰。
更进一步:
哪些任务可以异步?哪些不能?
例如:
用户下单:
检查库存 支付
通常不能随便异步。
但:
发短信 积分统计 行为日志
往往可以异步。
这就是: 技术 → 业务
架构师必须能够做这种判断。
十一、你还应该建立“从底层往上看”的习惯
例如: 为什么 Java 程序很慢? 不要停留: Spring慢。
继续往下拆: 业务代码 ↓ Java ↓ JVM ↓ 线程 ↓ 操作系统 ↓ CPU ↓ 内存 ↓ 网络 / 磁盘
然后逐层问: 到底是哪一层出了问题? 这就是以后性能优化的核心思维。
十二、你以后学习一个技术,大概按照这个顺序
比如学 Kafka:
先知道是什么 ↓ 知道为什么需要 ↓ 知道怎么用 ↓ 理解核心原理 ↓ 比较其他方案 ↓ 思考优缺点 ↓ 思考极端情况 ↓ 制造故障 ↓ 看源码 ↓ 自己实现简化版 ↓ 放进项目 ↓ 进行性能测试 ↓ 思考架构取舍。
十三、最终练出来三种本能
第一种:为什么
为什么需要它? 为什么这样设计? 为什么不能换一种?
第二种:如果
如果数据增加10倍? 如果流量增加100倍? 如果组件挂掉? 如果网络断了?
第三种:代价
这样做有什么好处? 代价是什么? 有没有更简单的方案?
这三种思维 你现在可以把以后学习的知识理解成一棵树:
一个技术 │ ┌────────────┼────────────┐ ↓ ↓ ↓ 为什么 怎么做 有什么代价 │ │ │ ↓ ↓ ↓原理/背景 实践/源码 权衡 │ ↓如果规模扩大? │ ↓ 如果出现故障? │ ↓ 能否换方案? │ ↓ 系统架构