层:软件的逻辑单元。
每一层都有特定的功能。
组件被分配到不同层。
将系统按照之策拆分和组织。
上层依赖于直接下层。(下层不可以依赖于上层,不可以跨层访问)
CS架构是典型的两层架构,分为Client客户端和Server服务端。
客户端运行于客户的终端,服务端处理应用服务、业务逻辑和数据存储。
客户端和服务端通过网络交换信息。
BS架构同样是典型的两层架构,分为Browser浏览器和Server服务端。
Browser运行于各种浏览器的瘦客户端。
客户端和服务端通过网络交换信息。
Presentation:与用户交互和呈现信息(UI)。
Domain:业务逻辑。
Data:数据存储。
隔离业务复杂度和技术复杂度。
解决不同层的问题,可以采用不同的技术栈。
每层变化速度不一致。
防止错误传播。
降低错误影响。
防水仓设计。(熔断)
本层功能内聚。
自主决策。
只有本层的知识。(知道的越少,泄密的可能性越小,受影响的可能性变小)
每一层的任何变更最多影响自身和上一层。
专注自身功能,其他层的影响被屏蔽。
符合单一职责原则。
每一层只依赖于下一层。
单向依赖。
通过接口交流。(接口聚合、依赖反转)
功能扩展,影响仅限本层。
内聚性,易于横向扩展。
独立部署,易于纵向扩展。
每层定义了清晰的边界,扩展发生在不同边界,符合开闭原则。
分工合作,开发者关注点集中。
每一层可以依据接口并行开发。
每一层功能单一,代码易于理解。
每层对外提供固定接口,可以直接测试接口。
分层测试。(比如Springboot分为@DataJpsTest和@WebMvcTest测试)
分层必定引入新的通信开销。
层信息不能泄漏,导致每层都有数据转化发生。
不能跨层访问,无法减少调用链路。
Full stack全栈少且难以培养。
跨组织提高沟通成本。
任何变更可能都需要多层参与。
越向外越具体,越朝内越抽象。
外圈是软件,内圈是规则。
依赖关系只能从外向内。
高层表示规则,底层实现细节。
逻辑内聚自治分组。
依据组织职责分工。
根据每层的需求各自选定。
借鉴成功案例。
部署方式局限,选定技术栈。
层对外暴露的接口,隐藏实现细节。
实现依赖于抽象,抽象不可依赖于实现细节。
代码不跨层调用,只依赖于直接的下一层。
集成前做单元测试、功能测试。
根据接口和技术栈确定集成方式。
集成联调。
Model:Domain model和业务逻辑。
View:展示数据和用户交互。
Controller:接收输入并转化为对model的操作,将model转化为view能展示的数据。
是MVC的派生变种。
View通过Presenter获得数据而非Model。
Presenter层充当了桥梁,双向绑定。
Model:除了自身也包含部分Controller功能。
ViewModel:View的模型、映射、显示逻辑和绑定器。
View:将ViewModel展示在特定界面。
BFF:Backend for frontend,一般用于微服务架构。
避免了终端与多个服务的交流。
比较常见的就是GraphQL。
源系统发送消息通知其他系统状态改变。
接收方响应非必须。
发送Event逻辑与处理Event逻辑无依赖,独立变化。
双方解耦,各自扩展。
(例如:使用MQ)
该模式下,生产者把详细状态数据添加到事件中,如此对消费者而言,不需要再访问事件生产者服务了解详情就可以完成后续任务。事件生产者需要仔细衡量,提供足够的信息以便对已知和未知订阅者有用。
该模式的好处显而易见,通过数据冗余增加了系统的可恢复性能力,因为消费者不依赖生产者就可以独立提供服务,同时可以降低延迟,不需要远程调用生产者系统,也不用担心生产者系统来自不同消费者过多的查询工作负载;但副作用也很明显,大量的副本,带来冗余的存储使用,同时增加了消费者从所有事件中维护一致性状态的复杂性(需要依赖事件顺序)。
源系统推送信息及变化。(依赖者生成信息副本)
容错(fault tolerance)。(源系统不可用时,依赖者可以使用副本)
依赖者维护信息副本和变化。(数据的冗余问题、数据一致性问题)
提高整体性能。(依赖者直接使用信息副本)
事件驱动架构模式是一种异步
分发事件的架构模式。
用于高扩展且低耦合的系统。
事件为核心,一系列解耦的、单一功能的事件处理器。
针对不同的IO event分配不同的handler。
Selector:监控哪些Channel有IO event。
SelectionKey:维护IO event的状态和绑定的handler。
nginx的工作进程一直监听端口并等待event。
event是由新建立的连接所触发。
所有的连接都会被分配到一个对应的状态机。
Non-blocking。
存在业务流程。
多步骤。
统一协调,集中调度。
事件分层次。
Event Queue:
源系统将event发送到queue。
Event处理系统从queue中消费event。
是源系统和事件处理系统的连接点。
Queue只关心事件的传输,对事件的处理不关心。
Event Mediator:
中介从queue中消费原始事件,并分配、协调各个执行步骤。
对应业务处理的每个步骤,产生待处理事件(业务事件)。
将待处理事件异步分发到不同的通道(channel)。
无具体业务逻辑,只知道有哪些步骤。
Event Channel:
Mediator向channel发送消息,processor从channel读取。
某种类型的业务事件(消息)的聚合。
多个processor可以监听同一个channel。
Event Processor:
监听channel的event。
具体的、单一功能的业务逻辑单元。
处理器之间无关联性。
所有处理器合作形成完整业务流程。
无中心控制器。
轻量的消息代理将消息串联成链状。
分发至事件处理器组件。
事件处理器独立运作。
Broker:
是轻量级的代理。(中介是知道业务流程的,Broker不需要知道业务流程)
无业务逻辑的简单消息分发。
源系统将event发送至代理(通道)提供processor消费。
事件通道可以是queue、topic或两者组合。
Event Processor:
监听channel的event,判断是否处理。
处理一个事件,并发送回Broker一个事件,标明其行为。
事件处理器,单一业务逻辑。
处理器无关联性,不构成业务逻辑链。
架构能否在不断改变的使用场景下快速响应。
事件处理器组件目的单一、高度解耦,可以独立变化。
代理拓扑结构比中介拓扑结构调度会更容易。(事件中介与事件处理器是耦合的,代理模式完全解耦)
高度解耦,独立变化。
横向扩展。(不同组件的运行节点数均可自行调整、组件本身可以自行决定是否再拆分实现)
纵向扩展。(计算密集型还是内存密集型,按需调整)
细粒度的事件处理器有利于提高性能。
整体架构是异步并行有利于提高性能。
高度解耦的事件处理器组件让整体部署相对容易。
单元测试无差异。
集成测试难。(组件众多、异步)
分布式部署,复杂性高。
异步,对程序员要求高。
异常处理难。
代码可读性较差,代码复杂度高。
分布式消息(事件)传递会降低性能。
(1)短信验证码异步发送
(2)电商订单生命周期管理
(3)数据同步消息广播
微内核,就是核心功能
、资源封装
。
提供可插拔
、功能扩展
的插件。
资源封装(提供硬件接口、系统资源访问接口、环境/上下文Context访问接口、系统事件接口)。
定义插件规范(使用场景、规则、条件)。
核心功能(支持系统运作的最小功能集)。
职责分离(通用流程由核心系统定义、核心定义规范,插件具体实现)。
插件模块是核心系统能力的扩展(遵循核心系统规范、实现其逻辑外延和业务逻辑)。
插件应该遵循单一职责原则(专注于其独立功能、只能通过核心提供的接口操作系统资源)。
插件间无依赖(尽可能避免依赖其他插件,只依赖于核心)。
隔离性(插件不能影响核心)。
插件注册:
需要获取插件可用性。
统一的获取插件的方式。
检查信息抽象规范(名称、数据规范、访问协议)。
插件连接:
自定义连接方式(OSGI,点对点绑定,依赖注入)(web service、message等)。
通信规范(标准规范配合版本策略、自定义规范配合Adapter)。
插件事件:
系统核心封闭。
插件提供开放性。
整体系统可持续升级。
核心系统可以关闭插件。
错误的传播范围有限。(插件内的错误不会被传播到核心系统)
各自独立升级改进。(可能有兼容性问题)
核心系统保持稳定,将变化尽量隔离在插件层。
插件根据核心提供的接口和规范来提供丰富的功能。
整体保持开放,持续进化。
核心系统和插件系统可以分开测试。
插件可以运行在模拟环境。
通过简化核心系统,提高其性能。
插件按需加载,降低资源消耗。
可以动态关闭插件以保护核心系统。
插件可在运行时动态添加到核心系统。
减少核心系统停机时间。
需要分离核心功能与插件功能。
插件需要可以热插拔。
需要专门注册协议和通信协议。
主要用于开发产品,不考虑扩展性。
不以可扩展性见长。
但是,可以结合其他模式获得扩展性。
定义核心功能。(实现MVP最小可行产品)
封装系统资源。(插件通过接口访问)
开放集成点。(支持与插件的集成和通信)
核心系统提供的接口及版本。
提供上下文(context)、环境参数。
提供回调(call back)、钩子(hook)、事件(event)。
集成规范。
同步/异步。
本地/远程调用。
数据格式。
基于注册表获取插件信息。
装载机制。(启动器/运行期装载、内存/远程装载)
装载条件。(触发条件符合才加载)
Eclipse开发者可以提供各种插件,为Eclipse提供更多额外的功能。
专家系统。(将人类专业知识转化为程序,用程序来解决专业问题)
Rule。(Condition、Action)
Rule Engine。(基于输入数据执行规则的专家系统,如果满足条件则执行对应的任务)
通过将不同应用接入ESB以扩展系统功能。
ESB是核心系统。
应用就是插件。
应用之间无依赖,都与ESB沟通。
通过BPM组合不同子流程形成新的流程扩展系统功能。
BPM是核心系统。
子流程是插件。
子流程间无直接依赖。
Nginx通过module为nginx添加新功能。
nginx是核心,module是plugin。
开源nginx在编译期指定要添加的模块。
nginx plus可以动态添加或移除module。
Servlet实现核心功能。
插件:(Filter:针对request和response的操作;Listener:Servlet生命周期事件并执行相应命令)
SpringMVC,Struts众多功能都是基于Listener和Filter实现。
同步调用变成异步调用。
生产数据与消费数据分离。
协调不同处理速度。
生产者是系统运转的动力。
为下一环节产生待处理的工作/数据。
与消费者关系:重点在如何将数据发送到容器、对消费者无依赖、不关注消费者的how/when。
发送顺序问题比较难处理。
从容器中获得数据,并按照自身业务逻辑处理。
依赖于容器,不直接依赖于生产者。
向容器确认数据已经被消费。
处理后的数据:从容器中删除(queue)、保留在容器中(topic)。
消费顺序问题比较难以处理。
容器是消费者与生产者的交汇点。
容器担当了保管数据的责任。(容量、保存时间、读写效率)
是生产者和消费者的差速器。
数据分配策略。(发给哪个消费者)
数据不堆积。(容器中数据不会溢出)
消费者无资源浪费。(最好是消费者的消费能力刚刚好)
调度算法。(多个消费者消息路由问题)
EDA架构模式:
事件触发流程;
重点在事件本身;
不解决事件/消息如何传递的问题。
生产者消费者模式:
强调的是从生产端到消费端的全流程;
从抽象程度来看EDA更抽象。
消费策略决定消费者如何消费数据。
消费方式:push(容器推送给消费者)、poll(消费者从容器拉取)。
分发方式:topic(消息一对多)、queue(消息点对点)。
事务性问题。
producer、consumer和container均可独立变化。
producer和consumer互无依赖。
无事务系统时,对三者都无约束。
异步运作。
producer、consumer和container均可分开部署。
producer、consumer和container自成分布式系统。
各自按需扩展。
通过container来平衡生产速度和消费速度。
通过动态调节producer和consumer数量,以平衡系统差速。
减少资源浪费。(避免生产过多数据,避免数据堆积在容器)
生产和消费速度不确定时,达到削峰填谷的效果。
削峰:生产数据超过消费数据,缓存数据。
填谷:生产数据的速度下降,消费端消费速度不变。
单点流量增加不影响系统稳定性,整体系统运行于匀速状态。
定义:生产者放入/发送到容器的单体、容器内存储的单体、消费者消费的单体。
从业务逻辑推导:数据单元具备业务含义、数据单元的颗粒度适中。
完整性保证:传输过程中数据单元不可缺失。
无依赖:数据单元是独立的,两个数据单元之间互不影响。
生产/发送,对发送成功的确认:
只管发送不管是否发送成功;
发送之后需要同步知道是否发送成功;
异步发送之后不需要同步知道是否发送成功,而是通过回调来知道是否发送成功。
数据单元变成用于网络传输的数据。(JSON、Avro、Thrift、Protobuf)
数据单元的时间、空间的独立性。
超时、错误、重试等。
推(pust):
由container发起,将数据单元推送给consumer;
consumer可以尽快获得数据。
如果推的太快,可能会导致consumer崩溃。
拉(pull):
由consumer主动发起,一直不停的询问container。
获取数据有一定的滞后,并不是实时。(Long polling)
好处就是,consumer可以自己控制拉取数据的数量。
Queue:点对点的模式,不可重复消费。
Pub/Sub:发布订阅,Topic模式,1对N,消息相当于可重复消费。
将网络数据流还原为数据单元。(JSON、Avro、Thrift、Protobuf)
Commit log(记录消息读到哪里了)。
ACK。(消息处理完毕之后,给容器一个应答)
批量/单体消费。
同步/异步消费。
保证幂等性。
Replica(数据复制)。主从节点复制、分区。
Non-replica(不复制)。只存meta data,读取转移。(读的时候会判断,数据和真实存储的地方有个关联关系,类似做了index索引)(用的较少)
数据单元的存储结构。
时效性。(不能一直保存下去)
分配数据单元到consumer。
Producer保证Consumer至少收到一次数据单元。
从业务分析Container中可能有重复数据单元。
Consumer实现要防重或幂等。
Producer保证Consumer最多收到一次数据单元。
从业务分析Container中可能会丢失部分数据单元。
Consumer可能无法读取到所需数据单元。
或许要引入第三方数据比对验证程序。
Producer保证Consumer收到并仅收到一次数据单元。
从业务分析Container中有且仅有一份数据单元。
Consumer无需防重。