mobile wallpaper 1mobile wallpaper 2mobile wallpaper 3mobile wallpaper 4
4087 字
11 分钟
数据库选型与实践:RDBMS、NoSQL 与 NewSQL
2024-09-02

“用什么数据库?“——这可能是架构设计中被问得最多、也最容易答错的问题。有人习惯性地选 MySQL,有人追逐新潮的 NewSQL,有人在 NoSQL 的世界里迷了路。选型的本质不是选”最好的”数据库,而是选”最合适的”数据库——而”最合适”取决于你的数据特征、一致性需求、扩展性压力和团队能力。

本章建立一套系统的选型决策框架:从数据库分类体系出发,理解 CAP 定理的实践含义,对比 RDBMS/NoSQL/NewSQL 的本质差异,掌握多语言持久化策略,最终用决策树和真实案例完成从理论到实践的闭环。

Tip

本章是系列”路线C:数据库怎么选怎么设计”的核心章节。如果你还没读过 数据库全景数据建模与 Schema 设计,建议先建立数据模型与分类体系的认知基础,再回来做选型决策。

一、数据库分类回顾#

数据库全景 中,我们按数据模型将数据库分为关系型、文档型、键值型等类别。选型时,需要一个更实用的分类维度——按设计目标与能力特征分类。

1.1 数据库分类全景#

graph TB DB["数据库"] DB --> RDBMS["RDBMS<br/>关系型数据库<br/>MySQL / PostgreSQL / Oracle"] DB --> NOSQL["NoSQL<br/>非关系型数据库"] DB --> NEWSQL["NewSQL<br/>分布式关系型数据库"] DB --> SEARCH["搜索引擎<br/>Elasticsearch / Meilisearch"] DB --> TS["时序数据库<br/>InfluxDB / TimescaleDB"] NOSQL --> DOC["文档型<br/>MongoDB"] NOSQL --> KV["键值型<br/>Redis / DynamoDB"] NOSQL --> COL["列族型<br/>Cassandra / HBase"] NOSQL --> GRAPH["图数据库<br/>Neo4j"] NEWSQL --> TIDB["TiDB"] NEWSQL --> COCK["CockroachDB"] NEWSQL --> OCEAN["OceanBase"] style DB fill:#e8eaf6,stroke:#283593 style RDBMS fill:#c8e6c9,stroke:#2e7d32 style NOSQL fill:#fff3e0,stroke:#e65100 style NEWSQL fill:#e1bee7,stroke:#6a1b9a style SEARCH fill:#ffe0b2,stroke:#f57c00 style TS fill:#e0f2f1,stroke:#00695c

1.2 各类数据库的核心特征#

类别代表数据模型一致性扩展方式典型场景
RDBMSMySQL, PostgreSQL关系表强一致(ACID)纵向扩展事务型业务、结构化数据
文档型MongoDBJSON/BSON 文档可配置横向扩展内容管理、灵活 Schema
键值型Redis, DynamoDBKey-Value最终一致/强一致横向扩展缓存、会话、配置
列族型Cassandra, HBase列族可调一致性横向扩展高写入吞吐、时序数据
图数据库Neo4j节点+边强一致纵向为主社交关系、知识图谱
搜索引擎Elasticsearch倒排索引最终一致横向扩展全文检索、日志分析
时序数据库InfluxDB时间戳+度量最终一致横向扩展监控、IoT 传感器
NewSQLTiDB, CockroachDB关系表强一致(分布式 ACID)横向扩展大规模事务型业务
Note

以上分类并非绝对——PostgreSQL 通过 JSONB 支持文档查询,Redis 通过 RedisGraph 支持图查询,TimescaleDB 本身就是 PostgreSQL 扩展。数据库的能力边界正在模糊,但设计目标决定了一款数据库的核心取舍。

二、CAP 定理实践#

CAP 定理是分布式系统选型的理论基石。它指出:一个分布式系统最多同时满足以下三个属性中的两个。

2.1 CAP 三要素#

graph TD CAP["CAP 定理<br/>最多同时满足两个"] C["一致性<br/>Consistency<br/>所有节点看到相同数据"] A["可用性<br/>Availability<br/>每个请求得到非错误响应"] P["分区容错<br/>Partition Tolerance<br/>网络分区时系统仍运行"] CAP --- C CAP --- A CAP --- P C & A -->|"网络分区时不可行"| CA["CA 系统<br/>无分区容错<br/>单机 RDBMS"] C & P -->|"牺牲可用性"| CP["CP 系统<br/>等待多数节点<br/>ZooKeeper / etcd"] A & P -->|"牺牲一致性"| AP["AP 系统<br/>接受旧数据<br/>Cassandra / DynamoDB"] style CAP fill:#e8eaf6,stroke:#283593 style C fill:#c8e6c9,stroke:#2e7d32 style A fill:#fff3e0,stroke:#e65100 style P fill:#e1bee7,stroke:#6a1b9a style CA fill:#bbdefb,stroke:#1565c0 style CP fill:#ffcdd2,stroke:#c62828 style AP fill:#ffe0b2,stroke:#f57c00
属性含义实践中的体现
一致性(C)读操作返回最近写入的值主从复制中,读是否一定读到主库最新数据
可用性(A)每个请求都能得到响应(不保证最新)节点故障时,系统是否仍能处理请求
分区容错(P)网络分区时系统继续运行分布式系统必须面对网络分区

2.2 CP vs AP:真实案例#

在分布式环境中,网络分区是不可避免的(P 是必选项),因此实际选择退化为 CP vs AP

CP 系统 — 牺牲可用性保证一致性

# ZooKeeper:CP 系统的典型代表
# 当 Leader 不可用时,集群进入选举状态,期间拒绝服务
# 客户端请求会超时,直到新 Leader 选出
# etcd 读写流程(简化)
etcdctl put /config/key "value" # 写入需多数节点确认
etcdctl get /config/key # 读取保证线性一致性
# 如果发生网络分区,少数派分区将无法提供服务
# 多数派分区仍可正常读写

AP 系统 — 牺牲一致性保证可用性

# Cassandra:AP 系统的典型代表
# 写入时指定一致性级别
# ANY — 只需一个节点确认(最高可用性,最低一致性)
# ONE — 只需一个副本确认
# QUORUM — 需要多数副本确认
# ALL — 需要所有副本确认(最高一致性,最低可用性)
# 写入时选择 QUORUM,读取时也选择 QUORUM
# 可以保证"读到的值一定比旧值新"(W + R > N)
cqlsh> CONSISTENCY QUORUM;
cqlsh> INSERT INTO users (id, name) VALUES (1, '张三');
cqlsh> SELECT * FROM users WHERE id = 1;

2.3 BASE 理论#

CAP 定理的实践延伸是 BASE 理论——它是 AP 系统的设计哲学:

BASE 要素含义与 ACID 的关系
基本可用(Basically Available)系统在故障时仍能响应,可能降级ACID 要求完全可用或完全不可用
软状态(Soft State)系统状态可能随时间变化,即使没有新输入ACID 要求状态只因事务而变
最终一致性(Eventual Consistency)没有新更新后,所有副本最终趋同ACID 要求强一致性(线性化)
Warning

“最终一致性”中的”最终”没有时间上限——可能是毫秒级,也可能是小时级。如果你的业务要求”转账后立即能查到余额”,最终一致性是不够的。关于一致性的精确语义(线性化、因果一致性等),详见 一致性与共识

2.4 一致性级别光谱#

一致性不是非此即彼的二元选择,而是一个光谱:

一致性级别保证典型系统适用场景
线性一致性所有操作看起来像在单一时间点上原子执行etcd, ZooKeeper分布式锁、Leader 选举
顺序一致性所有节点看到相同的操作顺序,但延迟可能不同PostgreSQL 同步复制配置中心
因果一致性有因果关系的操作顺序一致,无因果关系的可乱序Cassandra LWT社交网络
前缀一致读分区消息按写入顺序读取DynamoDB Streams消息处理
最终一致性无新写入后,副本最终趋同DNS, Cassandra 默认缓存、CDN

三、RDBMS vs NoSQL vs NewSQL#

3.1 本质区别#

三类数据库的设计哲学截然不同:

  • RDBMS:以一致性为中心,牺牲扩展性换取 ACID 保证
  • NoSQL:以扩展性为中心,牺牲一致性换取水平扩展能力
  • NewSQL:试图兼得——分布式架构 + SQL 接口 + ACID 事务

3.2 全维度对比#

维度RDBMSNoSQLNewSQL
数据模型关系表(Schema-on-Write)多样(文档/键值/列族/图)关系表(兼容 SQL)
一致性强一致(ACID)可调(最终一致 → 强一致)强一致(分布式 ACID)
扩展方式纵向扩展(Scale-Up)横向扩展(Scale-Out)横向扩展(Scale-Out)
事务支持完整 ACID有限(单文档/单分区)分布式 ACID
查询能力SQL(JOIN/子查询/窗口函数)专用 API(受限查询)SQL(部分支持分布式 JOIN)
写入性能中等(B+ 树随机写)高(LSM 顺序写)中高(分布式 Raft 复制)
生态成熟度
运维复杂度低(单机)高(分布式运维)
典型代表MySQL, PostgreSQLMongoDB, Redis, CassandraTiDB, CockroachDB

3.3 NoSQL 四大子类对比#

维度文档型(MongoDB)键值型(Redis)列族型(Cassandra)图型(Neo4j)
数据模型JSON/BSON 文档Key → Value行键 + 列族 + 时间戳节点 + 边 + 属性
查询方式MongoDB Query LanguageRedis CommandsCQL(类 SQL)Cypher / Gremlin
Schema灵活(Schema-on-Read)灵活(可动态加列)图 Schema
强项灵活结构、嵌套数据极低延迟、丰富数据结构高写入吞吐、多地域多跳关系查询
弱项多对多 JOIN数据持久化、复杂查询读取延迟不稳定全图扫描、分布式困难
最佳场景CMS、用户画像缓存、排行榜、会话IoT、日志、消息社交推荐、风控

3.4 NewSQL 的承诺与现实#

NewSQL 的核心承诺是:像 NoSQL 一样水平扩展,像 RDBMS 一样保证 ACID

-- TiDB:透明的分布式 SQL
-- 应用层几乎不需要修改 SQL,TiDB 自动处理分布式查询
-- 创建表(自动按主键范围分区)
CREATE TABLE orders (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
user_id BIGINT NOT NULL,
amount DECIMAL(10,2),
status VARCHAR(20),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX idx_user (user_id)
);
-- 分布式事务:跨分区操作自动使用 2PC
BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;
COMMIT;
-- TiDB 保证分布式 ACID,应用层无需感知分片

但 NewSQL 也有代价:

优势代价
水平扩展,无需分库分表分布式事务延迟更高(2PC/Raft 复制)
兼容 SQL,迁移成本低分布式 JOIN 性能不如单机
自动分片与再平衡运维复杂度高(多组件集群)
分布式 ACID跨地域部署延迟敏感
Important

NewSQL 不是银弹。如果你的数据量在单机 RDBMS 的能力范围内(通常 TB 级以下),使用 NewSQL 反而引入了不必要的复杂度。NewSQL 的价值在于:数据量超出单机容量,且需要强一致性事务的场景。

四、多语言持久化#

4.1 为什么需要多种数据库#

真实的生产系统很少只用一种数据库。不同类型的数据有不同的访问模式、一致性要求和性能特征——用一种数据库满足所有需求,必然在某些维度上妥协。

多语言持久化(Polyglot Persistence)的思想是:为每种数据选择最合适的存储引擎

graph LR APP["应用层"] APP -->|"事务型数据<br/>强一致"| MYSQL["MySQL<br/>订单/账户/库存"] APP -->|"热点数据<br/>低延迟"| REDIS["Redis<br/>缓存/会话/排行榜"] APP -->|"搜索查询<br/>全文检索"| ES["Elasticsearch<br/>商品搜索/日志"] APP -->|"关系查询<br/>多跳遍历"| NEO["Neo4j<br/>好友推荐/风控"] MYSQL -.->|"CDC 同步"| ES MYSQL -.->|"Binlog 解析"| REDIS style APP fill:#e8eaf6,stroke:#283593 style MYSQL fill:#c8e6c9,stroke:#2e7d32 style REDIS fill:#ffe0b2,stroke:#f57c00 style ES fill:#ffcdd2,stroke:#c62828 style NEO fill:#e1bee7,stroke:#6a1b9a

4.2 经典组合:RDBMS + Redis + Elasticsearch#

这是最常见的企业级数据库组合:

组件角色数据特征一致性要求
MySQL/PostgreSQL主数据存储(Source of Truth)结构化、事务型强一致
Redis缓存层热点、临时、低延迟最终一致即可
Elasticsearch搜索引擎非结构化、全文检索最终一致即可
# 典型的读写分离模式
class ProductService:
def get_product(self, product_id: str):
# 1. 先查缓存
product = redis.get(f"product:{product_id}")
if product:
return json.loads(product)
# 2. 缓存未命中,查主库
product = mysql.query(
"SELECT * FROM products WHERE id = %s", product_id
)
if product:
# 3. 回填缓存(设置 TTL 防止数据过期)
redis.setex(
f"product:{product_id}",
300, # 5 分钟 TTL
json.dumps(product)
)
return product
def search_products(self, keyword: str):
# 搜索走 Elasticsearch,不走主库
return es.search(
index="products",
body={"query": {"match": {"name": keyword}}}
)

4.3 数据同步策略#

多数据库的核心挑战是数据一致性——主库更新后,如何保证从库/缓存/搜索引擎的数据同步?

flowchart TB subgraph 同步策略["数据同步策略"] direction TB DUAL["双写<br/>应用层同时写两个库"] CDC["CDC<br/>捕获变更数据流"] SYNC["同步调用<br/>串行写入"] end DUAL --> DUAL_PROS["延迟低<br/>一致性难保证<br/>代码侵入性强"] CDC --> CDC_PROS["解耦<br/>保证最终一致<br/>延迟较高<br/>基础设施复杂"] SYNC --> SYNC_PROS["强一致<br/>延迟高<br/>可用性降低"] style 同步策略 fill:#e8eaf6,stroke:#283593 style DUAL_PROS fill:#fff3e0,stroke:#e65100 style CDC_PROS fill:#c8e6c9,stroke:#2e7d32 style SYNC_PROS fill:#ffe0b2,stroke:#f57c00

策略一:双写(Dual Write)

# 双写:应用层同时写入 MySQL 和 Elasticsearch
def create_order(order):
# 问题:如果 ES 写入失败,MySQL 已提交,数据不一致
mysql.insert("orders", order) # 成功
es.index("orders", order) # 失败 → 数据不一致
# 改进:使用本地消息表保证最终一致性
def create_order_safe(order):
# 1. 写入主库 + 本地消息表(同一事务)
with mysql.transaction():
mysql.insert("orders", order)
mysql.insert("outbox", {
"aggregate_id": order.id,
"event_type": "order_created",
"payload": json.dumps(order),
"status": "pending"
})
# 2. 异步消费者读取 outbox 表,写入 ES
# 3. 写入成功后标记 outbox 为 completed

策略二:CDC(Change Data Capture)

# Debezium + Kafka CDC 配置示例
# Debezium 捕获 MySQL Binlog,发送到 Kafka,再写入 ES
version: "3.8"
services:
# MySQL 源库
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: root
command: --log-bin=mysql-bin --binlog-format=ROW
ports:
- "3306:3306"
# Debezium Connector
connect:
image: debezium/connect:2.5
environment:
BOOTSTRAP_SERVERS: kafka:9092
GROUP_ID: connect-cluster
ports:
- "8083:8083"
# 注册 MySQL Connector
# curl -X POST http://localhost:8083/connectors \
# -H "Content-Type: application/json" \
# -d '{
# "name": "mysql-connector",
# "config": {
# "connector.class": "io.debezium.connector.mysql.MySqlConnector",
# "database.hostname": "mysql",
# "database.port": "3306",
# "database.user": "root",
# "database.password": "root",
# "database.server.id": "1",
# "database.server.name": "mysql_prod",
# "database.include.list": "ecommerce",
# "table.include.list": "ecommerce.orders,ecommerce.products"
# }
# }'
同步策略一致性延迟复杂度适用场景
双写弱(可能不一致)最低对一致性不敏感的场景
本地消息表最终一致秒级大多数业务场景
CDC最终一致亚秒级需要解耦的复杂系统
同步双写强一致最高对一致性要求极高的场景
Warning

多语言持久化增加了系统的复杂度——数据同步、一致性保证、运维成本都会上升。不要为了”技术多样性”而引入多种数据库,只在单一数据库确实无法满足需求时才引入新的存储引擎。

五、选型决策框架#

5.1 决策树#

flowchart TD START["开始选型"] --> Q1{"数据量是否超出<br/>单机容量?"} Q1 -->|"否"| Q2{"是否需要<br/>强一致性事务?"} Q1 -->|"是"| Q3{"是否需要<br/>强一致性事务?"} Q2 -->|"是"| RDBMS["RDBMS<br/>MySQL / PostgreSQL"] Q2 -->|"否"| Q4{"数据模型特征?"} Q4 -->|"结构化"| RDBMS Q4 -->|"灵活 Schema"| DOC["文档型<br/>MongoDB"] Q4 -->|"关系密集"| GRAPH2["图数据库<br/>Neo4j"] Q4 -->|"全文检索"| ES2["搜索引擎<br/>Elasticsearch"] Q3 -->|"是"| Q5{"能否接受<br/>分布式运维复杂度?"} Q3 -->|"否"| Q6{"写入模式?"} Q5 -->|"能"| NEWSQL["NewSQL<br/>TiDB / CockroachDB"] Q5 -->|"不能"| SHARD["分库分表<br/>ShardingSphere"] Q6 -->|"高吞吐写入"| COL2["列族型<br/>Cassandra"] Q6 -->|"低延迟读取"| KV2["键值型<br/>Redis / DynamoDB"] Q6 -->|"时序数据"| TS2["时序型<br/>InfluxDB"] style START fill:#e8eaf6,stroke:#283593 style RDBMS fill:#c8e6c9,stroke:#2e7d32 style NEWSQL fill:#e1bee7,stroke:#6a1b9a style DOC fill:#fff3e0,stroke:#e65100 style KV2 fill:#ffe0b2,stroke:#f57c00 style COL2 fill:#e0f2f1,stroke:#00695c style GRAPH2 fill:#f3e5f5,stroke:#6a1b9a style ES2 fill:#ffcdd2,stroke:#c62828 style TS2 fill:#bbdefb,stroke:#1565c0 style SHARD fill:#fff9c4,stroke:#f9a825

5.2 关键评估维度#

选型不是只看数据模型,需要从多个维度综合评估:

维度关键问题权重
数据特征结构化/半结构化/非结构化?关系密集还是嵌套为主?
一致性需求能否接受最终一致?事务范围是单条还是跨实体?
读写模式读多写少?写多读少?读写均衡?是否有热点?
数据量与增长当前数据量?年增长率?是否需要水平扩展?
延迟要求P99 延迟要求?能否接受跨地域延迟?
团队能力团队对哪种数据库最熟悉?运维能力如何?
生态与工具监控、备份、迁移工具是否成熟?社区是否活跃?
成本许可证费用?硬件成本?运维人力成本?

5.3 POC 验证清单#

在正式选型前,务必进行概念验证(POC)。以下是 POC 的核心验证项:

# POC 验证脚本框架
#!/bin/bash
# 数据库选型 POC 自动化测试
# 1. 基准性能测试
echo "=== 1. 性能基准 ==="
sysbench oltp_read_write \
--db-driver=mysql \
--mysql-host=localhost \
--threads=32 \
--tables=10 \
--table-size=1000000 \
run
# 2. 故障恢复测试
echo "=== 2. 故障恢复 ==="
# 模拟节点宕机,验证 RTO
docker stop db-node-2
sleep 30 # 等待故障检测
docker start db-node-2
# 测量恢复时间
# 3. 数据一致性验证
echo "=== 3. 一致性测试 ==="
# 并发写入后,验证所有副本数据一致
for i in $(seq 1 1000); do
mysql -e "INSERT INTO test VALUES ($i, 'data_$i')"
done
# 比对主从数据
POC 验证项测试方法通过标准
写入吞吐批量写入压测满足峰值写入 QPS 的 1.5 倍
读取延迟并发读取 P99P99 < 业务 SLA
故障恢复模拟节点宕机RTO < 30s,RPO = 0
数据一致性并发写入后校验零数据丢失
扩容能力在线加节点数据再平衡期间服务不受影响
运维复杂度日常运维操作备份恢复、版本升级可自动化

六、选型案例#

6.1 电商系统#

graph TB subgraph 电商系统["电商系统数据库架构"] GW["API Gateway"] GW --> ORDER["订单服务<br/>MySQL<br/>ACID 事务"] GW --> PRODUCT["商品服务<br/>MySQL<br/>主库 + ES 搜索"] GW --> CART["购物车服务<br/>Redis<br/>低延迟读写"] GW --> RECOMMEND["推荐服务<br/>Neo4j<br/>用户-商品关系图"] GW --> LOG["日志服务<br/>Elasticsearch<br/>行为日志分析"] ORDER -.->|"CDC 同步"| LOG PRODUCT -.->|"Binlog → ES"| PRODUCT end style 电商系统 fill:#f5f5f5,stroke:#616161 style ORDER fill:#c8e6c9,stroke:#2e7d32 style PRODUCT fill:#c8e6c9,stroke:#2e7d32 style CART fill:#ffe0b2,stroke:#f57c00 style RECOMMEND fill:#e1bee7,stroke:#6a1b9a style LOG fill:#ffcdd2,stroke:#c62828
服务数据库选型理由
订单/支付MySQL强一致事务(扣库存+创建订单原子性)
商品MySQL + ESMySQL 存结构化数据,ES 提供全文检索
购物车Redis低延迟读写,临时数据可容忍丢失
推荐Neo4j用户-商品-标签的多跳关系查询
日志Elasticsearch海量日志的全文检索与聚合分析

关键设计决策

# 电商核心:库存扣减的强一致性保证
def deduct_stock(product_id: str, quantity: int) -> bool:
"""库存扣减必须在同一事务中完成"""
with mysql.transaction():
# 悲观锁:SELECT ... FOR UPDATE 防止超卖
stock = mysql.query(
"SELECT stock FROM products WHERE id = %s FOR UPDATE",
product_id
)
if stock < quantity:
return False # 库存不足
mysql.execute(
"UPDATE products SET stock = stock - %s WHERE id = %s",
quantity, product_id
)
# 创建订单记录(同一事务)
mysql.execute(
"INSERT INTO orders (product_id, quantity, status) "
"VALUES (%s, %s, 'created')",
product_id, quantity
)
return True

6.2 社交系统#

服务数据库选型理由
用户资料MySQL结构化数据,强一致性
好友关系Neo4j多跳关系查询(朋友的朋友)
动态 FeedCassandra高写入吞吐,时间线模型
消息MongoDB灵活 Schema(文本/图片/视频消息)
热点缓存Redis低延迟,排行榜/在线状态
# 社交系统:Feed 流的写入与读取
def publish_post(user_id: str, content: str):
"""发布动态:写入作者时间线 + 粉丝时间线(扇出写模式)"""
post_id = generate_id()
# 1. 写入动态表
cassandra.insert("posts", {
"id": post_id, "user_id": user_id,
"content": content, "created_at": now()
})
# 2. 写入作者自己的时间线
cassandra.insert("timeline", {
"user_id": user_id, "post_id": post_id,
"created_at": now()
})
# 3. 扇出写入粉丝时间线(异步)
followers = redis.smembers(f"followers:{user_id}")
for follower_id in followers:
cassandra.insert_async("timeline", {
"user_id": follower_id, "post_id": post_id,
"created_at": now()
})

6.3 IoT 系统#

服务数据库选型理由
设备元数据MySQL结构化,强一致(设备注册/认证)
传感器数据InfluxDB时序数据,高写入吞吐,自动降采样
设备状态Redis低延迟读写,设备在线状态
告警规则MySQL + Redis规则存储在 MySQL,实时判断在 Redis
历史分析TimescaleDB长期存储 + SQL 分析能力
-- IoT 系统:InfluxDB 时序数据查询
-- 查询最近 1 小时每 5 分钟的平均温度
SELECT mean("temperature") AS "avg_temp"
FROM "sensor_data"
WHERE time > now() - 1h
AND "device_id" = 'sensor-001'
GROUP BY time(5m)
-- 连续查询:自动降采样(保留原始数据 30 天,聚合数据永久保留)
CREATE CONTINUOUS QUERY "cq_5m_avg" ON "iot_db"
BEGIN
SELECT mean("temperature") AS "avg_temp",
mean("humidity") AS "avg_humidity"
INTO "downsampled"."sensor_5m"
FROM "sensor_data"
GROUP BY time(5m), "device_id"
END

6.4 日志系统#

服务数据库选型理由
日志采集Kafka高吞吐消息队列,解耦生产者与消费者
日志存储Elasticsearch全文检索 + 聚合分析
热日志缓存Redis最近日志的快速查询
归档存储HDFS / S3冷数据低成本存储
指标监控Prometheus + InfluxDB时序指标采集与存储
# 日志系统:ELK Stack 典型配置
# Logstash → Elasticsearch → Kibana
# Logstash 配置:解析 Nginx 访问日志
input:
file:
path: "/var/log/nginx/access.log"
start_position: "beginning"
filter:
grok:
match: { "message": "%{COMBINEDAPACHELOG}" }
date:
match: [ "timestamp", "dd/MMM/yyyy:HH:mm:ss Z" ]
output:
elasticsearch:
hosts: ["http://elasticsearch:9200"]
index: "nginx-access-%{+YYYY.MM.dd}"
# 同时写入 Redis 缓存最近日志
redis:
host: "redis"
data_type: "list"
key: "logstash:recent"

6.5 四类系统对比总结#

维度电商社交IoT日志
核心数据库MySQLCassandraInfluxDBElasticsearch
一致性要求强一致最终一致最终一致最终一致
写入模式中等 QPS高吞吐极高吞吐极高吞吐
读取模式读多写少读多写多写多读少写多读少
数据库数量3-4 种4-5 种3-4 种4-5 种
同步方式CDC + 双写异步扇出Kafka 流Kafka 流

七、总结#

7.1 选型核心原则#

  1. 数据特征决定数据模型——结构化用关系表,灵活用文档,关系密集用图,时序用时间线
  2. 一致性需求决定架构模式——强一致用 RDBMS/NewSQL,最终一致用 NoSQL
  3. 数据量决定扩展策略——单机能撑住就不上分布式,分布式是最后手段
  4. 团队能力决定技术边界——选团队 hold 得住的,而不是”最先进”的
  5. 多语言持久化是手段不是目的——只在单一数据库无法满足时才引入新存储

7.2 选型反模式#

反模式表现正确做法
简历驱动开发为了学新技术而选新数据库根据业务需求选型
单一数据库打天下所有数据都塞进 MySQL不同数据用不同存储
过度工程日活千人的应用上 TiDB 集群数据量在单机范围内就用单机
忽视运维成本只看功能不看运维复杂度POC 阶段就评估运维难度
追逐一致性所有数据都要求强一致区分核心数据与非核心数据

7.3 知识串联#

数据库选型不是孤立的决策,它与系列中多个章节紧密关联:

本章概念关联章节关联内容
数据模型与分类数据库全景数据模型决定数据库类型
Schema 设计数据建模与 Schema 设计Schema 灵活度影响选型
一致性级别一致性与共识一致性需求决定 CP/AP 选择
分布式事务一致性与共识NewSQL 的分布式 ACID 实现
数据同步数据复制多语言持久化的数据同步基础
扩展策略数据分区水平扩展的分区策略
Tip

选型没有标准答案,但有系统方法。掌握本章的决策框架后,面对”用什么数据库”的问题,你不再凭直觉回答,而是能从数据特征、一致性需求、扩展压力、团队能力四个维度给出有理有据的方案。下一章 MySQL 深入 将带你走进 RDBMS 的内部实现——理解选型背后的工程细节。

支持与分享

如果这篇文章对你有帮助,欢迎支持作者或分享给更多人

数据库选型与实践:RDBMS、NoSQL 与 NewSQL
https://blog.souloss.com/posts/database/database-selection-and-practice/
作者
Souloss
发布于
2024-09-02
许可协议
CC BY-NC-SA 4.0

部分信息可能已经过时