关系型数据库(见 tech-database)不是万能的:海量文档、超高并发缓存、时序指标、关系网络、全文检索,各有更适合的存储。NoSQL 不是"反 SQL",而是"按数据形状选存储"。本页覆盖文档库(MongoDB)、列族(Cassandra/HBase)、缓存与协调(Redis/etcd)、图库(Neo4j)、以及全文检索王者 Elasticsearch——补上 tech-database 没讲的半壁江山。我会把每个知识点拆成"是什么 → 为什么 → 怎么用 → 踩什么坑"。基线:MongoDB 7、Cassandra 4、Redis 7、Neo4j 5、Elasticsearch 8。
为什么是 NoSQL:CAP 与 AP/CP 取舍
NoSQL 的兴起不是因为 SQL"不好",而是因为某些数据形状用关系模型代价太高。先搞懂它背后的一致性哲学,才知道什么时候该用、什么时候别用。
NoSQL 到底"N"什么
NoSQL 最早指 "Not only SQL"(不仅是 SQL),强调不局限于关系模型。它涵盖文档、列族、KV、图、时序等多种数据模型。核心动机:① 海量数据要水平扩展(加机器而不是换大机器);② 结构多变、不想被固定 schema 绑住;③ 超高并发读写(缓存/计数);④ 特定查询形态(全文、图遍历)。它不是要取代关系库,而是补关系库不擅长的那一摊。
论别被名字误导
很多 NoSQL 现在也支持类 SQL 查询(如 MongoDB 的 aggregation、Cassandra 的 CQL、ES 的 SQL 接口)。"NoSQL" 指的是数据模型与扩展哲学,不是"不能写 SQL"。选型看的是模型与一致性,不是名字。
CAP 定理:三者最多取其二
分布式系统里:C 一致性(所有节点同一时刻看到相同数据)、A 可用性(每个请求都有响应,不保证最新)、P 分区容忍(网络断了系统还能跑)。现实网络一定会分区(P 不可免),所以真实取舍是 CP(保一致、分区时宁可拒绝,如 ZooKeeper/etcd/HBase)还是 AP(保可用、接受短暂不一致,如 Cassandra/DynamoDB)。
| 类型 | 含义 | 典型 | 适合 |
|---|---|---|---|
| CP | 保一致,分区时部分不可用 | ZooKeeper / etcd / HBase | 协调、元数据、账务 |
| AP | 保可用,接受最终一致 | Cassandra / DynamoDB / Redis | 海量写入、会话、 feed |
| CA(理论) | 单点无分区才成立 | 单机 MySQL | 非分布式场景 |
BASE:AP 系统的哲学
AP 系统常用 BASE 概括:Basically Available(基本可用)、Soft state(软状态,允许中间不一致)、Eventually consistent(最终一致)。它和关系库的 ACID 是两种世界观:ACID 要"现在就绝对对",BASE 要"最终会对,中间可能旧"。多数互联网场景其实能接受 BASE。
论什么时候必须 CP
钱、锁、元数据这类"错一点就出大事"的数据,必须 CP:分布式锁用 etcd/ZK(基于租约)、库存扣减要强一致、服务注册中心要一致。反过来,浏览量、推荐、草稿这类"旧一点无妨"的数据,AP 更划算。按"出错代价"定一致性目标,别一刀切。
一致性强弱谱:不止 CP/AP 两档
现实比 CP/AP 更细:线性一致(最强,如 etcd)、因果一致、会话一致(同一用户看到自己刚写的)、最终一致(最弱)。选多强的"一致性",直接决定性能与复杂度。多数业务用"会话一致 + 最终一致"就够,不必追线性一致。
选型的第一性原理
论先问数据形状,再问数据库
别从"哪个数据库火"出发。先列:数据结构固定吗?查询是点查还是扫描还是图遍历?要强一致吗?读多写多?答案出来,候选库自然缩小。NoSQL 的价值正是"为特定形状而生",用错形状比用错品牌更致命。
一个速查矩阵
| 数据形状 | 首选 | 一致性倾向 |
|---|---|---|
| 结构化、强一致、事务 | MySQL / PostgreSQL | CP |
| 半结构化文档 / 快速迭代 schema | MongoDB | CP(单分片)/ 可调 |
| 海量宽表写入 | Cassandra / HBase | AP / CP |
| 极热 KV / 缓存 / 协调 | Redis / etcd | AP / CP |
| 关系网络 | Neo4j | — |
| 全文检索 / 聚合 | Elasticsearch | AP(近实时) |
何时不该用 NoSQL:三个反模式
NoSQL 不是银弹。三种滥用:① 用 Cassandra 跑报表(ad-hoc 查询弱);② 用 MongoDB 硬 join(没有外键,反复 $lookup);③ 用 Redis 存必须一致的状态(会丢)。判断标准就一句:你的查询形态是不是这种存储的强项?不是就回头用关系库。
| 反模式 | 正确选择 |
|---|---|
| 用列族库跑多维报表 | OLAP / ES |
| 文档库反复 join | 关系库 |
| Redis 存强一致状态 | etcd / 关系库 |
见过太多团队因为"同行都在用 X"就上 X,结果 80% 的数据关系库就能搞定,反而多了同步与运维负担。选型由数据形状驱动,不由流行度驱动。能一个关系库解决的,别上五个。
文档数据库:MongoDB 与灵活 schema
文档库以 JSON 风格文档为单位存储,同集合里的文档结构可以不同——适合需求快速变化、嵌套结构多的场景(商品、内容、日志)。这一章讲清模型、聚合、索引、事务与分片。
文档模型:把"对象"原样存
关系库要把对象拆成多张表、用外键 join;文档库一个对象就是一个文档,嵌套、数组直接存,读一次就拿到,不用 join。这对"商品有多种属性、用户有可变 profile"这类场景极友好。
schema 自由容易变成"一团乱麻"。仍要规划好查询模式并建立索引;否则"灵活"会变成"慢查询温床"。MongoDB 也支持事务(多文档),但别拿它当 PostgreSQL 用——需要复杂 join / 强跨文档事务时,关系库更合适。
嵌套 vs 引用:建模的两难
文档库有两种关联方式:嵌套(embed)把子对象塞进父文档,读快、但数组会膨胀;引用(reference)存别的文档 id,像外键,灵活但要二次查询。经验:"一对一/一对少且常一起读"就嵌;"一对多且会无限增长/独立访问"就引用。
| 场景 | 选 | 理由 |
|---|---|---|
| 用户地址 / profile | 嵌套 | 少、常一起读 |
| 订单列表 | 引用 | 多、独立增长 |
| 评论(无限) | 引用 | 避免超宽文档 |
| 商品规格 | 嵌套 | 结构固定、同读 |
聚合管道:文档库的"SQL"
MongoDB 用聚合管道(aggregation pipeline)做复杂查询:一串 stage($match 过滤、$group 分组、$sort、$project 投影、$lookup 关联)像流水线一样串起来。比写命令式代码清晰,也能下推到索引。
论$lookup 不是免费 join
$lookup 能跨集合关联,但它不是关系库的 join——没有外键约束、无索引优化时是大开销,且跨分片更慢。如果只是常用的一对一关联,优先"嵌套"而非 $lookup。把文档库当关系库用,等于放弃它的优势。
索引:查得快的关键
和关系库一样,没索引的查询是集合全扫描。MongoDB 支持单字段、复合、唯一、文本、地理空间索引。复合索引要遵循ESR 规则:等值(Equality)字段在前、排序(Sort)其次、范围(Range)最后,顺序错了索引用不上。
每个索引拖慢写入、占存储。文档库默认给 _id 建唯一索引,你自己加的索引要"为高频查询而建"。用 explain 验证是否真命中,别凭感觉建一堆用不上的索引。
事务:多文档也能 ACID(有限度)
MongoDB 4.0+ 支持多文档事务,4.2+ 支持分片事务。语法类似关系库:session.startTransaction() ... commitTransaction()。但它性能与范围有代价,且事务默认有 60s 限制、持有锁影响并发。能用一个文档嵌套搞定的,别上事务。
分片:文档库也要水平扩展
单 mongod 容量/吞吐到顶时,分片集群(sharded cluster)把数据按 shard key 分布到多个 shard。选 shard key 的原则和关系库分片键一样:高基数、分布均匀、贴合查询。坏 key(如自增 id)会造成"热点块"。
Change Stream:把变更流出去做同步
MongoDB 的 Change Stream 类似 CDC:监听集合的插入/更新/删除,实时推给消费者。它是"文档库 → 其它存储(ES/缓存/数据仓库)"同步的官方通道,比自己轮询高效得多,也是多语言持久化里文档库的"出口"。
论Change Stream vs 应用双写
应用双写在业务代码里同时写多库,容易因异常漏写导致不一致;Change Stream 由数据库保证"写了就流出",业务无感知、更稳。多存储同步优先 CDC / Change Stream,双写只作简单场景兜底。
列族数据库:Cassandra 与 HBase
当写入量是"每秒百万条"、且要跨机房多副本,行式关系库就吃力了。列族(宽表)数据库用 LSM-Tree 把随机写变成顺序写,专为海量写入与横向扩展而生。本章对比 Cassandra(AP)与 HBase(CP)。
宽表模型:行键 + 列族 + 动态列
列族库的"表"由行键(row key)索引,每行里有列族,列族下是动态、稀疏的列。同一行的列可以完全不同——非常适合"同一用户的行为日志,列随时间无限增加"。查询基本只能按 row key(或 row key 范围)取,不支持任意列上的高效过滤。
论为什么"按查询建模"
关系库先建模再写查询;列族库反过来——先想清楚查询,再设计表。因为过滤只能高效发生在主键/分区键上,所以常为一个查询建一张表("查询驱动建模")。这让写入极其快,但 ad-hoc 查询弱。
LSM-Tree:写入为什么这么快
关系库 B+树每次写可能要随机改树节点(慢)。LSM-Tree 把写先进内存 MemTable,满了刷成不可变的有序文件(SSTable)顺序落盘(快),后台再compaction合并去重。读时可能要查内存 + 多个 SSTable,再用布隆过滤器跳过无关文件。结果:写极快、读稍慢(可被缓存补偿)。
| 阶段 | 动作 | 特点 |
|---|---|---|
| 写 | 进 MemTable(内存) | 顺序、极快 |
| 刷盘 | MemTable → SSTable | 顺序 IO |
| 读 | 内存 + 多层 SSTable + 布隆 | 可能多查,靠缓存 |
| 合并 | Compaction | 去重、回收空间 |
写入路径:一条写请求的一生
写入量大时 Compaction 会和正常读写抢 IO/CPU,造成"读延迟突刺"。调参(compaction 策略、并发度)和监控 SSTable 数量是运维重点。新手常忽略这点,上线后半夜被延迟告警叫醒。
Cassandra(AP)vs HBase(CP)
两者都用宽表 + LSM,但定位不同:Cassandra 多主、无中心、AP 倾向、易跨机房伸展,适合"写多、容忍最终一致"(物联网、feed);HBase 依赖 HDFS + ZooKeeper、CP 倾向、强一致行级读写,适合"和 Hadoop 生态一体的海量存储"(日志归档、画像)。
| 维度 | Cassandra | HBase |
|---|---|---|
| 架构 | 无中心多主 | Master/RegionServer + ZK |
| 一致性 | AP(可调) | CP(行级强一致) |
| 部署 | 独立、轻 | 依赖 HDFS,重 |
| 适合 | 高写、跨机房 | 海量存储 + 分析 |
适用场景与不适用场景
论什么时候上列族库
上:写入量极大(时序、日志、事件流)、需要线性扩展、查询模式固定(按 row key)。别上:需要复杂 join、ad-hoc 报表、事务跨行——这些它天生弱,硬上就是和自己过不去。那种需求留给关系库/OLAP。
数据建模反例
Cassandra 的分区键决定数据落在哪个节点。若用"事件类型"这种低基数列做分区键,所有同类事件挤一个分区→热点节点;若 row key 设计成单一大账号,行会无限宽→超宽行读爆。务必用高基数、均匀分布的分区键,并给宽行加时间边界。
读写一致性级别:ONE / QUORUM / ALL
Cassandra 允许按请求调一致性级别,在性能与一致强度间自由取舍。ONE 只写/读一个副本,最快但可能读到旧值;QUORUM 过半数(读 + 写都 QUORUM 保证线性一致);ALL 全副本,最强但最慢、任一节点挂就不可用。多数场景用 QUORUM。
论读写一致性的"组合拳"
要保证强一致,规则是 写 QUORUM + 读 QUORUM(或写 ALL + 读 ONE)。因为 Quorum 读写必然在至少一个副本上相交,读到的一定含最新写。只写 ONE 读 ONE 最快但可能脏读——按数据重要性分级设置级别,而非全局一刀切。
KV 存储:Redis 与 etcd
KV 是最简单的模型——一个 key 对应一个 value。但"简单"让它极快、极通用。本章分两半:Redis(内存 KV,扛热点与数据结构)与 etcd(一致 KV,做分布式协调)。
Redis:内存 KV 的多种面孔
Redis 表面是 KV,实际 value 可以是字符串、哈希、列表、集合、ZSet、Stream——前面数据库进阶页讲过它的缓存/锁/集群。这里强调它的另一面:数据结构服务器。用对结构,很多"业务难题"变一行命令。
Redis 的应用形态清单
| 用法 | 结构 | 场景 |
|---|---|---|
| 缓存 | String/Hash | 商品详情、配置 |
| 分布式锁 | String (SET NX) | 防并发重复 |
| 排行榜 | ZSet | 积分、热度 |
| 限流 | ZSet/计数器 | 滑动窗口 |
| 消息流 | Stream | 事件溯源 |
| UV 估算 | HyperLogLog | 去重计数 |
几个容易被低估的 Redis 结构,用对能省大把空间:HyperLogLog 用 ~12KB 估算上亿 UV(误差约 0.8%,但不存具体谁);Bitmap 每位代表一天签到,统计极省。
大 key(如一个存了百万元素的 Hash)删除/序列化会阻塞单线程,拖垮整个实例;热 key(某个 key 被海量请求打)会让单节点成为瓶颈。解法:大 key 拆分、热 key 本地缓存 + 多副本。Redis 单线程,一个慢命令全实例都卡,务必警惕。
etcd:一致 KV 与分布式协调
etcd 是强一致、高可用的 KV 存储(基于 Raft),它慢但绝对可靠。Kubernetes 的所有元数据就存在 etcd 里。它不用来扛业务流量,而是用来存配置、服务发现、分布式锁、选主这类"少写、必须一致"的数据。
论Redis 锁 vs etcd 锁
Redis 锁基于 SET NX,快但主从切换可能丢锁(前面讲过)。etcd 锁基于 Raft 租约,强一致、不会因切换丢,且自动过期(lease)防死锁。结论:高频、可最终一致用 Redis;元数据、选主、必须一致用 etcd/ZK。别用错场景。
Raft:etcd 一致性的根基
etcd 用 Raft 协议保证多副本一致:一个 Leader 接收写、复制到多数派(quorum)才算成功;Leader 挂了自动选新 Leader。写要过半数节点,所以节点数通常奇数(3/5)。这让它慢于 AP 系统,但保证"你读到的不会是过时的少数派"。
Watch 与配置热更新
etcd 的 Watch 机制让客户端订阅 key 变化,配置一改,所有监听方秒级收到——这是"配置中心 / 服务发现"的核心能力。比"轮询数据库"优雅且实时。
选型小结:内存 KV 与协调 KV 别混
Redis AOF 默认每秒刷盘、主从异步,极端情况会丢或脏读。把"服务注册表/锁/配置"这类必须一致的数据放 Redis,集群抖动时会出现"两个 Leader"或"配置读到旧值"的诡异事故。协调类数据交给 etcd/ZK,这是它们存在的意义。
Redis Cluster:槽位分片与扩缩容
Redis Cluster 把数据分成 16384 个哈希槽,每个节点负责一部分槽。key 通过 CRC16(key) % 16384 落在某槽、进而某节点。扩缩容就是把槽迁移到新节点,迁移期间旧节点对新 key 返回 MOVED 重定向,业务无感知。
Cluster 不支持跨槽的事务 / mget 多 key,除非这些 key 用 {hashtag} 强制落到同一槽(如 {user1}:name 和 {user1}:age)。忘了 hashtag 会导致 "CROSSSLOT 错误"。需要原子多 key 操作时,把相关 key 用同一 hash tag 包起来。
图数据库:Neo4j 与关系查询
"某人好友的好友里谁和我同公司"——这种多跳关系查询,用 SQL 要自连接 N 次,越跳越慢。图数据库把"关系"当一等公民,遍历边天然高效。社交、反欺诈、推荐、知识图谱都靠它。
属性图模型:点、边、属性
图由节点(Node)和关系(Relationship/边)组成,两者都能带属性。节点可有标签(如 Person、Company),关系有类型和方向(如 FOLLOWS、WORKS_AT)。"关系"不再是外键,而是数据库里真实存储、带索引的边——所以"顺着边走"极快。
论为什么图库快
关系库没有"边"这种结构,多跳要靠 join 拼表,join 成本随跳数指数涨。图库把边存成"指针",从节点 A 直接顺着指针走到邻居 B、C——遍历成本只和"实际关联数"有关,和总数据量无关。数据越大、跳越多,优势越夸张。
Cypher:声明式图查询语言
Neo4j 用 Cypher,用 () 表节点、--> 表有向边、[] 表关系类型,像画 ascii 图一样写查询。比 SQL 的自连接直观太多。
遍历与最短路径
图库天生擅长路径类查询:最短路径(Dijkstra/BFS)、社区发现、环路检测。反欺诈里"这笔交易的上游资金链"就是典型:顺着转账边向上遍历,几跳内找到可疑源头。
索引与约束
图库不是"免索引"。起点查询("找 name=MJ 的人")仍要靠节点索引/约束,否则全图扫描。常用 CREATE INDEX 和 CREATE CONSTRAINT(如唯一约束防重复节点)。
如果查询没有可以利用索引的起点(如"找出所有互相认识的人"),Neo4j 要扫全图,数据一大就爆。务必让高频查询带有索引的锚点(如先定位某个用户/账户,再向外遍历)。别写"无边界 * 多跳"的野查询。
什么时候用图库、什么时候别
| 场景 | 该用图库吗 | 理由 |
|---|---|---|
| 社交好友/关注 | ✅ | 多跳关系 |
| 反欺诈资金链 | ✅ | 路径遍历 |
| 知识图谱 / RAG | ✅ | 实体关系 |
| 订单 CRUD | ❌ | 关系库更合适 |
| 海量宽表写入 | ❌ | 列族库更合适 |
落地形态:图库常作"关系层"
生产里图库通常不是"主库",而是关系层:主数据在关系/文档库,把"谁和谁有关"同步进图库做关系查询。比如推荐系统:用户行为进图库,实时算"相似用户",再把结果回写业务库。它和 ES 一样是"专才",不是"通才"。
图算法:不止查询,还能挖掘结构
图库除了遍历查询,还内置图算法:PageRank 算节点影响力(识别关键账户/KOL)、社区发现(Louvain)找紧密子群(社群划分)、最短路径算距离。这些在反欺诈(资金网络核心节点)、推荐(相似社群)、知识图谱里极有用。
论图算法 vs 关系库自连接
关系库算"影响力/社群"要写极复杂的递归 CTE 或应用层迭代,数据一大就爆;图库把图结构常驻内存,算法是原生算子,几千万边也能秒级出结果。这属于"用对模型省一年开发"的典型。
选型矩阵与混合持久化落地
前面五种模型都讲了。这一章把它们收口成一张可执行的选型矩阵,并讲清"多语言持久化"在真实系统里怎么拼、怎么同步、怎么不把自己搞死。
一张能直接用的选型矩阵
把全页内容压成一张表,下次选型照着对:
| 数据形状 | 首选 | 一致性 | 别用它做 |
|---|---|---|---|
| 结构化、事务 | MySQL/PostgreSQL | CP | 全文检索 |
| 半结构化文档 | MongoDB | 可调 | 复杂 join |
| 海量宽表写入 | Cassandra/HBase | AP/CP | ad-hoc 查询 |
| 极热 KV/缓存 | Redis | AP | 元数据存储 |
| 协调/配置/锁 | etcd/ZK | CP | 业务流量 |
| 关系网络 | Neo4j | — | 通用 CRUD |
| 全文/聚合 | Elasticsearch | AP | 主数据库 |
| 时序指标 | InfluxDB | AP | 事务 |
混合持久化的真实拼盘
一个电商/内容平台的典型组合:主数据(用户/订单)→ PostgreSQL;商品详情/草稿 → MongoDB;热点缓存/会话/锁 → Redis;搜索 → Elasticsearch;监控指标 → 时序库;推荐关系 → Neo4j;配置/选主 → etcd。每种只干最擅长的事。
论它们怎么保持一致
核心心法:源唯一。关系/文档库是强一致源,其余都是副本。变更发生后通过 CDC(Canal/Debezium)+ MQ 异步同步到 ES/图库/缓存;每条消费链路都要幂等,再用对账兜底。没有"实时强一致同步所有库",而是"源唯一、副本异步追、最终一致"。
同步的三种姿势
| 方式 | 做法 | 优劣 |
|---|---|---|
| 应用双写 | 业务里同时写多库 | 简单但易不一致 |
| CDC 同步 | 监听 binlog 喂副本 | 解耦、稳(推荐) |
| 定时批同步 | 离线任务搬运 | 最弱,仅非实时 |
| 源(唯一真相) | 管道 | 副本目标 | 用途 |
|---|---|---|---|
| MySQL binlog | Debezium → Kafka | es_consumer | 更新检索 |
| MySQL binlog | Debezium → Kafka | graph_consumer | 更新关系网络 |
| MySQL binlog | Canal → MQ | cache_refresh | 刷新热点缓存 |
业务代码完全不感知这些副本——它只写源库,源库是唯一真相。副本延迟几秒对搜索、推荐、缓存通常可接受,靠 幂等消费 + 对账 兜底做到最终一致。这也是为什么"应用双写"最危险:业务里同时写多库,任何一次失败都会留下永久不一致,还不如让 CDC 统一搬运。
不要把架构搞成"全家桶灾难"
每加一种存储,就多一套部署、监控、备份、告警、人员学习成本。新手最容易"看啥潮用啥",结果 8 种数据库互相同步、没人敢动。原则:能用一个关系库解决的,别上五个;新存储必须有 owner、监控、降级方案,否则宁可不上。
一致性分级:别一刀切
同一系统里不同数据定不同一致性目标:余额/锁要 CP(etcd/关系事务);商品评分/PV 接受 AP(最终一致)。按"出错代价"分级,而不是给所有数据同目标——那既浪费又没必要。出错代价高(钱、锁)就 CP,出错代价低(计数、热度)就 AP,下面是常用的分级参考:
| 数据 | 目标 | 容忍 |
|---|---|---|
| 余额 / 锁 | CP | 几乎零 |
| 订单状态 | CP 源 + 近似读 | 秒级 |
| 商品评分 | AP | 分钟级 |
| PV / UV | AP | 可估算 |
落地清单与下一步
路动手前先过这五关
① 数据形状定模型;② 一致性定 CP/AP;③ 查询形态定能否命中索引;④ 规模定要不要分片/集群;⑤ 运维定谁扛、挂了怎么降级。五关过了,选型自然稳。多语言持久化的精髓不是"用很多库",而是"每个库都用对地方"。
成本与团队:让架构可持续
多语言持久化的最大隐性成本是人。每多一种存储,团队就要有人懂它的运维、调优、故障处理。选型的终点是"团队扛得住":小团队优先少而精(一个关系库 + 一个缓存 + 一个检索),大团队才按瓶颈逐个引入专才存储。
| 团队规模 | 推荐存储组合 |
|---|---|
| 小(<10 人) | PostgreSQL + Redis + ES |
| 中 | + MongoDB(文档场景) |
| 大 | + Cassandra / Neo4j / etcd 按瓶颈加 |
每种存储上线前必须明确 owner(谁负责容量、告警、升级、故障演练)。"大家都能看一眼"等于"没人负责"。没 owner 的数据库,出问题时没人敢动、恢复最慢。这是比技术选型更常被忽视的翻车点。
NoSQL 的本质是"按数据形状选存储"(多语言持久化):CAP 决定 CP/AP 取舍,AP 系统用 BASE 接受最终一致。文档库 MongoDB 用嵌套/引用建模、聚合管道做查询、注意 ESR 索引与事务代价、shard key 选高基数;列族库 Cassandra/HBase 用宽表 + LSM-Tree 把随机写变顺序写、适合海量写入但查询必须按 row key,Cassandra 偏 AP、HBase 偏 CP;KV 里 Redis 是内存数据结构服务器(大 key/热 key 要防),etcd 是一致 KV 做协调/锁/配置(基于 Raft 租约,强于 Redis 锁);图库 Neo4j 把关系当一等公民,Cypher 多跳遍历天然快,但要有索引锚点避免全图扫描;Elasticsearch 以倒排索引称霸搜索与聚合。落地原则:源唯一、副本异步追、按出错代价分级一致性、每个存储有监控有降级。
1.什么场景该选文档库而不是关系库?MongoDB 的嵌套和引用怎么选?
查看答案
数据结构多变、嵌套深、schema 迭代快(商品属性、草稿、日志)且不强依赖跨文档事务时选文档库。建模上:一对一/一对少且常一起读就"嵌套"(embed),一对多且会无限增长/独立访问就"引用"(reference)。需要强一致事务与复杂 join 仍应选关系库。
2.Cassandra 和 HBase 都是列族库,为什么一个 AP 一个 CP?分别适合什么?
查看答案
两者都用宽表 + LSM-Tree,但 Cassandra 无中心多主、AP 倾向、易跨机房,适合高写/可最终一致(物联网、feed);HBase 依赖 HDFS+ZK、CP 倾向、行级强一致,适合与 Hadoop 一体的海量存储与分析。选错一致性模型会出数据正确性或扩展性问题。
3.Redis 锁和 etcd 锁哪个更"稳"?为什么?
查看答案
etcd 锁更稳。Redis 锁基于 SET NX,主从异步复制时主挂锁可能丢;etcd 基于 Raft 租约,强一致且租约过期自动释放防死锁。所以:高频可最终一致用 Redis;元数据/选主/必须一致用 etcd/ZK。
4.为什么"好友的好友"这类多跳查询用图库比 SQL 快?
查看答案
关系库的"边"不存在,多跳要靠自连接拼表,成本随跳数指数涨;图库把关系存成带索引的指针,从节点顺着边走到邻居,遍历成本只和"实际关联数"有关、与总数据量无关。数据越大跳越多,优势越明显。但查询必须有索引锚点,否则全图扫描。
5.混合持久化里"源唯一、副本异步追"是什么意思?为什么不能直接多库强一致同步?
查看答案
让关系/文档库作为强一致"源",ES/图库/缓存都是它的异步副本,通过 CDC+MQ 同步,消费端幂等、对账兜底。因为跨库强一致同步代价极高(2PC 阻塞、单点),且多数副本查询容忍几秒延迟,最终一致 + 幂等 + 对账在实践中更稳更可扩展。
下一步往哪走
路学完 NoSQL 之后
① 回 tech-database:那里讲 MySQL/PG/Redis 基础与分布式事务、分库分表,本页是它的"另一半"(文档/列族/图/协调)。
② 串系统设计:缓存、分片、读写分离在本页是"单点技术",在 tech-systemdesign 是"架构拼图",配合看才成体系。
③ 动手:用 Docker 起 MongoDB + Redis + etcd + Neo4j + ES,写个小项目把五种存储各用一遍,体会"各司其职 + CDC 同步"。
④ 深入可观测:多存储架构的监控基线(命中率、写入延迟、副本延迟)是调优前提,别等线上炸了才看。