架构设计衡量标准
1. 高内聚低耦合 (High Cohesion, Low Coupling)
原理:
高内聚: 指一个模块(类、组件、服务、子系统)内部的各个元素(函数、数据)彼此紧密相关,共同完成一个单一的、明确的职责。模块内部联系紧密,对外提供清晰、有限的接口。就像一本书的章节,每章都聚焦一个主题。
低耦合: 指不同模块之间的依赖关系尽可能少、尽可能弱、尽可能简单清晰。一个模块的变化,尽可能少地或不影响其他模块。模块之间通过定义良好的接口(契约)进行交互,而不是深入到对方的内部实现细节。就像积木,通过标准接口连接,而不是粘在一起。
为什么重要:
可维护性: 修改一个内聚模块内部,影响范围小;修改一个模块,对低耦合的其他模块影响小。更容易理解、修改、测试、重构。
可复用性: 高内聚、职责单一的模块更容易被复用到其他场景。
可测试性: 模块独立性强,更容易进行单元测试和集成测试。
可扩展性: 添加新功能或修改现有功能时,影响范围可控,更容易实现。
降低复杂度: 系统被分解为相对独立的单元,降低了整体认知复杂度。
建议:
遵循单一职责原则(SRP): 确保每个类/模块只做一件事,并把它做好。
定义清晰的接口/契约: 模块间通过明确定义的接口(API、消息格式、事件)进行交互,隐藏内部实现。
依赖倒置原则(DIP): 高层模块不应该依赖低层模块,两者都应该依赖于抽象(接口或抽象类)。使用依赖注入(DI)。
接口隔离原则(ISP): 客户端不应该被迫依赖它不使用的接口。尽量设计小而专一的接口,而不是大而全的接口。
迪米特法则/最少知识原则(LoD): 一个对象应该对其他对象有最少的了解。只与直接的朋友通信。避免链式调用穿透多个层级(如
a.getB().getC().doSomething()
)。模块化/服务化: 将系统划分为界限上下文清晰的模块或微服务,每个模块/服务高度自治。
使用消息队列/事件驱动: 解耦生产者和消费者,实现异步通信。
避免全局变量和单例滥用: 它们会隐式地增加耦合度。
2. 高性能实现方案三板斧 - 缓存、异步、分布式
原理:
缓存 (Caching):
原理: 将计算结果或数据副本存储在访问速度更快的介质(如内存)中,避免重复执行昂贵的计算(如复杂查询)或访问慢速数据源(如数据库、远程API)。核心是利用空间换时间和局部性原理(数据访问在时间和空间上往往集中)。
目标: 减少延迟、提高吞吐量、降低后端压力。
异步 (Asynchrony):
原理: 将非实时必需或耗时的操作(如发送邮件、处理图片、写入日志、调用外部服务)从主请求处理路径中剥离出来,放入队列或后台线程处理。主线程快速响应用户,提升响应速度。核心是时间换资源利用率和解耦。
目标: 提高响应速度、系统吞吐量、资源利用率;削峰填谷。
分布式 (Distribution):
原理: 将单体应用或单一数据库拆分成多个可以部署在不同物理机器(节点)上的独立部分(服务、数据库分片),利用多台机器的计算、存储、网络资源并行处理任务。核心是并行处理和水平扩展。
目标: 突破单机性能瓶颈(CPU、内存、IO、网络),处理海量数据/请求,提高系统容量和可用性。
为什么重要: 它们是解决性能瓶颈最常用、最有效、经过实践检验的核心手段。能显著提升用户体验(响应快)和系统处理能力(支持更多用户/数据)。
建议:
缓存:
分层缓存: 结合浏览器缓存、CDN、反向代理缓存、应用本地缓存、分布式缓存(如Redis, Memcached)。
缓存策略: 理解并合理选择缓存失效/更新策略(TTL、主动失效、写穿透/写回)。
缓存穿透: 解决查询不存在数据的攻击(布隆过滤器、缓存空值)。
缓存击穿: 解决热点Key突然失效导致大量请求压到后端(互斥锁、永不过期+异步更新)。
缓存雪崩: 解决大量Key同时失效(随机TTL、高可用缓存集群)。
一致性考虑: 明确缓存数据一致性要求(强一致、最终一致?),设计更新机制。
异步:
消息队列: 核心工具(如Kafka, RabbitMQ, RocketMQ, Pulsar)。解耦生产者消费者,缓冲流量,保证消息可靠传递。
后台任务/线程池: 处理非实时任务。
事件驱动架构: 基于事件通知进行解耦和异步处理。
流处理: 处理连续的数据流(如Flink, Spark Streaming)。
超时与重试: 设计合理的超时和重试机制处理异步调用失败。
补偿事务: 处理异步操作失败后的数据一致性(如Saga模式)。
分布式:
服务拆分(微服务/SOA): 按业务领域拆分服务,独立部署扩展。
读写分离: 数据库主库写,多个从库读。
分库分表: 水平拆分数据库(按范围、哈希、一致性哈希),解决单库存储和性能瓶颈。引入分布式数据库(如TiDB, CockroachDB, Cassandra)。
分布式缓存: 如Redis Cluster。
负载均衡: 将请求分发到多个服务实例(如Nginx, HAProxy, 云LB)。
分布式计算: 处理海量数据(如Hadoop, Spark)。
复杂性问题: 认识到分布式带来的挑战(网络延迟/分区、数据一致性、分布式事务、服务发现、配置管理、监控调试),并采用相应解决方案(如CAP权衡、BASE理论、分布式锁、Raft/Paxos共识算法)。
3. 扩展性 (Scalability) - 代码扩展/应用扩展/数据扩展
原理:
扩展性 (Scalability): 指系统能够通过增加资源(通常是廉价的、标准化的资源,如服务器)来平滑地提升其处理能力(如吞吐量、用户数、数据量)的能力。分为:
垂直扩展 (Scale Up): 升级单台服务器的硬件(更强的CPU、更多内存、更大磁盘、更快网卡)。上限明显,成本高昂。
水平扩展 (Scale Out): 增加更多相同或相似的服务器节点,通过负载均衡将请求分发到这些节点上处理。理论上无限扩展,成本线性增长,是主流方式。
代码扩展性: 指代码设计本身易于修改、添加新功能、适应变化的能力。是高内聚低耦合的直接结果。
应用扩展性: 指应用服务(通常是运行在服务器上的进程)能够方便地进行水平扩展的能力。通常要求应用是无状态的(或状态外部化)。
数据扩展性: 指数据存储系统(数据库、文件存储等)能够处理不断增长的数据量和访问量的能力。通常通过分片、读写分离、使用分布式数据库等技术实现。
为什么重要: 业务是发展的,流量和数据量是增长的。良好的扩展性确保系统能够支撑业务增长,避免推倒重来。
建议:
代码扩展性:
遵循SOLID原则: 尤其是开闭原则(OCP - 对扩展开放,对修改关闭)。
面向接口编程: 依赖抽象。
模块化设计: 清晰的边界。
使用设计模式: 策略模式、工厂模式、模板方法等提高灵活性。
配置化: 将易变部分提取到配置文件中。
应用扩展性:
无状态设计: 会话状态存储在外部(如Redis),应用本身无状态,任何实例都能处理任何请求。
容器化: 使用Docker打包应用,便于部署和复制。
编排调度: 使用Kubernetes等平台自动化部署、伸缩、管理容器。
自动化部署: CI/CD流水线实现快速、可靠的应用部署和回滚。
服务发现与注册: 动态管理服务实例(如Consul, Nacos, Eureka, Kubernetes Service)。
配置中心: 统一管理应用配置(如Spring Cloud Config, Apollo, Nacos)。
数据扩展性:
读写分离: 缓解读压力。
分库分表: 解决单库容量和性能瓶颈。难点在分片策略(均匀性、避免热点)、跨分片查询/事务、扩容(数据迁移)。
选择合适的分布式数据库: 根据业务需求(强一致?最终一致?OLTP? OLAP?)选择NewSQL(TiDB, CockroachDB)或NoSQL(Cassandra, MongoDB分片集群, HBase)。
数据分区: 在文件存储、消息队列等系统中也广泛应用分区概念提升并行能力。
冷热数据分离/归档: 将访问频率低的历史数据迁移到成本更低的存储介质。
缓存: 缓解数据库压力(见高性能部分)。
4. 高可用 (High Availability - HA)
原理:
高可用性: 指系统能够提供持续可用的服务的能力,通常用可用性百分比(如99.9% - “三个九”, 99.99% - “四个九”)或年度停机时间来衡量。核心是冗余和故障自动转移。
关键概念:
冗余 (Redundancy): 消除单点故障(SPOF)。关键组件(服务器、网络、磁盘、电源、数据中心)都有备份。
故障检测 (Failure Detection): 快速发现故障(如心跳检测、健康检查)。
故障转移 (Failover): 当主节点故障时,能自动或半自动地将流量/服务切换到备用节点。
恢复 (Recovery): 故障节点修复后能重新加入系统。
为什么重要: 系统宕机意味着业务中断、用户流失、收入损失、声誉受损。高可用是核心业务系统的必备要求。
建议:
消除单点故障(SPOF):
应用层: 无状态设计 + 多实例部署 + 负载均衡(LB自身也需HA)。
数据层:
主从复制: 主库故障,从库提升为主(手动或自动)。
多副本/集群: 分布式数据库(如Redis Sentinel/Cluster, MongoDB Replica Set, MySQL Group Replication/InnoDB Cluster, PG流复制+Patroni, 分布式NewSQL/NoSQL)。
共享存储(谨慎): 如SAN,但存储本身可能成为SPOF。
网络层: 多网卡绑定、多交换机、多ISP线路。
基础设施层: UPS、备用发电机、异地多机房/可用区部署。
负载均衡(HA): 使用高可用的负载均衡器(如Keepalived+VIP for Nginx/HAProxy, 云厂商的托管LB)。
自动故障转移:
应用层: LB健康检查自动剔除故障节点。
数据层: 数据库集群的自动选主机制(如Raft, Paxos)。
熔断与降级:
熔断 (Circuit Breaker): 当依赖的服务故障达到阈值,快速失败(直接返回错误或默认值),避免资源耗尽和级联故障(如Hystrix, Sentinel, Resilience4j)。
降级 (Degradation): 在系统压力过大或部分故障时,暂时关闭非核心功能或提供简化版服务,保障核心功能的可用性。
限流 (Rate Limiting): 控制请求速率,防止突发流量压垮系统(如令牌桶、漏桶算法)。
异地多活 (Multi-Site Active/Active): 在多个地理位置的机房部署独立可用的系统单元,任何一个机房故障,其他机房能接管全部或部分流量。这是最高级别的可用性方案,但复杂度也最高(涉及数据同步延迟、一致性、流量调度)。
备份与恢复: 定期备份数据并验证可恢复性。制定详细的灾难恢复计划(DRP)并演练。
监控与告警: 全面的监控(基础设施、应用性能、业务指标)和及时的告警是发现和快速响应故障的前提。
混沌工程: 主动在生产环境中注入故障(如关闭节点、增加延迟、模拟网络分区),验证系统的容错能力,提前发现弱点。