程序员跳槽必备(二)

下面几道面试题您知道多少?

1、不同版本的 Spring Framework 有哪些主要功能?

2、什么是 Spring Framework?

3、列举 Spring Framework 的优点。

4、Spring Framework 有哪些不同的功能?

5、Spring Framework 中有多少个模块,它们分别是什么?

6、什么是 Spring 配置文件?

7、Spring 应用程序有哪些不同组件?

8、使用 Spring 有哪些方式?

9、什么是 Spring IOC 容器?

10、什么是依赖注入?

11、可以通过多少种方式完成依赖注入? 

​12、区分构造函数注入和 setter 注入。

​13、spring 中有多少种 IOC 容器? 

​14、区分 BeanFactory 和 ApplicationContext。 15、列举 IoC 的一些好处。 

​15、列举 IoC 的一些好处。

16、Spring IoC 的实现机制。 

​17、什么是 spring bean? 

​18、spring 提供了哪些配置方式? 

​19、spring 支持集中 bean scope? 

​20、spring bean 容器的生命周期是什么样的? 

​21、什么是 spring 的内部 bean? 

​22、什么是 spring 装配 

​23、自动装配有哪些方式? 

​24、自动装配有什么局限? 

​25、什么是基于注解的容器配置

26、如何在 spring 中启动注解装配?

 ​27、@Component, @Controller, @Repository,@Service 有何区别? 

​28、@Required 注解有什么用? 

​29、@Autowired 注解有什么用? 

30、@Qualifier 注解有什么用? 

​31、@RequestMapping 注解有什么用?

​32、spring DAO 有什么用?

​33、列举 Spring DAO 抛出的异常。

​34、spring JDBC API 中存在哪些类? 

​35、使用 Spring 访问 Hibernate 的方法有哪些?

 ​36、列举 spring 支持的事务管理类型

​37、spring 支持哪些 ORM 框架 

​38、什么是 AOP? 

​39、什么是 Aspect? 

​40、什么是切点(JoinPoint) 

​41、什么是通知(Advice)? 

​42、有哪些类型的通知(Advice)? 

​43、指出在 spring aop 中 concern 和 cross-cuttingconcern的不同之处。 

​44、AOP 有哪些实现方式? 

​45、Spring AOP and AspectJ AOP 有什么区别? 

​46、如何理解 Spring 中的代理? 

​47、什么是编织(Weaving)? 

​48、Spring MVC 框架有什么用?

49、描述一下 DispatcherServlet 的工作流程 

​50、介绍一下 WebApplicationContext 

​51、什么是 spring? 

​52、使用 Spring 框架的好处是什么? 

​53、Spring 由哪些模块组成? 

​54、核心容器(应用上下文) 模块。 

​55、BeanFactory – BeanFactory 实现举例。 

66、XMLBeanFactory 

​67、解释 AOP 模块 

​69、解释对象/关系映射集成模块。 

​70、解释 WEB 模块。 

​72、Spring 配置文件 

​73、什么是 Spring IOC 容器? 

​74、IOC 的优点是什么? 

​75、ApplicationContext 通常的实现是什么? 

​76、Bean 工厂和 Application contexts 有什么区别? 

​77、一个 Spring 的应用看起来象什么? 

​78、什么是 Spring 的依赖注入? 

​79、有哪些不同类型的 IOC(依赖注入)方式?

 ​80、哪种依赖注入方式你建议使用,构造器注入,还是 Setter方法注入? 

​81.什么是 Spring beans?

82、一个 Spring Bean 定义 包含什么? 

​83、如何给 Spring 容器提供配置元数据? 

​84、你怎样定义类的作用域? 

​85、解释 Spring 支持的几种 bean 的作用域。 

​86、Spring 框架中的单例 bean 是线程安全的吗?

87、解释 Spring 框架中 bean 的生命周期。 

​88、哪些是重要的 bean 生命周期方法?你能重载它们吗? 

​89、什么是 Spring 的内部 bean? 

​90、在 Spring 中如何注入一个 java 集合? 

​91、什么是 bean 装配?

92、什么是 bean 的自动装配? 

​93、解释不同方式的自动装配 。 

94.自动装配有哪些局限性 ? 

​95、你可以在 Spring 中注入一个 null 和一个空字符串吗?

96、什么是基于 Java 的 Spring 注解配置? 给一些注解的例 子. 

​97、什么是基于注解的容器配置? 

​98、怎样开启注解装配? 

​99、@Required 注解 

​100、@Autowired 注解 

​101、@Qualifier 注解 

​102.在 Spring 框架中如何更有效地使用 JDBC?

103、JdbcTemplate 

​104、Spring 对 DAO 的支持 

​105、使用 Spring 通过什么方式访问 Hibernate? 

​106、Spring 支持的 ORM 

​107. 如何通过 HibernateDaoSupport 将 Spring 和 Hibernate 结合起来? 

​108、Spring 支持的事务管理类型 

​109、Spring 框架的事务管理有哪些优点? 

​110、你更倾向用那种事务管理类型? 

​111、解释 AOP 

​112、Aspect 切面

​113、在 Spring AOP 中,关注点和横切关注的区别是什么? 

​114、连接点 

​115、通知 

​116、切点 

​117、什么是引入? 

118、什么是目标对象? 

119、什么是代理? 

120、有几种不同类型的自动代理?

121、什么是织入。什么是织入应用的不同点? 

​122、解释基于 XML Schema 方式的切面实现。 

123、解释基于注解的切面实现 

124、什么是 Spring 的 MVC 框架? 

125、DispatcherServlet 

126、WebApplicationContext 

127、什么是 Spring MVC 框架的控制器? 

128、@Controller 注解 

129、@RequestMapping 注解 
答案自行搜索

Spring Cloud面试题

1、什么是 Spring Cloud?

2、使用 Spring Cloud 有什么优势?

3、服务注册和发现是什么意思?Spring Cloud 如何实现?

4、Spring Cloud 和dubbo区别?

5、SpringBoot和SpringCloud的区别?

6、负载平衡的意义什么?

7、什么是 Hystrix?它如何实现容错?

8、什么是 Hystrix 断路器?我们需要它吗?

9、什么是 Netflix Feign?它的优点是什么?

10、什么是 Spring Cloud Bus?我们需要它吗?

11、Spring Cloud断路器的作用

12、什么是SpringCloudConfig?

13、Spring Cloud Gateway?

Spring Boot 面试题

1、什么是 Spring Boot?
2、Spring Boot 有哪些优点?
3、什么是 JavaConfig?
4、如何重新加载 Spring Boot 上的更改,而无需重新启动服务器?
5、Spring Boot 中的监视器是什么?
6、如何在 Spring Boot 中禁用 Actuator 端点安全性?
7、如何在自定义端口上运行 Spring Boot 应用程序?
8、什么是 YAML?
9、如何实现 Spring Boot 应用程序的安全性?
10、如何集成 Spring Boot 和 ActiveMQ?
11、如何使用 Spring Boot 实现分页和排序?
12、什么是 Swagger?你用 Spring Boot 实现了它吗?
13、什么是 Spring Profiles?
14、什么是 Spring Batch?
15、什么是 FreeMarker 模板?
16、如何使用 Spring Boot 实现异常处理?
17、您使用了哪些 starter maven 依赖项?
18、什么是 CSRF 攻击?
19、什么是 WebSockets?
20、什么是 AOP?
21、什么是 Apache Kafka?
22、我们如何监视所有 Spring Boot 微服务?

 

三,spring系列全家桶 boot  cloud及其组件

 

Spring,最好能抽空看看源码,最起码bean的生命周期,如何解决循环依赖,父子容器,还有boot的启动流程,事务实现原理,动态代理原理等,你知道越多越好。

什么是Spring IOC,Spring AOP?应用场景有哪些?数据库事务隔离级别,数据库的四大属性底层实现原理、Spring如何实现事务、传播行为?

Spring Bean的作用域和生命周期

SpringCould组件说七八个等等这些问题得必须深入的进行理解表达出来。

什么是Spring IOC,Spring AOP?应用场景有哪些?数据库事务隔离级别,数据库的四大属性、Spring如何实现事务、传播行为
AOP:面向切面编程
即在一个功能模块中新增其他功能,比方说在工作中如果系统中有些包和类中没有使用AOP,例如日志,事务和异常处理,那么就必须在每个类和方法中去实现它们。 代码纠缠每个类和方法中都包含日志,事务以及异常处理甚至是业务逻辑。在一个这样的方法中,很难分清代码中实际做的是什么处理。AOP 所做的就是将所有散落各处的事务代码集中到一个事务切面中。

场景

比方说我现在要弄一个日志,记录某些个接口调用的方法时间。使用Aop我可以在这个接口前插入一段代码去记录开始时间,在这个接口后面去插入一段代码记录结束时间。

又或者你去访问数据库,而你不想管事务,所以,Spring在你访问数据库之前,自动帮你开启事务,当你访问数据库结束之后,自动帮你提交/回滚事务!

异常处理你可以开启环绕通知,一旦运行接口报错,环绕通知捕获异常跳转异常处理页面。

动态代理

Spring AOP使用的动态代理,所谓的动态代理就是说AOP框架不会去修改字节码,而是在内存中临时为方法生成一个AOP对象,这个AOP对象包含了目标对象的全部方法,并且在特定的切点做了增强处理,并回调原对象的方法。它的动态代理主要有两种方式,JDK动态代理和CGLIB动态代理。JDK动态代理通过反射来接收被代理的类,并且要求被代理的类必须实现一个接口。JDK动态代理的核心是InvocationHandler接口和Proxy类。如果目标类没有实现接口,那么Spring AOP会选择使用CGLIB来动态代理目标类。CGLIB是一个代码生成的类库,可以在运行时动态的生成某个类的子类,注意,CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的。

IOC:依赖注入或者叫做控制反转
正常情况下我们使用一个对象时都是需要new Object()的。而ioc是把需要使用的对象提前创建好,放到spring的容器里面。

所有需要使用的类都会在spring容器中登记,告诉spring你是个什么东西,你需要什么东西,然后spring会在系统运行到适当的时候,把你要的东西主动给你,同时也把你交给其他需要你的东西。所有的类的创建、销毁都由 spring来控制,也就是说控制对象生存周期的不再是引用它的对象,而是spring。DI(依赖注入)其实就是IOC的一种实现方式。

场景:

正常情况下我们使用一个对象时都是需要new Object() 的。而ioc是把需要使用的对象提前创建好,放到spring的容器里面。需要使用的时候直接使用就行,而且可以设置单例或多例,非常灵活。

我们在service层想调用另外一个service的方法,不需要去new了,直接把它交给spring管理,然后用注解的方式引入就能使用。

IOC三种注入方式

(1)XML:Bean实现类来自第三方类库,例如DataSource等。需要命名空间等配置,例如:context,aop,mvc。

(2)注解:在开发的类使用@Controller,@Service等注解

(3)Java配置类:通过代码控制对象创建逻辑的场景。例如:自定义修改依赖类库。

@Resource,@Autowired,@Qualifier区别?

@resource:默认是按照名称来装配注入的,只有在找不到名称匹配bean的时候才会按照类型来注入

@Autowired:默认是按照类型进行装配注入,默认情况下,它要求依赖对象必须存在,如果允许null值,可以设置它required为false

如果我们想要按照名称进行装配的话,可以添加一个@Qualifier注解解决。

@Autowired

@Qualifier(“loginService”)

private LoginService loginService;

@resource注解式J2EE提供的,@Autowired是Spring提供的,如果想要减少对Spring的依赖建议使用@resource注解。

数据库事务隔离级别
Read uncommitted 读未提交
公司发工资了,领导把20000元打到xxx的账号上,但是该事务并未提交,而xxx正好去查看账户,发现工资已经到账,是20000元整,非常高兴。可是不幸的是,领导发现发给xxx的工资金额不对,是16000元,于是迅速修改金额,将事务提交,最后xxx实际的工资只有16000元,xxx空欢喜一场。

出现上述情况,即我们所说的脏读,两个并发的事务,“事务A:领导给xxx发工资”、“事务B:xxx查询工资账户”,事务B读取了事务A尚未提交的数据。当隔离级别设置为Read uncommitted时,就可能出现脏读,如何避免脏读,请看下一个隔离级别。

Read committed 读提交
xxx拿着工资卡去消费,系统读取到卡里确实有2000元,而此时她的老婆也正好在网上转账,把xxx工资卡的2000元转到另一账户,并在xxx之前提交了事务,当xxx扣款时,系统检查到xxx的工资卡已经没有钱,扣款失败,xxx十分纳闷,明明卡里有钱,为何…

出现上述情况,即我们所说的不可重复读,两个并发的事务,“事务A:xxx消费”、“事务B:xxx的老婆网上转账”,事务A事先读取了数据,事务B紧接了更新了数据,并提交了事务,而事务A再次读取该数据时,数据已经发生了改变。当隔离级别设置为Read committed时,避免了脏读,但是可能会造成不可重复读。大多数数据库的默认级别就是Read committed,比如Sql Server , Oracle。如何解决不可重复读这一问题,请看下一个隔离级别。

Repeatable read 重复读
当xxx拿着工资卡去消费时,一旦系统开始读取工资卡信息(即事务开始),xxx的老婆就不可能对该记录进行修改,也就是xxx的老婆不能在此时转账。这就避免了不可重复读。xxx的老婆工作在银行部门,她时常通过银行内部系统查看xxx的信用卡消费记录。有一天,她正在查询到xxx当月信用卡的总消费金额(select sum(amount) from transaction where month = 本月)为80元,而xxx此时正好在外面胡吃海喝后在收银台买单,消费1000元,即新增了一条1000元的消费记录(insert transaction … ),并提交了事务,随后xxx的老婆将xxx当月信用卡消费的明细打印到A4纸上,却发现消费总额为1080元,xxx的老婆很诧异,以为出现了幻觉,幻读就这样产生了。当隔离级别设置为Repeatable read时,可以避免不可重复读,但会出现幻读。注:MySQL的默认隔离级别就是Repeatable read。

Serializable 序列化
Serializable是最高的事务隔离级别,同时代价也花费最高,性能很低,一般很少使用,在该级别下,事务顺序执行,不仅可以避免脏读、不可重复读,还避免了幻像读。

属性(特性) 底层实现原理
A(原子性):要么全部完成,要么完全不起作用。底层实现原理:undo log(当这个事务对数据库进行修改的时候,innodb生成对应undo log,他会记录这个SQL执行的相关信息,如果SQL执行失败发生这个回滚,innodb根据这个undo log内容去做相反的工作,比如说我执行了一个insert操作,那么回滚的时候,就会执行一个相反的操作,就是delete,对应update,回滚的时候也是执行相反的update)
C(一致性):一旦事务完成(不管成功还是失败),业务处于一致的状态,而不会是部分完成,部分失败。事务执行前后,数据库的完整约束没有遭受破坏,事务执行前后都是合法的一个数据状态。
I(隔离性):多事务会同时处理相同的数据,因此每个事务都应该与其他事务隔离开来,防止数据损坏。底层实现原理:写-写操作:锁(和java里面的锁机制是一样的)。写-读操作:MVCC(多版本并发控制,可以通过乐观锁和悲观锁实现,只在读已提交和可重复读二个隔离级别,事务的排它锁形式修改数据,修改之前把数据放到undolog里面,通过回滚指针关联,成功了什么都不做,失败了,从undolog回滚数据。)
D(持久性):一旦事务完成,无论发生什么系统错误,它的结果都不应该受到影响,事务的结果被写到持久化存储器中。底层实现原理:redo log(mysql的数据是存放在这个磁盘上的,但是每次去读数据都需要通过这个磁盘io,效率就很低,使用innodb提供了一个缓存buffer,这个buffer中包含了磁盘部分数据页的一个映射,作为访问数据库的一个缓冲,当从这个数据库读取一个数据,就会先从这个buffer中获取,如果buffer中没有,就从这个磁盘中获取,读取完再放到这个buffer缓冲中,当数据库写入数据的时候,也会首先向这个buffer中写入数据,定期将buffer中的数据刷新到磁盘中,进行持久化的一个操作。如果buffer中的数据还没来得及同步到这个磁盘上,这个时候MySQL宕机了,buffer里面的数据就会丢失,造成数据丢失的情况,持久性就无法保证了。使用redolog解决这个问题,当数据库的数据要进行新增或者是修改的时候,除了修改这个buffer中的数据,还会把这次的操作写入到这个redolog中,如果msyql宕机了,就可以通过redolog去恢复数据,redolog是预写式日志(会先将所有的修改写入到日志里面,然后再更新到buffer里面,保证了这个数据不会丢失,保证了数据的持久性))

spring事务的传播行为
Spring的事务是对数据库的事务的封装,最后本质的实现还是在数据库,假如数据库不支持事务的话,Spring的事务是没有作用的。所以说Spring事务的底层依赖MySQL的事务,Spring是在代码层面利用AOP实现,执行事务的时候使用TransactionInceptor进行拦截,然后处理。本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,执行完目标方法之后根据执行的情况提交或者回滚。

Spring支持7中事务传播行为
一个场景:假设外层方法里面包含二个新增用户和新增角色的方法后面还会抛一个异常。
propagation_required(需要传播):当前没有事务则新建事务,有则加入当前事务。

外围方法未开启事务,插入用户表和用户角色表的方法在自己的事务中独立运行,外围方法异常不影响内部插入,所以两条记录都新增成功。
外围方法开启事务,内部方法加入外围方法事务,外围方法回滚,内部方法也要回滚,所以两个记录都插入失败。
propagation_supports(支持传播):支持当前事务,如果当前没有事务则以非事务方式执行

外围方法未开启事务,插入用户表和用户角色表的方法以非事务的方式独立运行,外围方法异常不影响内部插入,所以两条记录都新增成功。
外围方法开启事务,内部方法加入外围方法事务,外围方法回滚,内部方法也要回滚,所以两个记录都插入失败。
propagation_mandatory(强制传播):使用当前事务,如果没有则抛出异常

外围方法开启事务,内部方法加入外围方法事务,外围方法回滚,内部方法也要回滚,所以两个记录都插入失败。
外围方法没有开启事务,两张表数据都为空,在调用用户新增方法时候已经报错了,所以两个表都没有新增数据。
propagation_nested(嵌套传播):如果当前存在事务,则在嵌套事务内执行,如果当前没有事务,则执行需要传播行为。
propagation_never(绝不传播):以非事务的方式执行,如果当前有事务则抛出异常。

外层方法没有事务会以非事务的方式运行,两个表新增成功;
外围方法有事务则抛出异常,两个表都都没有新增数据
propagation_requires_new(传播需要新的):新建事务,如果当前有事务则把当前事务挂起,创建新的事务。

无论当前存不存在事务,都创建新事务,所以两个数据新增成功。
propagation_not_supported(不支持传播):以非事务的方式执行,如果当前有事务则把当前事务挂起。

外围方法未开启事务,插入用户表和用户角色表的方法在自己的事务中独立运行,外围方法异常不影响内部插入,所以两条记录都新增成功。
外围方法开启事务,两个数据新增成功。
CAP,BASE理论,分布式事务的四种解决方案
CAP
分布式环境下(数据分布)要任何时刻保证数据一致性是不可能的,只能采取妥协的方案来保证数据最终一致性。这个也就是著名的CAP定理。

C一致性:对于指定的客户端来说,读操作保证能够返回最新的写操作结果。

A可用性:非故障的节点在合理的时间内返回合理的响应(不是错误和超时的响应)。

P分区容错性:当出现网络分区后,系统能够继续“履行职责”。

对于一个分布式系统而言,网络失效一定会发生,分区容错性P其实就是每个服务都会有多个节点(一般都是主从),这样就可以保证此服务的一个节点挂了之后,此服务的其他节点依然可以响应,其实这就是分区容错性。
但是一个服务有多个节点之后,一个服务的多个节点之间的数据为了保持一致性就要进行的数据复制,在此过程中就会出现数据一致性C(强一致性)的问题。也就是说,分区耐受性是必须要保证的,那么在可用性和一致性就必须二选一。网络不可用的时候,如果选择了一致性,系统就可能返回一个错误码或者干脆超时,即系统不可用。如果选择了可用性,那么系统总是可以返回一个数据,但是并不能保证这个数据是最新的。

BASE
BASE 理论是对 CAP 理论的延伸,核心思想是即使无法做到强一致性,但应用可以采用适合的方式达到最终一致性。

    基本可用: 基本可用是指分布式系统在出现故障的时候,允许损失部分可用性,即保证核心可用。电商大促时,为了应对访问量激增,部分用户可能会被引导到降级页面,服务层也可能只提供降级服务。这就是损失部分可用性的体现。
    软状态: 软状态是指允许系统存在中间状态,而该中间状态不会影响系统整体可用性。分布式存储中一般一份数据至少会有三个副本,允许不同节点间副本同步的延时就是软状态的体现。MySQL Replication 的异步复制也是一种体现。
    最终一致性: 最终一致性是指系统中的所有数据副本经过一定时间后,最终能够达到一致的状态。弱一致性和强一致性相反,最终一致性是弱一致性的一种特殊情况。
 
应用场景:

Erueka

erueka是SpringCloud系列用来做服务注册和发现的组件,作为服务发现的一个实现,在设计的时候就更考虑了可用性,保证了AP。

Zookeeper

Zookeeper在实现上牺牲了可用性,保证了一致性(单调一致性)和分区容错性,也即:CP。所以这也是SpringCloud抛弃了zookeeper而选择Erueka的原因。

具体根据各自业务场景所需来制定相应的策略而选择适合的产品服务等。例如:支付订单场景中,由于分布式本身就在数据一致性上面很难保证,从A服务到B服务的订单数据有可能由于服务宕机或其他原因而造成数据不一致性。因此此类场景会酌情考虑:AP,不强制保证数据一致性,但保证数据最终一致性。

 

分布式事务指事务的操作位于不同的节点上,需要保证事务的 AICD 特性,在下单场景下,库存和订单如果不在同一个节点上,就涉及分布式事务。

两阶段提交(2PC)
第一阶段:协调者询问参与者事务是否执行成功,参与者发回事务执行结果。这一阶段的协调者有超时机制,假设因为网络原因没有收到某参与者的响应或某参与者挂了,那么超时后就会判断事务失败,向所有参与者发送回滚命令。

第二阶段:如果事务在每个参与者上都执行成功,事务协调者才发送通知让参与者提交事务;否则,协调者发送通知让参与者回滚事务。这一阶段的协调者的没法超时,只能不断重试。

协调者是一个单点,存在单点故障问题。
假设协调者在发送准备命令之前挂了,还行等于事务还没开始。
假设协调者在发送准备命令之后挂了,这就不太行了,有些参与者等于都执行了处于事务资源锁定的状态。不仅事务执行不下去,还会因为锁定了一些公共资源而阻塞系统其它操作。
假设协调者在发送回滚事务命令之前挂了,那么事务也是执行不下去,且在第一阶段那些准备成功参与者都阻塞着。
假设协调者在发送回滚事务命令之后挂了,这个还行,至少命令发出去了,很大的概率都会回滚成功,资源都会释放。但是如果出现网络分区问题,某些参与者将因为收不到命令而阻塞着。
假设协调者在发送提交事务命令之前挂了,这个不行,傻了!这下是所有资源都阻塞着。
假设协调者在发送提交事务命令之后挂了,这个还行,也是至少命令发出去了,很大概率都会提交成功,然后释放资源,但是如果出现网络分区问题某些参与者将因为收不到命令而阻塞着。

存在的缺点:

同步阻塞 所有事务参与者在等待其它参与者响应的时候都处于同步阻塞状态,无法进行其它操作。
单点问题 协调者在 2PC 中起到非常大的作用,发生故障将会造成很大影响。特别是在阶段二发生故障,所有参与者会一直等待状态,无法完成其它操作。
数据不一致 在阶段二,如果协调者只发送了部分 Commit 消息,此时网络发生异常,那么只有部分参与者接收到 Commit 消息,也就是说只有部分参与者提交了事务,使得系统数据不一致。
太过保守 任意一个节点失败就会导致整个事务失败,没有完善的容错机制。
3PC
相比于 2PC 它在参与者中也引入了超时机制,并且新增了一个阶段使得参与者可以利用这一个阶段统一各自的状态,3PC 包含了三个阶段,分别是准备阶段、预提交阶段和提交阶段
准备阶段的变更成不会直接执行事务,而是会先去询问此时的参与者是否有条件接这个事务,因此不会一来就干活直接锁资源,使得在某些资源不可用的情况下所有参与者都阻塞着。
而预提交阶段的引入起到了一个统一状态的作用,它像一道栅栏,表明在预提交阶段前所有参与者其实还未都回应,在预处理阶段表明所有参与者都已经回应了。
假如你是一位参与者,你知道自己进入了预提交状态那你就可以推断出来其他参与者也都进入了预提交状态。

缺点:

多引入一个阶段也多一个交互,因此性能会差一些,而且绝大部分的情况下资源应该都是可用的,这样等于每次明知可用执行还得询问一次。

和2PC对比:


2PC 是同步阻塞的,协调者挂在了提交请求还未发出去的时候是最伤的,所有参与者都已经锁定资源并且阻塞等待着,提交阶段 2PC 协调者和某参与者都挂了之后新选举的协调者不知道当前应该提交还是回滚

改进的优势:


新协调者来的时候发现有一个参与者处于预提交或者提交阶段,那么表明已经经过了所有参与者的确认了,所以此时执行的就是提交命令。
所以说 3PC 就是通过引入预提交阶段来使得参与者之间的状态得到统一,也就是留了一个阶段让大家同步一下。
但是这也只能让协调者知道该如果做,但不能保证这样做一定对,这其实和上面 2PC 分析一致,因为挂了的参与者到底有没有执行事务无法断定。
所以说 3PC 通过预提交阶段可以减少故障恢复时候的复杂性,但是不能保证数据一致,除非挂了的那个参与者恢复。


总结一下

3PC 相对于 2PC 做了一定的改进:引入了参与者超时机制,并且增加了预提交阶段使得故障恢复之后协调者的决策复杂度降低,但整体的交互过程更长了,性能有所下降,并且还是会存在数据不一致问题。
2PC 和 3PC 都不能保证数据100%一致,因此一般都需要有定时扫描补偿机制

补偿事务(TCC)
针对每个操作,都要注册一个与其对应的确认和补偿(撤销)操作。它分为三个阶段:

Try 阶段主要是对业务系统做检测及资源预留

Confirm 阶段主要是对业务系统做确认提交,Try阶段执行成功并开始执行 Confirm阶段时,默认 Confirm阶段是不会出错的。即:只要Try成功,Confirm一定成功。

Cancel 阶段主要是在业务执行错误,需要回滚的状态下执行的业务取消,预留资源释放。

举个例子,假入 Bob 要向 Smith 转账,思路大概是:我们有一个本地方法,里面依次调用

首先在 Try 阶段,要先调用远程接口把 Smith 和 Bob 的钱给冻结起来。

在 Confirm 阶段,执行远程调用的转账的操作,转账成功进行解冻。

如果第2步执行成功,那么转账成功,如果第二步执行失败,则调用远程冻结接口对应的解冻方法 (Cancel)。

优点: 跟2PC比起来,实现以及流程相对简单了一些,但数据的一致性比2PC也要差一些

缺点: 缺点还是比较明显的,在2,3步中都有可能失败。TCC属于应用层的一种补偿方式,所以需要程序员在实现的时候多写很多补偿的代码,在一些场景中,一些业务流程可能用TCC不太好定义及处理。

 

本地消息表(异步确保)
本地消息表与业务数据表处于同一个数据库中,这样就能利用本地事务来保证在对这两个表的操作满足事务特性,并且使用了消息队列来保证最终一致性。

在分布式事务操作的一方完成写业务数据的操作之后向本地消息表发送一个消息,本地事务能保证这个消息一定会被写入本地消息表中。

之后将本地消息表中的消息转发到 Kafka 等消息队列中,如果转发成功则将消息从本地消息表中删除,否则继续重新转发。

在分布式事务操作的另一方从消息队列中读取一个消息,并执行消息中的操作。

优点: 一种非常经典的实现,避免了分布式事务,实现了最终一致性。

缺点: 消息表会耦合到业务系统中,如果没有封装好的解决方案,会有很多杂活需要处理。

 

 

Zuul和Spring Cloud Gateway
两者均是web网关,处理的是http请求
gateway对比zuul多依赖了spring-webflux,在spring的支持下,功能更强大,内部实现了限流、负载均衡等,扩展性也更强,但同时也限制了仅适合于Spring Cloud套件,而zuul则可以扩展至其他微服务框架中,其内部没有实现限流、负载均衡等
gateway很好的支持异步,而zuul仅支持同步,那么理论上gateway则更适合于提高系统吞吐量(但不一定能有更好的性能),最终性能还需要通过严密的压测来决定
从框架设计的角度看,gateway具有更好的扩展性,并且其已经发布了2.0.0的RELESE版本,稳定性也是非常好的
编码上看,zuul更加简洁易懂,注释规范清晰,而gateway作为Spring家族的一份子,竟然几乎不注释…
总的来说,在微服务架构,如果使用了Spring Cloud生态的基础组件,则Spring Cloud Gateway相比而言更加具备优势,单从流式编程+支持异步上就足以让开发者选择它了。

而对于小型微服务架构或是复杂架构(不仅包括微服务应用还有其他非Spring Cloud服务节点),zuul也是一个不错的选择,当然,这种场景下一般会选择nginx,因为nginx从各个方面都会表现的更好…

3 Nginx在微服务中的地位
最后简单聊一下nginx,在过去几年微服务架构还没有流行的日子里,nginx已经得到了广大开发者的认可,其性能高、扩展性强、可以灵活利用lua脚本构建插件的特点让人没有抵抗力。

有一个能满足我所有需求还很方便我扩展的东西,还免费,凭啥不用??
但是,如今很多微服务架构的项目中不会选择nginx,我认为原因有以下几点:
微服务框架一般来说是配套的,集成起来更容易
如今微服务架构中,仅有很少的公司会面对无法解决的性能瓶颈,而他们也不会因此使用nginx,而是选择开发一套适合自己的微服务框架
spring boot对于一些模板引擎如FreeMarker、themleaf的支持是非常好的,很多应用还没有达到动、静态文件分离的地步,对nginx的需求程度并不大。
无论如何,nginx作为一个好用的组件,最终使不使用它都是由业务来驱动的,只要它能为我们方便的解决问题,那用它又有何不可呢?

4 小结
通过总结发现,在微服务架构中网关上的选择,最好的方式是使用现在比较成熟的Spring Cloud套件,其提供了Spring Cloud Gateway网关,或是结合公司情况来开发一套适合自己的微服务套件,至少从网关上可以看出来其内部实现并不难,同时也比较期待开源项目Nacos、Spring Cloud Alibaba 建设情况,期待它能构建一个高活跃社区的、稳定的、适合中国特色(大流量、高并发)的微服务基础架构。
竞争是发展的催化剂。在这个网关服务层出不穷的年代,各公司都铆足力气打造自己的网关产品,尽量让自己的产品成为用户的第一选择。而广大开发者也在享受这样的红利,使用高性能的网关来开发自己的应用。作为广大开发者的一员,我们欣然接受这样良性竞争的出现,并且也乐于尝试市面上出现的任何新产品,谁也说不准某一个产品以后就会成为优选的代名词。虽然从现在网关的性能差距看来,后发优势明显,但在可预见的将来,各网关迟早会到达性能瓶颈,在性能差距不大并且产品稳定之后,就会有各种差异化特性出现。而等到网关产品进入百舸争流的时代之后,用户就可以不再根据性能,而是根据自己的需求选择适合的网关服务了
 

Spring Cloud 与 Dubbo 对比。

dubbo由于是二进制的传输,占用带宽会更少

springCloud是http协议传输,带宽会比较多,同时使用http协议一般会使用JSON报文,消耗会更大

dubbo的开发难度较大,原因是dubbo的jar包依赖问题很多大型工程无法解决

springcloud的接口协议约定比较自由且松散,需要有强有力的行政措施来限制接口无序升级

dubbo的注册中心可以选择zk,redis等多种,springcloud的注册中心只能用eureka或者自研
 

表 1 Spring Cloud与Dubbo功能对比
功能名称Dubbo Spring Cloud
服务注册中心ZooKeeperSpring Cloud Netflix Eureka
服务调用方式RPCREST API
服务网关Spring Cloud Netflix Zuul
断路器不完善Spring Cloud Netflix Hystrix
分布式配置Spring Cloud Config
服务跟踪Spring Cloud Sleuth
消息总线Spring Cloud Bus
数据流Spring Cloud Stream
批量任务Spring Cloud Task


Spring Cloud 抛弃了 Dubbo 的 RPC 通信,采用的是基于 HTTP 的 REST 方式。严格来说,这两种方式各有优劣。虽然从一定程度上来说,后者牺牲了服务调用的性能,但也避免了上面提到的原生 RPC 带来的问题。而且 REST 相比 RPC 更为灵活,服务提供方和调用方,不存在代码级别的强依赖,这在强调快速演化的微服务环境下显得更加合适。

很明显,Spring Cloud 的功能比 Dubbo 更加强大,涵盖面更广,而且作为 Spring 的拳头项目,它也能够与 Spring Framework、Spring Boot、Spring Data、Spring Batch 等其他 Spring 项目完美融合,这些对于微服务而言是至关重要的。

前面提到,微服务背后一个重要的理念就是持续集成、快速交付,而在服务内部使用一个统一的技术框架,显然比将分散的技术组合到一起更有效率。

更重要的是,相比于 Dubbo,它是一个正在持续维护的、社区更加火热的开源项目,这就可以保证使用它构建的系统持续地得到开源力量的支持。

下面列举 Spring Cloud 的几个优势。

  • Spring Cloud 来源于 Spring,质量、稳定性、持续性都可以得到保证。
  • Spirng Cloud 天然支持 Spring Boot,更加便于业务落地。
  • Spring Cloud 发展得非常快,从开始接触时的相关组件版本为 1.x,到现在将要发布 2.x 系列。
  • Spring Cloud 是 Java 领域最适合做微服务的框架。


相比于其他框架,Spring Cloud 对微服务周边环境的支持力度最大。对于中小企业来讲,使用门槛较低。

 

spring cloud gateway 之如何限流

在高并发的系统中,往往需要在系统中做限流,一方面是为了防止大量的请求使服务器过载,导致服务不可用,另一方面是为了防止网络攻击。

常见的限流方式,比如Hystrix适用线程池隔离,超过线程池的负载,走熔断的逻辑。在一般应用服务器中,比如tomcat容器也是通过限制它的线程数来控制并发的;也有通过时间窗口的平均速度来控制流量。常见的限流纬度有比如通过Ip来限流、通过uri来限流、通过用户访问频次来限流。

一般限流都是在网关这一层做,比如Nginx、Openresty、kong、zuul、Spring Cloud Gateway等;也可以在应用层通过Aop这种方式去做限流。

在 Spring Cloud Gateway 中如何实现限流。

常见的限流算法

计数器算法

计数器算法采用计数器实现限流有点简单粗暴,一般我们会限制一秒钟的能够通过的请求数,比如限流qps为100,算法的实现思路就是从第一个请求进来开始计时,在接下去的1s内,每来一个请求,就把计数加1,如果累加的数字达到了100,那么后续的请求就会被全部拒绝。等到1s结束后,把计数恢复成0,重新开始计数。具体的实现可以是这样的:对于每次服务调用,可以通过AtomicLong#incrementAndGet()方法来给计数器加1并返回最新值,通过这个最新值和阈值进行比较。这种实现方式,相信大家都知道有一个弊端:如果我在单位时间1s内的前10ms,已经通过了100个请求,那后面的990ms,只能眼巴巴的把请求拒绝,我们把这种现象称为“突刺现象”

漏桶算法

漏桶算法为了消除"突刺现象",可以采用漏桶算法实现限流,漏桶算法这个名字就很形象,算法内部有一个容器,类似生活用到的漏斗,当请求进来时,相当于水倒入漏斗,然后从下端小口慢慢匀速的流出。不管上面流量多大,下面流出的速度始终保持不变。不管服务调用方多么不稳定,通过漏桶算法进行限流,每10毫秒处理一次请求。因为处理的速度是固定的,请求进来的速度是未知的,可能突然进来很多请求,没来得及处理的请求就先放在桶里,既然是个桶,肯定是有容量上限,如果桶满了,那么新进来的请求就丢弃。

 

在算法实现方面,可以准备一个队列,用来保存请求,另外通过一个线程池(ScheduledExecutorService)来定期从队列中获取请求并执行,可以一次性获取多个并发执行。

这种算法,在使用过后也存在弊端:无法应对短时间的突发流量。

令牌桶算法

从某种意义上讲,令牌桶算法是对漏桶算法的一种改进,桶算法能够限制请求调用的速率,而令牌桶算法能够在限制调用的平均速率的同时还允许一定程度的突发调用。在令牌桶算法中,存在一个桶,用来存放固定数量的令牌。算法中存在一种机制,以一定的速率往桶中放令牌。每次请求调用需要先获取令牌,只有拿到令牌,才有机会继续执行,否则选择选择等待可用的令牌、或者直接拒绝。放令牌这个动作是持续不断的进行,如果桶中令牌数达到上限,就丢弃令牌,所以就存在这种情况,桶中一直有大量的可用令牌,这时进来的请求就可以直接拿到令牌执行,比如设置qps为100,那么限流器初始化完成一秒后,桶中就已经有100个令牌了,这时服务还没完全启动好,等启动完成对外提供服务时,该限流器可以抵挡瞬时的100个请求。所以,只有桶中没有令牌时,请求才会进行等待,最后相当于以一定的速率执行。

 

实现思路:可以准备一个队列,用来保存令牌,另外通过一个线程池定期生成令牌放到队列中,每来一个请求,就从队列中获取一个令牌,并继续执行。

Spring Cloud Gateway限流

在Spring Cloud Gateway中,有Filter过滤器,因此可以在“pre”类型的Filter中自行实现上述三种过滤器。但是限流作为网关最基本的功能,Spring Cloud Gateway官方就提供了RequestRateLimiterGatewayFilterFactory这个类,适用Redis和lua脚本实现了令牌桶的方式。具体实现逻辑在RequestRateLimiterGatewayFilterFactory类

 

SpringCloud 服务熔断、降级组件:Hystrix与Sentinel

 

Hystrix 断路器
Hystrix 基础概念
Hystrix Github

它是什么?

   Hystrix 是一个库,通过隔离服务之间的访问点,停止级联失败和提供回退选项等来提高微服务系统的高可用性。

   通俗的讲,Hystrix 是用来解决相互依赖调用的服务之间,不会因某一环节出现问题,而浪费相关的资源,进而导致整个系统无法响应的问题。

可以做什么?

提供快速失败,快速恢复
回退、降级功能
近实时监控、警报和操作控制
服务降级
服务降级的触发,有运行时异常、超时、线程池等饱和情况,一般放在消费方配置比较合理

消费方配合 @FeignClient ,使用在接口上,解耦降级方法

服务熔断
熔断流程:降级方法执行 --》 熔断拒绝访问 --》 感知恢复服务

开启断路器后的执行流程:

  开启断路器后,在一个滑动窗口期内,requestVolumeThreshold 次请求,请求失败率达到errorThreshold 时,进入长为 sleepWindow 的睡眠窗口期(该时间段内所有请求都会直接走对应的降级方法),睡眠窗口期结束后尝试请求,决定是否关闭断路器

Hystrix 配置参数解析

所有配置参数均在类 HystrixCommandProperties 中配置了默认值。

Sentinel 下的熔断与限流
是什么?

   它是分布式系统的流量防卫兵,以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护多个服务的稳定性。

相比与 Hystrix 的优势:

   Hystrix 中对流量控制、熔断降级等服务需要去代码中配置,Web 监控界面无法管理。Sentinel 的管理界面完善了这些问题,让使用、管理更加方便。

Sentinel 分为两个部分:

核心库(Java 客户端)不依赖任何框架/库,能够运行于所有 Java 运行时环境,同时对 Dubbo / Spring Cloud 等框架也有较好的支持。
控制台(Dashboard)基于 Spring Boot 开发,管理配置流控等规则。
 

名称解释:

资源名:唯一名称,请求路径

流控应用:可以对调用者进行限流,填写微服务名,默认default(即不区分来源)

阈值类型/单机阈值:
QPS:每秒请求数量,当超过该值时进行限流
线程数:当调用该 api 的线程数到达该阈值时,进行限流。(当所有线程都在工作,没有空闲线程时,线程数才会增加)

流控模式:
直接:api 达到限流条件时,直接限流
关联:当关联的 API 资源 A 达到限流值时,就限流自己 R,不会限流 A。(如支付接口达到限流条件时,限流下单接口)
链路:只记录配置的入口资源,到流控;其他入口不计入流控规则中。(暂时没实验成功?????????)

流控效果:
快速失败:达到限流规则后,直接抛出 FlowException。适用于对系统处理能力确切已知的情况下。
Warm up:让通过的流量缓慢增加,在一定时间内逐渐增加到阈值上限,给冷系统一个预热的时间。默认 coldFactor 为 3,即请求 QPS 从 threshold / 3 开始,经预热时长逐渐升至设定的 QPS 阈值
匀速排队:严格控制请求通过的间隔时间,即让请求按设置的 QPS 值,以均匀的速度通过。

熔断降级
  除了流量控制以外,对调用链路中不稳定的资源进行熔断降级也是保障高可用的重要措施之一。


降级策略:

RT 平均响应时长:当 1s 内持续进入 N 个请求,其平均响应时间超过阈值,触发熔断,在接下来的时间窗口中执行降级方法。

异常比例:当资源的每秒请求量 >= N(可配置),并且每秒异常总数与通过量的比值超过阈值之后,触发熔断。

异常数:当资源近 1 分钟的异常数目超过阈值之后会进行熔断。注意由于统计时间窗口是分钟级别的,若 timeWindow 小于 60s,则结束熔断状态后仍可能再进入熔断状态(即时间窗口的配置需要大于 60 s)。

热点参数限流


解释:

该图表示在时间窗口2s内,对该资源的指定 参数索引 访问量超过 阈值 后,触发该资源对应的熔断,但当该参数值为2时,其对应的阈值为200。

热点参数限流会对设置的参数索引或包含该索引的请求进行限流。

参数例外项是为了实现 当参数是某个特殊值时,它的限流值和普通限流阈值不一样。

blockHandler 指向的方法,只负责 hotkey 抛出的 BlockException ,即只负责 sentinel 控制台配置的违规情况,其他情况的异常,需要自行处理,如果没有处理则会被抛出到调用方。
系统自适应限流

  系统自适应限流是从整体维度对应用入口流量进行控制,追求的目标是 在系统不被拖垮的情况下,提高系统的吞吐率,而不是 load 一定要到低于某个阈值,因为阈值的设置,会有延迟的特性,无法取得很好的效果。

@SentinelResource的使用

   blockHandler 对应处理 BlockException 类型的异常,即 sentinel 控制台配置规则的违规情况;fallback 处理抛出异常的时候提供 fallback 处理逻辑,即业务代码运行时的异常情况。

限流阻塞方法的指定
...
@SentinelResource(value = "hotkeyRes", blockHandler = "blockHotKey")
...

//blockHandler参数类型要和源方法保持一致
public String blockHotKey(Integer id, Integer p, BlockException e) {
    return "blockHotKey.system is :blocked by Sentinel flow limiting";
}

该种限流方法,业务代码和阻塞逻辑在同一个类种,带来的问题有:

业务代码与限流阻塞方法代码耦合度高
为了解决该问题,可以选用如下的方式指定 blockHandler 的处理。

...
@SentinelResource(value = "hotkeyRes",blockHandlerClass = ConsumerBlockClass.class,blockHandler = "blockHotKey")
...

ConsumerBlockClass:

//blockHotKey参数类型要和源方法保持一致或加一个 Throwable 类型的参数;该函数必须是 static 函数.
public static String blockHotKey(Integer id, Integer p, BlockException e) {
    return "blockHotKey.system is :blocked by Sentinel flow limiting";
}

结论:
  超过 dashboard 的流控规则后,同一时间窗口的请求会进入到 blockHandler 指定的方法中

异常降级方法指定
  业务异常降级方法的指定,编码和上面的一致,只是 blockHandler 修改为 fallback 。

结论:
  超过 dashboard 的降级规则后,触发异常的请求进入到 fallback 指定的方法中;正常的访问请求,也会进入到 fallback 指定的方法中

限流阻塞方法和异常降级方法都指定
结论:
  dashboard 中不指定流控规则,只指定降级规则情况下,当超过流控规则后,所有的请求都会进入到 blockHandler 指定的方法中

异常忽略
@SentinelResource(value = "hotkeyRes",
    exceptionsToIgnore = {IllegalArgumentException.class,RuntimeException.class})
1
2
  用于指定哪些异常被排除掉,不会计入异常统计中,也不会进入 fallback 逻辑中,而是会原样抛出。

Sentinel规则持久化
为什么需要?

  Dashboard 的推送规则方式是通过 API 将规则推送至,客户端并直接更新到内存中,所以应用重启,对应的规则就会消失。

选用什么方式完成持久化?

  为实现规则更新后,能够被客户端及时感知到,采用规则中心统一推送,客户端通过注册监听器的方式时刻监听变化。
  规则中心可以使用 Nacos、Zookeeper 、自研等数据源。
 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值