系统设计组件选型

2019年,某技术团队在设计一个新项目时,爆发了一场激烈的技术争论。

争论的焦点是:消息队列用Kafka还是RabbitMQ?

Kafka派说:Kafka吞吐量大、支持百万QPS、适合大数据场景。

RabbitMQ派说:RabbitMQ功能丰富、支持复杂路由、社区活跃。

吵了两天,最后CTO拍板:先用RabbitMQ,如果扛不住再换Kafka。

一年后,系统日活从100万增长到1000万,RabbitMQ的集群被打成筛子,性能急剧下降。

迁移到Kafka花了3个月,损失不可估量。

这是一个典型的技术选型失误案例。选型时不考虑业务增长预期,等出了问题再补救,代价往往是选型的10倍。

【架构权衡】

技术选型的核心不是"哪个技术更先进",而是"哪个技术最适合当前和未来的业务需求"。理解每个技术的适用场景和局限性,才能做出正确的选型决策。

一、数据库选型 🔴

1.1 关系型 vs NoSQL

选型决策树:

需要强事务支持(ACID)?
  是 → 关系型数据库(MySQL/PostgreSQL)
  否 → 下一步

数据结构是否固定(表结构)?
  是 → 关系型数据库
  否 → 下一步

数据量 < 1亿条?
  是 → MySQL + 分库分表
  否 → 下一步

需要海量存储 + 高并发写入?
  是 → NoSQL(HBase/ClickHouse)
  否 → MongoDB / Cassandra

1.2 MySQL vs PostgreSQL

维度MySQLPostgreSQL
事务支持完整ACID完整ACID
复杂查询一般强大(窗口函数、CTE)
JSON支持5.7+支持原生JSON类型,性能好
全文搜索有限内置支持
扩展性主从复制FDW外部表
生态成熟成熟
适用场景Web应用数据分析、复杂业务

1.3 OLAP vs OLTP

OLTP(联机事务处理):
- 场景:订单、支付、用户
- 特点:高频写入、简单查询
- 推荐:MySQL / PostgreSQL / TiDB

OLAP(联机分析处理):
- 场景:报表、统计、数据分析
- 特点:海量数据、复杂查询
- 推荐:ClickHouse / Hive / Presto / StarRocks

二、缓存选型 🔴

2.1 Redis vs Memcached

维度RedisMemcached
数据结构String/Hash/List/Set/ZSet仅String
持久化支持(RDB/AOF)不支持
集群Redis Cluster客户端分片
复制主从复制
Lua脚本支持不支持
性能略低(功能多)略高(简单)
适用场景复杂缓存、队列简单缓存

2.2 Redis Cluster vs Codis

Redis Cluster(官方方案):
- 数据自动分片(16384个槽)
- 去中心化,无Proxy
- 优点:官方支持、简单
- 缺点:多键操作受限、迁移时阻塞

Codis(豌豆荚方案):
- 中间Proxy + Redis Group
- 支持多键操作
- 优点:兼容性好、功能全
- 缺点:需要维护Proxy

2.3 选型建议

简单缓存(无需持久化):
→ Memcached

复杂缓存(需要数据结构):
→ Redis 单机/主从

高可用集群(需要分片):
→ Redis Cluster(简单场景)
→ Codis(复杂场景)

分布式锁、序列号生成、限流:
→ Redis + RedLock

三、消息队列选型 🟡

3.1 Kafka vs RocketMQ vs RabbitMQ

维度KafkaRocketMQRabbitMQ
吞吐量百万级QPS十万级QPS万级QPS
延迟低(毫秒级)低(毫秒级)低(毫秒级)
消息持久化顺序写、效率高支持支持
事务消息不支持支持不支持
延迟消息不支持(需插件)支持支持
死信队列不支持支持支持
延迟级别微秒毫秒毫秒
生态大数据生态好阿里生态通用
适用场景日志、大数据、流处理交易、订单业务消息

3.2 选型决策树

消息队列选型:

吞吐量 > 10万QPS?
  是 → Kafka / RocketMQ
  否 → 下一步

需要事务消息?
  是 → RocketMQ
  否 → 下一步

需要复杂路由(Exchange)?
  是 → RabbitMQ
  否 → 下一步

大数据场景(日志、流处理)?
  是 → Kafka
  否 → RocketMQ / RabbitMQ

3.3 实际案例

案例1:日志采集系统
→ Kafka(高吞吐、大数据生态)

案例2:订单消息
→ RocketMQ(事务消息、可靠投递)

案例3:普通异步通知
→ RabbitMQ(简单路由、功能丰富)

案例4:实时计算
→ Kafka + Flink(流处理生态)

四、搜索引擎选型 🟡

4.1 Elasticsearch vs Solr

维度ElasticsearchSolr
分布式原生支持Cloud方案复杂
实时性接近实时接近实时
搜索能力强大强大
聚合能力强大一般
生态Beats、LogstashLucene生态
易用性
适用场景日志、搜索、分析搜索

4.2 选型建议

全文搜索 + 日志分析:
→ Elasticsearch

复杂搜索场景(企业搜索):
→ Elasticsearch / Solr

简单搜索(< 1000万文档):
→ MySQL全文索引 / ES

时序数据:
→ InfluxDB / Prometheus

五、分布式存储选型 🟡

5.1 对象存储

对象存储选型:

自建(MinIO):
- 优点:兼容S3协议、运维可控
- 缺点:需要自己维护

云存储:
- 阿里OSS / 腾讯COS / AWS S3
- 优点:托管、稳定
- 缺点:成本、数据主权

选型建议:
- 小公司 → 云存储
- 大公司 → 自建 + 云存储备份

5.2 分布式文件系统

维度HDFSCephFSGlusterFS
场景大数据云存储文件共享
小文件
大文件
扩展性
复杂度

六、微服务框架选型 🟢

6.1 注册中心

注册中心选型:

Zookeeper:
- 优点:成熟、可靠
- 缺点:性能一般、需要维护

Nacos(阿里):
- 优点:配置+注册一体、轻量
- 缺点:相对年轻

Consul(HashiCorp):
- 优点:多数据中心支持、健康检查
- 缺点:国内社区相对小

选型建议:
- Spring Cloud生态 → Nacos
- 多语言 + 多数据中心 → Consul
- 简单场景 → Nacos

6.2 API网关

维度KongSpring Cloud GatewayAPISIX
性能
功能丰富一般丰富
插件生态丰富一般丰富
语言LuaJavaLua/OpenResty
适用场景企业级Spring Cloud高性能

6.3 链路追踪

链路追踪选型:

Zipkin:
- 优点:轻量、简单
- 缺点:功能有限

Jaeger(CNCF):
- 优点:支持多语言、功能全
- 缺点:UI一般

SkyWalking:
- 优点:APM能力、UI好
- 缺点:Agent侵入性

Pinpoint:
- 优点:零侵入
- 缺点:社区相对小

选型建议:
- 简单场景 → Zipkin
- 全链路APM → SkyWalking
- 多语言 → Jaeger

七、面试高频追问 🟡

7.1 为什么选MySQL不用PostgreSQL?

常见回答:
1. MySQL社区更成熟,资料更多
2. MySQL性能更好(OLTP场景)
3. 公司技术栈是MySQL

更好的回答:
1. MySQL的InnoDB引擎在OLTP场景下性能更好
2. MySQL的分库分表方案更成熟(如ShardingSphere)
3. 团队MySQL经验更丰富,运维成本低

7.2 为什么选Kafka不用RocketMQ?

常见回答:
1. Kafka吞吐量大
2. Kafka生态好

更好的回答:
1. 我们是日志采集和大数据场景,Kafka的生态无缝对接
2. Kafka的顺序写性能在日志场景下优势明显
3. 但如果未来有交易类消息需求,我们会考虑RocketMQ的事务消息

【架构权衡】

技术选型的核心是根据业务需求选择最合适的技术。不要因为"XX技术更先进"就选择它,也不要因为"我们一直用这个"就拒绝新事物。理解每个技术的适用场景,权衡利弊,才能做出正确的决策。

八、选型自检清单 🟢

技术选型自检:

1. 需求匹配度
   - [ ] 这个技术能解决我的核心问题吗?
   - [ ] 这个技术的局限性是什么?
   - [ ] 我的业务场景在技术适用范围内吗?

2. 团队能力
   - [ ] 团队有相关经验吗?
   - [ ] 学习曲线有多高?
   - [ ] 有足够的运维能力吗?

3. 成本评估
   - [ ] 开发成本
   - [ ] 运维成本
   - [ ] 基础设施成本

4. 扩展性
   - [ ] 能支撑业务增长吗?
   - [ ] 迁移成本有多高?
   - [ ] 有Plan B吗?

5. 生态与社区
   - [ ] 社区活跃吗?
   - [ ] 有足够的资料吗?
   - [ ] 有商业支持吗?

九、真实面试回放 🟡

面试官:你们项目里为什么选RocketMQ不用Kafka?

候选人(订单架构师):有三个原因:

一是事务消息。我们有下单 -> 扣库存 -> 发送消息的场景,需要RocketMQ的事务消息保证一致性。

二是我们的日均消息量是1000万,Kafka的百万QPS吞吐量对我们来说是过度设计,反而增加运维复杂度。

三是RocketMQ支持延迟消息,我们的订单超时取消需要这个功能。

面试官:如果将来日活增长到1亿呢?

候选人:1亿日活时,RocketMQ的十万QPS可能不够。我们有两种方案:

一是扩容:增加RocketMQ的Broker和Consumer。

二是分层:关键交易消息用RocketMQ,日志类消息迁移到Kafka。

但这是以后的问题。现在用RocketMQ是最合适的。

【面试官手记】

订单架构师这场面试的亮点:

  1. 有量化依据:日均1000万 vs Kafka的百万QPS

  2. 知道功能需求:事务消息、延迟消息

  3. 有扩展意识:知道将来的瓶颈和应对方案

这场面试属于P7级别,技术选型是架构师的核心能力。

技术选型没有绝对的对错,只有合适与否。记住三个要点:

  1. 需求匹配:选最合适的,而非最先进的
  2. 成本评估:考虑开发成本 + 运维成本 + 基础设施成本
  3. 扩展性:考虑未来增长,留下迁移空间

理解了这些,你就掌握了技术选型的精髓。