SpringCloud
SpringCloud
回顾
三层架构 + MVC
框架:
Spring IOC AOP
SpringBoot:新一代的JavaEE开发标准,自动装配 ---》模块化
微服务框架4个核心问题?
1.服务很多,客户端该怎么访问?
2.这么多服务?服务之间如何通信?
3.这么多服务?如何治理? eureka
4.服务挂了怎么办?
解决方案:
Spring Cloud 生态! SpringBoot
1、Spring Cloud NetFlix --- 一站式解决方案
Api网关 zuul组件
Feign ---HttpClinet --- Http通信方式,同步,阻塞
服务祖册发现:Eureka
熔断机制:Hystrix
...
2、Apache Dubbo Zookeeper --- 半自动,需要整合别人的
API:没有,找第三方组件,或者自己实现
Dubbo
Zookeeper
没有:借助 Hystrix
Dubbo这个方案并完善~
3、Spring Cloud Alibaba --- 最新的一站式解决方案!更简单!
新概念:服务网格~ service Mesh --》 istio
万变不离其宗
1、API
2、HTTP RPC
3、注册和发现
4、熔断机制
根本原因:网络不可靠~
常见面试题
- 什么是微服务?
微服务架构是一种架构模式,或者说是一种架构风格,它提倡将单一的应用程序划分成一组小的服务,每个服务独立运行,服务之间互相协调,互相配置。每个服务都围绕着具体的业务进行构建,并且能够独立的部署到生产中。
微服务的核心就是将传统的一站式应用,根据业务拆分成一个一个的服务,彻底地去解耦,每个微服务提供单个业务功能的服务,一个服务做一件事情,从技术角度看就是一种小而独立的处理过程,类似进程的概念,能够自行单独启动或者销毁,拥有自己独立的数据库。
- 微服务之间如何独立通信的?
- SpringCloud和Dubbo有哪些区别?
- Springboot和SpringCloud,请谈谈对他们的理解
- 什么是服务熔断?什么是服务降级、
- 微服务的优缺点分别是什么?说下你在项目开发中遇到的坑?
优点
1、单一职责原则
2、每个服务足够内聚,足够小,代码容易理解,这样能聚焦一个指定的业务功能或业务需求;
3、开发简单,开发效率提高,一个服务可能就专一的只干一件事情
4、微服务能够被小团队单独开发,这个小团队2-5开发人员组成
5、微服务是松耦合的,有功能意义的服务,无论是在开发阶段或部署阶段都是独立的。
6、微服务能使用不同的语言开发
7、易于和第三方集成,微服务允许容易且灵活的方式集成自动部署,通过持续集成工具,如jenkins、Hudson、bamboo
8、微服务易于被一个开发人员理解,修改和维护,这样小团队能够更关注自己的工作成果。无需通过合作才能体现价值。
9、微服务允许你利用融合最新技术
10、微服务只是业务逻辑的代码,不会和HTML、CSS或者其他界面混合
11、每个微服务都有自己的存储能力,可以有自己的数据库,也可以有统一数据库
缺点
1、开发人员要处理分布式系统的复杂性
2、多服务运维难度,随着服务的增加,运维的压力也在增大
3、系统部署依赖
4、服务间通信成本
5、数据一致性
6、系统集成测试
7、性能监控...
-
你所指的微服务技术栈有哪些?请列举一二
-
eureka和zookeeper都可提供服务注册与发现的功能,请说说两个区别?
什么是SpringCloud
SpringCloud,基于Springboot提供了一套微服务解决方案,包括服务注册与发现,配置中心,全链路监控,服务网关,负载均衡,熔断器等组件,除了基于NetFlix的开源组件做高度抽象封装之外,还有一些选型中立的开源组件。
SpringCloud利用Springboot的开发便利性,巧妙地简化了分布式系统基础设施的开发,SpringCloud为开发人员提供了快速构建分布式系统的而一些工具,包括配置管理,服务发现,断路器,路由,微代理,事件总线,全局锁,决策竞选,分布式会话等等,他们都可以用Springboot的开发风格做到一键启动和部署。
SpringCloud是分布式微服务架构下的一站式解决方案,是各个微服务架构落地技术的集合体,俗称微服务全家桶。
SpringBoot和SpringCloud关系
- Springboot专注于快速方便的开发单个个体微服务
- SpringCloud是关注全局的微服务协调整理治理框架,它将Springboot开发的一个个单体微服务整合并管理起来,各个微服务之间提供:配置管理,服务发现,断路器,路由,微代理,事件总线,全局锁,决策竞选,分布式会话等等集成服务。
- Springboot可以离开SpringCloud独立使用,开发项目,但是SpringCloud离不开SpringBoot,属于依赖关系
- Springboot专注于快速、方便的开发当个个体微服务,SpringCloud关注全局的服务治理框架。
Dubbo和SpringCloud技术选型
可以看下社区活跃度
https://github.com/spring-cloud
结果
Dubbo | Spring | |
---|---|---|
服务注册中心 | Zookeeper | Spring Cloud Netflix Eureka |
服务调用方式 | RPC | Rest API |
服务监控 | Dubbo-monitor | Spring Cloud Admin |
断路器 | 不完善 | Spring Cloud Neflix Hystrix |
服务网关 | 无 | Spring Cloud Netflix Zuul |
分布式配置 | 无 | Spring Cloud Config |
服务跟踪 | 无 | Spring Cloud Sleuth |
消息总线 | 无 | Spring Cloud Bus |
数据流 | 无 | Spring Cloud Stream |
批量任务 | 无 | Spring Cloud Task |
最大区别:SpringCloud抛弃了Dubbo的RPC通信,采用的是基于HTTP的REST方式
REST相比RPC更为灵活,服务提供方和调用方的依赖只依靠一纸契约,不存在代码级别的强依赖,这在强调快速演化的微服务环境下,显得更加合适。
解决的问题域不一样:Dubbo的定位是一款RPC框架,SpringCloud的目标是微服务架构下的一站式解决方案
SpringCloud是一个由众多独立子项目组成的大型综合项目,每个子项目有不同的发行节奏,都维护着自己的发布版本号。SpringCloud通过一个资源清单BOM(bill of materials)来管理每个版本的子项目清单。为避免与子项目的发布号混淆,所以没有采用版本号的方式,而是通过命名的方式。
这些版本名称的命名方式采用了伦敦地铁站的名称,同时根据字母表的顺序来对应版本时间顺序,比如;最早的Release版本:Angel,第二个Release版本:Brixton,然后是Camden、Dalston、Edgware,目前最新的是Finchley版本。
参考网站:
- https://springcloud.cc/spring-cloud-netflix.html
- 中文API文档:https://springcloud.cc/spring-cloud-dalston.html
- SpringCloud中国社区:https://springcloud.cn/
- SpringCloud中文网:https://springcloud.cc
SpringCloud的版本选择
RestFul
Eureka服务注册与发现
什么是Eureka?
- 读:you rui ka
- Netflix 在设计Eureka是,遵循的就是AP原则
- Eureka是Netflix的一个子模块,也是核心模块之一,Eureka是一个基于REST的服务,用于定位服务,已实现云端中间层服务发现和故障转移,服务注册与发现对于微服务来说是非常重要的,有了服务发现与注册,只需要使用服务的标识符,就可以访问到服务,而不需要修改服务调用的配置文件了,功能类似于Dubbo的注册中心,比如ZooKeeper.
原理讲解
-
Eureka的基本架构
-
SpringCloud 封装了NetFlix公司开发的Eureka模块来实现服务注册中心(对比Zookeeper)
-
Eureka 采用了C-S的架构设计,EurekaServer 作为服务注册功能的服务器,他就是服务注册中心
-
而系统中的其他微服务,使用Eureka的客户端连接到EurekaServer并维持心跳连接。这样系统的维护人员就可以通过EurekaServer来监控系统中各个微服务是否正常运行,SpringCloud的一些其他模块(比如Zuul)就可以通过EurekaServer来发现系统中的其他微服务,并执行相关逻辑。
-
和Dubbo架构对比
-
-
Eureka包含两个组件:Eureka Server 和 Eureka Client
-
Eureka Server 提供服务注册服务,各个节点启动后,会在Eureka Server中进行注册,这样Eureka Server中的服务注册表中将会存储所有可用服务节点的信息,服务节点的信息可以在界面中直观的看到。
-
Eureka Client 是一个Java客户端,用于简化Eureka Server的交互,客户端同时也具备一个内置的,使用轮询负载算法的负载均衡器。在应用启动后,将会向Eureka Server发送心跳(默认周期为30s)。如果Eureka Server在多个心跳周期内没有收到某个节点的心跳。Eureka Server将会从服务注册表中把这个服务节点移除掉(默认周期为90s)。
-
三大角色
- Eureka Server:提供服务的注册与发现 Zookeeper
- Service Provider:将自身服务注册到Eureka中,从而使消费方能够找到
- Servide Consumer:服务消费方从Eureka中获取注册服务列表,从而找到消费服务。
eureka server配置yml
server:
port: 7001
eureka:
instance:
hostname: localhost #Eureka服务端的实例名
client:
register-with-eureka: false #表示是否向Eureka注册中心注册自己
fetch-registry: false #fetch-registry为false 表示自己是一个注册中心
service-url: # 注册中心页面 fangwen http://localhost:7001
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka
eureka server的pom
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
eureka server开启注解
@EnableEurekaServer
eureka client配置yml
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka
instance:
#修改eureka上的默认描述信息
instance-id: springcloud-provider-summer-test-8083
#可以显示服务的ip
prefer-ip-address: true
eureka client的pom
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<version>3.0.3</version>
</dependency>
eureka client开启注解
@EnableEurekaClient
eureka自我保护机制
一句话总结:某时刻某一个微服务不可以用了,eureka不会立刻清除,依旧会对该微服务的信息进行保存!
- 默认情况下,如果EurekaServer在一定时间内没有接口到某一个微服务实例的心跳,EurekaServer将会注销该实例(默认90秒)。但是当网络分区故障发生时,微服务与Eureka之间无法正常通行,以上行为可能变得非常危险了--因为微服务本身其实是健康的,此时本不应该注销这个服务。Eureka通过自我保护机制来解决这个问题--当EurekaServer节点在短时间内丢失过多客户端时(可能发生了网络分区故障),那么这个节点就会进入自我保护模式。一旦进入该模式,EurekaServer就会保护服务注册表中的信息,不再删除服务注册表中的数据(也就是不会注销任何微服务)。当网络故障恢复后,该EurekaServer节点会自动退出自我保护模式。
- 在自我保护模式中,EurekaServer会保护服务注册表中的信息,不再注销任何服务实例。当它收到的心跳数重新恢复到阈值以上时,该EurekaServer节点就会自动退出自我保护模式。它的设计哲学就是宁可保留错误的服务注册信息,也不盲目注销任何可能健康的服务实例。一句话:好死不如赖活着。
- 综上,自我保护模式是一种应对网络异常的安全保护措施 。自我保护模式可以让Eureka集群更加的健壮和稳定
- 在SpringCloud中,可以使用
eureka.server.enable-self-preservation=false
禁用自我保护模式【不推荐关闭自我保护机制】
Eureka集群
server集群yml配置:
server:
port: 7001
eureka:
instance:
hostname: eureka7001 #Eureka服务端的实例名
client:
register-with-eureka: false #表示是否向Eureka注册中心注册自己
fetch-registry: false #fetch-registry为false 表示自己是一个注册中心
service-url: # 注册中心页面 fangwen http://localhost:7001
defaulZone: http://eureka7002:7002/eureka,http://eureka7003:7003/eureka
spring:
application:
name: summer7001
client注册集群yml配置:
eureka:
client:
service-url:
defaultZone: http://eureka7002:7002/eureka/,http://eureka7003:7003/eureka/,http://eureka7001:7001/eureka/
instance:
#修改eureka上的默认描述信息
instance-id: springcloud-summer-test-8083
Eureka对比Zoomkeeper
回顾CAP原则
RDBMS(MySQL Oracle sqlServer)====》ACID
NoSQL(Redis mongodb)====》CAP
ACID原则
- A(Atomicity)原子性
- C(Consistency)一致性
- I(Isolation)隔离性
- D(Durability)持久性
CAP原则
- C(consistency)强一致性
- A(Aviailability)可用性
- P(Partition tolerance)分区容错性
CAP理论的核心
- 一个分布式系统不可能同时很好的满足一致性,可用性和分区容错性这三个需求
- 根据CAP原则,将NoSQL数据库分为了CA CP AP 三类
- CA:单点集群,满足一致性,可用性的系统,通常可扩展性较差
- CP:满足一致性,分区容错性的系统,通常可用性不是很高
- AP:满足可用性,分区容错性的系统,通常可能对一致性要求低一点
作为服务注册中心,Eureka比Zookeeper好在哪里?
著名的CAP理论指出,一个分布式系统不可能同时满足 C A P
由于分区容错性P在分布式系统中是必须要保证的,因此我们只能在AC之间进行权衡
- Zookeeper保证的是CP
- Eureka保证的是AP
Zookeeper保证的是CP
当向注册中心查询服务列表时,我们可以容忍注册中心返回的是几分钟以前的注册信息,但不能接受服务直接down掉不可用。也就是说,服务注册功能对可用性的要求一致性的要求要高于可用性。但是ZK会出现这样一种情况,当master节点因为网络故障与其他节点失去联系时,剩余节点会重新进行leader选举。问题在于,选举leader的时间太长,30~120s,且选举期间整个ZK集群都是不可用的,这就导致在选举期间注册服务瘫痪。在云部署的环境下,因为网络问题使得ZK集群失去master节点是较大概率会发生的事件,虽然服务最终能够恢复,但是漫长的选举时间导致的注册长期不可用是不能容忍的。
Eureka保证的是AP
Eureka看明白了这一点,因此在设计时就优先保证可用性。Eureka各个节点都是平等的。几个节点挂掉不会影响正常工作,剩余的节点依然可以提供注册和查询服务。而Eureka的客户端在向某个Eureka注册时,如果发现连接失败,则会自动切换至其他节点,只要有一台Eureka还在,就能保证注册服务的可用性,只不过查到的信息可能不是最新的,除此之外,Eureka还有一种自我保护机制,如果在15分钟内超过85%的节点都没有正常的心跳,那么Eureka就认为客户端与注册中心出现了网络故障,此时会出现一下几种情况:
1、Eureka不在从注册列表中移除因为长时间没收到心跳而应该过期的服务
2、Eureka仍然能够接受新服务的注册和查询请求,但是不会被同步到其他节点上(即保证当前节点依然可用)
3、当网络稳定时,当前实例新的注册信息会被同步到其他节点中
因此,Eureka可以很好的因对因网络故障导致部分节点失去联系的情况,而不会像zookeeper那样使整个注册服务瘫痪
Ribbon负载均衡
ribbon是什么?
- SpringCloud Ribbon是基于Netflix Ribbon实现的一套 客户端负载均衡的工具
- 简单的说,ribbon是Netflix发布的开源项目,主要功能是提供客户端的软件负载均衡算法,将Netflix的中间层服务连接在一起。ribbon的客户端组件提供一系列完成的配置项,如:连接超时、重试等等。简单的说,就是在配置文件中列出LoadBalancer(简称LB:负载均衡)后面所有的机器,ribbon会自动的帮助你基于规则(如简单轮询,随机连接等等)去连接这些机器。我们也很容器使用ribbon实现自定义的负载均衡算法。
ribbon能干嘛?
- LB,即负载均衡(load balance),在微服务或者分布式集群中经常用的一种应用
- 负载均衡简单的说就是将用户的请求平摊的分配到多个服务上,从而达到系统的HA(高可用)
- 常见的负载均衡软件有nginx,lvs等等
- dubbo、springcloud中均给我们提供了负载均衡,springcloud的负载均衡算法可以自定义
- 负载均衡简单分类:
- 集中式LB
- 即在服务的消费方和提供方之间使用独立的LB设施,如Nginx:反向代理服务器!由该设施负责把访问请求通过某种策略转发至服务的提供方!
- 进程式LB
- 将LB逻辑集成到消费方,消费方从服务注册中心获知有哪些地址可用,然后自己再从这些地址中选出一个合适的服务器。
- ribbon就属于进程内LB,它只是一个类库,集成于消费方进程,消费方通过它来获取到服务方的地址!
- 集中式LB
ribbon的pom依赖
报错:No instances available for XXX
原因:由于Eureka_Client中存在了负载均衡的依赖,而我在依赖中又导入了Ribbon造成依赖冲突
<!-- netflix-eureka-client中集成了ribbon所以不需引入依赖了,否则会冲突-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<version>3.0.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-netflix-ribbon -->
<!-- <dependency>-->
<!-- <groupId>org.springframework.cloud</groupId>-->
<!-- <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>-->
<!-- <version>2.2.6.RELEASE</version>-->
<!-- </dependency>-->
controller
package com.example.demo.contrller;
import com.example.demo.pojo.Dog;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestOperations;
import org.springframework.web.client.RestTemplate;
import java.util.List;
@RestController
public class DemoController {
@Autowired
private Dog dog;
@Autowired
private DiscoveryClient client;
@Autowired
// private RestTemplate restTemplate;
private RestOperations restTemplate;
private static final String REST_URL_PREFIX="http://SUMMER";
@GetMapping("/hello")
private String sayHello() {
System.out.println(dog.getName());
System.out.println(dog.getAge());
return "hello guys,welcome to spring boot!";
}
@GetMapping("/discovery")
private Object discovery() {
List<String> services = client.getServices();
System.out.println(services);
List<ServiceInstance> summer = client.getInstances("SUMMER");
for (ServiceInstance serviceInstance : summer) {
System.out.println(serviceInstance.getInstanceId() + "\n" +
serviceInstance.getHost() + "\n" +
serviceInstance.getPort() + "\n" +
serviceInstance.getUri());
}
return this.client;
}
//---------------------------restful consummer-----------------
@RequestMapping("/discovery/rest")
public Object discoveryRest(){
return restTemplate.getForEntity(REST_URL_PREFIX+"/discovery",Object.class);
}
@RequestMapping("/hello/rest")
public String sayHelloRest(){
return restTemplate.getForObject(REST_URL_PREFIX+"/hello",String.class);
}
}
config
package com.example.demo.config;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestOperations;
import org.springframework.web.client.RestTemplate;
@Configuration
public class ConfigBean {
//配置负载均衡实现RestTemplate
@Bean
@LoadBalanced//ribbon
// public RestTemplate getRestTemplate() {
// return new RestTemplate();
// }
public RestOperations getRestTemplate(RestTemplateBuilder builder) {
return builder.build();
}
}
结论
Ribbon和Eureka整合以后,客户端可以直接调用,不用关系ip地址和端口号
Ribbonz自定义负载均衡算法
默认是轮询算法
主要接口类IRule
package com.netflix.loadbalancer;
public interface IRule {
Server choose(Object var1);
void setLoadBalancer(ILoadBalancer var1);
ILoadBalancer getLoadBalancer();
}
// IRule
// RoundRobinRule ==> 轮询访问
// RandomRule ==> 随机访问
// AvailabilityFilteringRule ==>会先过滤掉跳闸即访问故障的服务,对剩下的服务进行轮询
// RetryRule ==> 会先按照轮询获取服务~如果服务获取失败,则会在指定的时间内进行重试
自定义步骤
step1:pom依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<version>3.0.3</version>
<!-- <exclusions>-->
<!-- <exclusion>-->
<!-- <groupId>org.springframework.cloud</groupId>-->
<!-- <artifactId>spring-cloud-starter-loadbalancer</artifactId>-->
<!-- </exclusion>-->
<!-- </exclusions>-->
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
<version>2.2.6.RELEASE</version>
</dependency>
step2:继承类重写方法
RibbonRule
package com.example.myrule;
import com.netflix.loadbalancer.IRule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RibbonRule {
@Bean
public IRule myRule(){
return new SummerRandomRule();
}
}
SummerRandomRule
package com.example.myrule;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractLoadBalancerRule;
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.Server;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
/**
* A loadbalacing strategy that randomly distributes traffic amongst existing
* servers.
*
* @author stonse
*/
public class SummerRandomRule extends AbstractLoadBalancerRule {
/**
* 每个服务 访问五次 换下一个服务
* <p>
* total=0 默认等于0 如果等于5 指向下一个服务节点
* index
*/
private static int total = 0;
private static int currentIndex = 0;
public Server choose(ILoadBalancer lb, Object key) {
if (lb == null) {
return null;
}
Server server = null;
while (server == null) {
if (Thread.interrupted()) {
return null;
}
// 获得活着的服务
List<Server> upList = lb.getReachableServers();
// 获得所有的服务
List<Server> allList = lb.getAllServers();
int serverCount = allList.size();
// 没有可用的服务
if (serverCount == 0) {
/*
* No servers. End regardless of pass, because subsequent passes
* only get more restrictive.
*/
return null;
}
//// 生成区间随机数
// int index = chooseRandomInt(serverCount);
//// 从活着的服务中随机获取一个
// server = upList.get(index);
// ======================自定义算法
if (total < 5) {
server = upList.get(currentIndex);
total++;
} else {
total = 0;
currentIndex++;
if (currentIndex >= upList.size()) {
currentIndex = 0;
}
server = upList.get(currentIndex);
}
// ======================
if (server == null) {
/*
* The only time this should happen is if the server list were
* somehow trimmed. This is a transient condition. Retry after
* yielding.
*/
Thread.yield();
continue;
}
if (server.isAlive()) {
return (server);
}
// Shouldn't actually happen.. but must be transient or a bug.
server = null;
Thread.yield();
}
return server;
}
protected int chooseRandomInt(int serverCount) {
return ThreadLocalRandom.current().nextInt(serverCount);
}
@Override
public Server choose(Object key) {
return choose(getLoadBalancer(), key);
}
@Override
public void initWithNiwsConfig(IClientConfig clientConfig) {
// TODO Auto-generated method stub
}
}
step3:启动类配置注解@RibbonClient
package com.example.demo;
import com.example.myrule.RibbonRule;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.ribbon.RibbonClient;
//@SpringBootApplication:标注这个类是一个springboot的应用
@SpringBootApplication
@EnableEurekaClient
@EnableDiscoveryClient
//在微服务七启动的时候就能去加载我们自定义的ribbon类
@RibbonClient(name = "SUMMER",configuration = RibbonRule.class)
public class SpringBootDemoApplication {
public static void main(String[] args) {
//将springboot应用启动
SpringApplication.run(SpringBootDemoApplication.class, args);
}
}
Feign负载均衡
Feign是什么?
-
feign是声明式的web service客户端,它让微服务之间的调用变得更简单了,类似controller调用service。SpringCloud集成了Ribbon和Eureka,可在使用Feign时提供负载均衡的http客户端。
只需要创建一个接口,然后添加注解即可!
-
feign,主要是社区,大家都习惯面向接口编程。这个是很多开发人员的规范。调用微服务访问两种方法
- 微服务名字【ribbon】
- 接口和注解【feign】
Feign能干什么?
- Feign指在使用编写java http客户端变得更容易
- 前面在使用Ribbon+RestTemplate时,利用RestTemplate对HTTP请求的封装处理,形成了一套模板化的调用方法。但是在实际开发中,由于对微服务依赖的调用可能不止一处,往往一个接口会被多处调用,所以通常都会针对每个微服务自行封装一些客户端类来包装这些依赖服务的调用。所以Feign在此基础上做了进一步封装,由它来帮助我们定义和实现依赖服务接口的定义,在Feign的实现下,我们只需要创建一个接口并使用注解的方式来配置它(类似于以前DAO接口上标注了Mapper注解,现在是一个微服务接口上面标注了一个Feign注解即可。)即可完成对服务提供方的接口绑定,简化了使用Spring Cloud Ribbon时,自动封装服务调用客户端的开发量。
Feign集成了Ribbon
- 利用Ribbon维护了微服务(task)的服务列表信息,并且通过轮询实现了客户端的负载均衡,而与Ribbon不同的是,通过Feign只需要定义服务绑定接口且以声明式的方法,优雅而且简单的实现了服务调用。
Feign使用步骤
pom依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
<version>2.2.6.RELEASE</version>
</dependency>
接口类上的注解
@FeignClient(value = "SUMMER")
启动类上的注解
@EnableFeignClients(basePackages = {"com.summer.springcloud"})//开启fegin 本质马上feign还是调用ribbon进行负载均衡 fegin只是便于java客户端封装请求
@ComponentScan("com.summer.springcloud")//扫描包
Hystrix断路器
分布式系统面临的问题
复杂分布式体系结构中的应用程序有数十个依赖关系,每个依赖关系在某些时候将不可避免的失败!
服务雪崩
多个微服务之间调用的时候,假设微服务A调用微服务B和微服务C,微服务B和微服务C又调用其他的微服务,这就是所谓的“扇出”、如果扇出的链路上某个微服务的调用响应时间过长或者不可用,对微服务A的调用就会占用越来越多的系统资源,进而引起系统崩溃,所谓的“雪崩效应”。
对于高流量的应用来说,单一的后端依赖可能会导致所有服务器上的所有资源都在几秒内饱和。比失败更糟糕的是,这些应用程序还可能导致服务之间的延时增加,备份队列,线程和其他系统资源紧张,导致整个系统发生更多的级联故障,这些都表示需要对故障和延时进行隔离和管理,以便单个依赖关系的失败,不能取消整个应用程序或系统。
我们需要,弃车保帅。
Hystrix是什么?
- Hystrix是一个用于处理分布式系统的延时和容错的开源库,在分布式系统里,许多依赖不可避免的会调用失败,比如超时,异常等等,Hystrix能够保证在一个依赖出问题的情况下,不会导致整体服务失败,避免级联故障,以提高分布式系统的弹性。
- “断路器”本身是一种开关装置,当某个服务单元发生故障之后,通过断路器的故障监控(类似熔断保险丝),向调用方返回一个服务预期的,可处理的备选响应(FallBack),而不是长时间的等待或者抛出调用方无法处理的异常,这样就可以保证了服务调用方的线程不会被长时间,不必要的占用,从而避免了故障在分布式系统中的蔓延,乃至雪崩
-
熔断机制是对应雪崩效应的一种微服务链路保护机制
当扇出链路的某个微服务不可用或者响应时间太长,会进行服务的降级,进而熔断该节点微服务的调用,快速返回 错误的响应信息。当检测到该节点微服务调用响应正常后恢复调用链路。在springcloud框架里熔断机制通过hystrix实现。Hystrix会监控微服务间调用的状况,当失败的调用到一定阈值,一般是5秒内20次调用失败就会启动熔断机制。熔断机制的注解是@HystrixCommand。
Hystrix能干嘛?
- 服务降级
- 服务熔断
- 服务限流
- 接近实时的监控
- ......
官网资料
https://github.com/Netflix/Hystrix/wiki
Hystrix使用步骤
pom依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
编写配置文件
熔断
接口上的注解
@GetMapping("/hello/hystrix")
@HystrixCommand(fallbackMethod = "sayHelloRestHystrixV2")
public Integer sayHelloRestHystrix(@PathVariable("id") Integer id) {
System.out.println(id);
if (id == 0) {
throw new RuntimeException("id不能为0");
}
return id;
}
启动类的开启注解
@EnableCircuitBreaker
demo
@GetMapping("/hello/hystrix/{id}")
@HystrixCommand(fallbackMethod = "sayHelloRestHystrixV2")
public Integer sayHelloRestHystrix(@PathVariable("id") Integer id) {
System.out.println(id);
if (id == 0) {
throw new RuntimeException("id不能为0");
}
return id;
}
// 备选方案
public Integer sayHelloRestHystrixV2(@PathVariable("id") Integer id) {
return 100;
}
注释掉HystrixCommand
@GetMapping("/hello/hystrix/{id}")
// @HystrixCommand(fallbackMethod = "sayHelloRestHystrixV2")
public Integer sayHelloRestHystrix(@PathVariable("id") Integer id) {
System.out.println(id);
if (id == 0) {
throw new RuntimeException("id不能为0");
}
return id;
}
降级
@FeignClient(value = "SUMMER",fallbackFactory = ServiceFallbackFactory.class)
ServiceFallbackFactory需要实现 hystrix中的FallbackFactory接口
重写create方法 然后new service接口 并实现每个接口的降级操作
配置文件
#开启降级 feign.hystrix
feign:
hystrix:
enable: true
理解一下:服务熔断是在服务端操作,服务降级是在客户端操作
总结
-
服务熔断:服务端 、某个服务超时或者异常,引起熔断,类似保险丝
-
服务降级:客户端、从整体的网站请求负载考虑,当某个服务熔断或者关闭之后,服务将不在被调用~
此时在客户端可以准备一个FallbcakFactory,返回一个默认的值(缺省值),整体的服务水平下降了~比直接挂掉强
DashBoard流监控
客户端配置
依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<!-- 监控信息的依赖 服务端要有这个依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
注解
//开启dashboard
@EnableHystrixDashboard
服务端要配置
访问页面
localhost:9001/hystrix
Zuul路由网关
Zuul是什么?
-
Zuul包含对请求的路由和过滤两个最主要的功能:
其中路由功能负责将外部请求转发到具体的微服务实例上,是实现外部访问统一入口的基础,而过滤器功能则负责对请求的处理过程进行干预,是实现请求校验,服务聚合等功能的基础。Zuul和Eureka进行整合,将Zuul自身注册为Eureka服务治理下的应用,同时从Eureka中获得其他微服务的信息,以及以后的访问微服务都是通过Zuul跳转后获得。
【注意】:Zuul服务最终还是会注册进Eureka
【提供】:代理+路由+过滤 三个功能!!!
Zuul能干嘛?
- 路由
- 过滤
官方文档:https://github.com/Netflix/zuul
Zuul配置步骤
pom依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>springcloud-zuul</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.1.RELEASE</version>
</parent>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Finchley.SR3</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zuul</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
</dependencies>
</project>
配置
server:
port: 9527
spring:
application:
name: springcloud-zuul-gateway
eureka:
client:
service-url:
defaultZone: http://eureka7002:7002/eureka/,http://eureka7003:7003/eureka/,http://eureka7001:7001/eureka/
instance:
instance-id: zuul9527.com
prefer-ip-address: true
启动类注解
@SpringBootApplication
@EnableEurekaClient
@EnableZuulProxy
public class ZuulApplication {
public static void main(String[] args) {
SpringApplication.run(ZuulApplication.class,args);
}
}
测试
更改微服务名字
zuul:
routes:
my.serviceId: summer
my.path: /my/**
ignore
隐藏服务名
zuul:
routes:
my.serviceId: summer
my.path: /my/**
ignored-services: summer #不能在使用这个路径访问了 ignore忽略
#ignored-services: "*" 真实项目中 会隐藏全部的名字
prefix
zuul:
routes:
my.serviceId: summer
my.path: /my/**
ignored-services: summer #不能在使用这个路径访问了 ignore忽略
prefix: /summer #设置公共的前缀
SpringCloud Config分布式配置
概述
分布式系统面临的--配置文件的问题
微服务意味着要将单体应用中的业务拆分成一个个子服务,每个服务的粒度相对较小,因此系统中会出现大量的服务,由于每个服务都需要必要的配置信息才能运行,所以一套集中式的,动态的配置管理设施是必不可少的。
springcloud提供了ConfigServer来解决这个问题,我们每个微服务自己带着一个application.yml,那上百的配置文件要修改起来,岂不是要发疯!
springcloud config是什么?
SpringCloud总结与展望
面试题
面试题连接:
https://www.jianshu.com/p/80283f3c2497
springcloud中文网:
springcloud alibaba:
阿里巴巴有自己的依赖~
nacos --- 服务注册与发现
重点
springboot和springcloud版本兼容问题!!!
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.1.RELEASE</version>
</parent>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Finchley.SR3</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>