文章目录
- 前言
- [Redis 知识](#Redis 知识)
-
- [1. 分布式存储方案](#1. 分布式存储方案)
- [2. 五种基本数据结构](#2. 五种基本数据结构)
- [3. 持久化机制](#3. 持久化机制)
- [4. 内存管理](#4. 内存管理)
-
- [内存淘汰策略(8 种)](#内存淘汰策略(8 种))
- 过期键删除策略
- [5. 事务](#5. 事务)
- [6. Lua脚本](#6. Lua脚本)
- [7. Pipeline(管道)](#7. Pipeline(管道))
- [8. 发布订阅(Pub/Sub)](#8. 发布订阅(Pub/Sub))
- [9. 分布式锁](#9. 分布式锁)
- [10. 乐观锁 vs 悲观锁](#10. 乐观锁 vs 悲观锁)
- [11. 高并发场景](#11. 高并发场景)
- [12. 高可用架构详解](#12. 高可用架构详解)
- [13. 常见案例秒判](#13. 常见案例秒判)
- 错题知识总结
- 补充常见易混易错知识
-
- [一、MVC、MVP、MVVM 对比](#一、MVC、MVP、MVVM 对比)
- 二、23种设计模式
- [三、Scrum 项目管理](#三、Scrum 项目管理)
- 四、架构风险、敏感点、权衡点
- 五、常见软件架构风格对比
- [六、关系数据库与 NoSQL](#六、关系数据库与 NoSQL)
- 七、反规范化设计
- 八、数据库设计三阶段
- 九、数据库访问方式与ORM
- 十、MemCache与Redis对比
- 十一、DNS负载均衡与反向代理负载均衡
- 十二、结构化分析与面向对象分析
- 十三、系统设计建模中的图
- 十四、用例关系与类关系
- 十五、Hibernate与MyBatis
- [十六、Java Web技术栈](#十六、Java Web技术栈)
- 十七、分布式事务(2PC/3PC/TCC)
- 十八、软件维护
- 参考资料
前言
本系列文章为软考系统架构设计师笔记,参考 b 站相关视频及相关资料结合自身思考总结而成,参考资料在文末给出,感谢相关博主的分享。如有侵权,立即删除。
摘要 :本文是一份面向系统架构设计师考试与 Redis 技术面试的综合性速查笔记。内容分为两大模块:第一部分系统梳理 Redis 核心知识,涵盖数据结构、持久化、内存管理、事务、Lua脚本、分布式锁、高并发处理、秒杀方案、集群架构等,并配有大量代码示例与口诀记忆;第二部分整理软考中软件架构风格、质量属性、设计模式、项目管理、数据库设计、建模图、分布式事务等高频考点。全书以表格、对比、口诀和秒判案例组织,适合考前速览、复习及日常查阅。
-
答题注意事项
- 尽量分点答题
- 优缺点类题目可结合题干回答
- 根据题目分值决定答题的分点数及详略程度
- 第一题必做,后面题看四选二,看问题能否读懂进行选择。
- 尽量多写:多写不会扣分,少写一定会扣分。
- 提供备选答案的问题:备选答案可能不一定都用上,而且可能其中一个备选答案会重复填。
-
案例的出法太变换莫测了,只能是多积累基础知识,就拿今年(2026年)上半年的题目来说,除了必选题,后面的题感觉都有点强度,没学过,不了解基础知识的话,只能是按自己的理解写,所以还是得多准备,Redis这部分博主认为最近几次考试出的比较频繁,所以补充了这部分的内容,在综合知识部分
Redis 知识
1. 分布式存储方案
- 主从模式(Master/Slave)
- 哨兵模式(Sentinel)
- 集群模式(Cluster)
集群切片方式
- 客户端分片:在客户端就通过 key 的 hash 值对应到不同的服务器。
- 中间件实现分片:在应用软件和 Redis 中间,例如 Twemproxy、Codis 等,由中间件实现路由分派。
- 客户端服务端协作分片:Redis Cluster 模式,客户端可采用一致性哈希,服务端提供错误节点的重定向服务 slot 上。
2. 五种基本数据结构
| 类型 | 说明 | 典型场景 |
|---|---|---|
| String | 最基础类型,可存字符串、整数、浮点数 | 缓存、计数器(INCR/DECR)、分布式锁(SETNX)、Session |
| List | 双向链表,两端操作LPUSH/RPUSH/LPOP/RPOP | 消息队列、最新消息列表、时间线 |
| Hash | 键值对集合,适合存储对象 | 用户信息、商品详情、配置项 |
| Set | 无序不重复集合,支持交并差运算 | 共同好友、标签、去重、抽奖 |
| ZSet | 带分数的有序集合 | 排行榜、延迟队列、范围查询 |
超纲常考扩展:
- HyperLogLog:基数统计(如 UV 统计),误差约 0.81%,极低内存
- Bitmap:位图,适合签到打卡、布隆过滤器
- Geo:地理位置,适合"附近的人"
- Stream:消息队列,支持消费者组(5.0+ 新增)
3. 持久化机制
RDB(快照持久化)
在指定时间间隔内将内存数据快照保存为二进制文件。
- 优点:文件小、恢复快、对性能影响小
- 缺点:可能丢失最后一次快照后的数据
- 触发方式:SAVE(阻塞)、BGSAVE(fork子进程不阻塞)、配置自动触发
AOF(追加日志持久化)
将每条写命令追加到日志文件。
- 优点:数据安全性高、可读性好、可设置不同同步策略
- 缺点:文件大、恢复慢、需要定期重写压缩
- 同步策略:always(最安全最慢)、everysec(推荐)、no(最快不安全)
RDB+AOF混合持久化(4.0+)
AOF重写时,前半段用RDB格式写全量数据,后半段用AOF格式写增量命令。兼顾恢复速度和数据安全。
4. 内存管理
内存淘汰策略(8 种)
| 策略 | 说明 |
|---|---|
| noeviction | 不淘汰,内存满时写操作报错(默认) |
| allkeys-lru | 所有 key 中淘汰最近最少使用的(最常用) |
| volatile-lru | 仅从设置了过期时间的 key 中淘汰 LRU |
| allkeys-lfu | 所有 key 中淘汰最不经常使用的(4.0+) |
| volatile-lfu | 仅从过期 key 中淘汰 LFU |
| allkeys-random | 所有key中随机淘汰 |
| volatile-random | 仅从过期key中随机淘汰 |
| volatile-ttl | 淘汰即将过期的key |
过期键删除策略
惰性删除 (访问时检查)+ 定期删除(每 100ms 随机抽取一批 key 检查)。两者配合,平衡CPU和内存。
5. 事务
- 命令:MULTI → 命令入队 → EXEC / DISCARD
- WATCH:乐观锁机制,监视key,若EXEC前被修改则事务失败
- 特点:不支持回滚 (某命令失败其他仍执行),不满足 ACID(仅满足隔离性)
- 局限:不能嵌套、不能条件判断,复杂场景用**Lua脚本**
原子性库存扣减示例(Lua 脚本):
lua
-- 原子性库存扣减脚本
-- KEYS[1]:库存 key(如 stock:product:1001)
-- ARGV[1]:扣减数量
local key = KEYS[1]
local decrement = tonumber(ARGV[1])
-- 获取当前库存
local stock = tonumber(redis.call("GET", key)) or 0
-- 判断库存是否充足
if stock >= decrement then
redis.call("DECRBY", key, decrement)
return 1 -- 扣减成功
else
return 0 -- 库存不足
end
EVAL 命令调用:
bash
EVAL "local key = KEYS[1]; local decrement = tonumber(ARGV[1]); local stock = tonumber(redis.call('GET', key)) or 0; if stock >= decrement then redis.call('DECRBY', key, decrement); return 1; else return 0; end" 1 stock:product:1001 2
参数说明:
| 参数 | 说明 |
|---|---|
| EVAL | Redis 执行 Lua 脚本的命令 |
| 脚本本体 | Lua 脚本字符串(支持多行或压缩为一行) |
| 1 | KEYS 数组的长度(本例仅 1 个 key) |
| stock:product:1001 | KEYS[1],库存 key |
| 2 | ARGV[1],本次扣减数量 |
优势: 整个"判断库存→扣减库存"过程在 Redis 服务端原子执行 ,避免并发场景下超卖 问题,且仅需一次网络往返。
6. Lua脚本
- EVAL :执行 Lua 脚本,在 Redis 服务端原子执行
- 优势:原子性执行多条命令、减少网络往返、支持条件逻辑
- 典型场景:分布式锁、限流、库存扣减
- EVALSHA:通过 SHA1 摘要执行已缓存脚本,减少传输量
7. Pipeline(管道)
- 原理:多条命令一次性发送,服务端顺序执行后一次性返回
- 优势:减少RTT、提高批量操作效率
- 注意:Pipeline 不是原子操作(与事务不同)
8. 发布订阅(Pub/Sub)
- 命令:PUBLISH、SUBSCRIBE、PSUBSCRIBE
- 特点:消息不持久化、不支持消息确认、无消费者组
- 适用:实时通知、广播;不适用可靠消息传递(建议用Stream或MQ)
9. 分布式锁
基本实现
SET key value NX EX seconds(NX=不存在才设置,EX=过期时间)
解锁(Lua脚本原子操作,防止误删他人锁):
lua
if redis.call("GET",KEYS[1]) == ARGV[1] then
return redis.call("DEL",KEYS[1])
else
return 0
end
Redisson看门狗机制
客户端获取锁后启动后台线程,自动续期 (默认30秒,每10秒续一次),解决锁过期但业务未完成的问题。
Redlock算法(多节点分布式锁)
- 原理:向N个(通常5个)**独立Redis实例加锁, 超过半数(N/2+1)成功**且总耗时小于锁有效期才算成功
- 优点:解决单点故障、更高可用性
- 缺点:实现复杂、存在时钟漂移争议
分布式锁常见问题
| 问题 | 解决方案 |
|---|---|
| 锁过期但业务未完成 | Redisson看门狗自动续期 |
| 误删他人锁 | Lua脚本原子比较+删除 |
| 主从切换丢锁 | Redlock或接受短暂不一致 |
| 可重入锁 | Redisson基于Hash结构(field=线程标识,value=重入次数) |
10. 乐观锁 vs 悲观锁
| 类型 | 思路 | Redis实现 | 适合场景 |
|---|---|---|---|
| 悲观锁 | 先加锁再操作 | SETNX/Redisson分布式锁 | 写多读少、冲突频繁 |
| 乐观锁 | 先操作再检查冲突 | WATCH+MULTI/EXEC(CAS) | 读多写少、冲突较少 |
区别:悲观锁**阻塞等待**,乐观锁** 失败重试**。
11. 高并发场景
缓存穿透
查询的数据在缓存和DB中**都不存在**,每次都打到DB。
- 解决:布隆过滤器 (拦截不存在的key)、缓存空值(设短过期时间)
缓存击穿(热点失效)
**热点key过期**瞬间,大量并发请求打到DB。
- 解决:互斥锁 (只让一个请求查DB)、逻辑过期 (异步更新)、永不过期+后台刷新
缓存雪崩
**大量key同时过期**或Redis宕机,请求全部打到DB。
- 解决:过期时间加随机值 、多级缓存 、熔断降级 、Redis高可用
缓存与数据库一致性
- 推荐:先更新DB + 再删除缓存(Cache Aside Pattern)
- 强一致:延迟双删 、订阅Binlog异步更新
- 最终一致:消息队列异步更新
热Key问题
单个热点key请求量极大,单节点过载。
- 解决:本地缓存分担读压力、** key拆分随机读、 读写分离+多从库**
大Key问题
单个 key 的 value 过大(String > 10KB、Hash/Set 元素 > 5000),导致阻塞。
- 解决:拆分 、压缩 、UNLINK 异步删除
- 发现:redis-cli --bigkeys 、memory usage key
限流
| 方案 | 实现 | 特点 |
|---|---|---|
| 固定窗口 | INCR+EXPIRE |
简单但有临界突刺 |
| 滑动窗口 | ZSET+时间戳 |
精确但内存开销大 |
| 令牌桶/漏桶 | Lua 脚本 | 平滑限流 |
| Redis Cell | CL.THROTTLE |
原生令牌桶 |
秒杀场景
秒杀活动面临瞬时高并发、库存超卖、重复下单等挑战。解决方案核心:Lua 原子扣减库存 + 防重复检查 + 异步下单(MQ 削峰)。
- 要点:原子性 (Lua 一次执行,杜绝竞态)、快速失败 (库存不足/重复下单立即返回)、异步下单(扣减成功后通过消息队列异步创建订单,解耦并发压力)
1. Lua 脚本:原子库存预扣减 + 防重复下单
lua
-- 秒杀原子扣减脚本
-- KEYS[1]:库存key,如 seckill:stock:1001
-- KEYS[2]:已购用户集合key,如 seckill:bought:1001
-- ARGV[1]:商品ID
-- ARGV[2]:用户ID
-- ARGV[3]:购买数量
local stockKey = KEYS[1]
local boughtSetKey = KEYS[2]
local userId = ARGV[2]
local quantity = tonumber(ARGV[3])
-- 1. 重复下单检查
if redis.call("SISMEMBER", boughtSetKey, userId) == 1 then
return -1 -- 已购买
end
-- 2. 库存检查及扣减
local stock = tonumber(redis.call("GET", stockKey) or "0")
if stock >= quantity then
redis.call("DECRBY", stockKey, quantity)
redis.call("SADD", boughtSetKey, userId) -- 标记已购买
return 1 -- 扣减成功
else
return 0 -- 库存不足
end
EVAL 命令调用示例:
bash
EVAL "local stockKey = KEYS[1]; local boughtSetKey = KEYS[2]; local userId = ARGV[2]; local quantity = tonumber(ARGV[3]); if redis.call('SISMEMBER', boughtSetKey, userId) == 1 then return -1; end; local stock = tonumber(redis.call('GET', stockKey) or '0'); if stock >= quantity then redis.call('DECRBY', stockKey, quantity); redis.call('SADD', boughtSetKey, userId); return 1; else return 0; end" 2 seckill:stock:1001 seckill:bought:1001 1001 user123 1
参数说明:
| 参数 | 值 | 说明 |
|---|---|---|
| KEYS1 | seckill:stock:1001 | 商品库存 key |
| KEYS2 | seckill:bought:1001 | 已购用户 Set key |
| ARGV1 | 1001 | 商品ID |
| ARGV2 | user123 | 用户ID |
| ARGV3 | 1 | 购买数量 |
返回值含义: 1=扣减成功,0=库存不足,-1=重复下单。应用层根据返回值决定后续流程。
下面是秒杀处理的整体流程:
#mermaid-svg-sNayPaEChlRbHJcx{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-sNayPaEChlRbHJcx .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-sNayPaEChlRbHJcx .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-sNayPaEChlRbHJcx .error-icon{fill:#552222;}#mermaid-svg-sNayPaEChlRbHJcx .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-sNayPaEChlRbHJcx .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-sNayPaEChlRbHJcx .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-sNayPaEChlRbHJcx .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-sNayPaEChlRbHJcx .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-sNayPaEChlRbHJcx .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-sNayPaEChlRbHJcx .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-sNayPaEChlRbHJcx .marker{fill:#333333;stroke:#333333;}#mermaid-svg-sNayPaEChlRbHJcx .marker.cross{stroke:#333333;}#mermaid-svg-sNayPaEChlRbHJcx svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-sNayPaEChlRbHJcx p{margin:0;}#mermaid-svg-sNayPaEChlRbHJcx .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-sNayPaEChlRbHJcx .cluster-label text{fill:#333;}#mermaid-svg-sNayPaEChlRbHJcx .cluster-label span{color:#333;}#mermaid-svg-sNayPaEChlRbHJcx .cluster-label span p{background-color:transparent;}#mermaid-svg-sNayPaEChlRbHJcx .label text,#mermaid-svg-sNayPaEChlRbHJcx span{fill:#333;color:#333;}#mermaid-svg-sNayPaEChlRbHJcx .node rect,#mermaid-svg-sNayPaEChlRbHJcx .node circle,#mermaid-svg-sNayPaEChlRbHJcx .node ellipse,#mermaid-svg-sNayPaEChlRbHJcx .node polygon,#mermaid-svg-sNayPaEChlRbHJcx .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-sNayPaEChlRbHJcx .rough-node .label text,#mermaid-svg-sNayPaEChlRbHJcx .node .label text,#mermaid-svg-sNayPaEChlRbHJcx .image-shape .label,#mermaid-svg-sNayPaEChlRbHJcx .icon-shape .label{text-anchor:middle;}#mermaid-svg-sNayPaEChlRbHJcx .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-sNayPaEChlRbHJcx .rough-node .label,#mermaid-svg-sNayPaEChlRbHJcx .node .label,#mermaid-svg-sNayPaEChlRbHJcx .image-shape .label,#mermaid-svg-sNayPaEChlRbHJcx .icon-shape .label{text-align:center;}#mermaid-svg-sNayPaEChlRbHJcx .node.clickable{cursor:pointer;}#mermaid-svg-sNayPaEChlRbHJcx .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-sNayPaEChlRbHJcx .arrowheadPath{fill:#333333;}#mermaid-svg-sNayPaEChlRbHJcx .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-sNayPaEChlRbHJcx .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-sNayPaEChlRbHJcx .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-sNayPaEChlRbHJcx .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-sNayPaEChlRbHJcx .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-sNayPaEChlRbHJcx .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-sNayPaEChlRbHJcx .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-sNayPaEChlRbHJcx .cluster text{fill:#333;}#mermaid-svg-sNayPaEChlRbHJcx .cluster span{color:#333;}#mermaid-svg-sNayPaEChlRbHJcx div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-sNayPaEChlRbHJcx .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-sNayPaEChlRbHJcx rect.text{fill:none;stroke-width:0;}#mermaid-svg-sNayPaEChlRbHJcx .icon-shape,#mermaid-svg-sNayPaEChlRbHJcx .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-sNayPaEChlRbHJcx .icon-shape p,#mermaid-svg-sNayPaEChlRbHJcx .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-sNayPaEChlRbHJcx .icon-shape .label rect,#mermaid-svg-sNayPaEChlRbHJcx .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-sNayPaEChlRbHJcx .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-sNayPaEChlRbHJcx .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-sNayPaEChlRbHJcx :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 返回 1:库存扣减成功
返回 0:库存不足
返回 -1:重复下单
👤 用户发起秒杀请求
(HTTP/RPC)
📦 应用层接收请求
构造 Lua 参数(库存 key、用户ID、数量)
⚡ Redis 执行 Lua 脚本
(EVAL)原子校验库存与防重
校验结果
✅ 发送异步下单消息
(Redis Stream / RabbitMQ)
❌ 返回「库存不足」
🔁 返回「不可重复购买」
📨 消息队列消费者
异步创建订单、扣款及后续流程
📬 返回「下单请求已提交」
(用户端等待最终订单结果)
2. 异步下单:消息队列削峰
Lua 脚本返回 1 后,应用侧立即将用户和商品信息推入消息队列,由后端消费者异步完成订单创建、支付等后续流程。这样既避免了同步写入数据库带来的性能瓶颈,又能平滑削峰,防止数据库压力过大。
- 使用 Redis Stream: 通过
XADD命令将订单消息写入 Stream,消费者组读取消费。 - 使用 RabbitMQ: 将订单消息发送到指定队列,由消费者监听处理。
伪代码示例(Java + Redis Stream):
java
Long result = (Long) jedis.evalsha(sha, keys, args);
if (result == 1L) {
// 扣减成功,发送异步下单消息
Map<String, String> orderMsg = new HashMap<>();
orderMsg.put("productId", productId);
orderMsg.put("userId", userId);
orderMsg.put("quantity", String.valueOf(quantity));
orderMsg.put("timestamp", String.valueOf(System.currentTimeMillis()));
jedis.xadd("order_stream", StreamEntryID.NEW_ENTRY, orderMsg);
return "下单请求已提交,请等待结果";
} else if (result == 0L) {
return "库存不足";
} else {
return "不可重复购买";
}
消费者监听 order_stream,读取消息后执行数据库下单逻辑,若失败可重试或回滚库存(补偿事务)。
3. 防止超卖与重复下单
- 防止超卖 :扣减库存的 Lua 脚本在 Redis 服务端原子执行,没有并发竞争窗口,从根本上避免了"读-判-写"造成的超卖。利用 Redis 单线程处理命令的特性,即使大量并发请求,扣减操作也是串行化的,库存不会变为负数。
- 防止重复下单 :在 Lua 脚本中通过
SADD和SISMEMBER将已购买用户 ID 存入 Set,后续同一用户请求会被直接拒绝。Set 的SISMEMBER是 O(1) 操作,不影响性能。对于已创建但未支付或取消的订单,可配合定时扫描清理过期购买记录,释放购买资格。
附加优化: 可将库存和已购 Set 设置过期时间(如活动结束后自动清理),或通过业务补偿释放库存。同时结合前端按钮防重、接口幂等性设计,形成多层防御。
分布式Session
将Session存Redis,实现**多服务器Session共享**。方案:Spring Session + Redis。
幂等性保证
利用 SETNX 生成唯一请求 ID,同一请求只处理一次。场景:支付回调、消息去重。
延迟队列
使用**ZSET**,score设为执行时间戳,定时轮询取出到期任务。5.0+也可用** Stream**。
12. 高可用架构详解
主从复制原理
- 全量同步:首次连接,主库BGSAVE生成RDB发给从库
- 增量同步 :主库维护**repl_backlog**缓冲区,从库断线重连后通过 offset 增量同步
- 问题:主库宕机需手动切换、从库写入延迟
哨兵模式原理
- 哨兵节点**监控主从节点健康**,主库下线后** 自动故障转移**
- 故障判定:主观下线 → 客观下线(quorum 个哨兵确认) → 选举 Leader 哨兵执行故障转移
- 适用:读多写少、需要自动故障转移
Cluster 集群模式
- 数据分片:16384个slot ,key通过**CRC16(key) % 16384**分配
- 节点通信:Gossip协议(PING/PONG/MEET/FAIL)
- MOVED 重定向:key 不在当前节点,返回正确地址
- ASK 重定向:slot 迁移中,临时重定向
- 优势:去中心化、自动分片、高可用
13. 常见案例秒判
| 问题 | 答案 |
|---|---|
| 为什么Redis单线程还这么快? | 纯内存操作、IO多路复用(epoll)、避免线程切换(6.0+IO线程多线程,命令执行仍单线程) |
| Redis和MySQL双写一致性? | 先更新DB再删缓存(Cache Aside) |
| Redis如何实现分布式锁? | SETNX+EX+Lua解锁 / Redisson |
| 缓存穿透/击穿/雪崩? | 布隆过滤器 / 互斥锁 / 随机过期时间 |
| 集群如何保证数据不丢失? | 主从复制+哨兵/集群故障转移+AOF持久化 |
- SAAM分析评估体系结构的过程包括五个步骤,即场景开发、体系结构描述、单个场景评估、场景交互和总体评估。
- ATAM被分为九个步骤,分别是:
- 描述ATAM方法
- 描述业务动机
- 描述体系结构
- 确定体系结构方法
- 生成质量属性效用树
- 分析体系结构方法
- 讨论和分级场景
- 分析体系结构方法
- 描述评估结果
错题知识总结
系统架构设计与评估
- (背) 软件架构风格 是描述某一类特定应用领域中软件系统组织方式和惯用模式。组织方式描述了系统的组成构件和这些构件的组织方式,惯用模式则反映众多系统共有的结构和语义。
- 面向对象架构风格:将数据表示和基本操作封装在对象中。这种模式的构件是对象,对象维护自身表示的完整性,对象之间通过消息机制进行通信,对象交互时需要知道彼此的标识,通过对象之间的协作完成计算过程。
- 控制环路架构风格:将过程输出的指定属性维护在一个特定的参考值(设定点)。控制环路风格包括过程变量、被控变量、输入变量、操纵变量和设定点等构件,通过收集实际和理想的过程状态信息,并能调整过程变量使得实际状态趋于理想状态。
- 主程序-子程序架构风格:所有的计算构件作为子程序协作工作,并由一个主程序顺序地调用这些子程序,构件通过共享存储区交换数据。
- 管道-过滤器架构风格:每个构件都有一组输入和输出,构件接受数据输入,经过内部处理,然后产生数据输出。这里的构件称为过滤器,构件之间的连接件称为数据流传输的管道。
- 常见软件质量属性名称及含义
- 性能 :指系统的响应能力,即要经过多长时间才能对某个事件做出响应,或者在某段时间内系统所能处理事件的个数。
- 设计策略:增加计算资源、改善资源需求(减少计算复杂度等)、资源管理(并发、数据复制等)和资源调度(先进先出队列、优先级队列等)。
- 可用性 :系统能够正常运行的时间比例。
- 设计策略:Ping/Echo、心跳、异常和主动冗余等。
- 可靠性:指软件系统在应用或错误面前,在意外或错误使用的情况下维持软件系统功能特性的基本能力。
- 健壮性:指在处理或环境中,系统能够承受压力或变更的能力。
- 安全性 :指系统向合法用户提供服务的同时能够阻止非授权用户使用的企图或拒绝服务的能力。
- 设计策略:抵御攻击(授权、认证和限制访问等)、攻击检测(入侵检测等)、从攻击中恢复(部分可用性策略)和信息审计等。
- 可修改性 :指能够快速地以较高的性能价格比对系统进行变更的能力。
- 设计策略:软件模块泛化、限制模块之间通信、使用中介和延迟绑定。
- 可变性:指体系结构经扩充或变更成为新体系结构的能力。
- 易用性:衡量用户使用一个软件产品完成指定任务的难易程度。
- 可测试性:指软件发现故障并隔离、定位其故障的能力特性,以及在一定的时间和成本前提下,进行测试设计、测试执行的能力。
- 功能性:系统所能完成所期望工作的能力。
- 互操作性:指系统与外界或系统与系统之间的相互作用能力。
- 性能 :指系统的响应能力,即要经过多长时间才能对某个事件做出响应,或者在某段时间内系统所能处理事件的个数。
- (背) 系统架构风险:是指架构设计中潜在的、存在问题的架构决策所带来的隐患。
- (背) 风险点与非风险点
- 风险点:不是以标准专业术语形式出现的,只是一个常规概念,即可引起风险的因素,可称为风险点。
- 非风险点:某个做法如果有隐患,有可能导致一些问题,则为风险点;如果某件事是可行的、可接受的,则为非风险点。
- (背) 敏感点:是指为了实现某种特定的质量属性,一个或多个构件所具有的特性。
- (背) 权衡点:是影响多个质量属性的特性,是多个质量属性的敏感点。
软件架构风格
- 数据流风格 【传统编译器,每个阶段产生的结果作为下一个阶段的输入,区别在于整体 】
- 批处理序列 :数据必须是完整的,以整理的方式传递(大量 整体 数据、无需用户交互)。
- 管道-过滤器 :数据流传输处理(流式数据 、弱用户交互)。
- 主要特点:过滤器相对独立
- 主要优点:功能模块复用;可维护性和可扩展性较强;具有并发性;模块独立性高。
- 主要缺点:不适于交互性强的应用,对于存在关系的数据流必须进行协调。
- 适合领域:系统可划分清晰的模块;模块相对独立;有清晰的模块接口。
- 早期编译器采用该架构。要一步一步处理的,均可考虑采用此架构风格。
- 优点
- 松耦合(高内聚低耦合)
- 良好的重用性/可维护性
- 可扩展性(标准接口适配)
- 良好的隐蔽性
- 支持并行
- 缺点
- 交互性较差
- 复杂性较高
- 性能较差(每个过滤器都需要解析与合成数据)
- 典型实例
- 传统编译器
- 网络报文处理
- 调用/返回风格 (构件之间 直接交互,紧耦合 )
- 主程序/子程序
- 面向对象
- 主要特点:力争实现问题空间和软件空间结构的一致性。
- 主要优点:高度模块性;实现封装;代码共享灵活;易维护;可扩充性好。
- 主要缺点:增加了对象之间的依赖关系
- 适合领域:多种领域
- 层次结构
- 优点
- 将一个复杂问题分解成一个增量步骤序列的实现。
- 每一层最多只影响两层,允许每层用不同的方法。
- 为软件复用提供了强大的支持。
- 缺点
- 并不是每个系统都可以很容易地划分为分层的模式。
- 很难找到一个合适的、正确的层次抽象方法。
- 独立构件风格 (构件之间 不直接交互,松耦合 )
- 进程通信
- 事件驱动系统(隐式调用) 【事件触发 推动动作,如程序语言的语法高亮、语法错误 提示】
- 主要特点:系统由若干子系统构成且称为一个整体;系统有统一的目标;子系统有主从之分;每一个子系统有自己的事件收集和处理机制。
- 主要优点:适合描写系统组;容易实现并发处理和多任务;可扩展性好;具有类层次结构;简化代码。
- 主要缺点:因为树型结构所以削弱了对系统计算的控制能力;各个对象的逻辑关系复杂。
- 适合领域:一个系统对外部的表现可以从它对事件的处理表征出来。
- 优点
- 松耦合
- 良好的重用性/可修改性/可扩展性
- 缺点
- 构件放弃了对系统计算的控制。一个构件触发一个事件时,不能确定其他构件是否会响应它。而且即使它知道事件注册了哪些构件的过程,它也不能保证这些过程被调用的顺序。
- 数据交换的问题。
- 既然过程的语义必须依赖于被触发事件的上下文约束,关于正确性的推理就存在问题。
- 特点
系统由若干子系统构成且成为一个整体;系统有统一的目标;子系统有主从之分;每一子系统有自己的事件收集和处理机制。
- 虚拟机风格 【自定义流程 ,按流程执行,规则随时改变,灵活定义,业务灵活组合机器人 】
- 解释器
- 主要特点:系统核心是虚拟机
- 主要优点:可以用多种操作来解释一个句子,灵活应对自定义场景。
- 主要缺点:适合于特定领域
- 适合领域:适用于需要"自定义规则"的场合;适合于模式匹配系统与语言编译器。
- 基于规则的系统(规则为中心) :在解释器的基础上增加经验规则
- 适合领域:适用于专家系统
- 优点:可以灵活应对自定义场景
- 缺点:复杂度较高
- 解释器
- 仓库风格(以数据为中心的风格) 【现代编译器的集成开发环境IDE,以数据为中心 ,又称数据共享风格】
- 主要特点:采用两个常用构件中央数据单元和一些相对独立的组件集合
- 主要优点:中央数据单元实现了数据的集中,以数据为中心。
- 主要缺点:适合于特定领域
- 适合领域:适合于专家系统等人工智能领域问题的求解
- 数据库系统
- 特点:以数据为中心
- 黑板系统 (信号处理、问题规划和编译器优化等):语音识别、知识推理
- 优点
- 可更改性和可维护性
- 可重用的知识源
- 容错性和健壮性
- 缺点
- 测试困难
- 不能保证有好的解决方案
- 难以建立好的控制策略
- 低效
- 开发困难
- 缺少并行机制
- 特点:在以数据为中心的基础上,使用中心数据触发业务逻辑部件。
- 典型实例
- 语音识别
- 模式识别
- 图像处理
- 知识推理
- 优点
- 超文本系统
- 现代集成编译环境一般采用这种架构风格。
- 闭环控制架构(过程控制) 【汽车巡航定速,空调调节温度 ,设定参数,并不断调整】
- 主要特点:通过不断的测量被控对象,认识和掌握被控对象;将控制理论引入体系结构构件。
- 主要优点:将控制理论引入到计算机软件体系结构中
- 主要缺点:适合于特定领域
- 适合领域:该系统中一定存在有目标的作用、信息处理闭环控制过程。
- 适合于嵌入式系统,涉及连续的动作与状态,用于解决简单闭环控制问题。
- 经典应用:空调温控,定速巡航。
- C2风格 (层次型架构风格)【构件和连接件、顶部和底部】
- 分层风格
- 主要特点:各个层次的组件形成不同功能级别的虚拟机;多层相互协同工作,而且实现透明。
- 主要优点:支持系统设计过程中的逐级抽象;可扩展性好;支持软件复用
- 主要缺点:不同层次之间耦合度高的系统很难实现
- 适合领域:适合功能层次的抽象和相互之间低耦合的系统
- 基本规则(构件与构件之间不能直接相连,必须要通过连接件)
- 构件和连接件都有一个顶部和一个底部
- 构件的顶部要连接到连接件的底部,构件的底部要连接到连接件的顶部,构件之间不允许直连。
- 一个连接件可以和任意数目的其他构件和连接件连接
- 当两个连接件进行直接连接时,必须由其中一个的底部到另一个的顶部。
- 分层风格
- MVC架构风格
- M:Model(模型)用于 处理应用程序数据逻辑的部分,是应用程序中用于处理应用程序数据逻辑的部分。通常模型对象负责在数据库中存取数据。模型表示业务数据和业务逻辑。
- V:View(视图)用于 处理数据显示的部分,是应用程序中处理数据显示的部分。通常视图是依据模型数据创建的。是用户看到并与之交互的界面。视图向用户显示相关的数据,并能接收用户的输入数据,但是它并不进行任何实际的业务处理
- C:Controller(控制器)用于 处理用户交互的部分,是应用程序中处理用户交互的部分。通常控制器负责从视图读取数据,控制用户输入,并向模型发送数据。
- MVC架构的优点
- 有助于管理复杂的应用程序 ,因为您可以 在一个时间内专门关注一个方面。例如,您可以在不依赖业务逻辑的情况下专注于视图设计。同时也让应用程序大的测试更加容易。
- 简化了分组开发。不同的开发人员可同时开发视图、控制器逻辑和业务逻辑。
- J2EE风格
- 客户层组件:J2EE应用程序可以是基于web方式的,也可以是基于传统的静态的HTML(标准通用标记语言下的一个应用)页面和Applets是客户层组件。
- web层组件:J2EE web层组件可以是JSP页面或Servlet。
- 业务层组件:业务层代码的逻辑用来满足特定领域的业务逻辑处理。
- 信息系统层:企业信息系统层处理企业信息系统软件包括企业基础建设系统例如企业资源计划(ERP),大型机事务处理,数据库系统和其它的遗留信息系统。例如,J2EE应用组件可能为了数据库连接需要访问企业信息系统。* JSP:用于显示、收集数据的部分。作为MVC中的视图V。
- Servlet:作为业务逻辑层,用于处理复杂的业务逻辑,如验证数据、实例化JavaBean、调用DAO连接数据库等。作为MVC中的控制器C。在其中会调用Service方法处理服务。
- JavaBean:用于数据的封装,方便将查询结果在servlet与jsp页面之间进行传递等。
- DAO:用于连接数据库及进行数据库的操作,如:查询、删除、更改等。
- DAO与JavaBean合在一起为MVC中的模型M。
- 基本流程:JSP发一个数据到servlet,servlet收到后做下解析再根据数据调用相应的service去服务,service如果有要调用数据库就通过DAO跟数据库交互,使用javaBean完成封装,返回结果给servlet,servlet再返回给JSP。
- 面向服务的架构SOA:SOA是一种设计理念,其中包含多个服务,服务之间通过相互依赖最终提供一系列完整的功能。各个服务通常以独立的形式部署运行,服务之间通过网络进行调用。
- 企业服务总线ESB :简单来说是一根管道,用来连接各个服务节点。ESB的存在是为了集成基于不同协议的不同服务,ESB做了消息的转化、解释以及路由的工作,以此来让不同的服务互联互通。
- ESB的特点
- SOA的一种实现方式,ESB在面向服务的架构中起到的是总线作用,将各种服务进行连接与整合;
- 描述 服务的元数据和服务注册管理;
- 在 服务请求者和提供者之间传递数据 ,以及对这些数据 进行转换的能力,并支持由实践中总结出来的一些模式如同步模式、异步模式等;
- 发现、路由、匹配和选择的能力,以支持服务之间的动态交互,解耦服务请求者和服务提供者。高级一些的能力,包括对安全的支持、服务质量保证、可管理性和负载平衡等。
- ESB的主要功能
- 服务位置透明性
- 传输协议转换
- 消息格式转换
- 消息路由
- 消息增强
- 安全性
- 监控与管理
- ESB的特点
- 给出系统架构风险、敏感点和权衡点的定义(2)。
答:
(1)系统架构风险:指架构设计中潜在的、存在问题的架构决策所带来的隐患;
(2)敏感点:指为了实现某种特定的质量属性,一个或多个构件所具有的特性;
(3)权衡点:指影响多个质量属性的特性,是多个质量属性的敏感点。 
- 在系统架构设计中,决定系统架构设计的非功能性需求主要有四类:操作性需求、性能需求、安全性需求和文化需求。请简要说明四类需求的含义。
答:
(1)操作性需求:指系统完成任务所需要的操作环境需求及如何满足系统将来可能的需求变更的要求。
(2)性能需求:针对系统性能要求的指标。常见的包括:响应时间、吞吐率。
(3)安全性需求:防止系统崩溃和保证数据安全所需要采取的保护措施或预防措施。
(4)文化需求:使用本系统的不同用户群体对系统提出的特有要求。 - 胖/瘦客户端区别
参考胖客户端与瘦客户端概念与区别
(1)胖客户端:它将应用程序的处理过程分为两个部分:客户端部分client-side和服务器部分server-side。
客户端部分既要处理UI界面的解析显示,又要对大部分的业务逻辑进行处理操作,要求客户端机器要有很强的处理能力,减轻服务器端压力,服务器端只进行客户端访问控制,数据表单接收等操作。
由于客户端做了大部分的工作,他的逻辑体积越发庞大,越来越'臃肿',于是我们就成这样的客户端为胖客户端,例如正常的C/S端类型
(2)瘦客户端:顾名思义,与胖客户端相反,客户端专注于处理UI的数据展示,而不再将大量的逻辑处理放在客户端上,这样客户端只需要简单的单据数据校验逻辑和表单数据提交。
而大量的业务逻辑将在服务器端接收到相关的请求后,通过表单数据进行相应的逻辑处理,然后将结果打包成HTML返回给客户端解析。
这样,客户端的所包含的逻辑代码将会变得很少,相反服务器端的压力将必须经得住考验。

- 从机器学习流程定义的灵活性和学习算法的可扩展性两个方面对解释器、管道过滤器、隐式调用三种架构风格进行对比与分析。
答:
(1)解释器:机器学习流程定义的灵活性高,可扩展能力强,因为解释器风格可以通过自定义流程规则及配套流程解释引擎开发,做到用户层面的流程完全定义,而不需要修改代码,所以无论是修改已有的业务流程,还是要扩展不同的角色,创建新角色的流程都非常便利。
(2)管道过滤器:机器学习流程定义的灵活性较低,可扩展能力较弱,因为管道过滤器是把数据处理智能做成过滤器,把数据传递做成管道,此时如果流程不发生变化,是可以通过这种方式实现的,但一旦流程变化,或是扩展功能,需要对过滤器进行修改调整,或是流程在程序层面重建,此时必须修改代码完成任务。
(3)隐式调用:机器学习流程定义的灵活性一般,可扩展能力一般,隐式调用强调的是通过间接方式进行调用,如采用事件机制,要完成某个动作时先触发事件,事件与相关动作关联,以提升灵活度。 

- 简述微服务架构,并对比单体架构和微服务架构的优缺点。
(1)微服务架构是一种将应用拆分为多个 小型、独立部署的服务单元 的架构模式。每个服务聚焦于一个业务功能,运行在独立进程中 ,通过轻量级协议(如HTTP/REST、消息队列等)与其他服务通信。服务间 松耦合、自治开发、独立部署,常配合容器化和DevOps实现快速迭代和弹性伸缩。
单体架构是将系统的所有功能模块 统一构建为一个整体应用 的架构模式。所有业务模块、逻辑处理、UI、数据库访问都 在一个进程中运行 ,部署时打包为一个整体,统一上线。
微服务架构是将系统按照业务边界 拆分为多个小型独立服务 的架构模式。每个服务 自治运行、独立部署,通过轻量级通信(如HTTP/REST、消息队列)协同工作。
(2)微服务架构的优点在于服务独立、易于扩展部署,支持技术异构,有利于故障隔离和小团队并行开发,提高了系统的灵活性和开发效率;但缺点是系统整体复杂度高,带来通信开销、运维监控难度增加、跨服务数据一致性难以保障,同时对自动化运维和服务治理能力提出更高要求。
单体架构是一体化构建部署的整体系统,适合简单场景;微服务架构则将系统拆解为多个独立服务,提升灵活性和扩展性,适合大型复杂系统。
- 用质量属性6要素描述可用性质量属性场景描述。
质量属性场景描述 = 刺激源+刺激+环境+制品+响应+响应度量
刺激源:系统内部、系统外部
刺激:疏忽、错误、崩溃、时间
环境:正常操作、降级模式
制品:系统处理器、通信信道、持久存储器、进程
系统响应:检测事件并进行以下一个或多个活动:将其记录下来。通知适当的各方,包括用户和其他系统。根据已定义的规则禁止导致错误或故障的事件源。在一段预先指定的时间间隔内不可用,其中,时间间隔取决于系统的关键程度。在正常或降级模式下运行。
响应度量:故障修复时间
- 请分别简述ping/echo和心跳的实现原理。
(1)Ping/Echo模式是主控端主动探测目标节点是否在线的一种机制,目标节点响应后即可判断其健康状态;
(2)心跳机制是由被监控节点周期性向主控端发送心跳信号,主控端是否连续收到心跳来判断节点健康状态。
Ping/Echo模式是较为常见的节点健康检测方法。主控端通过定时发送 Ping 请求,若被监控节点正常工作,会返回 Echo 应答。该方法实现简单,适用于小规模或测试场景。但在大规模系统中,主控端需要同时管理大量探测请求,容易造成 CPU、网络带宽和内存开销过大,影响系统性能与可扩展性。
心跳机制的核心思想是"被监控节点自己证明自己存在"。节点会周期性地向主控端发送心跳包,通常为轻量级数据结构,主控端只需检查是否在指定时间窗口内收到心跳消息。如果心跳信号中断,便可认为节点出现故障。由于心跳包通常较小且由各节点独立发送,因此不会形成集中压力,能够更好地适应 分布式系统和大规模集群场景。
数据库系统与缓存设计
- 反规范化技术 :规范化设计后,数据库设计者希望牺牲部分规范化来提高性能,这种从规范化设计的回退方法称为反规范化技术。
- 采用反规范化技术的益处:降低连接操作的需求、降低外码和索引的数目,还可能减少表的数目,能够提高查询效率。
- 可能带来的问题:数据的重复存储,浪费了磁盘空间;可能出现数据的完整性问题,为了保障数据的一致性,增加了数据维护的复杂性,会降低修改速度。
- 常见的反规范化技术
- 增加冗余列:在多个表中保留相同的列,通过增加数据冗余减少或避免查询时的连接操作。
- 增加派生列:在表中增加可以由本表或其他表中数据计算生成的列,减少查询时的连接操作并避免计算或使用集合函数。
- 重新组表:如果许多用户需要查看两个表连接出来的结果数据,则把这两个表重新组成一个表来减少连接而提高性能。
- 水平分割表:根据一列或多列数据的值,把数据放到多个独立的表中,主要用于表数据规模很大、表中数据相对独立或数据需要存放到多个介质上时使用。
- 垂直分割表:对表进行分割,将主键与部分列放到一个表中,主键与其他列放到另一个表中,在查询时减少I/O次数。
- 分布式数据库缓存的基本概念。
答:分布式数据库缓存指的是 在高并发环境下 ,为了 减轻数据库压力和提高系统响应时间,在数据库系统和应用系统之间增加的独立缓存系统。
Redis 与 MemCache 的差异主要体现在:
①数据结构,MemCache 仅支持简单的 key-value,而 Redis 支持 string、list、hash、set、zset 等复杂结构,更适合处理多样化业务场景;
②持久化,MemCache 不支持持久化,掉电数据全丢,而 Redis 提供 RDB、AOF 等机制保障数据可靠性;
③分片机制,MemCache 一般依赖客户端一致性哈希,而 Redis 提供 Cluster 模式实现服务端分片;
④内存管理,Redis 使用私有内存池,减少内存碎片;
⑤事务支持,Redis 提供事务功能,而 MemCache 不支持。正因如此,Redis 常被用于对可靠性、一致性有要求的场景,而 MemCache 更适合纯缓存、读多写少的轻量级应用。
- Redis分布式存储的常见方案,并解释说明Redis集群切片的几种常见方式。
答:
(1)Redis分布式存储的常见方案:主从模式(Master/Slave)、哨兵模式(Sentinel)、集群模式(Cluster) 。
(2)Redis集群切片的常见方式:
- 客户端分片。即在客户端就通过key的hash值对应到不同的服务器。
- 中间件实现分片。在应用软件和Redis中间,例如Twemproxy、Codis等,由中间件实现服务到后台Redis节点的路由分派。
- 客户端服务端协作分片。Redis Cluster模式,客户端可采用一致性哈希,服务端提供错误节点的重定向服务slot上。不同slot对应到不同服务器。
Redis 单机虽高效,但受限于内存和并发能力,必须通过分布式扩展支撑高并发业务。三种常见方案分别针对不同场景:
主从模式主要解决读写分离和数据备份,但主库宕机时需人工切换;
哨兵模式在主从基础上增加自动化监控与故障转移,提升高可用性;
集群模式则通过内置的 slot 分片机制,支持多主多从、自动负载均衡,是互联网企业应对大规模业务的主流方案。
在 数据分片方式上,客户端分片逻辑简单但耦合度高,需要客户端维护分片策略;中间件分片通过代理层屏蔽复杂性,应用透明,但会引入转发开销;Redis Cluster采用 16384 个 slot,服务端负责管理 slot 与节点映射,客户端根据 key 的 CRC16 计算 slot 并路由到对应节点,若节点迁移则通过 MOVED/ASK 重定向实现动态调整。
- 说明在关系型数据库开发中,逻辑数据模型设计过包含哪些任务?什么是超类实体?什么是派生属性?
答:
(1)逻辑数据模型设计过程包含的任务:确定数据模型、将E-R图转为关系模式、确定完整性约束、确定用户视图 。
(2)超类实体是将多个实体中相同的属性组合起来构造出的新实体 。
(3)派生属性是指某个实体的非主键属性由该实体其他主键属性决定。(派生属性指不必单独存储,而可通过计算得出的属性) - Redis有两种持久化方式,分别是RDB(Redis DataBase)持久化方式和AOF(Append OnlyFile)持久化方式,从磁盘更新频率、数据安全、数据一致性、 重启性能和数据文件大小五个方面比较两种方式。
答:
(1)磁盘更新频率:RDB方式在指定时间间隔内将内存中的数据快照保存到磁盘,而AOF方式则实时记录每次写操作到磁盘。(AOF比RDB文件更新频率高 )
(2)数据安全:AOF方式通过追加日志的方式记录每次写操作,可以更好地保证数据的安全性,但可能会增加磁盘IO负担。(AOF比RDB更安全 )
(3)数据一致性:RDB方式在快照时刻保存数据,可能会导致部分数据丢失,而AOF方式记录每次写操作,数据更加完整和一致。(RDB间隔一段时间存储,可能发生数据丢失和不一致;AOF 通过append模式写文件,即使发生服务器宕机,也可通过redis-check-aof 工具解决数据一致性问题。 )
(4)重启性能:RDB方式在重启时加载快照文件,速度较快;而AOF方式需要重新执行日志文件中的写操作,重启时间可能较长。(RDB性能比AOF好 )
(5)数据文件大小:AOF方式通常比RDB方式的数据文件更大,因为AOF记录了每次写操作。(AOF 文件比RDB文件大) - 给出三种内存淘汰机制
答:LRU(最近最少使用)、LFU(最不经常使用)和随机淘汰 。
(1)从已设置过期时间的数据集最近最少使用的数据淘汰。(2)从已设置过期时间的数据集将要过期的数据淘汰。(3)从已设置过期时间的数据集任意选择数据淘汰。(4)从数据集最近最少使用的数据淘汰。(5)从数据集任意选择数据淘汰。 - 说明常见的反规范化设计方法。
答:
(1)增加冗余列 :增加冗余列是指在多个表中具有相同的列,它常用来在查询时避免连接操作。
(2)增加派生列 :增加派生列指增加的列可以通过表中其他数据计算生成。它的作用是在查询时减少计算量,从而加快查询速度。
(3)重新组表 :重新组表指如果许多用户要查看两个表连接出来的结果数据,则把这两个表重新组成一个表来减少连接而提高性能。
(4)分割表:通过横向或纵向切分提高查询效率,有时对表做分割可以提高性能。 - 在反规范化设计中,解决数据不一致性问题的三种常见方法,
答:
(1)定期同步更新 :通过定时任务批量更新冗余字段,适合实时性要求不高的场景。
(2)触发器同步 :在数据库中设置触发器,当源表更新时自动同步冗余字段,实时性高。
(3)应用程序级同步 :在业务逻辑中,更新源表数据的同时也更新冗余数据,通常借助事务保持一致性。
(触发器能保证在数据更新时自动修改冗余字段,应用程序级同步则可以结合事务管理,确保一次性更新所有相关数据。二者结合能够在保证性能的同时,确保数据一致性。)
- 涉及到排名 相关数据结构设计,一般采用
ZSet(有序集合类型)
- 说明解决Redis和MySQL数据实时同步问题的常见方案。(缓存与数据库的数据一致性问题)
答:
(1)应用层双写 :应用同时写MySQL和Redis,通过事务保证一致性,适合低并发场景。
(2)基于Binlog异步同步 :通过Canal等工具监听MySQL Binlog,捕获更新操作并推送到Redis,适合高并发但可容忍延迟的场景。
(3)消息队列异步更新 :写MySQL后发送消息到消息队列,由消费者异步更新Redis,可解耦、抗高并发。
(4)延迟双删策略 :更新MySQL前后各删除一次Redis缓存,确保脏数据概率最小,适合读多写少的场景。
(5)结合数据库触发器:在MySQL设触发器,监听数据变更并调外部程序更新Redis。会增加数据库负载,维护困难。适用于遗留系统改造。 - 关于缓存和数据库的数据一致性问题,简要介绍数据实时同步更新方案和数据异步准实时更新方案两种方案的基本思路。
答:
(1)实时同步方案 :数据库数据一旦更新,立即同步更新缓存中的对应数据,保证 数据强一致性 。
(2)** 异步准实时方案** :数据库更新时不立即更新缓存,而是 将变更记录入日志或消息队列中 ,再由后台任务 异步刷新缓存,最终实现数据一致性。 - 缓存分片方法常用的有哈希算法和一致性哈希算法,请用200字以内的文字简要说明两种算法的基本原理。
答:
(1)普通哈希算法 :通过哈希函数将键值映射到 固定缓存节点 上,节点变动会导致 大量数据迁移 。
(2)一致性哈希算法 :将节点和数据通过哈希函数映射到一个 环形空间 ,节点增减 只影响局部数据,迁移量小。 - 解释布隆过滤器的工作原理和优缺点。
答:
(1)布隆过滤器通过 多个哈希函数将元素映射到位数组上 ,用于 判断某元素是否存在于集合中 。查询时检查对应位是否全为1,若有0则必然不存在。
(2)优点:占用内存小,查询速度快,适合大规模数据过滤 ;缺点:存在 误判率 (可能将不存在的数据判断为存在),且 不支持删除操作 。布隆过滤器可有效 拦截大量无效请求 ,防止缓存穿透 ,提升系统稳定性。 - 旁路缓存模式。
答:旁路模式在开发中用的比较多,其核心是 将缓存模块设置为I/O路径的一个非强制性组成部分 。在这种模式下,缓存是一个附加组件。(1)在读操作中,首先根据Key在缓存中查找所需的数据。如果成功找到(命中),则直接返回数据;若未命中,则会从存储模块中获取,并在适当的时候把数据写入缓存。
(2)在写操作中,接收到写请求后,首先更新数据库中的数据;数据库中的数据更新完毕后,会发请求给缓存,删除相关联的缓存条目。(是删除,而非更新缓存)
旁路模式在多线程场景下:线程1 正在写入数据库,但还没来得及删除缓存;线程2 此时仍然从旧缓存读取,拿到过期数据。
解决方案如下:
(1)延迟双删。在写入数据时,先删除缓存中的数据,然后更新数据源中的数据,最后在经过一段短暂的延迟后再次删除缓存(记住结论推论比较复杂)。
(2)分布式锁。在写入数据时,先删除缓存中的数据,然后更新数据源中的数据。这一环节加锁解锁确保一致性(获取写锁、更新数据库、删除缓存、释放写锁)。读数据的时候也要对访问数据库的操作获取读锁,缓存读取完毕之后,释放读锁,确保读写操作序列化。
(3)消息队列进行序列化读写操作。消息队列进行读写操作。把同一业务键的写请求路由到同一消息队列,天然顺序、无乱序覆盖。
(4)订阅binlog日志。在写入数据时,先数据源中的数据。同时可以使用阿里的canal将binlog日志采集发送到MQ队列里面,然后通过 ACK 机制确认处理这条更新消息,修改缓存,保证数据缓存一致性。因为队列消费是按顺序的,所以缓存最终会依据顺序修改达到最后的状态。
(5)先写数据库再删除缓存(会有失效的情况,但是概率很低,就是缓存失效和写数据库同时发生的时候,记住结论即可)。
系统设计与建模
- 请用200字以内的文字对ESB的定义进行描述,给出ESB的五个主要功能。
答:
(1)ESB是传统中间件技术与XML、Web服务等技术结合的产物,主要支持异构系统集成。ESB基于内容的路由和过滤,具备复杂数据的传输能力,并可以提供一系列的标准接口。
(2)ESB的主要功能:服务位置透明性;传输协议转换;消息格式转换;消息路由;消息增强;安全性;监控与管理。 - 请用300以内文字说明数据流图(Data Flow Diagram)的基本元素及其作用。
答:
(1)数据流 :数据流是数据在系统内传播的路径,因此由一组成分固定的数据组成。
(2)外部实体 :代表系统之外的实体,可以是人、物或者其他软件系统。
(3)加工(处理) :加工是对数据进行处理的单元,它接收一定的数据输入,对其进行处理,并产生输出。
(4)数据存储:表示信息的静态存储,可以是文件、文件的一部分、数据库的元素等。 - 数据流图常见错误。
数据流图的常见错误分为逻辑错误与语法错误两大类。逻辑错误主要指加工节点输入输出不平衡:
①黑洞------加工只有输入无输出,好比数据"被吞掉";
②奇迹------加工无输入却能输出数据,仿佛"凭空变出";
③灰洞------输入与输出在语义或数量级上不相称(如"输入一个订单号,输出整套综合统计报表"),违反了合理的因果与守恒。
语法错误聚焦于连线/对象的法定组合关系,例如数据存储与外部实体、数据存储与数据存储之间禁止直连,必须经由加工读写;不允许悬空数据流;同一层级图的父子平衡也必须成立,即上层输入/输出在下层应能追溯到具体加工与数据存储的组合。
- CRUD矩阵
数据--过程--CRUD 矩阵用于把"过程模型(DFD 的加工/活动)"与"数据模型(实体/数据存储)"逐格映射,确保读写关系全覆盖、无越权、无遗漏。其中:C(Create) 创建新记录,R(Read) 读取,U(Update) 更新,D(Delete) 删除。构建矩阵的关键是基于业务语义逐一判断每个加工对每个数据存储的操作类型,并与DFD中的数据流方向、名称、含义保持一致,形成一致性与可追溯性证据链。
- 状态图和活动图是软件系统设计建模中常用的两种手段,请用200字以内文字简要说明状态图和活动图的含义及其区别。
答:
(1)状态图主要用于描述 一个对象在其生存期间的动态行为 ,表现一个对象所经历的 状态序列 ,引起状态转移的事件(event),以及因状态转移而伴随的动作(action)。
(2)活动图可以用于描述 系统的工作流程和并发行为 。活动图其实可以看作状态图的特殊形式,活动图中一个活动结束后将立即进入下一个活动(在状态图中状态的转移可能需要事件的触发)。
(3)两者最大的区别是:状态图侧重于描述 行为的结果 ,而活动图侧重于描述 行为的动作 。其次活动图可描述 并发行为,而状态图不能。 - 面向对象系统建模中,用例之间的关系有哪几种类型?
答:用例之间的关系包括:包含、扩展、泛化
(1)当可以从两个或多个用例中提取公共行为时,可以使用包含关系来表示。
(2)如果一个用例混合了两种或两种以上不同场景,即根据情况可能发生多种分支,则可以将这个用例分为一个基本用例和一个或多个扩展用例。
(3)当多个用例共同拥有一个类似的结构和行为的时候,可以将它们的共性抽象成父用例,其他的用例作为泛化关系中的子用例。
- 面向对象系统建模中,类之间的关系有哪几种类型?
答:类之间的关系包括:关联、聚合、组合、依赖、泛化、(实现)
(1)关联关系:描述了一组链,链是对象之间的连接。
(2)聚合关系:整体与部分生命周期不同。
(3)组合关系:整体与部分生命周期相同。
(4)依赖关系:一个事物发生变化影响另一个事物。
(5)泛化关系:特殊/一般关系。
(6)实现关系:接口与类之间的关系。
- MVC
视图(View) → 与"图形""界面"直接相关。
控制器(Controller) → 动作 + 名词,如"会议调度器""任务处理器"。
模型(Model) → 实体类、数据、对象。
- (1)信息工程方法中的"实体(entity)" 与面向对象方法中的"类(class)"之间有哪些不同之处?
(2)在面向对象方法中通常采用用例(Use Case)来捕获系统的功能需求。用例可以按照不同的层次来进行划分,其中的Essential Use Cases和Real Use Cases有哪些区别?
请用100字以内文字解释说明上述两个问题。
答:
(1)实体用于数据建模,而类用于面向对象建模。实体只有属性,而类有属性和操作。
(2)Essential Use Cases可翻译为抽象用例,Real Use Cases可翻译为真实用例。他们的区别在于:Essential Use Cases用于分析阶段,Real Use Cases用于设计阶段。Essential Use Cases描述用例的本质属性,它与如何实现这个用例无关,独立于实现该用例的本质属性,它与如何实现这个用例无关,独立于实现该用例的软硬件技术。Real Use Cases描述的是用例的实现方式,表达了设计和实现该用例时所采用的方法和技术。 - 根据数据流图的含义,请说明数据流图和系统流程图之间有哪些方面的区别。
答:
(1)数据流图中的处理过程可并行;系统流程图在某个时间点只能处于一个处理过程。
(2)数据流图展现系统的数据流;系统流程图展现系统的控制流。
(3)数据流图展现全局的处理过程,过程之间遵循不同的计时标准;系统流程图中处理过程遵循一致的计时标准。 - 请简要说明在描述对象之间的动态交互关系时,协作图与顺序图存在哪些区别。
答:顺序图强调的是对象交互的时间次序;通信图强调的是对象之间的组织结构。 - 采用面向对象方法开发软件,通常需要建立对象模型、动态模型和功能模型,请分别介绍这3种模型,并详细说明它们之间的关联关系,针对上述模型,说明哪些模型可用于软件的需求分析?
答:
(1)对象模型用于描述 系统数据结构 ;动态模型用于描述 系统控制结构 ;功能模型用于描述 系统功能 。
(2)这3种模型都涉及数据、控制和操作等共同的概念,但侧重点不同,从不同侧面反映了系统的实质性内容,综合起来全面地反映了对目标系统的需求。
功能模型指明了 系统应该"做什么" ;动态模型明确了 规定什么时候做 ;对象模型则定义了 做事情的实体 。
(3)对象模型、动态模型和功能模型均可用于软件的需求分析。 - 简要介绍数据流图在分层细化过程中遵循的数据平衡原则。
答:
细化分层数据平衡原则:
(1)子图与父图之间的平衡 :父图与子图之间的平衡要求子图边界上的输入/输出数据流必须与其父图对应的输入/输出数据流保持一致。如果父图中某个加工的数据流在子图中对应多条数据流,但这些数据流的数据项总量与父图中的数据流相匹配,则仍然保持平衡。
(2)子图内部平衡:子图内部加工的输入和输出需保持平衡。 - 在结构化分析和设计过程中,数据流图和数据字典是常用的技术手段,请用200字以内的文字简要说明它们在软件需求分析和设计阶段的作用。
答:
(1)数据流图分析阶段:建立系统的功能模型,从而完成需求分析 ;数据流图设计阶段:为模块划分与模块之间接口设计提供依据 。
(2)数据字典在分析与设计阶段的作用为:是所有人员工作的依据,统一的标准。它可以确保数据在系统中的完整性和一致性 。具体作用包括:按各种要求列表、相互参照、由描述内容检索名称、一致性检验和完整性检验。 - 在序列图存在哪三种消息?
答:同步消息、异步消息、返回消息。 - 系统分析设计过程中两种交互图的选取原则。
答:
(1)在系统设计过程中,常用两种交互图来描述系统的动态行为:序列图(顺序图)和通信图(协作图)。
(2)当你需要 清晰地展现消息的时间顺序,以及对象之间交互的时序关系 时,选择 序列图 。序列图强调的是时间顺序,它像电影胶片一样,按时间顺序展现了每个对象发送和接收消息的时刻。适用于描述复杂交互流程,特别是涉及多个对象之间消息传递顺序至关重要的场景,例如异步操作、并发行为等。
当你需要 清晰地展现对象之间的静态关系,以及它们之间如何通过消息进行协作 时,选择 通信图。通信图强调的是对象之间的连接关系,它像地图一样,展示了对象之间的链接路径以及消息如何在这些路径上传递。适用于描述系统结构,以及对象之间的协作关系,特别是需要清晰地展现对象之间静态连接关系的场景。 - UML序列图中表示条件分支的片段包括哪些?
答:
UML序列图中表示条件分支的片段包括:
- alt(Alternative):表示"如果-否则"条件分支(if-else);
- opt(Optional):表示可选执行(if);
- loop(Loop):表示循环执行(如for、while);
- break:表示中断流程的执行(类似break语句);
- par(Parallel):表示并发分支执行;
- region(Critical):表示临界区,即互斥执行块。
- 请用150字简要说明风险驱动的安全分析4个步骤的内容。
答:
(1)风险识别 :全面查找系统中可能存在的各类危险,如物理风险、软件故障等;
(2)风险评估 :对识别出的风险进行评估,考量其发生的可能性及潜在后果的严重程度;
(3)安全需求定义 :基于风险评估结果,明确系统应具备的安全需求和功能;
(4)安全设计与验证:依据安全需求进行系统设计,并验证是否满足需求,降低风险。 - 请用300字论述形式化开发和软件测试技术各自的特点。
答:
形式化开发和软件测试技术是保障软件质量的两种重要方法,它们在理念、实施方式和适用场景上各具特点。
(1)形式化开发 基于数学逻辑和形式化语言对系统需求、设计与实现进行建模和验证,强调 在开发早期消除缺陷 。其优点是 严谨性强、适用于高安全性系统 ,如航空、核能或医疗系统。形式化方法能发现传统测试难以覆盖的边界条件或逻辑错误,但其缺点是 学习成本高、建模复杂、推广受限 。
(2)软件测试技术 是一种动态验证方法,主要通过 实际运行软件并观察输出结果 来发现问题,覆盖面广、实施灵活,适合各类开发场景。测试包括单元测试、集成测试、系统测试等,支持自动化。其缺点是 无法穷尽所有路径、不能完全保证程序无错。 - 请简要说明区块链技术的六个层次,并简要描述每一层的功能和作用。
答:区块链技术体系可分为以下六个层次,每一层分别承担特定的功能:
- 数据层 :负责区块链中数据的结构定义与存储,如区块结构、链式结构、时间戳、哈希函数、非对称加密和梅克尔树等。作用:确保数据的完整性、不可篡改性和可验证性。
- 网络层 :负责节点间的数据传播与通信,采用P2P网络协议。作用:构建一个去中心化、点对点的传输网络,支持节点发现、数据广播与同步等。
- 共识层 :定义各个节点之间如何就数据达成一致的机制,如PoW(工作量证明)、PoS(权益证明)、PBFT(拜占庭容错)等。作用:保障全网数据一致性,防止双重支付和分叉问题。
- 激励层 :设定经济激励机制,用于奖励参与维护区块链网络运行的节点。作用:吸引节点参与系统运行,并对不良行为起到制约作用。
- 合约层 :支持智能合约的定义与执行,允许用户设定自动执行的逻辑规则。作用:实现业务逻辑自动化执行,提高效率,减少人为干预。
- 应用层 :为用户提供各类应用接口和可视化工具,实现工具的业务功能。作用:承载具体的区块链应用,如农产品溯源、数字资产管理、身份认证等。
- 介绍下什么是智能合约,并说明智能合约包含哪三方面。
答:
智能合约是一种 运行在区块链上 的 自动化程序 ,用于在满足预设条件时 自动执行 合约条款。它不依赖第三方,具有 去中心化、不可篡改和自动执行 的特点,广泛应用于数字资产转账、供应链管理等场景。
智能合约主要包含以下三方面内容:
- 参与方身份信息:包括合同各方的地址、公钥等;
- 合约执行规则:明确合同执行的条件、逻辑和触发机制;
- 状态与结果记录:记录合同执行状态、数据变更及最终结果,确保全网可验证与追溯。
面向对象系统建模
- 设计模式
-
分类
- 创建型模式:主要用于创建对象,为设计类实例化新对象提供指南。
- 包括:工厂方法模式、抽象工厂模式、原型模式、单例模式、构建器模式
- 结构型模式:主要用于处理类或对象的组合,对类如何设计以形成更大的结构提供指南。
- 包括:适配器模式、桥接模式、组合模式、装饰模式、外观模式、享元模式、代理模式
- 行为型模式:主要用于描述类或对象的交互以及职责的分配,对类之间交互以及分配责任的方式提供指南。
- 包括:职责链模式、命令模式、解释器模式、迭代器模式、中介者模式、备忘录模式、观察者模式、状态模式、策略模式、模板方法模式、访问者模式
-
Web应用系统架构设计
- 面向资源架构的核心思想:表现层转换(REST)
- REST从资源的角度来定义整个网络系统结构,分布在各处的资源由统一资源标识符(URI)确定,客户端应用程序通过URI获取资源的表现,并通过获得资源表现使得其状态发生改变。
- REST中将资源、资源的表现和获取资源的动作三者进行分离。
- 从设计模式的角度,简要说明设计方案
答:采用XML作为GUI描述语言的机制。
从设计模式的角度来说,整个XML表现层解析的机制是一种 策略模式 。在调用显示GUI时,不是直接调用 特定的表现技术的API,而是 装载 GUI对应的 XML配置文件 ,然后根据特定的表现技术的解析器 解析XML ,得到GUI视图实例对象 。这样,对于GUI开发人员来说,GUI视图只需要维护一套XML文件即可。【注:策略模式 是一种定义 一系列算法 (或行为)的方式,并将每一个算法封装起来,使它们可以 相互替换 ,从而让 算法的变化独立于使用它的客户端。】 - 简要解释什么是MVC架构以及其中的组件交互关系。
答:(1)MVC架构风格是一种 业务逻辑、数据、界面显示分离 的方法组织代码,将业务逻辑聚集到一个部件里面,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑 。
(2)MVC架构将整个软件系统划分为 模型、视图和控制器 3各部分。模型负责 维护并保存具有持久性的业务数据,实现业务处理功能 ,并将业务数据的变化情况及时通知视图;视图负责呈现模型中包含的业务数据 ,相应模型变化通知,更新呈现形式,并向控制器传递用户的界面动作;控制器负责将用户的界面动作映射为模型中的业务处理功能并实际调用 之,然后根据模型返回的业务处理结果选择新的视图。 - 简要解释基于DNS的负载均衡机制和基于反向代理的负载均衡机制。
答:

(1)基于DNS的负载均衡是在DNS服务器中 为同一个主机名配置多个IP地址 ,在应答DNS查询时,DNS服务器对每个查询将以DNS文件中主机记录的IP地址按顺序返回不同的解析结果,将客户端的访问引导到不同的节点上去 ,使得 不同的客户端访问不同的节点 ,从而达到负载均衡的目的。
(2)基于反向代理的负载均衡是将来自Internet上的连接请求以反向代理的方式 动态地转发给内部网络上的多个节点进行处理,从而达到负载均衡的目的。
- DNS负载均衡适合 小规模、低成本 场景,但在 高并发和高安全 需求下,反向代理机制更优。
-
引入主从复制机制对系统的好处 (2次)
答:主从复制机制使得 同样的数据,存在多个副本 ,这样让用户 查询数据 时,可以 选择该数据最近的副本进行访问 ,提高效率,降低资源使用时的冲突。另一方面,主从复制机制中 一台数据库服务器故障不会导致站点无法访问。
-
从缓存架构、缓存有效性及缓存数据类型等方面分析使用Memcached代替数据库查询缓存的原因。
答:(1)缓存架构 :数据库查询缓存只是将 查询结果 进行缓存,适用面很窄,而Memcached缓存是将数据库中的 表 进行缓存,对于在这些表上的操作均可适用。
(2)缓存有效性 :Memcached缓存 时效较长 ,只要未更新,就属于有效状态,而数据库查询缓存 时效较短 (具体时效与配置有关)。
(3)缓存数据类型 :Memcached缓存数据为 键值对 ,而数据库查询缓存为 元组。
-
简要说明什么是数据持久层,使用数据持久层能够为项目带来的好处。
答:(1)数据持久层是指应用程序中 负责与数据库或其他数据存储系统进行交互的模块或组件 。它 负责数据的读取、写入、更新和删除操作,以及数据的持久化和管理 。数据持久层的设计旨在实现 数据访问的有效性、可靠性和安全性 ,同时与业务逻辑层和表示层相互独立,提高系统的灵活性和可维护性 。
(2)使用数据持久层可以为项目带来的好处:1)数据持久层将数据访问逻辑与业务逻辑分离,降低了系统的耦合度,使得系统更易于维护和扩展 ;2)通过数据持久层的封装和抽象,可以提高数据访问的效率和性能,减少重复代码的编写,提高开发效率 ;3)数据持久层可以提供数据安全性和一致性的保障,确保数据的完整性和可靠性。
MyBatis/iBatis虽然在 SQL编写灵活性上有优势,但在移植性上不如 Hibernate,更换数据库时可能需要对 SQL 语句进行大量修改;而且 MyBatis 更多依赖手动编写 SQL,开发效率在一些场景下不如 Hibernate;在对象状态管理方面,MyBatis 也没有 Hibernate 那么完善的对象状态管理机制。使用Hibernate:移植性强 ,易于在不同数据库平台之间移植;减少SQL语句开发工作量 ,提供持久层操作方法;提供对象状态管理功能,减少对底层数据库细节的关注,简化开发流程。
JDBC 封装:Spring JdbcTemplate 属于 JDBC 封装技术。SQL Mapping:iBatis/MyBatis 是典型的 SQL Mapping 技术。
O/R Mapping(对象关系映射) :TopLink、JDO、Hibernate 都是 O/R Mapping 技术。
Entity Bean :BMP (Bean-Managed Persistence,Bean 管理的持久化)和 CMP(Container-Managed Persistence,容器管理的持久化)是 EJB(Enterprise JavaBean)中 Entity Bean(实体 Bean )的两种持久化管理方式 ,属于 Entity Bean 相关技术。
- 请简要说明应用服务器的概念,并重点说明应用服务器如何来保障系统在大负荷和长时间运行下的稳定性以及可扩展性。
答:
(1)应用服务器是一种 软件框架 ,用于 托管、管理和运行应用程序 ,提供各种服务和功能 ,如处理用户请求、管理数据库连接、执行业务逻辑等。
(2)应用服务器通过负载均衡、集群部署、资源管理、监控调优和自动扩展等功能来保障系统在大负荷和长时间运行下的稳定性和可扩展性。负载均衡可分发请求,集群部署提高可用性,资源管理避免瓶颈,监控调优实时调整,自动扩展根据负载动态调整服务器实例,确保系统高性能、稳定运行。
J2EE的N层体系结构
- MVC架构中包含哪三种元素,它们的作用分别是什么?
答:MVC架构包含:视图、控制器、模型
(1)视图(View):负责 显示数据并向用户展示交互界面 。它接收用户的输入,但不处理业务逻辑。典型的实现是JSP。
(2)控制器(Controller):负责 接收用户输入、处理请求并决定如何更新模型和视图 。Servlet是MVC中典型的控制器。
(3)模型(Model):表示业务数据和业务逻辑,并与视图和控制器交互。它处理数据、计算或其他业务操作。典型的JavaBean和Service类属于模型部分,DAO负责数据访问,封装了对数据库的操作。
-
请说明EJB构件中的Bean (构件)分为哪三种类型,每种类型Bean的职责是什么。
答:EJB中的Bean分三种类型:Session Bean、Entity Bean和Message-Driven Bean 。
(1)Session Bean的职责:负责 实现业务逻辑和处理客户端请求 ,维护一个短暂的会话 。
(2)Entity Bean的职责:表示 系统中的实体对象并与数据库交互 ,维护一行持久稳固的数据 。
(3)Message-Driven Bean的职责:处理异步消息通信 ,监听消息队列并执行相应的业务逻辑,异步接受消息。
-
说明数据库程序在线访问方式和ORM方式的优缺点。
答:
(1)数据库程序的在线访问方式是 直接使用SQL语句与数据库进行交互 ,开发人员需要手动编写SQL查询、更新等操作。优点是 对数据库操作更加灵活 ,可以直接优化SQL语句以提高性能,适用于 复杂查询和特定性能要求 ;缺点是需要开发人员 具备较强的数据库知识和编程技能 ,且容易引入 安全风险和代码冗余 。
(2)ORM(对象关系映射)方式 通过数据库表映射为面向对象的实体类 ,由ORM框架自动处理对象与数据库之间的映射关系,开发人员无需编写SQL语句,提高了开发效率和代码可维护性。优点包括 减少了开发工作量、降低了数据库操作的复杂度、提高了代码的可读性和可维护性 ;缺点是可能存在 性能损失、对复杂查询支持不足 等问题。
数据库程序在线访问方式优点包括性能较优、能处理复杂查询;缺点是要求程序员懂SQL且修改维护相对困难。ORM优点有降低学习和开发成本、无需编写SQL、减少代码量和降低SQL质量带来的影响;缺点是处理复杂查询困难且性能不如直接SQL。
- 新体系架构中增加数据访问层的原因。
答:增加数据访问层的原因是为了 实现数据与业务逻辑的分离 ,提高系统的可维护性、扩展性和灵活性。数据访问层负责处理数据库操作,封装数据访问细节,使业务逻辑与具体的数据存储技术解耦,简化开发流程,同时也方便对数据访问进行统一管理和优化,从而提升系统的整体性能和可靠性。
增加数据访问层的原因包括:1. 数据库异构性增加,数据访问复杂,不宜与业务逻辑混合;2. 数据管理复杂,分层有利于逻辑清晰;3. 统一处理异构数据库,需要数据访问层屏蔽差异性,确保业务逻辑以一致方式操作不同数据库。
- 请解释工厂设计模式,并说明其优点和应用场景。
答:工厂模式分抽象工厂与工厂方法。抽象工厂设计模式 提供一个接口 ,可以创建一系列相关或相互依赖的对象,而 无需指定它们具体的类 。其优点使可以 非常方便地创建一系列的对象,其使用场景也是创建系列对象的情况。
工厂设计模式定义了创建对象的接口,允许子类决定实例化哪个类,而且允许请求者无须知道要被实例化的特定类,这样可以在不修改代码的情况下引入新类。优点是:没有了将应用程序类绑定到代码中的要求,可以使用任何实现了接口的类;允许子类提供对象的扩展版本。工厂设计模式的应用场景有:类不能预料它必须创建的对象的类,类希望其子类指定它要创建的对象。
- 什么是"响应式 Web 设计",并列举2个响应式Web设计的实现方式。
答:
(1)响应式Web设计式一种网页设计方法,旨在 使网站能够在不同设备上提供最佳的用户体验 。通过响应式设计,网页能根据访问设备的屏幕大小、分辨率和方向等特征,自动调整布局和内容展示方式,确保页面内容在各种设备上都能清晰、易读和易用。这种设计方法能够 提高网站的可访问性和用户满意度 ,适应了多样化的设备和屏幕尺寸 。
(2)实现响应式Web设计的方式包括 流式布局 和 媒体查询 。流式布局通过 使用百分比或相对单位定义元素宽度 ,使页面能根据屏幕大小 自动调整布局 ,适应不同设备的显示尺寸 。而媒体查询则利用CSS3中的功能,根据 设备特性 (如屏幕宽度、分辨率等)应用不同样式表,以在不同设备上呈现不同布局和样式,实现页面的响应式展示。
响应式web设计是指我们设计与开发的页面可以根据用户的行为(比如改变浏览器的窗口大小)和不同的设备环境(比如系统平台、屏幕分辨率以及横竖屏等)做出相应的响应来调整页面的布局,以提供用户可感知的、流畅的阅读和操作体验。响应式设计一般遵循"设计先行,内容优先,移动优先"的原则。就是说,如果一个页面想要响应PC端和移动终端包括用户的一些行为等,那么设计师至少需要设计两套以上页面的设计图(PC端一套,移动终端一套),交互设计师也需先根据终端进行交互设计,把需求中最重要的内容展示在移动小屏幕上,然后前端工程师据此设计开发出响应式框架。
- 什么是面向服务架构(SOA)以及ESB在SOA中的作用与特点。
答:
(1)面向服务架构(SOA)是一种软件架构设计理念,将应用程序功能模块抽象为可复用的服务 ,通过服务之间的松耦合和相互通信来实现系统的灵活性、可扩展性和互操作性。SOA强调 服务的独立性、标准化接口和服务的组合 ,使得 系统更易于维护、扩展和集成 。
(2)企业服务总线(ESB)是SOA架构中的关键组件,用于 实现不同服务之间的通信、消息路由、转换和协调 。ESB提供了统一的消息传递机制和中介服务,可以实现 服务之间的解耦和集成,同时具备消息传递、安全性、事务管理等功能。其特点包括灵活性、可扩展性、异步通信、消息路由和转换、安全性和监控等,为构建复杂的分布式系统提供了支持。ESB在SOA中扮演着关键的角色,促进了服务之间的互联和协作,提高了系统的可靠性和可维护性。 - 列举3种可实现信息系统安全保障的措施。
答:
(1)引入https协议或采用加密技术对数据先加密再传输;
(2)采用信息摘要技术对重要信息进行完整性验证;
(3)防火墙系统;
(4)安全检测;
(5)网络扫描。
软件质量属性有可用性、可修改性、性能、安全性、可测试性、易用性等六种。可用性关注的是系统产生故障的可能性和从故障中恢复的能力;性能关注的是系统对事件的响应时间;安全性关注的是系统保护合法用户正常使用系统、阻止非法用户攻击系统的能力;可测试性关注的是系统发现错误的能力;易用性关注的是对用户来说完成某个期望任务的容易程度和系统所提供的用户支持的种类。
- 什么是SQL注入攻击,并列举出两种抵御SQL注入攻击的方式。
答:
(1)SQL注入攻击是一种利用应用程序对用户输入数据的处理不当,通过 在输入中插入恶意的SQL代码 来实现对数据库的攻击方式。攻击者可以通过注入恶意SQL语句来执行未经授权的数据库操作,如删除表、泄露数据等。
(2)要抵御SQL注入攻击,可以采取以下两种方式:
1)使用 参数化查询 :通过预编译SQL语句并将用户输入的数据作为参数传递,而不是直接拼接到SQL语句中,可以有效防止SQL注入攻击。
2)输入验证和过滤:对用户输入的数据进行过严格的验证和过滤,确保输入数据符合预期格式和范围,过滤掉可能包含恶意SQL代码的字符,从而防止注入攻击。
SQL注入攻击是黑客对数据库进行攻击的常用手段之一。随着B/S模式应用开发的发展,使用这种模式编写应用程序的程序员也越来越多。但是由于程序员的水平及经验也参差不齐,相当大的一部分程序员在编写代码的时候,没有对用户输入数据的合法性进行判断,使应用程序存在安全隐患。用户可以提交一段数据库查询代码,根据程序返回的结果,获得某些他想得知的数据,这就是所谓的SQL Injection,即SQL注入。
SQL注入攻击属于数据库安全攻击手段之一,可以通过数据库安全防护技术实现有效防护,数据库安全防护技术包括:数据库漏扫、数据库加密、数据库防火墙、数据脱敏、数据库安全审计系统。
为了抵御SQL注入攻击,可以采用如下方式:使用正则表达式、使用参数化的过滤性语句、检查用户输入的合法性、用户相关数据加密处理、存储过程来执行所有的查询、使用专业的漏洞扫描工具等。
- Spring 是一个轻量级的 Java 开发框架,能对其他组件进行管理和整合,为 MyBatis 和 Spring MVC 等提供支持,像依赖注入、事务管理等功能都是 Spring 提供的。
- JSP(Java Server Pages)是一种动态网页技术,常被用于构建 Web 应用的视图层,能结合 Java 代码和 HTML 等创建动态页面展示给用户。
- 采用标准的数据访问机制的原因。
答:通过采用标准的数据访问机制,可以屏蔽不同设备之间数据交互的差异,解决了系统使用数据不一致性,又在一定程度上减少了数据结构与应用系统的耦合度,减少了应用系统的维护的工作量。
可从三方面展开叙述
- 兼容性和互操作性
- 可扩展性与可维护性
- 成本效益
- 简要说明 MQTT 协议.
答:MQTT(消息队列遥测传输)是一个基于发布/订阅模式的消息协议。它工作在TCP/IP协议族上,是为 硬件性能低下的远程设备以及网络状况糟糕的情况下 而设计的发布/订阅型消息协议。MQTT协议是轻量、简单、开放和易于实现的。
MQTT(Message Queuing Telemetry Transport,消息队列遥测传输协议),是一种基于发布/订阅(publish/subscribe)模式的"轻量级"通讯协议,该协议构建于TCP/IP协议上,由IBM在1999年发布。MQTT最大优点在于,可以以极少的代码和有限的带宽,为远程连接设备提过实时可靠的消息服务,作为一种低开销、低带宽占用的即时通讯协议,使其在物联网、小型设备、移动应用等方面有较广泛的应用。MQTT是一个基于客户端-服务器的消息发布/订阅传输协议。MQTT协议是轻量、简单、开放和易于实现的,这些特点使它适用范围非常广泛。
- 从数据通信、数据安全和系统性能等方面简要分析在传统云计算模型中引入边缘计算模型的优势。
答:
(1)数据通信:通信更快捷,数据量更少 。因为数据处理对比在边缘设备上完成,通信更多时候只传输匹配与结果的指令。
(2)数据安全:数据以加密方式存储在需要用到的边缘设备上,本地化处理比对,减少原始信息在网上的传递带来的安全隐患 。黑客也无法通过攻破一个结点使整个系统瘫痪。
(3)性能更高,以人脸识别为例,在进行识别时,只在本地进行比对,不用把人脸数据传递到远程服务器对比。 - JWT 是由哪三个部分组成,请写出对应的组成和作用。
答:
(1)Header(头部):描述算法和类型,如{"alg": "HS256", "typ": "JWT"};
(2)Payload(载荷):存放用户信息和声明,如用户ID、角色、过期时间;
(3)Signature(签名):由Header+Payload+密钥生成,防止数据篡改。 - 基于数据库实现分布式锁的缺点。
答:基于数据库实现分布式锁虽然实现简单、依赖少,但存在明显缺点:在 高并发场景下性能较差 ,容易成为系统瓶颈;若服务异常未能释放锁,易导致 死锁 ;可重入性和公平性支持弱;扩展性差,难以支撑大规模分布式系统的稳定运行。因此,在对性能和可靠性要求较高的系统中,通常不推荐使用数据库作为分布式锁的实现方式。 - 举一个产生Redis分布式锁死锁的场景。
答:当用Redis做分布式锁时,当A用户竞争锁成功,A用户所在的主机挂了,这时候还没有来得及释放锁,且设置的过期时间较长,还未到期,那么其他用户去用setnx指令去竞争锁时发现Redis有这个锁的key,所以就导致其他用户永远都竞争不成功。 - 如何使用前后端分离实现RESTful。
答: 在前后端分离架构中,前端通过 HTTP协议调用后端提供的RESTful接口 进行数据交互。后端根据资源(如用户、商品)设计统一的URL路由,并通过GET、POST、PUT、DELETE等方法表示不同操作。前端通过Ajax或Axios发起请求,后端返回JSON格式数据,实现逻辑与视图解耦,提高了开发效率与模块复用性。这种方式契合现代前端框架与微服务架构的协作需求。 - Redis 的数据持久化机制在生产环境中至关重要,当系统遭遇故障时需依赖持久化数据进行快速恢复。请详细阐述 Redis 的两种主要持久化方式,并对比分析其优缺点。
答:Redis主要有两种数据持久化方式:RDB(快照持久化) 和 AOF(追加日志) 。
(1)RDB是通过 定期生成内存快照 的方式将数据保存为 二进制文件 ,优点是 文件体积小、恢复速度快 ,适合用于灾备和冷启动场景,但它是定时保存,可能在故障时丢失最近修改的数据。
(2)AOF则是将每一次写命令以 日志形式追加记录到磁盘 ,优点是 数据丢失更少、可读性高,但缺点是文件更大、恢复速度相对慢,且长期运行后需要重写以控制体积。 - 关系型数据库管理系统和文件系统两种存储方式的比较。
在信息系统架构设计中,选择文件系统还是关系数据库管理系统(RDBMS),取决于 系统复杂性、数据增长趋势、扩展需求 等。
- 设计难度:文件系统的数据组织简单,开发者仅需编写 I/O 操作即可,但缺乏数据模型约束,容易造成混乱。关系数据库必须遵循关系模式,需要设计 数据表、主外键、范式约束 等,设计难度更大,但数据结构更规范,利于长期维护。
- 数据冗余程度:文件系统往往是 应用驱动的数据存储,各应用独立管理数据,容易出现相同数据被重复存储在多个文件中,冗余度大,数据一致性难以保证。关系数据库通过 集中式数据管理 和规范化设计,能够有效减少冗余,提高一致性。
- 数据架构:文件系统是"以应用为中心"的数据架构,即应用直接驱动数据存取,数据组织依赖具体应用,缺乏统一的全局管理。关系数据库是"以数据为中心"的架构,数据库系统作为独立组件运行,应用通过标准接口访问数据,更具规范性。
- 应用扩展性:文件系统扩展性差,新应用往往无法直接重用已有数据,需要单独开发数据接口。关系数据库具有 标准化接口(如 JDBC/ODBC),实现了数据与应用的分离,使得数据更易共享和扩展。
综上,文件系统适用于数据量小、业务简单、开发周期短的场景,而关系数据库更适合 数据量大、业务复杂、扩展性要求高的企业应用。
软件系统数据架构建模
- 集中式数据架构 :是由一个处理器、与它相关联的数据存储设备以及其他外围设备组成,它被物理地定义到单个位置。系统提供数据处理能力,用户可以在同样的站点上操作,也可以在地理位置隔开的其他站点上通过远程终端来操作。系统及其数据管理被某个或中心站点集中控制。
- 向上扩展 提升系统的可扩展性:具体实现方式包括硬件扩容(增加CPU数量、内存容量、磁盘数量)和硬件升级(更换高端主机或高速磁盘等)。
- 分布式数据架构 :使用多个计算机系统上的多个局部数据库系统构成,数据可以在多个不同的局部数据库中进行传送,由不同的数据库管理系统软件进行管理,运行在多种不同的计算机上,支持多种不同的操作系统。这些机器位于(或分布在)不同的地理位置并通过多种通信网络连接在一起。企业数据可以分布在不同的计算机上,一个应用程序可以操作位于不同地理位置的机器上的数据。
- 向外扩展 提升系统的可扩展性:具体实现方式包括数据复制、数据垂直切分(或/和)水平切分、缓存和全文搜索。
系统设计与开发工具集成
- 企业服务总线(ESB) 的核心功能
- 应用程序的位置透明性
- 传输协议转换
- 消息格式转换
- 消息路由
- 消息增强
- 安全支持
- 监控和管理
数据流图
- 数据流图与流程图
数据流图作为一种图形化工具,用来说明业务处理流程、系统边界内所包含的功能和系统中的数据流;流程图以图形化的方式展示应用程序从数据输入开始到获得输出为止的逻辑过程,描述处理过程的控制流。两者的区别如下:- 数据流图中的处理过程可并行;流程图在某个时间点只能处于一个处理过程。
- 数据流图展现系统的数据流;流程图展现系统的控制流。
- 数据流图展现全局的处理过程,过程之间遵循不同的计时标准;流程图中处理过程遵循一致的计时标准。
- 数据流图适用于系统分析中的逻辑建模阶段;流程图适用于系统设计中的物理建模阶段。
- 数据流图中常见的错误分为两种类型:一类是 语法错误 ,包括外部实体之间、数据存储之间或外部实体与数据存储之间不经过加工而存在直接数据流;另一类是 逻辑错误,包括数据黑洞(只有输入没有产生输出)、灰洞(输入不足以产生输出)和无输入。
- 高质量数据流图设计时应考虑的三个原则
- 复杂性最小化原则。 DFD分层结构就是把信息划分为小的且相对独立的一大批子集例子,这样就可以单独考查每一个DFD。如果要了解某个过程更加详细的信息,可以跳转到该过程的下一层;如果要知道一个DFD如何与其他DFD相关联,可以跳转到上一层的DFD进行考查。
- 接口最小化原则。 接口最小化是复杂性最小化的一种具体规则。在设计模式时,应使得模型中各个元素之间的接口数或连接数最小化。
- 数据一致性原则。 一个过程和它的过程分解在数据流内容中是否有差别?是否存在有数据流出但没有相应数据流入的加工?是否存在有数据流入但没有相应的数据流出的加工?
嵌入式软件体系架构(非重点)
- TSL结构框架的主要特点
- 应用软件仅与操作系统服务相关,不直接操作硬件。
- 操作系统通过模块支持原软件访问硬件,可与具体硬件无关。
- 模块支持层将硬件抽象成标准操作。
- 通过三层栈的划分可实现硬件的快速更改与升级,应用软件的升级不会引起硬件的变更。
- 嵌入式系统中的故障主要分为:
- 硬件故障:如CPU、存储器和定时器等。
- 应用软件故障:如数值越界、异常和超时等。
- 操作系统故障:如越权访问、死锁和资源枯竭等。
- 滤波算法
- 门限算法
- 递减算法
- 递增算法
- 周期滤波算法
- 容错算法
- N+1备份
- 冷备
- 温备
- 热备
- 采用PowerPC实现系统隔离和保护的两种机制是
- 内存管理机制(MMU)。MMU能够实现逻辑地址到物理地址的转化,并且对访问权进行控制,既可以保护系统内核不受应用软件有意或无意的破坏,也可有效防止各应用软件之间的互相破坏。
- TRAP系统调用机制。操作系统为实现对内核以及应用之间的保护,提供了用户态和系统态两种运行形态。操作系统内核在系统态运行,因此用户态的应用不能直接调用系统内核提供的功能接口,必须通过TRAP系统调用的方式进行。因此可以实现应用与内核之间的隔离与保护。
- 开放式架构 的四个基本特点
- 可移植性。各种计算机应用系统可在具有开放式架构特性的各种计算机系统间进行移植,不论这些计算机是否同种型号、同种机型。
- 可互操作性。如计算机网络中的各结点机都具有开放式架构的特性,则该网上各结点机间可相互操作和资源共享。
- 可剪裁性。如某个计算机系统是具有开放式架构特性的,则在该系统的低档机上运行的应用系统应能在高档机上运行,原在高档机上运行的应用系统经剪裁后也可在低档机上运行。
- 易获得性。在具有开放式架构特性的机器上所运行的软件环境易从多方获得,不受某个来源所控制。
信息系统(非重点)
- 信息系统的安全威胁
信息系统面临的安全威胁来自物理环境、通信链路、网络系统、操作系统、应用系统以及管理等多个方面。- 物理安全 威胁:指对系统所用设备的威胁,如自然灾害、电源故障、数据库故障和设备被盗等造成数据丢失或信息泄漏。
- 通信链路安全 威胁:指在传输线路上安装窃听装置或对通信链路进行干扰。
- 网络安全 威胁:指由于因特网的开放性、国际性与无安全管理性,对内部网络形成的严重安全威胁。
- 操作系统安全 威胁:指操作系统本身的后门或安全缺陷,如"木马"和"陷阱门"等。
- 应用系统安全 威胁:指对网络服务或用户业务系统安全的威胁,包括应用系统自身漏洞,也受到"木马"的威胁。
- 管理系统安全 威胁:指的是人员管理和各种安全管理制度。
- 认证方式
- 用户名和口令认证:主要是通过一个客户端与服务器共知的口令(或与口令相关的数据)进行验证。根据处理形式的不同,分为验证数据的明文传送、利用单向散列函数处理验证数据、利用单向散列函数和随机数验证数据。
- 使用令牌认证:该方式中,进行验证的密钥存储于令牌中,目前的令牌包括安全证书和智能卡等方式。
- 生物识别认证:主要是根据认证者的图像、指纹、气味和声音等作为认证数据。
- 授权侵犯:指的是被授权以某一目的使用某一系统或资源的某个人,将此权限用于其他非授权的目的,也称作"内部攻击"。
- 可靠度:系统在规定的条件下、规定时间内不发生失效的概率。
- 失效率 又称风险函数,也可称为条件失效强度:是指运行至此刻系统未出现失效的情况下,单位时间系统出现失效的概率。
- 动态冗余 又称主动冗余:通过故障检测、故障定位及故障恢复等手段达到容错的目的。其主要方式是多重模块待机储备,当系统检测到某工作模块出现错误时,就用一个备用的模块来替代它并重新运行。各备用模块在待机时,可与主模块一样工作,也可以不工作。前者叫热备份系统(双重系统),后者叫冷备份系统(双工系统、双份系统)。
- N版本程序设计:是一种静态的故障屏蔽技术,其设计思想是用N个具有相同功能的程序同时执行一项计算,结果通过多数表决来选择。其中N个版本的程序必须由不同的人独立设计,使用不同的方法、设计语言、开发环境和工具来实现,目的是减少N个版本的程序在表决点上相关错误的概率。
- 检错技术
- 检错技术的优缺点:检错技术实现的代价一般低于容错技术和冗余技术,但有一个明显的缺点,就是不能自动解决故障,出现故障后如果不进行人工干预,将最终导致系统不能正常运行。
- 检错技术常见的实现方式:最直接的一种实现方式是判断返回结果,如果返回结果超出正常范围,则进行异常处理;计算运行时间也是一种常用技术,如果某个模块或函数运行时间超过预期时间,可以判断出现故障;还有置状态标志位等多种方法,自检的实现方式需要更具实际情况来选用。
- 检错技术的处理方式:大多数都采用"查处故障-停止软件运行-报警"的处理方式。但根据故障的不同情况,也有采用不停止或部分停止软件系统运行的情况,这一般由故障是否需要实时处理来决定。
- 对称加密策略
- 机密性:发送者利用对称密钥对要发送的数据进行加密,只有拥有相同密钥的接收者才能将数据正确解密,从而提供机密性保障。
- 完整性:发送者根据要发送的数据生成消息认证码(或信息摘要),利用对称密钥对消息认证码进行加密并附加到数据上发送;接收者使用相同密钥将对方发送的消息认证码解密,并根据接收到的数据重新生成消息认证码,比较两个认证码是否相同以验证数据的完整性。
- 公钥加密策略
- 机密性:发送者利用接收者的公钥对要发送的数据进行加密,只有拥有对应私钥的接收者才能将数据正确解密,从而提供机密性保障。
- 完整性:发送者根据要发送的数据生成消息认证码(或消息摘要),利用自己的私钥对消息认证码进行加密并附加到数据上发送;接收者利用对方的公钥将对方发送的消息认证码解密,并根据接收到的数据重新生成消息认证码,比较两个认证码是否相同以验证数据的完整性。
补充常见易混易错知识
一、MVC、MVP、MVVM 对比
总口诀:MVC是Controller调度,MVP是Presenter调度,MVVM是ViewModel+数据绑定调度。
| 模式 | 核心角色 | 核心关系 | 极简记忆 |
|---|---|---|---|
| MVC | Model、View、Controller | View和Model不完全隔离,Controller负责调度 | C在中间管流程 |
| MVP | Model、View、Presenter | View更被动,Presenter负责主要逻辑和协调 | P最忙,V最轻 |
| MVVM | Model、View、ViewModel | View与ViewModel通过数据绑定联动 | 绑定最强,代码更简 |
| 对比点 | MVC | MVP | MVVM |
|---|---|---|---|
| 谁最核心 | Controller | Presenter | ViewModel |
| View是否很被动 | 一般 | 是 | 较被动 |
| 界面更新方式 | Controller选择View | Presenter更新View | 数据绑定自动更新 |
| 测试友好度 | 中 | 高 | 较高 |
| 适合场景 | 传统Web/管理系统 | Android/富客户端/强测试需求 | 前端框架/Vue/响应式界面 |
易混区分: MVC vs MVP:Controller调流程 vs Presenter全负责;MVP vs MVVM:手动更新 vs 绑定自动更新。
考场秒判: Controller/请求分发/传统Web→MVC;Presenter/被动视图/便于测试→MVP;数据绑定/ViewModel/响应式→MVVM
案例题分析
先定模式→再写职责分工(MVC:Model数据业务,View展示,Controller分发;MVP:Presenter核心协调;MVVM:ViewModel绑定联动)→再写流转路径→最后写效果(降低耦合、可维护、可扩展、可测试)
二、23种设计模式
三大类口诀: 创建型:单原建工抽 ;结构型:适桥组装外享代 ;行为型:链命解迭中备观状策模访
| 类别 | 包含模式 | 速记 |
|---|---|---|
| 创建型 | 工厂方法、抽象工厂、原型、单例、构建器 | 创建对象指南 |
| 结构型 | 适配器、桥接、组合、装饰、外观、享元、代理 | 类和对象的组合 |
| 行为型 | 职责链、命令、解释器、迭代器、中介者、备忘录、观察者、状态、策略、模板方法、访问者 | 类和对象的交互 |
高频易混口诀: 工厂方法vs抽象工厂:一个产品vs一套产品 ;装饰vs代理:加功能vs控访问 ;适配器vs桥接:事后转换vs事先分离 ;状态vs策略:自动切换vs主动选择 ;观察者vs中介者:广播通知vs集中协调
考场秒判: 唯一实例→单例;克隆→原型;分步创建→建造者;子类创建→工厂方法;一套对象→抽象工厂;接口转换→适配器;抽象实现分离→桥接;树形目录→组合;动态增强→装饰;统一入口→外观;共享节省→享元;控制访问→代理;链式处理→职责链;请求封装→命令;遍历集合→迭代器;中间协调→中介者;存档回滚→备忘录;发布订阅→观察者;状态变化→状态;算法切换→策略;父类定流程→模板方法;不改结构加操作→访问者
案例题分析
需要创建复杂对象族→抽象工厂;不改类加功能→装饰;统一多个子系统接口→外观;灵活切换算法→策略;对象状态影响行为→状态;通知多个观察者→观察者
三、Scrum 项目管理
总口诀:三角色、三工件、四会议;2~4周一轮Sprint,边做边改进。
| 模块 | 内容 | 极简记忆 |
|---|---|---|
| 三角色 | Product Owner、Scrum Master、Development Team | 产品、教练、开发 |
| 三工件 | Product Backlog、Sprint Backlog、Increment | 总需求、迭代任务、可交付增量 |
| 四会议 | Sprint Planning、Daily Scrum、Sprint Review、Sprint Retrospective | 计划、站会、评审、回顾 |
三角色: PO管需求(决定做什么);SM管流程(保证按Scrum做好);团队管实现(把东西做出来)
三工件: Product Backlog=总清单;Sprint Backlog=本轮清单;Increment=可交付版本
四会议口诀:先计划,天天站,做完评,最后改
Sprint:2~4周一个冲刺,周期短、反馈快、持续交付、持续改进
优缺点: 优点=响应变化快、交付快、沟通强、风险早暴露 ;缺点=团队协作要求高、文档可能不足
考场秒判: 2~4周迭代→Scrum;产品待办列表→Product Backlog;每日站会→Daily Scrum;产品负责人→PO;障碍清除者→SM;本轮任务→Sprint Backlog
案例题分析
为什么用Scrum(需求变化快、缩短交付周期)→怎么组织(PO/SM/团队+Backlog+Sprint)→怎么推进(计划→站会→评审→回顾)→效果(响应快、协作效率高、风险早暴露)
四、架构风险、敏感点、权衡点
总口诀:风险看隐患,敏感看单点,权衡看多点。
| 概念 | 超短定义 | 极简记忆 |
|---|---|---|
| 架构风险 | 潜在的、有问题的架构决策带来的隐患 | 错了会出事 |
| 敏感点 | 对某个质量属性影响特别大的关键特性 | 动了变化大 |
| 权衡点 | 同时影响多个质量属性的特性 | 顾此要顾彼 |
考场秒判: 潜在隐患/设计缺陷→架构风险;某参数对性能影响特别大→敏感点;性能安全可修改性互相牵制→权衡点
高频联想: 缓存机制/数据库连接数/并发策略→常是敏感点;加密强度/日志审计→常形成权衡点;单点部署/强耦合/无冗余→常是架构风险
五、常见软件架构风格对比
总口诀:分层最稳,事件最松,微核最活,微服务最拆,云架构最能扩。
| 架构 | 数据处理 | 可扩展性 | 性能 | 极简记忆 |
|---|---|---|---|---|
| 分层架构 | 逐层处理 | 中等 | 中等 | 结构清楚,层层下传 |
| 事件驱动 | 事件触发 | 较强 | 较强 | 事件一响,各自处理 |
| 微核架构 | 插件处理 | 强 | 中等 | 内核小,插件多 |
| 微服务 | 服务独立处理 | 很强 | 较强 | 服务拆细,独立部署 |
| 云架构 | 分布式处理 | 最强 | 很强 | 资源弹性,节点可伸缩 |
扩展性排序:云架构>=微服务>微核>事件驱动>分层
性能口诀:层多则慢、异步则快、拆细则灵、分布式则强
案例题分析
稳定管理系统→分层;异步事件处理→事件驱动;插件化扩展→微核;独立部署扩展→微服务;高并发弹性→云架构。结合质量属性说明选型原因。
六、关系数据库与 NoSQL
总口诀:关系库强约束,NoSQL强扩展;关系库重一致,NoSQL重性能。
| 对比点 | 关系数据库 | NoSQL |
|---|---|---|
| 数据组织 | 表 | 键值/文档/列/图 |
| 事务能力 | 强 | 一般较弱 |
| 一致性 | 强一致性 | 常做权衡 |
| 扩展方式 | 垂直扩展 | 水平扩展 |
NoSQL四类:键值、列存、文档、图形
秒判: 要事务/约束/强一致→关系库;要海量/高并发/灵活扩展→NoSQL
七、反规范化设计
反规范化=牺牲部分规范化,换查询性能。核心:用空间换时间,用冗余换性能。
常见方法口诀:冗余列、派生列、重组表、分割表
一致性维护:定时同步、触发器同步、应用程序同步
秒判: 减少join/提高查询效率/空间换时间→反规范化
八、数据库设计三阶段
总口诀:概念设计先抽象,逻辑设计变成表,物理设计落到盘。
| 阶段 | 核心任务 | 极简记忆 |
|---|---|---|
| 概念设计 | E-R模型抽象业务 | 抽象业务 |
| 逻辑设计 | 关系模式、完整性约束 | 转换成表 |
| 物理设计 | 存储结构、索引、访问路径 | 落地存储 |
秒判: E-R图/实体/联系→概念设计;关系模式/主键外键→逻辑设计;索引/B树/存储→物理设计
九、数据库访问方式与ORM
总口诀:直连库函,SQL嵌入,标准接口,ORM映射。越往后越抽象。
| 方式 | 极简记忆 |
|---|---|
| 库函数级别 | 最底层,最直接 |
| 嵌入SQL | SQL嵌程序 |
| 通用数据接口 | JDBC/ODBC |
| ORM | 表变类,行变对象 |
秒判: 表映射成类/记录映射成对象→ORM;JDBC/ODBC→通用接口
十、MemCache与Redis对比
MemCache 偏"缓存工具",Redis 偏"缓存 + 数据库"。
| 对比维度 | MemCache | Redis |
|---|---|---|
| 数据结构 | 仅支持简单的 key-value(字符串) | 支持 String、List、Hash、Set、ZSet、Stream、GEO、Bitmap、HyperLogLog 等丰富类型 |
| 持久化 | 不支持,重启即丢数据 | 支持 RDB 快照 + AOF 日志,以及混合持久化 |
| 线程模型 | 多线程,充分利用多核 CPU | 早期版本 单线程处理命令(6.0+ 引入 IO 多线程,命令执行仍单线程),基于 epoll IO 多路复用 |
| 内存管理 | 采用 Slab Allocation 机制,易产生内存碎片 | 使用 jemalloc 分配器,配合 8 种淘汰策略(LRU/LFU/TTL 等) |
| 集群方案 | 通常通过 客户端一致性哈希 实现分布式 | 原生支持 主从复制 + 哨兵 + Cluster 集群(16384 个 slot),支持自动故障转移 |
| 事务/原子性 | 不支持 | 支持 MULTI/EXEC 事务(不支持回滚) 以及 Lua 脚本原子执行 |
| 发布订阅 | 不支持 | 支持 Pub/Sub 消息通知 |
| 过期策略 | 惰性删除(访问时检查) | 惰性删除 + 定期删除 |
| 网络模型 | TCP,简单二进制协议 | TCP,RESP 协议,支持 Pipeline 管道批量操作 |
| 适用场景 | 纯缓存:用于加速数据库读访问,对数据丢失不敏感 | 缓存 + 数据存储:排行榜、计数器、分布式锁、消息队列、Session 共享、实时数据分析等 |
十一、DNS负载均衡与反向代理负载均衡
DNS管解析,代理管转发;DNS成本低,代理控制强。
| 方式 | 极简记忆 |
|---|---|
| DNS负载均衡 | 同域名多IP,轮流回 |
| 反向代理负载均衡 | 同入口,代转发,动态分 |
适用场景:DNS适合小规模低成本;反向代理适合高并发高可靠高安全。
十二、结构化分析与面向对象分析
结构化重过程(自顶向下分解功能),面向对象重对象(先找对象再看关系)。
结构化工具:DFD、数据字典、ER图、状态转换图
面向对象工具:用例图、类图、顺序图、活动图、状态图
极简区分: 结构化看"事怎么做",面向对象看"谁来做、怎么配合做"
十三、系统设计建模中的图
需求看用例,静态看类包,动态看顺活状,实现看组件,物理看部署。
| 图 | 看什么 | 极简记忆 |
|---|---|---|
| 用例图 | 参与者、用例、边界 | 看需求 |
| 类图 | 类、属性、关系 | 看结构 |
| 顺序图 | 消息先后 | 看先后 |
| 活动图 | 业务流程、并发 | 看流程 |
| 状态图 | 状态、事件、迁移 | 看状态 |
| 组件图 | 组件、接口 | 看构件 |
| 部署图 | 节点、设备 | 看落地 |
| DFD | 数据流、加工 | 看数据流 |
十四、用例关系与类关系
用例三关系:含扩泛(包含=抽公共,扩展=加例外,泛化=分父子)
类图六关系:关聚组依泛实(关联=有联系,聚合=可分离,组合=同生死,依赖=临时用,泛化=继承,实现=接口落地)
易混: 聚合vs组合=可分家vs同生共死;关联vs依赖=稳定联系vs临时使用;泛化vs实现=继承vs接口
十五、Hibernate与MyBatis
Hibernate偏全自动ORM,MyBatis偏半自动SQL Mapper。Hibernate重对象映射,MyBatis重SQL控制。
| 对比点 | Hibernate | MyBatis |
|---|---|---|
| 本质 | ORM | SQL Mapper |
| SQL控制力 | 较弱 | 很强 |
| 适合场景 | 领域模型清晰、对象关系复杂 | 查询复杂、报表多、联表多 |
秒判: 对象关系映射/JPA兼容→Hibernate;Mapper/XML SQL/自定义SQL→MyBatis
十六、Java Web技术栈
标准定规范,Spring搭骨架,Boot快启动,Cloud管分布式。
| 技术 | 极简记忆 |
|---|---|
| Jakarta EE | 标准规范 |
| Spring | 搭骨架(DI/AOP/事务) |
| Spring Boot | 快启动(自动配置) |
| Spring Cloud | 管治理(注册发现/网关/熔断) |
| Spring MVC | 管页面 |
| MyBatis | 管SQL |
| MySQL | 真存数 |
| Redis | 做缓存 |
| RabbitMQ | 传消息 |
十七、分布式事务(2PC/3PC/TCC)
2PC先投票再提交,3PC多预提交降阻塞,TCC靠业务补偿,消息表靠异步重试。
| 方案 | 核心流程 | 极简记忆 |
|---|---|---|
| 2PC | 准备+提交 | 先投票,再提交 |
| 3PC | CanCommit+PreCommit+DoCommit | 先问,再预提交,后正式提交 |
| TCC | Try+Confirm+Cancel | 先试,再确,再撤 |
| 消息表 | 本地事务+发消息+异步补偿 | 消息驱动,最终一致 |
CAP/BASE: CAP=三选二(一致性/可用性/分区容错);CP=先一致;AP=先可用;BASE=基本可用,最终一致
秒判: 协调者/参与者/准备阶段→2PC;Try/Confirm/Cancel→TCC;三选二→CAP;基本可用/最终一致→BASE
十八、软件维护
总口诀:错了就纠,环境变就适应,功能不够就完善,怕出事就预防。
| 类型 | 极简记忆 |
|---|---|
| 纠错性维护 | 错了就修 |
| 适应性维护 | 变了就适应 |
| 完善性维护 | 不够就完善 |
| 预防性维护 | 没坏先预防 |
易混: 纠错性vs预防性=已经出错再修vs没出错先防;适应性vs完善性=外部变了被迫改vs主动优化增强
秒判: 修Bug→纠错;适配新环境→适应;增加功能/优化性能→完善;重构/漏洞修复→预防

