架构设计

GoF的23种设计模式

分布式单体架构 分布式架构设计_分布式

创建型:
单例(Singleton)模式:某个类只能生成一个实例,该类提供了一个全局访问点供外部获取该实例,其拓展是有限多例模式。
原型(Prototype)模式:将一个对象作为原型,通过对其进行复制而克隆出多个和原型类似的新实例。
工厂方法(Factory Method)模式:定义一个用于创建产品的接口,由子类决定生产什么产品。
抽象工厂(AbstractFactory)模式:提供一个创建产品族的接口,其每个子类可以生产一系列相关的产品。
建造者(Builder)模式:将一个复杂对象分解成多个相对简单的部分,然后根据不同需要分别创建它们,最后构建成该复杂对象。
结构型:
代理(Proxy)模式:为某对象提供一种代理以控制对该对象的访问。即客户端通过代理间接地访问该对象,从而限制、增强或修改该对象的一些特性。
适配器(Adapter)模式:将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类能一起工作。
桥接(Bridge)模式:将抽象与实现分离,使它们可以独立变化。它是用组合关系代替继承关系来实现,从而降低了抽象和实现这两个可变维度的耦合度。
装饰(Decorator)模式:动态的给对象增加一些职责,即增加其额外的功能。
外观(Facade)模式:为多个复杂的子系统提供一个一致的接口,使这些子系统更加容易被访问。
享元(Flyweight)模式:运用共享技术来有效地支持大量细粒度对象的复用。
组合(Composite)模式:将对象组合成树状层次结构,使用户对单个对象和组合对象具有一致的访问性。
行为型:
模板方法(TemplateMethod)模式:定义一个操作中的算法骨架,而将算法的一些步骤延迟到子类中,使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤。
策略(Strategy)模式:定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的改变不会影响使用算法的客户。
命令(Command)模式:将一个请求封装为一个对象,使发出请求的责任和执行请求的责任分割开。
职责链(Chain of Responsibility)模式:把请求从链中的一个对象传到下一个对象,直到请求被响应为止。通过这种方式去除对象之间的耦合。
状态(State)模式:允许一个对象在其内部状态发生改变时改变其行为能力。
观察者(Observer)模式:多个对象间存在一对多关系,当一个对象发生改变时,把这种改变通知给其他多个对象,从而影响其他对象的行为。
中介者(Mediator)模式:定义一个中介对象来简化原有对象之间的交互关系,降低系统中对象间的耦合度,使原有对象之间不必相互了解。
迭代器(Iterator)模式:提供一种方法来顺序访问聚合对象中的一系列数据,而不暴露聚合对象的内部表示。
访问者(Visitor)模式:在不改变集合元素的前提下,为一个集合中的每个元素提供多种访问方式,即每个元素有多个访问者对象访问。
备忘录(Memento)模式:在不破坏封装性的前提下,获取并保存一个对象的内部状态,以便以后恢复它。
解释器(Interpreter)模式:提供如何定义语言的文法,以及对语言句子的解释方法,即解释器。

JDK中几个常用的设计模式:

适配器模式:InputStreamReader(适配器)实现了Reader接口(目标接口),并且持有InputStream(源接口)的引用(利用InputStreamDecoder间接引用),实现将InputStream转换为Reader。

装饰器模式

分布式单体架构 分布式架构设计_数据_02


以FileInputStream为例,InputStream类就是以抽象组件存在的,而FileInputStream就是具体组件,它实现了抽象组件的所有功能。FilterInputStream类无疑就是装饰角色,它实现了InputStream类的所有功能,并且持有InputStream对象实例的引用。BufferedInputStream是具体的装饰器实现者,它给InputStream类附加了功能。这个装饰器类的作用就是使得InputStream读取的数据保存在内存中,从而提高读取的性能。

桥接模式: jdbc为所有的数据库提供通用的接口, 一个应用系统可以根据需要选择合适的驱动程序, 通过驱动程序向数据库发送指令。

观察者模式:java.util.Observable和java.util.Observer,主题继承自Observable类,观察者实现Observer接口。

Spring中常见的几个设计模式:

控制反转和依赖注入

IoC(Inversion of Control,控制翻转) 是一种解耦的设计思想。它的主要目的是借助于“第三方”(Spring 中的 IOC 容器) 实现具有依赖关系的对象之间的解耦,从而降低代码之间的耦合度。IOC 是一个原则,而不是一个模式,以下模式(但不限于)实现了IoC原则。

分布式单体架构 分布式架构设计_分布式单体架构_03


Spring IOC 容器就像是一个工厂一样,当我们需要创建一个对象的时候,只需要配置好配置文件/注解即可,完全不用考虑对象是如何被创建出来的。 IOC 容器负责创建对象,将对象连接在一起,配置这些对象,并从创建中处理这些对象的整个生命周期,直到它们被完全销毁。

DI(Dependecy Inject,依赖注入)是实现控制反转的一种设计模式,依赖注入就是将实例变量传入到一个对象中去。

工厂模式:通过 BeanFactory 或 ApplicationContext 创建 bean 对象;
两者对比:

  • BeanFactory:延迟注入(使用到某个bean的时候才会注入),占用更少的内存,程序启动速度更快;
  • ApplicationContext:扩展了BeanFactory,容器启动的时候一次性创建所有的bean;

ApplicationContext的三个实现类:

  • ClassPathXmlApplicationContext:加载类路径下的配置文件;
  • FileSystemXmlApplicationContext:加载磁盘任意路径下的配置文件
  • AnnotationConfigApplicationContext:用于读取注解创建ioc容器

代理模式:Spring AOP功能的实现;

AOP能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任(如:事务处理,日志管理,权限控制等)封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可扩展性和可维护性。

Spring AOP基于动态代理,如果要代理的对象实现了某个接口,那么Spring AOP会使用JDK Proxy去创建代理对象,而对于没有实现接口的对象,使用Cglib生成一个被代理对象的子类来作为代理。

分布式单体架构 分布式架构设计_分布式单体架构_04


Spring AOP 和 AspectJ AOP 有什么区别?

Spring AOP 属于运行时增强,而 AspectJ 是编译时增强。 Spring AOP 基于代理(Proxying),而 AspectJ 基于字节码操作(Bytecode Manipulation)。

如果我们的切面比较少,那么两者性能差异不大。但是,当切面太多的话,最好选择 AspectJ 。

单例模式:Spring中Bean的默认作用域就是singleton(单例)的,另外日志对象,线程池也是单例;

静态代理、JDK动态代理、CGLIB代理

静态代理:在程序运行之前,提前写好被代理方法的代理类;
动态代理:主要通过反射机制,在运行时动态生成所需的class
CGLIB代理:其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。

单例模式

保证一个类仅有一个实例,并提供一个访问它的全局访问点。

public class Singleton7 {

    private static volatile Singleton7 instance = null;

    private Singleton7() {}

    public static Singleton7 getInstance() {
        if (instance == null) {
            synchronized (Singleton7.class) {
                if (instance == null) {
                    instance = new Singleton7();
                }
            }
        }

        return instance;
    }

}

工厂模式

创建一个对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行。

观察者模式

当对象间存在一对多的依赖关系时,当一个对象的状态发生改变,所有依赖于它的对象都得到通知并被自动更新(气象站);

装饰者模式

用于动态给一个对象添加一些额外的功能,同时又不改变原有结构。

分布式

分布式概述

分布式

分布式是为了解决单个物理服务器容量和性能瓶颈问题而采用的优化手段,将一个业务拆分成不同的子业务,分布在不同的机器上执行,服务之间通过远程协调工作,对外提供服务。
水平扩展:当一台机器扛不住流量时,通过添加机器的方式,将流量平分到所有服务器上,所有机器都可以提供相同的服务。
垂直拆分:前端有多种查询需求时,一台机器扛不住,可以将不同的业务需求分发到不同的机器上;

集群

集群是指在多台不同的服务器中部署相同应用或服务模块,构成一个集群,通过负载均衡设备对外提供服务。
两个特点:
可扩展性:集群中的服务节点,可以动态地添加机器,从而增加集群的处理能力;
高可用性:如果集群中某个节点发生故障,这台节点上面运行的服务,可以被其他服务节点接管,从而增强集群的高可用性。
两大能力:
负载均衡:负载均衡能把任务比较均衡地分布到集群环境下的服务器。
集群容错:集群服务调用失败后,服务框架需要能够在底层自动容错。

微服务

微服务就是很小的服务,一个服务对应一个单一的功能,只做一件事,这个服务可以单独部署运行,服务之间通过远程调用协调工作,每个微服务都是由独立的小团队开发,测试,部署,上线,负责它的整个生命周期。

多线程

多线程是指程序中包含多个执行流,即在同一个程序中可以同时运行多个不同的线程来执行不同的任务,多线程是为了提高CPU的利用率。

高并发

高并发是指系统运行过程中发生了一种“短时间内遇到大量请求”的情况,可以通过多线程、分布式、集群、算法优化、数据库优化等方法解决。

分布式系统设计理念

设计目标和要素

分布式系统的目标是提升系统的整体性能和吞吐量,另外还要尽量保证分布式系统的容错性。

设计思路:中心化和去中心化

中心化设计
两个角色:“领导”和“员工”
角色职责:“领导”负责分发任务并监督“员工”,如果某个“员工”瘫痪,将其开除,将任务分配给其他“员工”
问题:“领导”出事了,整个系统就崩了,另外就是“领导”能力问题,往往会成为系统的瓶颈;
解决办法:自动选举切换“领导”,以提升系统对可用性。
去中心化设计
去中心化不是说不需要中心节点,而是由节点自己来选举中心节点。
问题:“脑裂”问题,即一个集群中由于网络的故障,被分为至少两个彼此无法通信的单独集群,如果两个集群都各自工作,则可能会产生严重的数据冲突和错误。
解决办法:当集群判断发生了脑裂问题时,规模较小的集群就“自杀”或者拒绝服务。

CAP和BASE

CAP定理

对于一个分布式计算系统来说,不可能同时满足一致性、可用性、分区容错性,分区容错性是必须的,我们在强一致性和可用性上只能二选一。

分布式单体架构 分布式架构设计_AOP_05


分布式单体架构 分布式架构设计_AOP_06


Spring Cloud在CAP法则上主要满足的是A和P法则,Dubbo和Zookeeper在CAP法则主要满足的是C和P法则

BASE理论

BASE 是 Basically Available(基本可用) 、Soft-state(软状态) 和 Eventually Consistent(最终一致性) 三个短语的缩写。

基本可用:分布式系统在出现不可预知故障的时候,允许损失部分可用性,比如响应时间上的损失,系统功能上的损失(双十一页面跳转);

软状态:允许系统中的数据存在中间状态,并认为该中间状态的存在不会影响系统的整体可用性,即允许系统在不同节点的数据副本之间进行数据同步的过程存在延时。

最终一致性:最终一致性强调的是系统中所有的数据副本,在经过一段时间的同步后,最终能够达到一个一致的状态。因此,最终一致性的本质是需要系统保证最终数据能够达到一致,而不需要实时保证系统数据的强一致性。