什么是Springboot ?
1.用来简化spring初始搭建和开发中使用特定的方式进行配置 (yml properties)
2.启动方式为main方法启动
3.嵌入tomcat容器 无需war包就可启动 直接jar包 nohup java -jar -项目
4.简化了maven的配置
5.自动配置spring添加对应的starter自动化配置
SpringBoot常用的starter
1.spring-boot-starter-web
2.spring-boot-starter-data-jpa (数据库)
3.spring-boot-starter-data-solr
4.spring-boot-starter-data-redis
5.mybatis-spring-boot-starter
SpringBoot自动装配的原理
1.@EnableAutoConfiguration这个注解会猜你如何配置spring ,比如:你添加了spring-boot-starter-web依赖(tomcat springmvc) 这个注解会认为你在开发一个web项目并添加相应的spring配置,会自动去maven里读取每个starter中的spring.factories文件,这个文件里包含了所有需要被创建的spring容器的bean
2.main方法中加上 @SpringBootApplication
SpringBoot starter原理
1.springboot在启动项目时会扫描jar包 ,并找寻每个依赖的 spring.factories文件中的jar
2.根据spring.factories配置加载AutoConfigure
3.根据@Conditional注解的条件 进行自动配置并将bean注入到Spring容器中
拓展:@Conditional注解
a.ConditionalOnBean("RedisConnectionFactory") 若果你配置了Redis相关依赖,就会实例化RedisTemplate进行操作,如果没有 ,就不实例化
@Bean
@ConditionalOnBean(RedisConnectionFactory.class)
public RedisTemplate redisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate template = new RedisTemplate();
template.setConnectionFactory(connectionFactory);
template.setKeySerializer(new StringRedisSerializer());
template.afterPropertiesSet();
return template;
}
b.ConditionalOnMissingBean("")这个注解比较骚 顾名思义就是不存在某个bean的时候实例化
c.ConditionalOnClass 存在某个类的时候实例化
d.ConditionalOnMissingClass 不存在某个类的时候实例化
e.ConditionalOnJava 如果是Java应用的话实例化
f.ConditionalOnWebApplication 如果是web应用的话 虚拟化
SpringBoot的优点
1.配置简单,用少量的配置文件就可以搭建完整项目
2.避免了大量的maven导入导致jar冲突
3.内置tomcat/jetty容器
SpringCloud微服务
SpringCloud解决了哪些问题:
配置管理,注册中心(Eureka,Zookeeper,Consul),服务发现,服务注册,断路器,路由策略,全局锁,分布式会话,客户端调用(RestTemplate Feign) ,接口网关(zuul) ,服务管理系统
SpringBoot和SpringCloud关系
1.springboot简化了xml配置,能够快速整合框架
2.SpringCloud是一套完整的微服务解决方案
3.SpringCloud依赖于SpringBoot (SpringCloud服务与服务之间的调用协议为 http+json 而 springmvc就 http+json , SpringBoot默认集成springmvc)
4.SpringBoot的配置文件 (yml/properties)可以通过${} 来取得配置文件中的内容
SpringCloud服务调用方式(Rest,feign) ,负载均衡 ribbon
ribbon原理 取模 完全可以手写类似于ribbon的功能
SpringCloud服务调用原理
application.yml配置文件中会配置该服务的别名 比如member服务
服务启动时会将此别名以key的形式注册到eureka中 值为此服务的 ip+端口
调用时会通过该别名取出值 来进行访问
高可用注册中心 (Eureka集群)
原理:你中有我,我中有你
将自己作为服务注册到另一个注册中心里
微服务的特点:
按业务划分为一个独立运行的程序
服务之间通过http互相通信
自动化部署
可以用不同的编程语言
可以用不同的存储技术
服务集中化管理
微服务的优势:
1.将一个复杂的业务拆分为若干小的业务,讲复杂的业务简单化,新人只需要了解他所接管的服务的代码,减少学习成本
2.服务与服务之间没有任何耦合 单个服务内部高度耦合 服务与服务之间互相独立运行 两个服务可以采用不同的语言进行开发
3.微服务是按照业务进行拆分的 如果说要重写某个业务代码 不需要了解整个业务 只需重写这个服务代码
4.每个服务都是单独部署的 某个服务进行修改和部署 对系统不会造成影响
5.微服务可以高可用集群 比如:member服务可以搭建集群 (分别部署在 8001 8002 8003 端口 ,ribbon可以实现负载均衡,实现高可用)
微服务的不足:
1.构建一个微服务项目比较复杂 ,服务之间采用http协议或者其他交互协议进行通信,开发者要选择合适的协议 并解决网络服务差是带来的风险
2.分布式事务:将事务分为多阶段提交,如果一阶段的某个节点失败 会导致数据不正确 ,如果某个节点的网络出现异常会到这整个事务处于阻塞状态,大大降低了数据库的性能
3.服务的划分:需要根据不同的业务场景来拆分出不同的服务 非常之麻烦
4.服务的部署:最佳部署容器为docker
微服务和soa的关系:
微服务是SOA的一种体现 也是面向服务的思想
SpringCloud如何实现服务的注册和发现
服务发布时指定对应的服务名(IP地址和端口号),将服务注册到注册中心(eureka和zookeeper),但是这一切是Springcloud自动实现的,只需要在SpringBoot的启动类上加上@EnableEurekaClient注解,同一服务修改端口就可以启动多个实例调用方法:传递服务名称通过注册中心获取所有的可用实例,通过负载均衡策略(Ribbon和Feign)调用对应的服务
Ribbon和Feign的区别:
Ribbon添加的maven依赖是spring-starter-ribbon,使用@RibbonClient(value=“服务名称”)使用RestTemplate调用远程服务对应的方法,
Feign添加的maven依赖是spring-starter-feign,服务提供方提供对外接口,调用方使用,在接口上使用FeignClient(“指定服务名”),
雪崩效应:
微服务项目中 服务与服务之间的通信依赖于网络 网络波动 会对分布式系统带来很大的影响 。服务与服务之间互相依赖,如果一个服务出现了故障或者网络延迟,在高并发的情况下,会导致线程阻塞,在很短的时间内线程资源会耗尽,最终导致该服务不可用,由于服务于服务之间相互依赖,可能导致整个系统不可用,这就是雪崩效应。
措施:熔断机制:(hystrix)
熔断机制(hystrix)
1.当一个服务出现故障或者网络波动时,请求失败的次数超过设定的阈值(默认为50次)之后,服务就会开启熔断器,之后该服务不进行任何业务逻辑操作,直接快速失败,直接返还请求失败的信息。其他依赖于该服务的服务就不会因为得不到响应而线程阻塞,除了该服务和依赖于该服务的部分功能不可用外,其他服务正常。
2.熔断器有个自我修复机制,当一个服务熔断以后,经过一段时间(5s)“半”打开熔断器。半打开的熔断器会坚持一部分请求(1个)是否正常,其他请求继续执行快速失败,检查的请求如果响应成功,则可判断该服务正常,则关闭改服务的熔断器,反之则继续打开熔断器。 熔断机制和自我修复机制使得程序更加健壮
3.熔断器会提供一系列的监控服务,比如:服务是否可用 ,熔断器是否打开,目前服务吞吐量(原理 :jmeter),当前网络延迟状态等监控
Eureka详解
1.服务注册中心:Eureka提供服务端(Eureka-Server),提供服务的注册于发现功能
2.Eureka失效剔除:对于那些非正常下线的服务(内存溢出,网络故障),服务注册中心收不到服务下线的请求,为了剔除这些无法提供服务的实例,Eureka在启动时会创建一个定时任务,默认60秒将失效服务剔除
3.Eureka自我保护机制:Eureka Server在运行期间,会统计心跳失败的比例在15分钟内是否低于85%
我们在单机测试的时候很容易满足心跳失败比例在 15 分钟之内低于 85%,这个时候就会触发 Eureka 的保护机制,
一旦开启了保护机制,则服务注册中心维护的服务实例就不是那么准确了,此时我们可以使用eureka.server.enable-self-preservation=false来关闭保护机制,这样可以确保注册中心中不可用的实例被及时的剔除(不推荐)。
如何计算心跳失败的比例?
自我保护模式被激活的条件是:在 1 分钟后,Renews (last min) < Renews threshold。
Renews threshold: Eureka Server 期望每分钟收到客户端实例续约的总数
Renews (last min):Eureka Server 最后一分钟收到客户端实例续约的总数
从上图我们可以看到 部署了3个Eureka Server ,另外又部署了7个服务 总计为10
- Renews threshold:17
- Renews (last min):20
那么问题来了 如何计算这两个值???????
Renews threshold 计算代码:
this.expectedNumberOfRenewsPerMin = count * 2; //count表示服务的数量 this.numberOfRenewsPerMinThreshold = (int) (this.expectedNumberOfRenewsPerMin * serverConfig.getRenewalPercentThreshold());
//serverConfig.getRenewalPercentThreshold()默认为0.85 这个值可以配置
因此可以计算出Renews threshold 的值 (int)(1020.85)=(int)17=17
Renews (last min) 计算代码:
count * 2 数字“2“表示 每30秒1个心跳,每分钟2个心跳,总计10个服务,所以为10*2=20
如果在一分钟之后 Renews (last min) < Renews threshold ,默认需等待5分钟,也就是5分钟之后你会看到下面的信息:
3.服务提供者:
服务注册: 启动项目时会将服务实例封装到双层map中
外层 key:服务名 value:map(服务实例名称,服务的访问地址)
服务同步:若有两个或两个以上的Eureka Server(服务注册中心)时,他们之间是互相注册的,当服务提供者发送 注册请求到一个服务注册中心时,它会将该请求转发到集群中相连的其他注册中心,从而实现注册中心间的服务同步,这样服务提供者的服务信息可以通过任意一台服务中心获取到
服务消费:Ribbon 或者 Feign
Ribbon (RestTemplete )
Feign (@FeignClient("实例名称"))
Eureka和zookeeper都可以提供服务注册与发现的功能,两者的区别:
CAP原则又称CAP定理,指的是在一个分布式系统中,Consistency(一致性)、 Availability(可用性)、Partition tolerance(分区容错性),三者不可得兼
分布式系统的CAP理论:理论首先把分布式系统中的三个特性进行了如下归纳:
一致性(C):在分布式系统中的所有数据备份,在同一时刻是否同样的值。(等同于所有节点访问同一份最新的数据副本)
可用性(A):在集群中一部分节点故障后,集群整体是否还能响应客户端的读写请求。(对数据更新具备高可用性)
分区容错性(P):以实际效果而言,分区相当于对通信的时限要求。系统如果不能在时限内达成数据一致性,就意味着发生了分区的情况,必须就当前操作在C和A之间做出选择。
Zookeeper保证了CP(C:一致性,P:分区容错性),Eureka保证了AP(A:高可用,P:分区容错)
1、Zookeeper-----当向注册中心查询服务列表时,我们可以容忍注册中心返回的是几分钟以前的信息,但不能容忍直接down掉不可用的。也就是说服务注册功能对高可用性要求比较高,但是zk会出现这样的一种情况,当master节点因为网络故障与其他节点失去联系时,剩余的节点会重新选leader。问题在于,选取leader的时间过长(30~120s),且选取期间zk集群都不可用,这样就会导致选取期间注册服务瘫痪。在云部署的环境下,因网络问题使得zk集群失去master节点是较大概率会发生的事,虽然服务最终恢复,但是漫长的选择时间导致的注册长期不可用是不能容忍的
用CAP理论来分析ZooKeeper
CAP理论告诉我们,一个分布式系统不可能同时满足以下三种
一致性(C:Consistency)
可用性(A:Available)
分区容错性(P:Partition Tolerance)
这三个基本需求,最多只能同时满足其中的两项,因为P是必须的,因此往往选择就在CP或者AP中。
在此ZooKeeper保证的是CP
分析:可用性(A:Available)
不能保证每次服务请求的可用性。任何时刻对ZooKeeper的访问请求能得到一致的数据结果,同时系统对网络分割具备容错性;但是它不能保证每次服务请求的可用性(注:也就是在极端环境下,ZooKeeper可能会丢弃一些请求,消费者程序需要重新请求才能获得结果)。所以说,ZooKeeper不能保证服务可用性。
进行leader选举时集群都是不可用。在使用ZooKeeper获取服务列表时,当master节点因为网络故障与其他节点失去联系时,剩余节点会重新进行leader选举。问题在于,选举leader的时间太长,30 ~ 120s, 且选举期间整个zk集群都是不可用的,这就导致在选举期间注册服务瘫痪,虽然服务能够最终恢复,但是漫长的选举时间导致的注册长期不可用是不能容忍的。所以说,ZooKeeper不能保证服务可用性。
2、Eureka则看明白这一点,因此再设计的优先保证了高可用性。Eureka各个节点都是平等的,几个节点挂掉不会影响到正常节点的工作,剩余的节点依然可以提供注册和查询服务。而Eureka的客户端再向某个Eureka注册时如果发现连接失败,则会自动切换至其他节点,只要有一台Eureka还在,就能保证注册服务的可用(保证可用性),只不过查到的信息可能不是最新的(不保证一致性)。除此之外Eureka还有一种自我保护机制,如果在15分钟内超过85%的节点都没有正常心跳,那么Eureka就认为客户端与注册中心出现了网络故障,此时就会出现以下几种情况:
1>、Eureka不再从注册列表移除因为长时间没收到心跳而应该过期的服务
2>、Eureka仍然能够接受新服务的注册和查询请求,但是不会被同步到其它节点上(保证当前节点可用)
3>、当网络稳定时,当前实例新的注册信息会被同步到其它节点中
Eureka还有客户端缓存功能(Eureka分为客户端程序和服务器端程序两个部分,客户端程序负责向外提供注册与发现服务接口)。所以即便Eureka集群中所有节点都失效,或者发生网络分隔故障导致客户端不能访问任何一台Eureka服务器;Eureka服务的消费者任然可以通过Eureka客户端缓存来获取所有的服务注册信息。甚至最极端的环境下,所有正常的Eureka节点都不对请求产生响应也没有更好的服务器解决方案来解决这种问题时;得益于Eureka的客户端缓存技术,消费者服务仍然可以通过Eureka客户端查询与获取注册服务信息,这点很重要,因此Eureka可以很好的应对网络故障导致部分节点失去联系的情况,而不像Zookeeper那样使整个注册服务瘫痪。
Ribbon和Nginx的区别:
Nginx性能好,但Ribbon可以剔除不健康节点,Nginx剔除比较麻烦,Ribbon是客户端负载均衡,Nginx是服务端负载均衡
分布式事务:???
其中一种jta-atomikos(底层 2PC)