架构规范
基本原则
制定完善和遵守开发过程的基本原则,可以减少软件的安全风险,提高代码可读性,可维护性,可扩展性,可复用性,可测试性等。可以帮助开发人员提高开发效率,降低开发成本。
| 原则名称 | 推荐级别 | 核心要点 | 适用场景 | 实施方式 |
|---|---|---|---|---|
| 最小化原则 | 强烈推荐 | 接口参数简洁、必要参数、封装对象传输、结果集仅包含必要数据 | 接口设计、数据查询 | 避免冗余字段、用户信息从 token 获取、使用 DTO 对象、SELECT 具体字段 |
| 最快收敛原则 | 强烈推荐 | 聚合数据传输、批量操作、优化 SQL 查询、减少数据传输次数 | 批量操作、数据查询 | 批量删除只传一组 id、预先准备数据一次调用、优化 join 条件 |
| 互不信任原则 | 强烈推荐 | 参数校验、权限校验、白名单模式、敏感操作日志 | 安全设计、接口校验 | 使用 @Valid 注解、Spring Security、RBAC 权限模型、Origin 白名单 |
| 金钱计算原则 | 强制执行 | 单位精确到分、BigDecimal.ROUND_HALF_UP | 金融计算、金额处理 | 前端:toFixed(n);后端:BigDecimal.setScale(2, BigDecimal.ROUND_HALF_UP) |
最小化原则
原则:最小化原则-强烈推荐
说明:为系统的参数更简洁,更方便维护,制定以下推荐条例:
| 规范点 | 说明 |
|---|---|
| 参数简洁 | 接口定义,参数需要尽可能的简洁。所有的参数都是必需参数 |
| 后端获取 | 能后端获取的参数,不要让前端传 |
| 对象封装 | 接口参数定义,尽可能封装对象传输,不要包含不必要的参数 |
| 结果精简 | 自定义 SQL 查询,结果集将只包含必要的数据 |
| 返回精简 | 接口参数返回,所有参数都需要是必要且不多余的 |
最快收敛原则
原则:最快收敛原则-强烈推荐
说明:为提高系统的性能,偷换数学的概念,结合编码学,创建了最快收敛原则。
原因:
| 场景 | 优化策略 | 效果 |
|---|---|---|
| 前端聚合 | 批量删除,只应传一组 id,调一次接口 | 减少 HTTP 请求次数 |
| 服务调用 | 如果需要调用其他服务模块,如果其他服务批量操作,应预先准备数据,进行一次调用 | 减少服务间通信 |
| 数据库操作 | 对数据库进行多次类似的操作,如果有批量操作接口,应预先准备数据,只对数据库进行一次操作 | 减少数据库连接开销 |
| SQL 查询 | SQL 查询进行数据关联时,应找对 join 条件,使得进行关联的数据以最快的速度减少 | 提升查询性能 |
| 数据返回 | 数据返回时,尽可能聚合参数,尽可能减少数据的传输次数 | 降低网络传输 |
结论:如果可以做到以上的快速收敛,可以不考虑 Java 代码对数据的处理量。原因是:以上的调用过程都要经过 HTTP 请求,或者磁盘的读写。而 Java 的运行,会全部在内存中运行。效率不是同一个数量级。
互不信任原则
原则:互不信任原则-强烈推荐
说明:在程序运行上下游的整个链路中,每个点都是不能保证绝对可靠的,任何一个点都可能随时发生故障或者不可预知的行为,包括机器网络、服务本身、依赖环境、输入和请求等,因此要处处设防。
| 防护措施 | 说明 |
|---|---|
| 参数严格校验 | 所有输入参数必须进行严格校验 |
| 权限严格校验 | 用户权限必须进行严格校验 |
| 数据返回严格筛选 | 返回数据必须进行严格筛选 |
| 权限最小化 | 仅授予必要的最小权限 |
| 白名单模式 | 采用白名单模式进行访问控制 |
| 健全的敏感操作日志体系 | 建立完善的敏感操作日志体系 |
| 其他防护 | 其他任何可能的疏忽,都提前防备 |
金钱的计算原则
原则:单位精确到分。BigDecimal.ROUND_HALF_UP 原则-强制执行
| 层级 | 处理方式 | 代码示例 |
|---|---|---|
| 前端 | 计算后的值,必需使用 toFixed(n) 函数进行处理。也可以使用:Math.round(parseFloat(price*100 * quantity))/100 | price.toFixed(2) 或 Math.round(parseFloat(price*100 * quantity))/100 |
| 后端 | 强制使用 BigDecimal | bigDecimal.setScale(2, BigDecimal.ROUND_HALF_UP) |
架构原则
设计原则
| 原则名称 | 核心思想 | 实践方法 | 收益 |
|---|---|---|---|
| 单一职责原则 | 每个模块/类只负责一个功能 | 职责分离、模块化 | 高内聚、低耦合 |
| 开闭原则 | 对扩展开放,对修改关闭 | 通过接口和抽象类实现扩展 | 易于扩展、稳定性好 |
| 依赖倒置原则 | 依赖抽象而非具体实现 | 面向接口编程、依赖注入 | 解耦、可测试 |
| 接口隔离原则 | 接口应该小而专 | 拆分大接口为多个小接口 | 灵活、易维护 |
| 迪米特法则 | 只与直接朋友通信 | 减少类之间的依赖 | 降低耦合度 |
分层架构
| 层级 | 职责 | 技术实现 | 典型组件 |
|---|---|---|---|
| 表现层 | 处理用户请求和响应 | Spring MVC | Controller、Interceptor |
| 业务逻辑层 | 实现核心业务逻辑 | Spring Service | Service 接口与实现 |
| 数据访问层 | 与数据库交互 | MyBatis/JPA | Mapper、Repository |
| 实体层 | 数据模型定义 | POJO/DTO | Entity、DTO、VO |
模块划分
| 类别 | 原则/方式 | 说明 | 示例 |
|---|---|---|---|
| 模块设计 | 按业务域划分 | 根据业务领域进行模块划分 | 用户中心、订单中心、商品中心 |
| 低耦合高内聚 | 模块内部紧密相关,模块之间松散耦合 | 用户模块不直接依赖订单模块 | |
| 明确边界 | 定义清晰的模块边界和接口 | 通过 API 进行模块间通信 | |
| 模块通信 | 同步调用 | 强一致性场景、需要立即响应 | 实时性好、简单直接,但耦合度高 |
| 异步消息 | 最终一致性场景、解耦需求 | 解耦、高可用,但有延迟 | |
| 事件驱动 | 多个模块需要响应同一事件 | 松耦合、扩展性好 | |
| 共享数据库 | 简单场景、同一系统内 | 简单、无需额外组件,但耦合度高 |
服务架构
| 类别 | 原则/组件 | 说明 | 实现方案 |
|---|---|---|---|
| 微服务设计 | 服务边界清晰 | 明确服务职责边界 | 通过领域驱动设计确定边界 |
| 独立部署 | 每个服务独立打包部署 | 使用 Docker 容器化 | |
| API 通信 | 服务间通过 API 进行通信 | RESTful API 或 gRPC | |
| 数据独立 | 每个服务独立管理数据库 | 避免跨服务数据耦合 | |
| 自治团队 | 每个服务由独立团队负责 | 全栈团队模式 | |
| 服务注册与发现 | 服务注册中心 | 服务注册和发现 | Nacos、Eureka、Consul |
| 服务注册 | 服务启动时注册到中心 | 自动注册机制 | |
| 服务发现 | 客户端发现可用服务 | 服务列表获取 | |
| 负载均衡 | 分发请求到多个服务实例 | Ribbon、Nacos 负载均衡 |
数据架构
| 类别 | 存储类型/一致性级别 | 适用场景 | 推荐技术/实现方式 | 特点/优缺点 |
|---|---|---|---|---|
| 数据存储 | 关系型数据库 | 结构化数据、事务性场景 | MySQL、PostgreSQL | 强一致性、复杂查询 |
| NoSQL 数据库 | 非结构化数据、高并发读写 | Redis、MongoDB | 高可用、高性能 | |
| 缓存 | 热点数据、读多写少场景 | Redis、Memcached | 低延迟、高吞吐 | |
| 消息队列 | 异步处理、解耦场景 | Kafka、RabbitMQ | 削峰填谷、解耦 | |
| 数据一致性 | 强一致性 | 金融交易、订单支付 | 分布式事务(XA)、两阶段提交 | 数据一致、性能开销大 |
| 最终一致性 | 日志同步、数据统计 | 消息队列、异步任务 | 性能好、存在延迟 | |
| 弱一致性 | 实时性要求低的场景 | 定期同步、缓存更新 | 实现简单、数据可能过期 |
高可用设计
| 类别 | 策略/机制 | 说明 | 实现方式/适用场景 | 特点 |
|---|---|---|---|---|
| 故障容错 | 熔断器模式 | 防止级联故障 | Hystrix、Resilience4j | 服务调用熔断 |
| 服务降级 | 故障时提供降级服务 | 开关控制、降级逻辑 | 核心功能保障 | |
| 兜底方案 | 熔断后的备选响应 | 默认数据、缓存数据 | 提升用户体验 | |
| 重试机制 | 失败后自动重试 | 重试次数、间隔配置 | 网络抖动场景 | |
| 负载均衡 | 轮询 | 按顺序分发请求 | 无状态服务 | 简单、均衡 |
| 加权轮询 | 根据权重分发请求 | 服务器性能不均 | 按能力分配 | |
| 最少连接 | 分发到连接数最少的服务器 | 长连接场景 | 动态调整 | |
| IP 哈希 | 根据客户端 IP 分发 | 需要会话保持 | 会话稳定 | |
| 健康检查 | 存活检查 | 服务是否运行 | TCP 连接、HTTP 请求 | 移除不健康节点 |
| 就绪检查 | 服务是否就绪处理请求 | 数据库连接、依赖服务 | 延迟加入负载均衡 | |
| 深度检查 | 业务功能是否正常 | 业务接口测试 | 全面健康评估 |
最佳实践
| 实践项 | 说明 | 实施频率 | 产出物 |
|---|---|---|---|
| 架构图绘制 | 绘制系统架构图和流程图 | 需求阶段 | 架构文档、流程图 |
| 文档化决策 | 记录架构决策及其理由 | 决策时 | 架构决策记录 |
| 架构评审 | 定期进行架构评审 | 季度/重大变更 | 评审报告 |
| 可扩展性考虑 | 设计时考虑未来扩展 | 设计阶段 | 可扩展架构设计 |
| 可维护性考虑 | 代码可读性、可测试性 | 开发阶段 | 代码规范文档 |
架构设计检查清单
| 检查项 | 检查内容 | 状态 |
|---|---|---|
| 边界清晰 | 各模块职责是否清晰,边界是否明确 | |
| 依赖合理 | 模块间依赖是否合理,是否存在循环依赖 | |
| 接口稳定 | 对外接口是否稳定,是否有版本控制 | |
| 高可用 | 是否考虑了故障容错、负载均衡、健康检查 | |
| 可扩展 | 是否考虑了未来业务扩展需求 | |
| 安全性 | 是否考虑了安全防护措施 | |
| 可监控 | 是否有完善的监控、日志、告警体系 | |
| 可测试 | 架构是否支持单元测试、集成测试 |