NoSql期末复习
存储「谁关注了谁」,并快速查询「A的关注列表」和「A的粉丝列表」。例子:Google App Engine, Heroku。例子:Gmail, 钉钉, Salesforce。这是考试的拉分项,请遵循以下结构化思路。例子:AWS EC2, 阿里云 ECS。
·
第一部分:核心概念 · 必须掌握的理论基石
1. CAP 定理:分布式系统的第一性原理
1.1 精确定义
- C(一致性): 在分布式系统中的所有数据副本,在同一时刻是否具有相同的值。强调的是 「数据视图的同一性」。
- A(可用性): 对于每一个非故障节点收到的每一个请求,都必须产生响应。强调的是 「服务的持续可访问性」。
- P(分区容错性): 系统在遇到任何网络分区故障时,仍然能够对外提供满足一致性和可用性的服务。强调的是 「对网络故障的容忍能力」。
1.2 深刻理解「三选二」
- 关键洞察: 「三选二」是一种 通俗化误解。更准确的描述是:在发生网络分区(P)的情况下,你必须在一致性(C)和可用性(A)之间做出选择。
- 网络分区是客观存在: 在分布式系统中,网络故障无法避免,因此 P 是必须接受的现实。所以,真正的选择是在 C 和 A 之间。
1.3 数据库分类与举例
- CA 系统: 单机数据库(MySQL, PostgreSQL)。当网络分区发生时,它们实际上无法提供服务,从而牺牲了 P。或者在主从架构中,通过主从切换来保证 A,但切换期间会短暂丧失 C。
- CP 系统: HBase, MongoDB, Redis Cluster。当网络分区发生时,为了保障数据一致性,系统会拒绝部分写入操作,从而牺牲了可用性。例如,某个分片无法与多数节点通信时,会变为只读或不可用。
- AP 系统: Cassandra, DynamoDB, CouchDB。当网络分区发生时,系统允许所有节点继续处理读写请求,即使它们持有的是旧数据。这保证了可用性,但牺牲了跨分区的一致性。
2. BASE 理论:对 CAP 的实践性补充
2.1 含义解析
- BA(基本可用): 系统在出现不可预知故障时,允许损失部分非核心功能的可用性或降低核心功能的性能。例如,电商网站在大促时,可以关闭商品评价功能,保证下单流程基本可用。
- S(软状态): 允许系统中的数据存在中间状态,并且认为该状态不会影响系统的整体可用性。即,不同数据副本之间的数据同步可以存在延迟。
- E(最终一致性): 经过一段「不一致窗口期」后,所有的数据副本最终会达到一致的状态。这是软状态的必然结果。
2.2 BASE vs. ACID 终极对决
| 特性 | ACID | BASE |
|---|---|---|
| 哲学 | 一致性优先 | 可用性优先 |
| 一致性 | 强一致性: 事务后立即可见 | 最终一致性: 存在延迟 |
| 事务模型 | 原子、隔离的事务 | 柔性事务 |
| 关注点 | 数据一致性、正确性 | 高可用、低延迟 |
| 适用场景 | 银行转账、库存扣减 | 社交媒体点赞、用户资料更新 |
| 比喻 | 婚礼: 严肃、严谨、一步到位 | 约会: 灵活、可能变化、最终走向稳定 |
3. 云计算与容器化
3.1 服务模式分层(经典披萨比喻)
- IaaS(基础设施即服务): 你租用了一个带烤箱和灶台的厨房。你需要自己准备面粉、酱料(OS、Runtime),自己烤披萨(应用)。控制权最大,也最麻烦。
- 例子:AWS EC2, 阿里云 ECS
- PaaS(平台即服务): 你走进一个披萨店的后厨,所有原料和工具都已备好。你只需要按配方揉面、放料即可。专注于应用开发本身。
- 例子:Google App Engine, Heroku
- SaaS(软件即服务): 你直接点外卖,享用做好的披萨。开箱即用,无需管理任何底层设施。
- 例子:Gmail, 钉钉, Salesforce
3.2 容器化技术(Docker)的核心价值
- 核心思想: 「一次构建,到处运行」。将应用代码、运行时环境、系统工具、系统库全部打包成一个独立的、轻量级的、可执行的软件单元(镜像)。
- 与虚拟机的本质区别:
- 虚拟机: 虚拟化的是硬件。每个 VM 都有自己的客户操作系统,在 Hypervisor 上运行。重量级。
- 容器: 虚拟化的是操作系统。所有容器共享主机的 OS 内核,但拥有独立的文件系统、进程空间。轻量级。
- 类比: 虚拟机是一整栋房子,容器是房子里的一个房间。
第二部分:系统架构 · 深入剖析四大数据库
1. MongoDB:灵活的文档数据库
1.1 核心架构:分片集群
mongos(查询路由器): 应用的统一入口。它缓存了来自 Config Server 的元数据,将查询和写入请求路由到正确的分片上。无状态,可部署多个以实现高可用。Config Server(配置服务器): 存储集群的元数据,包括数据块与分片的映射关系。本身是一个副本集,保证元数据的高可用。Shard(分片): 存储实际数据。每个分片通常也是一个副本集,用于保证数据的高可用和冗余。
1.2 分片策略
- 哈希分片: 对分片键计算哈希值,根据哈希范围分配数据。优点: 数据分布均匀,写操作可分散到所有分片。缺点: 范围查询效率低,需要查询所有分片。
- 范围分片: 根据分片键的值范围分配数据。优点: 范围查询效率高,可以定向扫描特定分片。缺点: 可能导致数据分布不均,产生「热点」分片。
1.3 适用场景与陷阱
- 适用: 内容管理系统、产品目录、用户配置文件、需要灵活 Schema 的任何场景。
- 陷阱: 不擅长多文档事务(虽然现在支持,但性能有损)、不擅长复杂的表关联查询。
2. Redis:内存中的数据结构存储
2.1 丰富的数据类型(不仅是 Key-Value)
- String: 缓存、计数器。
- List: 消息队列、最新动态列表。
- Set: 共同好友、标签系统。
- Sorted Set: 排行榜、延迟队列。
- Hash: 存储对象(如用户信息)。
- Bitmap/HyperLogLog: 统计日活、UV。
2.2 持久化机制:RDB vs. AOF
- RDB(快照):
- 原理: 在特定时间点,创建整个数据集的二进制快照。
- 优点: 文件紧凑,恢复速度快,最大化 Redis 性能。
- 缺点: 会丢失最后一次快照之后的所有数据;
fork()子进程时,如果数据集很大,会阻塞主线程。
- AOF(追加日志):
- 原理: 记录每一个写操作命令,并在重启时重新执行这些命令来恢复数据。
- 优点: 数据耐久性高,最多丢失一秒的数据。文件易于解析。
- 缺点: AOF 文件通常比 RDB 大;恢复速度慢;写负载高时可能影响性能。
- 生产环境建议: 通常两者结合使用,用 AOF 保证数据安全,用 RDB 做冷备份。
2.3 集群模式:Redis Cluster
- 数据分片: 采用 「哈希槽」,共 16384 个槽。每个节点负责一部分槽。
- 无中心架构: 客户端可以连接任何节点。如果数据不在该节点,节点会返回
MOVED重定向错误,指引客户端连接正确的节点。 - 高可用: 采用主从复制,每个主节点都有若干个从节点。主节点故障时,从节点会选举成为新的主节点。
3. HBase:面向列的分布式数据库
3.1 架构角色与职责
- HMaster: 管理角色。负责表的 DDL 操作(创建、删除)、RegionServer 的负载均衡、Region 的分配和故障转移。本身是无状态的,通过 ZooKeeper 实现高可用。
- RegionServer: 数据服务角色。负责处理对其上 Region 的读写请求。管理多个 Region。
- Region: 表的数据分片。当表越来越大时,一个 Region 会被拆分成两个。
- ZooKeeper: 协调者。负责维护集群的元信息(如 HMaster 地址、RegionServer 存活状态),是集群的「神经中枢」。
3.2 数据模型与存储设计
- 行键: 是数据访问的唯一标识和首要路径。设计好坏直接决定性能。
- 设计原则: 散列、有序、简短。
- 例子: 将
user_id反转后作为行键,可以避免热点。
- 列族: 物理存储单元。同一列族下的数据存储在一起。列族需要在建表时预定义,且不宜过多(1-3个)。
- 列限定符: 在列族下动态创建,不需要预定义。
- 时间戳: 实现数据多版本。
3.3 LSM-Tree:写入高性能的秘诀
- 写入路径: 写入首先进入 MemStore(内存),当 MemStore 填满后,异步刷写到磁盘形成 HFile。HFile 是不可变的、有序的键值对集合。
- 读取路径: 需要同时查找 MemStore 和多个 HFile,并将结果合并。
- Compaction: 定期将多个小 HFile 合并成一个大 HFile,并清理已删除的数据,以优化读取性能。
4. Cassandra:无主的分布式数据库
4.1 去中心化的 P2P 架构
- 所有节点对等: 没有主从之分,每个节点功能完全相同。客户端可以连接集群中的任意节点。
- 数据分布: 采用一致性哈希,形成一个逻辑环。每个节点负责环上的一段令牌范围。
- 种子节点: 新节点加入集群时的联络人,用于引导发现集群中的其他节点。
4.2 灵活的一致性级别
- 可调一致性: 可以为每次读写操作设置一致性级别。
- 写一致性:
ONE,QUORUM,ALL。 - 读一致性:
ONE,QUORUM,ALL。
- 写一致性:
- 实现强一致性: 设置
W + R > N(W:写一致性级别,R:读一致性级别,N:副本因子)。例如,设置QUORUM读写,即可在分布式环境下实现强一致性读。
5. Neo4j:原生图数据库
5.1 图数据库的核心概念
- 节点(Node):表示实体,如用户、产品、文章。
- 关系(Relationship):连接两个节点的有向边,表示实体之间的关联。
- 属性(Property):节点和关系上可以存储的键值对。
- 标签(Label):节点的分类标记,如
:User、:Product。
5.2 适用场景
- 社交网络:好友推荐、影响力分析
- 推荐系统:基于关系的商品推荐
- 知识图谱:实体关系查询与推理
- 欺诈检测:识别异常关联模式
5.3 性能特点
- 优点:关系遍历极快,支持复杂路径查询
- 缺点:不适合大规模属性过滤、聚合计算
六大数据库对比总表
| 特性 | MongoDB | Redis | HBase | Cassandra | Neo4j | MySQL/PostgreSQL |
|---|---|---|---|---|---|---|
| 数据模型 | 文档型 | 键值+数据结构 | 列存储 | 宽列存储 | 图模型 | 关系型 |
| CAP | CP | CP | CP | AP(可调为CP) | CA(单机) | CA |
| 事务支持 | 多文档事务 | 单命令原子性 | 单行事务 | 轻量事务 | ACID 事务 | 完整 ACID |
| 扩展性 | 水平扩展 | 集群扩展 | 线性水平扩展 | 线性水平扩展 | 主从复制 | 垂直/有限水平 |
| 典型场景 | 内容管理、用户画像 | 缓存、会话、队列 | 日志、时序数据 | 全球分布式写入 | 社交网络、推荐系统 | 交易、关系查询 |
第三部分:设计实战 · 五大数据库场景设计
场景一:图书管理系统(MongoDB)
需求:
- 管理图书、作者、出版社信息
- 支持分类、标签、多级目录
- 查询频繁,结构相对稳定但有扩展需求
MongoDB 文档结构示例:
{
"book_id": "BK001",
"title": "分布式系统导论",
"authors": [
{ "author_id": "A001", "name": "张三", "country": "中国" },
{ "author_id": "A002", "name": "李四", "country": "美国" }
],
"publisher": {
"publisher_id": "P001",
"name": "清华大学出版社"
},
"categories": ["计算机科学", "分布式系统"],
"tags": ["NoSQL", "CAP定理", "数据库"],
"metadata": {
"isbn": "978-7-302-12345-6",
"pages": 350,
"publish_date": "2023-05-01"
},
"stock": 50,
"price": 89.90
}
设计理由:
- 使用嵌入式文档存储作者和出版社信息,避免多表 JOIN
- 数组字段支持多分类和标签
- 动态扩展的 metadata 字段适应未来需求
场景二:在线购物车(Redis)
需求:
- 高并发读写
- 临时存储,可过期
- 支持商品数量增减、合并
Redis 数据结构示例:
- Key:
cart:user:1001 - Value(Hash):
item001 → 2 item005 → 1 item012 → 5 - 过期时间:24小时
设计理由:
- Hash 结构适合存储购物车商品 ID 和数量的映射
- 内存存储保证极速读写
- 设置过期时间自动清理不活跃购物车
场景三:聊天消息存储(Cassandra)
需求:
- 全球用户,写入极高
- 按时间范围查询聊天记录
- 高可用,分区容忍
Cassandra 表结构示例:
表名:messages
分区键:chat_id, bucket(按月分桶)
聚类键:message_time DESC, message_id
列示例:
chat_id: uuid
bucket: int(如202310表示2023年10月)
message_time: timestamp
message_id: uuid
sender_id: uuid
receiver_id: uuid
content: text
message_type: text(text/image/file)
read_status: boolean
设计理由:
- 分区键包含 chat_id 和 bucket,避免单个分区过大
- 按时间倒序聚类,最新消息优先
- 宽表设计适合 Cassandra 的存储模型
场景四:社交网络关注关系(Neo4j)
需求:
- 快速查询 N 度人脉
- 推荐可能认识的人
- 分析社群结构
Neo4j 图结构示例:
节点标签:User
节点属性:
- user_id: "U001"
- name: "张三"
- age: 28
- city: "北京"
- interests: ["编程", "摄影", "旅行"]
关系类型:FOLLOWS
关系属性:
- since: "2022-03-15"
- closeness: 0.8(亲密程度)
示例关系:
(张三:User)-[:FOLLOWS {since: "2022-03-15"}]->(李四:User)
(李四:User)-[:FOLLOWS]->(王五:User)
(张三:User)-[:FOLLOWS]->(王五:User)
(赵六:User)-[:FOLLOWS]->(张三:User)
设计理由:
- 图结构天然表示关注关系
- 支持复杂路径查询(如查找共同关注)
- 关系属性可存储关注时间和亲密程度
场景五:物联网设备日志(HBase)
需求:
- 海量时间序列数据写入
- 按设备 ID 和时间范围查询
- 长期存储,偶尔分析
HBase 表结构示例:
表名:iot_device_logs
行键:device_id + (Long.MAX_VALUE - timestamp)
(反转时间戳使最新数据排在前面)
列族:cf(所有指标放在同一列族)
列限定符示例:
cf:temperature → 25.6
cf:humidity → 65.2
cf:voltage → 220.5
cf:status → "normal"
cf:location → "room_101"
cf:error_code → null(空值不存储,体现稀疏性)
设计理由:
- 反转时间戳实现时间倒序排列
- 列族设计适合存储多维指标
- 稀疏存储节省空间
第四部分:数据库转换思维
1. 关系型 → 文档型(图书管理系统)
关系型设计:
表:books
book_id, title, author_id, publisher_id, category_id, isbn, pages, price
表:authors
author_id, name, country
表:publishers
publisher_id, name, address
表:categories
category_id, name, parent_id
文档型转换:
- 策略:将作者、出版社信息嵌入图书文档
- 反规范化:在 book 文档中直接存储作者姓名、出版社名称
- 数组化:将分类从外键关系转为数组字段
- 保留引用:同时保留 author_id、publisher_id 用于关联更新
2. 文档型 → 列存储型(用户画像系统)
文档型设计:
{
"user_id": "U1001",
"profile": {
"basic": { "name": "张三", "age": 28, "gender": "male" },
"preferences": { "hobbies": ["篮球", "电影"], "color": "蓝色" },
"behavior": { "last_login": "2023-10-01", "login_count": 156 }
}
}
列存储型转换:
行键:user_id
列族:basic
basic:name → "张三"
basic:age → "28"
basic:gender → "male"
列族:pref
pref:hobbies → "篮球,电影"
pref:color → "蓝色"
列族:behavior
behavior:last_login → "2023-10-01"
behavior:login_count → "156"
转换原则:
- 将嵌套文档扁平化为列族+列限定符
- 数组字段转为逗号分隔字符串
- 保持用户 ID 作为行键
3. 键值型 → 图型(社交关系系统)
键值型设计:
Redis Sets:
followers:U001 → ["U002", "U003", "U005"]
following:U001 → ["U004", "U006"]
Redis Hashes:
user:U001 → {name: "张三", age: 28}
user:U002 → {name: "李四", age: 32}
图型转换:
节点:
(:User {id: "U001", name: "张三", age: 28})
(:User {id: "U002", name: "李四", age: 32})
关系:
(U002)-[:FOLLOWS]->(U001)
(U003)-[:FOLLOWS]->(U001)
(U005)-[:FOLLOWS]->(U001)
(U001)-[:FOLLOWS]->(U004)
(U001)-[:FOLLOWS]->(U006)
转换原则:
- 将键中的用户ID提取为图节点
- 将集合中的关系转为图关系边
- 将Hash中的属性转为节点属性
4. 列存储型 → 关系型(日志分析系统)
列存储型设计:
HBase表:web_logs
行键:timestamp + user_id
列族:req
req:url → "/product/123"
req:method → "GET"
req:ip → "192.168.1.1"
列族:res
res:status → "200"
res:size → "1456"
res:time → "45"
关系型转换:
表:web_logs
log_id, timestamp, user_id, url, method, ip, status, size, response_time
索引:
idx_timestamp (timestamp)
idx_user_id (user_id)
idx_url (url)
转换原则:
- 将行键拆分为多个字段
- 将列限定符转为表字段
- 将稀疏列转为可为空的字段
- 添加合适索引优化查询
5. 图型 → 文档型(知识图谱系统)
图型设计:
节点:
(:Person {id: "P001", name: "爱因斯坦", born: 1879})
(:Theory {id: "T001", name: "相对论", year: 1905})
(:Field {id: "F001", name: "物理学"})
关系:
(Person:P001)-[:PROPOSED]->(Theory:T001)
(Theory:T001)-[:BELONGS_TO]->(Field:F001)
(Person:P001)-[:STUDIED]->(Field:F001)
文档型转换:
{
"entity_id": "P001",
"type": "Person",
"properties": {
"name": "爱因斯坦",
"born": 1879
},
"relationships": [
{
"type": "PROPOSED",
"target_id": "T001",
"target_type": "Theory",
"target_name": "相对论"
},
{
"type": "STUDIED",
"target_id": "F001",
"target_type": "Field",
"target_name": "物理学"
}
]
}
转换原则:
- 将节点转为文档主体
- 将关系转为文档内的嵌套数组
- 保留目标节点的关键信息避免过度查询
- 适合读取密集型场景
第五部分:综合设计决策框架
场景 → 数据库选型决策树:
-
是否需要强事务保证?
- 是 → MySQL/PostgreSQL
- 否 → 进入下一判断
-
数据结构是否灵活多变?
- 是 → MongoDB
- 否 → 进入下一判断
-
是否主要处理关系/网络?
- 是 → Neo4j
- 否 → 进入下一判断
-
写入吞吐是否极高?
- 是 → HBase/Cassandra
- 否 → 进入下一判断
-
是否需要极低延迟读写?
- 是 → Redis
- 否 → 根据其他因素选择
混合架构示例:
-
社交应用:
- Neo4j:存储用户关系
- MongoDB:存储用户资料、帖子
- Redis:存储会话、缓存
- Cassandra:存储聊天消息
-
电商系统:
- MySQL:存储订单、库存(强事务)
- MongoDB:存储商品目录、评论
- Redis:购物车、秒杀缓存
- HBase:用户行为日志
更多推荐



所有评论(0)