案例分析题知识点总结。
1 结构化分析(数据流图)
1.1 数据流图和流程图的含义及其区别
数据流图(Data Flow Diagram,DFD):作为一种图形化工具,用来说明业务处理过程、系统边界内所包含的功能和系统中的数据流。
流程图(Flowchart):以图形化的方式展示应用程序从数据输入开始到获得输出为止的逻辑过程,描述处理过程的控制流。
两者的主要区别:
- 数据流图中的处理过程可并行;流程图在某个时间点只能处于一个处理过程。
- 数据流图展现系统的数据流;流程图展现系统的控制流。
- 数据流图展现全局的处理过程,过程之间遵循不同的计时标准;流程图中处理过程遵循一致的计时标准。
- 数据流图适用于系统分析中的逻辑建模阶段;流程图适用于系统设计中的物理建模阶段。
1.2 数据流图中所包含的基本元素及其作用
4种组成元素:
- 数据流:数据在系统内传播的路径,因此由一组成分固定的数据组成。
- 加工(处理):对数据进行处理的单元,它接收一定的数据输入,对其进行处理,并产生输出。
- 数据存储:表示信息的静态存储,可以是文件、文件的一部分、数据库的元素等。
- 外部实体:代表系统之外的实体,可以是人、物或其他软件系统。
图元如下:
1.3 数据流图的平衡原则
两条平衡原则:
- 子图与父图之间的平衡:任何一张DFD子图边界上的输入/输出数据流必须与其父图对应加工的输入/输出数据流保持一致。
- 如果父图中某个加工的一条数据流对应于子图中的几条数据流,而子图中组成这些数据流的数据项全体正好等于父图中的这条数据流,那么它们仍然是平衡的。
- 子图内部:加工的输入和输出需要平衡。
- 常见的3种错误:
- 黑洞:一个加工只有输入数据流而无输出数据流。
- 奇迹:一个加工只有输出数据流而无输入数据流。
- 灰洞:若一个加工的输入数据流无法通过加工产生输出流。
- 常见的3种错误:
1.4 数据流图、数据字典在需求分析和设计阶段的作用
数据流图 | 数据字典 | |
---|---|---|
分析阶段 | 建立系统的功能模型,从而完成需求分析 | 主要描述数据流图中各个成分的具体含义,以及给出详细的定义和说明 |
设计阶段 | 为模块划分于模块之间的接口设计提供依据 | 为系统设计提供详细的数据定义和说明,有助于保证系统的数据一致性和完整性 |
2 面向对象分析(UML图)
面向对象设计原则:单一职责、开闭原则、里氏替换原则、依赖倒置原则、接口分离原则
2.1 状态图和活动图的含义及其区别
状态图(State Diagram):描述一个对象在其生存期间的动态行为,表现一个对象所经历的状态序列、引起状态转移的事件(Event),以及因状态转移而伴随的动作(Action)。
活动图(Activity Diagram):描述系统的工作流程和并发行为。活动图其实可看作状态图的特殊形式,活动图中一个活动结束后将立即进入下一个活动(在状态图中状态的转移可能需要事件的触发)。
两者的主要区别:
- 状态图侧重于描述行为的结果,而活动图侧重描述行为的动作。
- 活动图可描述并发行为,而状态图不能。
2.2 活动图和流程图的区别
两者的主要区别:
- 活动图描述的是对象活动的顺序关系所遵循的规则,着重表现系统的行为,而非处理过程;而流程图着重描述处理过程。
- 活动图可以支持并发进程,而流程图一般都限于顺序进程。
- 活动图是面向对象的,而流程图是面向过程的。
2.3 用例之间的关系
用例图(Use Case Diagram)中,用例之间的3种关系:
- 包含(Include):当可以从两个或多个用例中提取公共行为时,可以使用包含关系来表示。
- 扩展(Extend):如果一个用例混合了两种或两种以上不同场景,即根据情况可能发生多种分支,则可以将这个用例分为一个基本用例和一个或多个扩展用例。
- 泛化(Generalization):当多个用例共同拥有一个类似的结构和行为的时候,可以将它们的共性抽象成父用例,其他的用例作为泛化关系中的子用例。
基础用例和抽象用例的区别:
- 基础用例是实实在在与用户需求由对应关系的用例,是从用户需求获取的渠道得到。
- 抽象用例是从基础用例中抽取的用例的公共部分,为了避免重复工作,优化结构而提出的用例。
2.4 类之间的关系
类图(Class Diagram)中,类之间的6种关系简述如下:
- 泛化(Generalization):特殊/一般关系(
特殊 --|> 抽象
)。 - 实现(Realization):接口与类之间的关系(
接口 ..|> 实现类
)。 - 依赖(Dependency):一个事物发生变化影响另一个事物(
类A ..> 类B(被依赖)
)。 - 关联(Association):描述了一组链,链是对象之间的连接(
类A -- 类B
)。 - 聚合(Aggregation):整体与部分生命周期不同,部分可以独立存在(
部分类 --o 整体类
)。 - 组合(Composition):整体与部分生命周期相同,部分不能独立存在(
部分类 --* 整体类
)。
实体和类的区别:实体用于数据建模,类用于面向对象建模;实体只有属性,类有属性和操作。
2.5 对象模型、动态模型、功能模型
系统设计的三种模型:
- 对象模型:用于描述系统数据结构。
- 动态模型:用于描述系统控制结构。
- 功能模型:用于描述系统功能。
三者的关联关系:
- 这3种模型都涉及数据、控制和操作等共同概念,但侧重点不同,从不同侧面反映了系统的实质性内容,综合起来全面地反映了对目标系统的需求。
- 功能模型指明了系统应该“做什么”;动态模型明确规定了什么时候做;对象模型则定义了做事情的实体(“对谁做”)。
2.6 设计类的三种分类及对应的职责
- 实体类:映射需求中的每个实体,保存需要存储在永久存储体中的信息,例如用户、商品等。
- 控制类:用于控制用例工作,对一个或几个用例所特有的控制行为进行建模,例如结算、备货等。
- 边界类:用于封装在用例内外流动的信息或数据流,例如浏览器、购物车等。
3 系统架构设计
3.1 架构相关基本概念
软件架构风格是描述特定软件系统组织方式的惯用模式。
- 组织方式描述了系统的组成构件和这些构件的组织方式
- 惯用模式则反映众多系统共有的结构和语义
风险点、敏感点、权衡点的含义:
- 风险点:架构设计中潜在的、存在问题的架构决策所带来的隐患。(架构风险/系统风险)
- 敏感点:为了实现某种特定的质量属性,一个或多个构件所具有的特性。
- 权衡点:影响多个质量属性的特性,是多个质量属性的敏感点。
系统架构设计中的非功能性需求(考频:1次):
- 操作性需求(Operational Requirements):系统完成任务所需的操作环境要求及如何满足系统将来可能的需求变更的要求。
- 性能需求(Performance Requirements):针对系统性能要求的指标。常见的包括响应时间、吞吐率。
- 安全性需求(Security Requirements):防止系统崩溃和保证数据安全所需要采取的保护措施或预防措施。
- 文化需求(Cultural Requirements):使用本系统的不同用户群体对系统提出的特有要求。
3.2 五大架构风格对比
- 数据流风格(Data Flow):批处理(Batch Sequential)、管道-过滤器(Pipes and Filters)
- 调用/返回风格(Call/Return):主程序/子程序(Main Program and Subroutine)、面向对象(Object-oriented)、分层架构(Layered System)
- 独立构件风格(Independent Components):进程通信(Communicating Processes)、事件驱动系统(隐式调用,Event System)
- 虚拟机风格(Virtual Machine):解释器(interpreter)、规则系统(Rule-based System)
- 以数据为中心(仓库风格,Data-centered):数据库系统(Database System)、黑板系统(Blackboard System)、超文本系统(Hypertext System)
其他:
- 闭环控制架构(过程控制):经典应用有空调温控,定速巡航等
常见风格特点、优缺点对比:
架构风格 | 主要特点 | 优点 | 缺点 | 适合领域 |
---|---|---|---|---|
管道-过滤器 | 过滤器相对独立 | 功能模块复用;可维护性和扩散性较强;具有并发性;模块独立性高 | 不利于交互性强的应用,对于存在关系的数据流必须进行协调 | 系统可划分清晰模块;模块相对独立;有清晰的模块接口 |
面向对象 | 力争实现问题空间和软件系统空间结构的一致性 | 高度模块性;实现封装;代码共享灵活;易维护;可扩充性好 | 增加了对象的依赖关系 | 多种领域 |
事件驱动 (隐式调用) |
系统有若干个子系统构成且为一个整体;系统有统一的目标;子系统有主从之分;每一个子系统都有自己的事件收集和处理机制 | 适合描写系统组;容易实现并发处理和多任务;可扩展性好;具有类层次结构;简化代码 | 因为树形结构所以削弱了对系统计算的控制能力;各个对象的逻辑关系复杂 | 一个系统对外部的表现可以从它对事件的处理表征出来 |
层次式 | 每个层次的组件形成不同功能级别的虚拟机;多层相互协同工作,而且实现透明 | 支持系统设计过程中的逐级抽象;可扩展好;支持软件复用 | 不同层次之间耦合度高的系统难以实现 | 适合功能层次的抽象和相互之间低耦合的系统 |
数据共享 (仓库风格) |
采用两个常用构件中央数据单元和一些独立构件集合 | 中央数据单元实现了数据的集中,以数据为中心 | 只适用于某些特定领域 | 适合专家系统等人工智能领域问题的求解 |
闭环控制 (过程控制) |
通过不断地测量被控对象,认识和掌握被控对象;将控制理论引入体系结构构件 | 将控制理论引入到计算机软件体系结构中 | 适用于特定领域 | 该系统一定存在有目标的作用,信息处理闭环控制过程 |
3.3 软件质量属性
常见的质量属性(非功能性指标):
- 性能(Performance):系统的响应能力,即要经过多长时间才能对某个事件做出响应,或者在某段时间内系统所能处理的事件的个数。
- 代表参数:响应时间、吞吐量
- 架构策略:优先级队列、资源调度
- 可靠性(Reliability):软件系统在应用或系统错误面前,在意外或错误使用的情况下维持软件系统的功能特性的基本能力。(详见可靠性分析)
- 子属性:
- 容错
- 健壮性(Robustness):在处理或环境中,系统能够承受压力或变更的能力。
- 子属性:
- 可用性(Availability):系统能够正常运行的时间比例。(可靠性的衍生;经常用两次故障之间的时间长度或在出现故障时系统能够恢复正常的速度来表示)
- 代表參数:故障间隔时间
- 架构策略:主动冗余、心跳线(Ping/Echo)
- 安全性(Security):系统在向合法用户提供服务的同时能够阻止非授权用户使用的企图或拒绝服务的能力。
- 特性(至少4种,具体实现详见安全架构-安全模型):
- 机密性:信息不泄露给未授权的用户
- 完整性:防止信息被篡改
- 不可否认性:不可抵赖
- 可控性:对信息的传播及内容具有控制的能力
- 架构策略:限制访问、追踪审计、冗余(同可用性,但优先提高可用性)
- 特性(至少4种,具体实现详见安全架构-安全模型):
- 可修改性(Modifiability):能够快速地以较高的性能价格比对系统进行变更的能力。(修改的方便程度)
- 子属性:
- 可维护性(Maintainability)
- 可扩展性(Extendibility)
- 结构重组(Reassemble)
- 可移植性(Portability)/复用性/重用性(Reusability):详见构件与中间件技术-软件复用
- 架构策略:运行时注册、接口-实现分离、信息隐藏
- 子属性:
- 功能性(Functionality):系统所能完成所期望工作的能力。
- 可变性(Changeability):体系结构经扩充或变更成为新体系结构的能力。
- 互操作性(Inter-operation):系统与外界或系统与系统之间的相互作用能力。
其他属性:
- 易用性(Usability):衡量用户使用一个软件产品完成指定任务的难易程度。
- 典例:①界面友好;② 新用户学习使用系统时间不超过2小时
- 可测试性(Testability):软件发现故障并隔离、 定位其故障的能力特性, 以及在一定的时间和成本前提下,进行测试设计、测试执行的能力。
- 典例:提供远程调试接口,支持远程调试
- 架构策略:记录-回放
3.4 层次式架构
3.4.1 MVC
MVC(Model-View-Controller)是一种软件设计模式,把一个应用的输入、处理、输出流程按照视图、控制、模型的方式进行分离,形成了控制器、模型、视图3大核心模块:
- Model(模型):应用程序的主体部分,表示业务数据和业务逻辑。一个模型通常为多个视图提供数据,提高应用的可重用性。
- 在J2EE体系结构中为EJB(Entity Bean、Session Bean等)
- View(视图):用户看到并与之交互的界面。接收用户输入数据,向用户展示数据。
- 在J2EE体系结构中为JSP
- Controller(控制器):用户界面与Model的接口。接受用户的输入,并调用模型和视图去完成用户的需求。
- 在J2EE体系结构中为Servlet
使用MVC模式来设计表现层,具有以下优点:
- 允许多种用户界面的扩展
- 易于维护
- 易于构件功能强大的用户界面
- 增加应用的可拓展性、强壮性、灵活性
3.4.2 EJB中Bean的三种类型
J2EE的EJB中有3种Bean:
- Session Bean(会话Bean):描述了与客户端的一个短暂的会话。当客户端的执行完成后,Session Bean和它的数据都将消失。
- Entity Bean(实体Bean):描述了存储在数据库表中的一行持久稳固的数据,如果客户端终止或者服务结束,底层的服务会负责Entity Bean数据的存储。
- Message-Driven Bean(消息驱动Bean):结合了Session Bean和Java信息服务(JMS)信息监听者的功能,它允许一个商业组件异步地接受JMS消息。
3.5 面向服务架构(SOA)
SOA(Service-Oriented Architecture)是一种设计理念,其中包含多个服务,服务与服务之间相互依赖最终提供一系列完整的功能。各个服务通常以独立的形式部署运行,服务之间通过网络进行调用。
3.5.1 企业服务总线(ESB)
企业服务总线(Enterprise Service Bus,ESB)的特点:
- ESB是SOA的一种实现方式,具有总线作用,将各种服务进行连接与整合。
- 描述服务的元数据和服务注册管理。
- 可在服务请求者和提供者之间传递数据,以及对这些数据进行转换,并支持由实践中总结出来的一些模式(如同步模式、异步模式等)。
- 具有发现、路由、匹配和选择的能力以支持服务之间的动态交互,解耦服务请求者和服务提供者,还具有对安全的支持、服务质量保证、可管理性和负载平衡等高级能力。
主要功能:
- 服务位置透明
- 传输协议转换
- 消息格式转换
- 消息路由
- 消息增强
- 安全支持
- 监控和管理
3.5.2 REST的5个原则
REST(REpresentational State Transfer,表述性状态转移)规范的5个原则:
- 网络上的所有事物都被抽象为资源。
- 每个资源对应一个唯一的资源标识。
- 通过通用的连接件接口对资源进行操作。
- 对资源的各种操作不会改变资源标识。
- 所有的操作都是无状态的。
3.6 微服务架构
微服务(Microservice)架构与单体架构的对比:
- 单体架构:
- 优点:
- 开发简单,集中式管理
- 基本不会重复开发
- 功能都在本地,没有分布式的管理和调用消耗
- 缺点:
- 效率低:开发都在同一个项目改代码,相互等待,冲突不断
- 维护难:代码功能耦合在一起,新人不知道从何下手
- 不灵活:构建时间长,任何小修改都要重构整个项目,耗时
- 稳定性差:一个微小的问题都可能导致整个应用挂掉
- 扩展性不够:无法满足高并发下的业务需求
- 优点:
- 微服务架构:
- 目的:有效地拆分应用,实现敏捷开发和部署
- 优点:
- 复杂应用解耦: 小服务(专注于做一件事),化整为零,易于小团队开发。
- 独立性强:独立开发、独立部署、独立测试、独立运行(每个服务在其独立进程中)
- 技术选型灵活: 支持异构(例如每个服务使用不同的数据库)
- 容错能力强:故障被隔离在单个服务中,通过重试、平稳退化等机制实现应用层容错。
- 松耦合、易扩展:可根据需求独立扩展。
- 面临的问题与挑战:
- 分布式环境下的数据一致性
- 测试的复杂性(服务间依赖测试)
- 运维的复杂性
微服务架构模式方案:
- 聚合器微服务:客户端通过API网关访问聚合器,后者调用多个微服务并提供统一的响应。
- 链式微服务:客户端通过API网关依次调用多个微服务,数据沿链条传递。
- 数据共享微服务:多个微服务通过读写共享数据库进行数据交互。
- 异步消息传递微服务:微服务之间使用消息队列(如Kafka、ActiveMQ、RabbitMQ、RocketMQ)进行异步通信,实现解耦和流量控制。
微服务与SOA的区别:
微服务 | SOA |
---|---|
能拆分的就拆分 | 一个整体,服务能放一起的都放一起 |
纵向业务划分 | 水平分多层 |
由单一组织负责 | 按层级划分不同部门的组织负责 |
细粒度 | 粗粒度 |
两句话可以解释明白 | 几百字只相当于SOA的目录 |
独立的子公司 | 类似大公司里划分了一些业务单元(BU) |
组件小 | 存在较复杂的组件 |
业务逻辑存在于每一个服务中 | 业务逻辑横跨多个业务领域 |
使用轻量级的通信方式,如HTTP | 企业服务总线(ESB)充当了服务之间通信的角色 |
类比:SOA-雕版印刷,微服务-活字印刷
3.7 云计算架构
- 管理层:提供对所有层次云计算服务的管理功能。
- 用户访问层:方便用户使用云计算服务所需的各种支撑服务,针对每个层次的云计算服务都需要提供相应的访问接口。
- 应用层:提供软件服务,如财务管理、客户关系管理、商业智能。
- 平台层:为用户提供对资源层服务的封装,使用户可以构建自己的应用。
- 资源层:提供虚拟化的资源,从而隐藏物理资源的复杂性。如:服务器,存储。
3.8 云原生架构
云原生(Cloud Native)架构具有以下原则:
- 服务化原则:使用微服务
- 弹性原则:可根据业务变化自动伸缩
- 可观测原则:通过日志、链路跟踪和度量
- 韧性原则:面对异常的抵御能力
- 所有过程自动化原则:自动化交付工具
- 零信任原则:默认不信任网络内部和外部的任何人/设备/系统
- 架构持续演进原则:业务高速迭代情况下的架构与业务平衡
4 数据库系统设计
4.1 数据库性能优化
集中式数据库优化(单节点)
- 硬件系统:CPU、内存、I/O(硬盘,阵列)、网络
- 系统软件:参数,如进程优先级、CPU使用权、内存使用
- 数据库设计
- 表与视图:表的规划;建立物化视图
- 索引:常查询——建索引;常修改——避免索引
- SQL优化:
- 以不相干子查询替代相干子查询
- 只检索需要的列
- 用带IN的条件子句等价替换OR子句
- 经常提交COMMIT,以尽早释放锁
- 尽可能减少多表查询
- 应用软件:数据库连接池
分布式数据库优化(结点之间):
- 通信代价:
- 全局查询树的变换
- 多副本策略
- 查询树的分解
- 半连接与直接连接
4.1.1 规范化
规范化(Normalization)用于解决数据冗余、插入异常、删除异常、修改异常。
关系模式R(U, F)
遵循如下的Armstrong公理系统:
- A1. 自反律(Reflexivity):若
Y ⊆ X ⊆ U
,则X → Y
- A2. 增广律(Augmentation):若
Z ⊆ U
且X → Y
,则XZ → YZ
- A3. 传递律(Transitivity):若
X → Y
且Y → Z
,则X → Z
根据上述自反律、增广律、传递律可得以下推理规则:
- 合并规则:由
X → Y
且X → Z
,有X → YZ
(A2, A3) - 伪传递规则:由
X → Y
且WY → Z
,有WX → Z
(A2, A3 - 分解规则:由
X → Y
且Z ⊆ Y
,有X → Z
(A1, A3)(X → YZ
⇒X → Y
且X → Z
)
常见范式(Normal Form,NF)如下所示,从上到下逐步优化:
- 第一范式(1NF):属性值都是不可分的原子值
- 第二范式(2NF):在1NF的基础上,不存在非主属性部分函数依赖依赖于候选键
- 第三范式(3NF):在2NF的基础上,不存在非主属性传递函数依赖于候选键
- 巴斯-科德范式(BCNF):在3NF的基础上,每个依赖关系的决定因素包含候选键(整体)(即不存在部分与传递函数依赖)
规范化可能查询慢的原因:数据库规范化的过程,实际是对数据表的不断拆分,以达到更高的规范程度。由此带来问题——系统中大量查询不能通过单表完成,而需要进行多表连接查询。因此表拆分得越多,查询性能也就越差。
4.1.2 反规范化
反规范化(Denormalization):规范化设计后,数据库设计者希望牺牲部分规范化来提高性能。核心思想为增加数据冗余。通过有选择地在数据中加入特定的冗余数据,使得查询时减少表连接操作,从而提高查询性能。
反规范化的常见方法:
- 增加冗余列:在多个表中具有相同的属性列,常用于在查询时避免连接操作。
- 增加派生列:增加的列可以通过表中其他属性列加工计算生成,作用为减少查询时的计算量。
- 重新组表:如果需要经常查询两个表连接之后的数据,则将这两个表重新组成一个表来减少连接而提高性能。
- 表分割:通过将较大的表分割为多个较小的表来提高查询性能,包括水平分割和垂直分割。
反规范化的优缺点:
- 优点:
- 连接操作少,检索快、统计快
- 需要查的表减少,检索容易(但又易出错)
- 缺点(除数据不一致外均无解):
- 数据冗余,需要更大存储空间
- 插入、修改、删除等操作开销更大(牺牲其他来加快查找)
- 数据不一致;可能产生添加、修改、删除异常
- 解决方法:
- 触发器数据同步:触发器是与表事件相关的特殊存储过程,通过执行事件来触发,由数据库管理系统在后台自动执行。常见方法为在更新数据的表上增加相应事件的触发器,在触发器内容同步更新冗余数据。触发器同步在解决查询性能的同时一致性最高。
- 应用程序数据同步:通过应用程序在更新数据的同时,同步更新对应的冗余数据,这两个操作会放到同一个事务中,从而保证两个操作的原子性。
- 批处理同步:该方法一般应用在对数据一致性要求不高的场景下。当更新数据操作执行了一段时间后,根据更新数据进行批量的同步操作,使得冗余数据和更新数据保持一致。
- 解决方法:
- 更新和插入代码更难编写
4.1.3 数据视图
视图(View)是虚表,从一个或几个基本表(或视图)中导出,在系统的数据字典中仅存放视图的定义(即SQL查询语句),不存放视图。
优点:
- 简化用户操作(多表联合查询)
- 使用户能以多种角度看待同一数据
- 对重构数据库提供了一定程度的逻辑独立性
- 可以对机密数据提供安全保护(只读)
物化视图:将视图的内容物理存储起来,其数据随原始表变化,同步更新。
4.1.4 分区分表分库
辨析分区与分表:
- 共性:
- 都针对数据表
- 都使用了分布式存储
- 都提升了查询效率
- 都降低了数据库的频繁I/O压力值
- 差异:
- 分区逻辑上还是1张表
- 分表逻辑上已是多张表(分库与之同理,为对整个数据库进行操作)
分区策略:
- 范围(Range)分区:按数据范围值来做分区。【例】按用户编号分区,
0~999999
映射到分区A,1000000~1999999
映射到分区B。 - 哈希(Hash)分区:通过对key进行hash运算分区。【例】取余后将余数相同的分到同一个区。
- 列表(List)分区:根据某字段的某个具体值进行分区。【例】长沙用户分成一个区,北京用户一个区。
分区的优点:
- 相对于单个文件系统或硬盘,分区可以存储更多的数据。
- 数据管理比较方便。例如要清理或废弃某年的数据,直接删除该日期的分区数据即可。
- 精准定位分区查询数据,不需要全表扫描查询,大大提高数据检索效率。
- 可跨多个分区磁盘查询,来提高查询的吞吐量。
- 在涉及聚合函数查询时,可以很容易进行数据的合并。
4.2 分布式数据库系统
4.2.1 分布透明性
分布式数据库的分布透明性:
- 分片透明性:用户感受不到是否分片。
- 水平分片:按记录分
- 垂直分片:按字段分
- 混合分片
- 位置透明性:用户不必知道数据放在何处。
- 局部映像透明性(逻辑透明):用户不必关心局部数据模型
4.2.2 分区数据一致性问题
两种解决方案:
- 实时方案:当数据库数据更新时,同时更新内存的缓存数据。
- 异步准实时更新方案:当数据库数据更新时,不立即更新缓存数据,而是将需要更新的操作记录成日志,再逐步排队完成更新。
4.2.3 布隆过滤器
布隆过滤器(Bloom Filter):用于快速识别1个元素不在一个集合中,由此减轻缓存穿透问题。为解决传统哈希算法的哈希冲突问题,通过一个长二进制向量(bitmap)和一系列随机映射函数来记录与识别某个数据是否在一个集合中。(如下图所示)
优点:
- 占用内存小
- 查询效率高
- 不需要存储元素本身,在某些对保密要求比较严格的场合有很大优势
缺点:
- 有一定的误判率,即存在假阳性,不能准确判断元素是否在集合中
- 一般情况下不能从布隆过滤器中删除元素
- 不能获取元素本身
4.3 NoSQL
NoSQL(Not-only SQL):不仅仅只是SQL,泛指非关系型数据库。
关系型与非关系型数据库的对比:
对比维度 | 关系型数据库 | NoSQL |
---|---|---|
数据一致性 | 实时一致性 | 最终一致性 |
应用领域 | 面向通用领域 | 特定应用领域 |
数据容量 | 有限数据 | 海量数据/大数据 |
数据类型 | 结构化数据【二维表】 | 非结构化数据 |
并发支持 | 支持并发,但性能低 | 高并发 |
事务支持 | 高事务性 | 弱事务性 |
扩展方式 | 向上扩展 | 向外扩展 |
4.4 Redis分布式缓存数据库
RedisRedis与Memcache能力对比:
工作 | MemCache | Redis |
---|---|---|
数据类型 | 简单key-value结构 | 丰富的数据结构 |
持久性 | 不支持 | 支持 |
分布式存储 | 客户端哈希分片/一致性哈希 | 多种方式,主从、Sentinel、Cluster等 |
多线程支持 | 支持 | 支持(Redis5.0及以前版本不支持) |
内存管理 | 私有内存池 | 无 |
事务支持 | 不支持 | 有限支持 |
数据容灾 | 不支持,不能做数据恢复 | 支持,可以在灾难发生时恢复数据 |
4.4.1 Redis数据类型
Redis提供了丰富的数据类型:
- String(字符串):二进制存储,可存任意类型数据,最大512MB。
- 例:缓存,计数,共享Session
- Hash(字典):无序字典,数组+链表,适合存对象。一个Key对应一个HashMap,针对一组数据。
- 例:存储、读取、修改用户属性
- List(列表):分为Linked List(双向链表,有序,增删快,查询慢)、Array List(数组方式,有序,增删慢,查询快)
- 例:消息队列,文章列表;记录前N个最新登录的用户ID列表
- Set(集合):键值对无序,唯一。增删查复杂度均为
O(1)
,支持交/并/差集操作。- 例:独立IP,共同爱好,标签
- Sorted Set(Zset,有序集合):键值对有序,唯一,自带按权重排序效果。
- 例:排行榜
4.4.2 Redis集群切片
常见的集群切片方式及核心特点:
- 客户端切片:在客户端通过key的hash值对应到不同的服务器。
- 中间件实现切片:在应用软件和Redis中间,例如Twemproxy、Codis等,由中间件实现服务到后台Redis节点的路由分派。
- 客户端服务端协作切片:客户端与服务端协作完成分片处理。
4.4.3 分布式存储方案
常见的分布式存储方案及其核心特点:
- 主从(Master/Slave)模式:一主多从,故障时手动切换。
- 一般情况下一主多从,也可以多主多从。
- 主库做写操作,从库做读操作。
- 哨兵(Sentinel)模式:有哨兵的一主多从,主节点故障自动选择新的主节点。
- 集群(Cluster)模式:分节点对等集群,分slots,不同slots的信息存储到不同节点。
4.4.4 数据分片
常见的分片方案:
- 范围分片:按数据范围值来做分。【例】按用户编号分片,0~999999映射到实例A,1000000~1999999映射到实例B。
- 哈希分片:通过对key进行hash运算分片,可以把数据分配到不同实例。【例】通过取余操作,余数相同的放在一个实例上。
- 一致性哈希分片:哈希分片的改进,把存储结点和需要存储的数据都存放在一个hash环上,数据根据hash值在hash环上按正时针方向找到对应的数据存储结点上。
- 一致性哈希分片的方式在扩充缓存结点时,只需要对少量数据进行存储位置的更新,而哈希分片需要对几乎所有数据进行存储位置更新。
4.4.5 Redis持久化方式
RDB(Redis Database Backup file):传统数据库中快照的思想。指定时间间隔将数据进行快照存储。
AOF(Append Only File):传统数据库中日志的思想。把每条改变数据集的命令追加到AOF文件末尾,发生问题时可以重新执行AOF文件中的命令来重建数据集。
对比维度 | RDB持久化 | AOF持久化 |
---|---|---|
备份量 | 重量级的全量备份,保存整个数据库 | 轻量级的增量备份,一次只保存一个修改命令 |
保存间隔时间 | 长 | 短,默认1秒 |
还原速度 | 快 | 慢 |
阻塞情况 | save会阻塞,但bgsave或自动不会阻塞 | 无论是平时还是AOF重写,都不会阻塞 |
数据体积 | 小 | 大 |
安全性 | 低,容易丢数据 | 高,根据策略决定 |
- 磁盘更新频率:AOF比RDB文件更新频率高。
- 数据安全:AOF比RDB更安全。
- 数据一致性:RDB间隔一段时间存储,可能发生数据丢失和不一致;AOF通过append模式写文件,即使发生服务器宕机,也可通过redis-check-aof工具解决数据一致性问题。
- 重启性能:RDB性能比AOF好。
- 数据文件大小:AOF文件比RDB文件大。
4.4.6 Redis数据淘汰算法
根据淘汰作用范围划分各种淘汰机制:
- 不淘汰
- noeviction:禁止驱逐数据。内存不足以容纳新入数据时,新写入操作会报错。【系统默认】
- 设置了过期时间的键空间
- volatile-random:随机移除某个key
- volatile-lru:优先移除最近未使用的key
- volatile-ttl:ttl(Time-To-Live,生存时间,数据的过期时间)值小的key优先移出
- 全键空间
- allkeys-random:随机移除某个key
- allkeys-lru:优先移除最近未使用的key
4.4.7 Redis和MySQL数据实时同步问题
解决Redis和MySQL数据实时同步问题的常见方案:
- 应用程序读数据时先读取Redis中的key,如读到且未失效则返回key对应的数据;如读不到或key失效,则读取数据库,并同步Redis。写数据时先写数据库,并设置内存对应的key失效。
5 微内核架构
5.1 微内核架构基本概念
微内核架构(Microkernel Architecture,又称插件化架构,Plug-in Architecture)是一种面向功能拆分的可扩展性架构,通常用于实现基于产品的应用。例如Eclipse类IDE软件、UNIX类操作系统、淘宝App类客户端软件等,也有部分企业将业务系统设计成微内核架构,例如保险公司的保险核算逻辑系统,不同保险品种可以将逻辑封装成插件。
平时常用的从IDE到框架——Eclipse、IntelliJ IDEA、SPI等,插件化架构设计的比比皆是。但如果深入一些,能够把插件化架构阐述清楚,并能够借鉴思想,对在做的工作进行优化,尤其是在架构设计上并不简单。
5.2 微内核架构风格-拓扑结构
微内核架构的拓扑结构由两部分组件组成:核心系统(Core System)、插件模块(Plug-in Modules)。
这种结构使得能够将其他应用程序功能作为插件添加到核心应用程序,从而提供可扩展性、灵活性以及功能分离和隔离。
核心系统的功能相对稳定,不会因为业务功能扩展而不断修改,而插件模块可以根据实际业务功能的需要不断调整或扩展。微内核架构的本质是将可能需要不断变化的部分封装在插件中,从而达到快速灵活扩展的目的,而又不影响整体系统的稳定。模块加载和模块通信是核心系统提供的功能。
5.3 核心系统设计的三个关键点
- 插件管理:需要知道当前系统中有多少个插件,哪些插件处于可用状态,何时加载一个插件,以及何如加载一个插件。
- 常见实现:插件注册表(配置文件、代码或者数据库)。由核心系统提供,插件注册表有每个插件的信息,包括名字、位置、加载时机(启动加载还是按需加载)等。
- 插件连接:制定了一个插件与核心系统的通信方式,即连接规范。
- 插件按照规范实现,核心系统按照规范加载。
- 常见的连接机制:OSGi(Eclipse使用)、消息模式、依赖注入(Spring使用)、分布式协议(例如RPC或HTTP)
- 插件通信:插件模块的设计要实现低耦合,但一个业务请求往往需要几个插件模块共同协作来实现,这就需要插件之间实现相互通信。
- 插件间并没有直接联系,所以插件间通信必须通过核心系统,因此核心系统需要提供插件通信机制。和计算机类似,计算机的CPU、硬盘、内存、网卡是独立设计的配件,但运行过程中各个部件肯定需要通信,计算机通过主板上的总线提供了组件间的通信功能。微内核的核心系统也需要提供类似的通信机制,各个插件间才能进行正常的通信。
5.4 微内核架构的优缺点
- 灵活性高:能够快速响应不断变化的环境,通过插件模块的松散耦合实现,可以进行隔离变更等,并且快速满足需求;易扩展、易裁剪。
- 易于部署:功能之间是隔离的,插件之间可以独立的加载和卸载。
- 可测试性高:插件模块可单独测试,能够非常简单地被核心系统模拟出来进行演示,或者在对核心系统很小影响甚至没有影响的情况下对一个特定的特性进行原型展示。
- 通信效率低:插件通过内核实现间接通信,需要更多开销。
- 开发难度高:微内核架构需要设计,因此实现起来比较复杂。
《系统架构设计案例分析强化教程》有3条评论