主流数据库对比
主流数据库对比
数据类型
::: info 扩展阅读
:::
类型 | Elasticsearch | MongoDB |
---|---|---|
整数型 | byte 、short 、integer 、long 、unsigned_long |
int、long |
浮点型 | float 、double |
double、decimal |
布尔型 | boolean |
bool |
字符串型 | keyword、text |
string |
二进制型 | binary |
binData |
时间类型 | date |
date、timestamp |
组合类型 | object 、nested |
object、array |
特殊类型 | null 、ip 、version |
null、regex、objectId、javascript |
CRUD
::: info 扩展阅读
:::
操作 | Elasticsearch | MongoDB |
---|---|---|
增 | PUT <index>/_doc/<id> PUT <index>/_create/<id> POST <index>/_doc |
db.collection.insertOne() db.collection.insertMany() |
删 | DELETE <index>/_doc/<id> |
db.collection.deleteOne() db.collection.deleteMany() |
改 | POST <index>/_update/<id> |
db.collection.updateOne() db.collection.updateMany() db.collection.replaceOne() |
查 | GET <index>/_doc/<id> |
db.collection.find() |
批处理 | _bulk 、_mget 、_msearch |
db.collection.insertMany() db.collection.bulkWrite() |
聚合
::: info 扩展阅读
:::
综合对比
RDBM | Elasticsearch | MongoDB |
---|---|---|
WHERE |
query | $match |
GROUP BY 、HAVING |
Bucket(桶聚合) | $group 、$match |
SELECT |
field | $project |
ORDER BY |
order | $sort |
LIMIT |
size | $limit |
SUM() |
sum | $sum |
COUNT() |
value_count | $count |
JOIN |
$lookup |
|
SELECT INTO NEW_TABLE |
$out |
|
MERGE INTO TABLE |
$merge |
|
UNION ALL |
$unionWith |
Elasticsearch 提供了极其丰富的聚合能力。
MongoDB 提供了丰富的聚合能力。
Elasticsearch 聚合
在 ES 中,不仅仅是普通搜索,相关性计算(评分)和聚合计算也是先在每个 shard 的本地进行计算,再由 coordinate node 进行汇总。由于分片的本地计算是独立的,只能基于数据子集来进行计算,所以难免出现数据偏差。
要解决聚合准确性问题,有两个解决方案:
- 解决方案 1:当数据量不大的情况下,设置主分片数为 1,这意味着在数据全集上进行聚合。但这种方案不太现实。
- 解决方案 2:设置
shard_size
参数,将计算数据范围变大,牺牲整体性能,提高精准度。shard_size 的默认值是size * 1.5 + 10
。
Elasticsearch 将聚合分为三类:
- Metric(指标聚合):根据字段值进行统计计算
- Bucket(桶聚合):根据字段值、范围或其他条件进行分组
- Pipeline(管道聚合):对其他聚合输出的结果进行再次聚合
MongoDB 聚合
MongoDB 使用 db.collection.aggregate()
方法分 阶段 进行聚合计算。
存储
逻辑存储
RDBM | Elasticsearch | MongoDB |
---|---|---|
database | 无 | database |
table | index | collection |
row | document | document |
column | field | field |
index | 无 | index |
物理存储
MongoDB:MongoDB 的物理存储机制和 MySQL 较为相近。
- 文件级存储: 一个 MongoDB 实例可以包含多个数据库,每个数据库对应一组
.wt
文件,集合和索引分散在这些文件中。collection-*.wt
: 存储集合数据的文件。index-*.wt
: 存储索引数据的文件。WiredTiger.wt
: 一个元数据文件,跟踪所有其他文件。WiredTiger.lock
: 锁文件,标识该数据目录正在被使用。journal/
: 预写事务日志目录。
- 内存优先: 几乎所有操作都在解压后的缓存中进行,延迟写入磁盘。
- 工作方式: 它缓存的是解压后的数据和索引的页(Page)。查询首先在缓存中查找,如果找不到(cache miss),才会从磁盘读取对应的页,解压后加载到缓存中。
- 页面淘汰: 使用 LRU (Least Recently Used) 算法淘汰最久未使用的页。
- 磁盘管理
- **记录 (Record)**: 对应一个 BSON 文档及其头部信息。
- **页 (Page)**: 磁盘 IO 的基本单位。一个页包含多个记录(文档)或索引项。
- **区域 (Extent)**: 一组连续的页,分配给特定的集合或索引。
- 当集合需要更多空间时,WiredTiger 会分配一个新的 Extent 给它。
- 这种预分配策略有助于减少碎片和提高写入性能。
- 持久化
- oplog:服务层的逻辑日志,类似 MySQL 服务层的 binlog,用于主从同步,恢复数据。
- Journal:WiredTiger 存储引擎的物理日志,类似 InnoDB 的 Redo Log,都是预写日志(Write-Ahead Log, WAL)的实现。
- Checkpoint:MySQL 和 MongoDB 都会定期将内存中的修改批量、一致地写入磁盘文件,减少随机 IO。需要故障恢复时,也都是基于最后一个 Checkpoint,逐一重放操作,以恢复数据。
索引
Elasticsearch | MongoDB | |
---|---|---|
索引数据结构 | 字典树(FST) | B+树 |
索引类型 | 倒排索引 | 单字段索引,复合索引,多键索引,全文搜索,地理空间索引,哈希索引 |
索引优化 | 覆盖索引、最左匹配原则 |
事务
复制
架构对比
特性 | MySQL (以 InnoDB 集群为例) | Elasticsearch | MongoDB |
---|---|---|---|
复制单元 | 数据库 (Database) | 索引 (Index) 的 分片 | 集合 (Collection) |
核心架构模型 | **主从复制 (Master-Slave)**:主负责读写,从只负责读 | **对等节点 (Peer-to-Peer)**:无中心主节点。任何节点都可接收请求并路由 | **副本集 (Replica Set)**:主负责读写,从只负责读 |
节点角色 | Primary & Replica:角色清晰固定 | 所有节点对等:但可配置专属角色(如 Master-eligible, Data, Ingest, Coordinating) | Primary, Secondary, Arbiter:角色清晰,内置自动故障转移(通过心跳和选举) |
数据同步方式 | 基于 Binlog 的逻辑复制:主节点将写操作记录到 Binlog,从节点拉取 Binlog,并重放(Replay)SQL 语句 | 基于 Translog 的段同步:主分片处理写请求,并将操作同步到副本分片 | 基于 Oplog 的逻辑复制:主节点将写操作记录到 Oplog,从节点异步拉取并重放这些操作 |
一致性模型 | 强一致性(默认):从节点默认异步复制,但可配置为半同步(至少一个从节点确认)以实现强一致性 | 最终一致性:默认异步复制,支持通过写入 consistency 参数来来控制写操作的一致性级别;通过 preference 参数来控制读一致性 |
最终一致性(默认):读写关注(Write Concern & Read Concern)可灵活配置,从最终一致到强一致(如 {w: "majority"} ) |
自动故障转移 | 依赖外部组件:如 Group Replication 或 InnoDB Cluster 提供内置选主。传统主从依赖外部工具(MHA, Orchestrator) | 内置:由主节点管理集群状态,并在节点失败时重新分配分片 | 内置:副本集成员通过心跳检测,自动触发选举产生新的主节点 |
相同点
- 核心目标一致:三者都为实现高可用(HA) 和灾难恢复(DR) 而设计,防止单点故障导致服务中断。
- 数据冗余:都是通过将数据复制到多个节点来实现数据冗余。
- 读写分离:都支持将读请求分发到副本节点,从而提升系统的整体读吞吐量。
- 异步复制为基:默认的复制方式都是异步的,以优先保证主节点的写入性能。
- 日志驱动:依赖于一种预写日志(WAL) 的变体来驱动复制:
- MySQL → Binlog 和 Redo Log(InnoDB 引擎)
- Elasticsearch → Translog
- MongoDB → Oplog 和 Journal(WiredTiger 引擎)
- 提供一致性配置: 三者都提供了配置参数,允许用户在性能和一致性之间进行权衡。
不同点
维度 | MySQL | Elasticsearch | MongoDB | 利弊分析 |
---|---|---|---|---|
架构哲学 | 中心化、主从分明 | 去中心化、对等网络 | 中心化、内置自治 | ES 的架构无单点瓶颈,更易于水平扩展。MySQL/MongoDB 的单一主节点简化了数据一致性管理,但主节点可能成为瓶颈和单点故障(需通过选主解决)。 |
配置与管理 | 相对复杂:传统主从配置繁琐;现代组复制/InnoDB 集群简化了操作,但依然较重 | 非常简单:开箱即用。节点加入集群后自动分配数据,运维成本极低 | 非常简单:副本集配置简单,内置自动化程度高,运维友好 | ES & MongoDB 在易用性上胜出,MySQL 的复制生态更庞大但也更复杂 |
一致性控制 | 最强最灵活:支持全局事务(XA)、半同步复制,能轻松实现跨节点的强一致性 | 最弱:主要为搜索场景设计,偏向最终一致性。虽支持仲裁,但不像关系型数据库那样严格 | 灵活可调:通过读写关注可在最终一致和强一致之间平滑切换,适应多种场景 | MySQL 是金融等强一致性场景的首选。MongoDB 提供了很好的灵活性。ES 不适合强一致性事务场景。 |
扩展性 | 读扩展性好,写扩展性差:可以通过添加只读副本来扩展读能力,但写操作始终只能在主节点上进行 | 读写扩展性极佳:通过分片将数据分散,读写都可以在多个分片上并行进行,真正实现水平扩展 | 读写扩展性好:结合分片集群,可以将数据分散到多个分片(每个分片是一个副本集),实现写的水平扩展。读扩展通过副本集本身实现 | ES 和 MongoDB(分片集群) 在应对海量数据和高并发写入方面天生优于 MySQL。MySQL 的写扩展需要通过应用层分库分表,复杂度高 |
延迟与性能 | 复制延迟可能导致从节点读到的数据是旧的 | 搜索性能极高,但数据同步延迟可能比数据库更高 | 复制延迟通常较低,Oplog 操作日志效率很高 | ES 为搜索性能优化,可能牺牲部分实时性。MySQL/MongoDB 更注重数据的实时同步。 |
适用场景 | 强一致性、复杂事务的 OLTP 应用:如金融系统、电商核心交易系统 | 搜索、日志分析、OLAP:如商品检索、日志平台、大数据分析 | 灵活模型、高吞吐的 Web 应用:如内容管理系统、用户画像、实时分析 | 复制机制的设计直接反映了其目标场景。MySQL 为交易而生,ES 为搜索而生,MongoDB 为灵活扩展的现代应用而生。 |
小结
数据库 | 复制机制优势 | 复制机制劣势 | 典型使用场景 |
---|---|---|---|
MySQL | 强一致性保证,事务支持完备,生态成熟。 | 写扩展性困难,架构复杂,运维成本较高。 | 银行系统、会计软件、任何需要严格 ACID 事务的场景。 |
Elasticsearch | 真正的水平扩展,读写性能极高,容错和恢复自动化程度极高,运维简单。 | 最终一致性,不支持事务,不保证数据的实时性。 | 全文搜索引擎、日志和指标分析、应用程序搜索。 |
MongoDB | 扩展性良好(读和写),灵活性高(一致性可调),运维简单,内置自动故障转移。 | 默认最终一致性,多文档事务性能有损耗(相比 MySQL)。 | 物联网、内容管理、移动应用、实时分析。 |
如何选择:
- 如果应用核心是「交易」和「强一致性」:选择 MySQL。它的复制机制为数据安全性和一致性提供了最坚实的基础。
- 如果应用核心是「搜索」和「大数据分析」:选择 Elasticsearch。它的分布式对等架构为海量数据的查询和分析提供了无与伦比的性能和扩展性。
- 如果应用需要「灵活的数据模型」、「快速迭代」和「水平扩展」,同时需要一定的一致性控制:选择 MongoDB。它在扩展性、一致性和易用性之间取得了最佳平衡。
分区
核心概念对比
特性维度 | MySQL | Elasticsearch | MongoDB |
---|---|---|---|
分区目的 | 水平扩展写入能力,管理超大表 | 水平扩展读写能力,实现分布式计算 | 水平扩展读写能力,支持海量数据增长 |
分区/分片单元 | 表 (Table) | 分片 (Shard) 一个独立的Lucene索引,是数据移动的基本单位。 |
块 (Chunk) 一个分片键值范围的连续数据段。默认大小64MB。 |
核心架构 | 需要外部中间件或自定义逻辑 | 原生集成,对应用完全透明 | 原生集成,对应用近乎透明 |
分片键 (Shard Key) | **分区键 (Partition Key)**,在表定义时指定。 | **路由键 (Routing Key)**,默认是 _id ,可自定义。 |
**分片键 (Shard Key)**,在集合分片时指定,选择至关重要。 |
分片策略 | 范围分区 (RANGE)、哈希分区 (HASH)、KEY 分区 | 哈希分片 (默认),基于路由键的哈希值。 | 范围分片 (Ranged)、哈希分片 (Hashed)、混合分片 (Zoned) |
数据分布目标 | 将数据拆分到不同物理文件, 便于管理和局部优化。并不自动分布到不同服务器。 | 将数据均匀分布到集群所有节点,实现负载均衡和并行处理。 | 将数据均匀分布到分片集群的所有分片(Shard) 上,每个分片是一个副本集。 |
查询路由 | 应用层负责。应用必须知道如何将查询路由到正确的分区。 | 协调节点负责。应用可连接任意节点,节点自动路由查询。 | mongos 路由器负责。应用连接 mongos ,由它自动路由和聚合结果。 |
跨分片查询 | 极其困难。需要查询所有分区并手动合并结果,性能极差。 | 原生支持。搜索和聚合查询自动并行化,由协调节点汇总结果。 | 原生支持。多数查询通过 mongos 自动路由和聚合。但某些操作(如$lookup )受限。 |
再平衡 (Rebalance) | 不支持自动再平衡。需要手动导出/导入数据,操作复杂且耗时。 | 自动再平衡 节点数变化后,ES 自动在节点间迁移分片,实现负载均衡 集群中的 master 节点负责所有元数据变更和分片分配决策 |
自动再平衡。 当分片间的块数量差异超过某个阈值时触发 由配置服务器(Config Server) 管理元数据,并触发平衡器迁移数据块 |
相同点
- 核心目标一致: 三者都为了突破单机硬件(CPU、内存、磁盘)的限制,通过将数据分散到多个节点来实现水平扩展。
- 基于键值分区: 都要求选择一个或多个字段的值作为依据(分片键/分区键/路由键),通过这个值的哈希或范围来决定数据的具体位置。
- 面临类似挑战: 都需要解决跨分片查询、数据分布均衡性、事务支持(难度高)和集群管理的复杂性。
不同点
维度 | MySQL | Elasticsearch | MongoDB | 利弊分析 |
---|---|---|---|---|
易用性与集成度 | 极低 自身分区功能弱,需借助中间件(如 Vitess, ShardingSphere)或应用层自己分库分表。 | 极高 开箱即用。创建索引时指定分片数即可,集群自动管理数据分布、查询路由和再平衡。 | 高 原生支持。需部署 mongos 和配置服务器,但一旦搭建完成,对应用透明。 |
ES > MongoDB > MySQL。ES 的分布式设计是骨子里的,体验最无缝。MySQL 的分片需要大量的开发和运维投入。 |
数据均衡与再平衡 | 手动 需要 DBA 手动干预数据迁移,过程繁琐且易出错。 | 全自动 是 ES 的核心优势之一。节点增减自动触发分片重平衡,无需人工干预。 | 自动 平衡器自动在分片间迁移数据块(Chunks) 以保持均衡。 | ES 和 MongoDB 的自动再平衡是巨大优势,极大降低了运维成本。MySQL 在这方面几乎是空白的。 |
查询支持 | 极差 跨分片查询是噩梦。JOIN、ORDER BY + LIMIT 等操作几乎无法高效进行。 | 极佳 核心优势。所有搜索和聚合 API 都是为分布式设计,自动并行化,对用户无感。 | 良好 大多数 CRUD 操作都能被正确路由。但跨分片聚合、$lookup (表连接)性能较差。 |
ES 作为搜索引擎,在分布式查询上碾压其他两者。MongoDB 支持常见操作,但复杂操作受限。MySQL 的跨分片查询基本不可用。 |
分片键选择 | 影响管理,不影响性能 选择主要影响数据归档和管理(如按时间分区删除旧数据)。 | 影响性能 路由键影响数据分布的均匀性。自定义路由键可优化查询,将相关数据放在同一分片。 | 至关重要 一旦选择不可更改。直接影响性能、数据分布和扩展性。不合适的键会导致数据热点和性能瓶颈。 | MongoDB 的分片键选择是“一次性”的重大架构决策,责任最大。ES 和 MySQL 相对灵活一些。 |
事务支持 | 强(单机) 在单分区内支持完整 ACID。跨分片事务需要借助中间件,复杂度高,性能差。 | 无 不支持 ACID 事务。提供部分原子性操作(如脚本更新)。 | 支持(多文档) 4.0+ 支持跨分片的多文档事务,但性能有损耗,默认有 60 秒超时限制。 | MySQL 在单机事务上最强。MongoDB 提供了跨分片事务的能力,是一个折中方案。ES 完全不考虑事务,这是为其搜索场景做的取舍。 |
小结
数据库 | 分区机制优势 | 分区机制劣势 | 典型使用场景 |
---|---|---|---|
MySQL | 单机性能强大,分区可用于数据生命周期管理(如高效删除旧数据)。 | 分片功能极其薄弱,需要大量外部工作和自定义开发,运维复杂度最高。 | 单表数据量巨大且需要定期归档清理的场景(如日志表、事件表)。真正的水平扩展必须依赖中间件。 |
Elasticsearch | 原生分布式,易用性顶级,自动再平衡,分布式查询能力无敌。 | 不支持事务,不适合强一致性要求的 OLTP 场景。 | 搜索、日志、分析等海量数据读多写少的场景。天生为分布式查询而生。 |
MongoDB | 原生分片,自动平衡,对应用透明。支持跨分片事务(有限制)。 | 分片键选择是永久且关键的,一旦选择错误代价巨大。复杂查询支持不如 ES。 | 需要水平扩展的 OLTP 类应用,数据模型灵活,读写吞吐量要求高。如游戏、物联网、内容平台。 |
如何选择:
- 如果主要需求是「搜索」和「分析」:选择 Elasticsearch。它的分区和分布式查询是业界的黄金标准,完全无需你操心数据如何分布和查询如何执行。
- 如果需要一个「可水平扩展的通用数据库」,用于现代应用:选择 MongoDB。它的分片集群是内置的,提供了良好的扩展性和灵活性,同时还能支持跨分片事务,适合各种 Web 和移动应用。
- 如果数据量很大但主要是「单机操作」,或需要「严格的单机事务」:选择 MySQL。可以使用其分区功能来管理大表,但不要指望它原生能提供分布式数据库的能力。真正的分片需要引入复杂的中间件,这通常是最后的选择。
故障恢复
核心机制对比
特性维度 | Elasticsearch | MongoDB |
---|---|---|
故障检测核心 | Zen Discovery:自定义的节点发现和故障检测协议。主节点(Master-elected)负责监控集群状态。 | 心跳机制 (Heartbeat) 副本集成员间每2秒发送一次心跳包。 |
检测指标 | 节点存活状态、网络分区、分片分配状态 | 节点存活状态、优先级、Optime(操作时间戳) |
故障恢复 | 重新选主 & 分片重分配 1. 选举新主节点 2. 新主节点将缺失的副本分片提升为主分片,并在其他节点上创建新的副本分片 |
自动故障转移 (Failover) 1. 剩余节点发起选举 2. 基于节点优先级、Optime 等规则选举出新主节点 |
选举算法 | Bully-like 算法 基于节点ID和集群状态,更简单高效。 | Raft 协议变体 在分布式共识和效率之间取得平衡,易于理解。 |
数据一致性保证 | 最终一致性 恢复期间可能读取旧数据,同步队列可能导致数据延迟。 | 最终一致性 -> 强一致可调 默认最终一致,但通过写关注 {w: "majority"} 可保证读己之写和强一致性。 |
恢复后数据同步 | 分片同步 新的副本分片从主分片拉取数据进行完整同步。 | 初始同步 & Oplog 重放 新节点先做全量同步,然后持续重放主节点的 Oplog 以保持数据最新。 |
运维复杂度 | 低 几乎全自动化,对用户透明,运维非常简单。 | 中 配置简单,但需要理解选举规则和优先级,运维比ES复杂但比MySQL简单。 |
相同点
- 基于心跳检测: 都依赖于节点间定期发送心跳包来检测对方是否存活。
- 自动选主: 在主节点故障时,都具备自动选举新主节点的能力,无需人工干预。
- 多数派原则: 都遵循“多数派”(Quorum)原则来避免脑裂(Split-Brain)。即集群必须拥有超过半数的投票节点在线才能正常进行主节点选举和数据写入,否则整个集群会进入只读或不可用状态以保护数据。
不同点
维度 | Elasticsearch | MongoDB | 利弊分析 |
---|---|---|---|
架构哲学 | 可用性与分区容错性优先 源自CAP理论的AP系统,优先保证服务可用性和扩展性,接受最终一致性。 | 灵活可调 在CAP中偏向CP(一致性+分区容错性),但通过读写关注允许应用选择一致性级别。 | ES 为搜索性能和可用性牺牲一致性。MongoDB 试图在中间取得平衡。 |
故障检测粒度 | 分片级 & 节点级 不仅检测节点,更关注每个分片(数据副本)的状态,粒度更细。 | 节点级 关注副本集成员节点的状态。 | ES 的检测粒度最细,因为它管理的是分片而非整个节点,恢复可以更精细。 |
恢复速度 | 非常快 选举速度快,且分片恢复是并行进行的,单个分片故障不影响其他分片。 | 快 Raft选举效率高,通常在10秒内完成故障转移。数据同步基于高效的Oplog。 | ES 和 MongoDB 的恢复速度通常快于 MySQL,对业务影响更小。 |
脑裂 | 通过 minimum_master_nodes 配置防止 需要人工正确配置,配置不当有脑裂风险。7.x 后,由集群自动控制 |
通过选举规则避免 只有拥有最新数据(最高optime)的节点才可能当选为主,防止数据回退。 | ES 需要人工配置保证,MongoDB 通过规则自动保证。 |
数据冲突解决 | 最后写入获胜 基于版本号或时间戳,可能导致数据丢失。 | 基于Oplog顺序 复制是单向的(主->从),从根本上避免了写入冲突。 | MySQL 和 MongoDB 能很好地避免数据冲突,ES 不擅长处理写入冲突。 |
小结
数据库 | 故障恢复优势 | 故障恢复劣势 | 典型使用场景 |
---|---|---|---|
Elasticsearch | 恢复自动化程度最高,速度最快,分片级故障隔离,集群扩展和恢复无比流畅。 | 只有最终一致性,故障期间和恢复后可能读到旧数据,有脑裂配置风险。 | 日志、监控、搜索等允许数据短暂不一致、但要求高可用和高吞吐的AP场景。 |
MongoDB | 在一致性和可用性之间平衡良好,故障转移快(秒级),配置简单,支持可调一致性。 | 分片集群的恢复比副本集更复杂,可能会遇到性能抖动(jumbo chunks、平衡器运行)。 | 现代Web应用、物联网平台等需要高可用、灵活数据模型,并能接受最终一致或配置强一致的场景。 |
如何选择:
- 如果业务要求是「数据绝对不能错」,宁可停止服务也要保证一致性:选择 MySQL。它的强一致性模型和基于共识的故障恢复机制为此而生。
- 如果业务要求是「服务绝对不能停」,可以接受秒级的数据延迟:选择 Elasticsearch。它的分布式设计和快速恢复能力能最大程度保证服务的可用性和连续性。非常适合可观测性场景。
- 如果需要一个「兼顾可用性与一致性」的通用数据库,希望故障恢复快速且对业务透明:选择 MongoDB。它在两者之间取得了最佳实践,故障转移速度快,并且通过读写关注给了开发者灵活选择的权利,适合大多数互联网应用。