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
导入依赖
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-feign -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
编写公用接口
在API项目中编写公用接口
修改客户端代码
@Component
//name 服务名称
@FeignClient(name = "PROVIDER-8001")
public interface DeptClientService {
//服务提供者 的服务地址
@PostMapping("/dept/save")
public Integer addDept(Dept dept);
@GetMapping("/dept/get/{id}")
public Dept queryById(@PathVariable("id") Long id);
@GetMapping("/dept/list")
public List<Dept> queryDept();
}
修改客户端代码 使用Feign的方式调用接口
@RestController
@RequestMapping("/consumer")
public class DeptConsumerController {
/* @Autowired
private RestTemplate restTemplate;
*/
//通过Ribbon 这里的地址应该是变量 通过服务名访问
//远程请求地址
// private static final String REST_URL_PROVIDER = "http://localhost:8001";
// private static final String REST_URL_PROVIDER ="http://PROVIDER-8001";
//注入Feign接口
@Autowired
private DeptClientService deptClientService;
@PostMapping("/save")
public Integer addDept(@RequestBody Dept dept){
//参数: url地址 请求参数 返回值类型
return deptClientService.addDept(dept);
}
@GetMapping("/get/{id}")
public Dept get(@PathVariable Long id){
return deptClientService.queryById(id);
}
@GetMapping("/list")
public List<Dept> list(){
return deptClientService.queryDept();
}
}
扫描Feign注解 主启动类下加入
@EnableEurekaClient
@EnableDiscoveryClient
@SpringBootApplication
@EnableFeignClients(basePackages = {
"com.tuxc"}) //扫描feign
@ComponentScan("com.tuxc")
public class ConsumerApplication {
public static void main(String[] args){
SpringApplication.run(ConsumerApplication.class,args);
}
@Bean
@LoadBalanced
public RestTemplate getResTemplate(){
return new RestTemplate();
}
}
Feign的底层依旧是使用Ribbon实现,只是这种编码方式更符合编码人员的面向接口开发
Hystrix降级熔断
服务熔断-服务端操作
分布式系统面临的问题
复杂分布式体系结构中的应用程序有数十个依赖关系,每个依赖关系在某些时候将不可避免的失败!
服务雪崩
多个微服务之间调用的时候,假设微服务A调用微服务B和微服务C,微服务B和微服务C又调用其他的微服务,这就是所谓的“扇出"、如果扇出的链路上某个微服务的调用响应时间过长或者不可用,对微服务A的调用就会占用越来越多的系统资源,进而引起系统崩溃,所谓的“雪崩效应"。
对于高流量的应用来说,单一的后端依赖可能会导致所有服务器上的所有资源都在几秒中内饱和。比失败更糟糕的是,这些应用程序还可能导致服务之间的延迟增加,备份队列,线程和其他系统资源紧张,导致整个系统发生更多的级联故障,这些都表示需要对故障和延迟进行隔离和管理,以便单个依赖关系的失败,不能取消整个应用程序或系统。
我们需要·弃车保帅·
什么是Hystrix
Hystrix是一个用于处理分布式系统的延迟和容错的开源库,在分布式系统里,许多依赖不可避免的会调用失败,比如超时,异常等,Hystrix能够保证在一个依赖出问题的情况下,不会导致整体服务失败,避免级联故障,以提高分布式系统的弹性。
"断路器"本身是一种开关装置,当某个服务单元发生故障之后,通过断路器的故障监控(类似熔断保险丝),向调用方返回一个服务预期的,可处理的备选响应(FallBack),而不是长时间的等待或者抛出调用方法无法处理的异常,这样就可以保证了服务调用方的线程不会被长时间,不必要的占用,从而避免了故障在分布式系统中的蔓延,乃至雪崩
什么是服务熔断
熔断机制是对应雪崩效应的一种微服务链路保护机制。
当扇出链路的某个微服务不可用或者响应时间太长时,会进行服务的降级,进而熔断该节点微服务的调用,快速返回错误的响应信息。当检测到该节点微服务调用响应正常后恢复调用链路。在SpringCloud框架里熔断机制通过Hystrix实现。Hystrix会监控微服务间调用的状况,当失败的调用到一定阈值,缺省是5秒内20次调用失败就会启动熔断机制。熔断机制的注解是@HystrixCommand。
使用Hystrix
这里我们使用8002来测试Hystrix 提供服务
导入依赖
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-hystrix -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
8002配置文件修改这个即可
编写代码
核心注解@HystrixCommand(fallbackMethod = "hystrixGet")
失败时调用某某方法
@RestController
@RequestMapping("/dept")
public class DeptController {
@Autowired
private DeptService deptService;
@HystrixCommand(fallbackMethod = "hystrixGet") //失败时调用下面方法
@GetMapping("/get/{id}")
public Dept get(@PathVariable Long id){
Dept dept = deptService.queryById(id);
if (dept == null){
throw new RuntimeException("未查到对应部门");
}
return dept;
}
//备选方法 上面的方法报错时调用
public Dept hystrixGet(@PathVariable Long id){
return new Dept().setId(id).setDname("默认部门").setDbSource("默认数据库");
}
}
配置Hystrix
核心注解@EnableCircuitBreaker//添加对熔断的支持
@EnableEurekaClient //服务启动后自动注册到Eureka
@EnableDiscoveryClient //服务发现
@SpringBootApplication
@EnableCircuitBreaker//添加对熔断的支持
public class DeptApplication_8002 {
public static void main(String[] args){
SpringApplication.run(DeptApplication_8002.class,args);
}
}
当原来服务失败时 会执行咱们的备用方法
服务降级-客户端操作
比如说:会员系统访问订单系统,执行远程RPC调用方法,但是当达到一定并发量的时候,比如200个人同时访问 orderTest()方法时,tomcat的容量设置的只有150个,剩余的50个人就在外面等待一直等待。服务降级就是不让他们一直等待,调用本地的方法来fallback消息。而不再去PRC方法。
降级测试
在API公共包下编写降级类DeptClientServiceFallback
它需要去实现FallbackFactory
接口
@Component
public class DeptClientServiceFallback implements FallbackFactory {
//之前的熔断返回的是一个接口
//现在的Object返回的是一个降级类 哪个接口需要进行降级
@Override
public Object create(Throwable cause) {
return null;
}
}
这里是我们的DeptClientService
需要进行降级
@Component
public class DeptClientServiceFallback implements FallbackFactory {
//之前的熔断返回的是一个接口
//现在的Object返回的是一个降级类 哪个接口需要进行降级
@Override
public DeptClientService create(Throwable cause) {
return new DeptClientService(){
//此处编写降级操作
@Override
public Integer addDept(Dept dept) {
return null;
}
@Override
public Dept queryById(Long id) {
return new Dept().setId(1L).setDname("降级操作在这里");
}
@Override
public List<Dept> queryDept() {
return null;
}
};
}
}
编写完降级类之后,我们需要在Fegin
上指定降级类
@Component
//参数: name 远程调用服务名 fallbackFactory 指定降级类
@FeignClient(name = "PROVIDER-8001",fallbackFactory = DeptClientService.class)
public interface DeptClientService {
@PostMapping("/dept/save")
public Integer addDept(Dept dept);
@GetMapping("/dept/get/{id}")
public Dept queryById(@PathVariable("id") Long id);
@GetMapping("/dept/list")
public List<Dept> queryDept();
}
最后在配置文件中开启降级服务
# 开启降级服务
feign:
hystrix:
enabled: true
小结
服务熔断
服务端操作,某个服务超时或者异常就会引起服务熔断,类似于保险丝
服务降级
客户端操作,一般从整体的网站负载考虑,如果某些服务关闭后,服务将不在被调用,用户正常请求只是不走服务器,返回默认值
服务监控-dashboard
创建项目导入依赖
<!-- hystrix -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<!-- hystrix-dashboard -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
启动服务
@SpringBootApplication
@EnableHystrixDashboard //开启监控
public class DashApplication {
public static void main(String[] args) {
SpringApplication.run(DashApplication.class,args);
}
}
在需要进行监控的服务中 配置监控断点
主启动类下加入以下内容
@Bean
public ServletRegistrationBean hystrixMetricsStreamServlet(){
ServletRegistrationBean registrationBean = new ServletRegistrationBean(new HystrixMetricsStreamServlet());
registrationBean.addUrlMappings("/actuator/hystrix.stream");
return registrationBean;
}
注意导入依赖
<!--Eureka监控信息-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
注意点
开启监控时,如果没有任何请求,访问http://localhost:8001/actuator/hystrix.stream
会出现一直ping的情况, 此时只需要访问接口 即可看到内容 然后开启监控即可
Zuul路由网关
什么是Zuul
Zuul包含了对请求的路由和过滤两个最主要的功能:
其中路由功能负责将外部请求转发到具体的微服务实例上,是实现外部访问统一入口的基础,而过滤器功能则负责对请求的处理过程进行干预,是实现请求校验,服务聚合等功能的基础。Zuul和Eureka进行整合
将Zuul自身注册为Eureka服务治理下的应用,同时从Eureka中获得其他微服务的消息,也即以后的访问微服务都是通过Zuul跳转后获得。
注意:Zuul服务最终还是会注册进Eureka提供:代理+路由+过滤三大功能!
快速开始
创建项目导入依赖
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-feign -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zuul</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
向Eureka进行注册
# eureka
eureka:
client:
service-url: # 向这个地址注册
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7003.com:7003/eureka/,http://eureka7002.com:7002/eureka/
instance:
instance-id: zuul
prefer-ip-address: true
开启服务
@EnableZuulProxy // 开启Zull服务代理
@EnableEurekaClient
@EnableDiscoveryClient
@SpringBootApplication
public class ZuulApplication {
public static void main(String[] args) {
SpringApplication.run(ZuulApplication.class,args);
}
}
将服务注册到Eureka后,用户通过zuul可以通过服务名+请求地址 访问到隐藏起来的真实服务
注意:访问的服务名必须是小写
隐藏服务名
之前的请求url中,我们显示了服务名,现在我们需要将它隐藏起来
编写配置
zuul:
routes: # 映射服务
mydept.serviceId: provider-8001
mydept.path: /mydept/**
ignored-services: provider-8001 #禁用此路径访问 "*" 禁用所有服务名访问
prefix: /tuxc # 访问路径前缀 localhots:9527/tuxc + 服务地址
Config配置中心
微服务面临的配置问题
微服务意味着要将单体应用中的业务拆分成一个个子服务,每个服务的粒度相对较小,因此系统中会出现大量的服务,由于每个服务都需要必要的配置信息才能运行,所以一套集中式的,动态的配置管理设施是必不可少的。SpringCloud提供了ConfigServer来解决这个问题,我们每一个微服务自己带着一个application.yml ,
那上百的的配置文件要修改起来,岂不是要发疯!
什么是Config
Spring Cloud Config为微服务架构中的微服务提供集中化的外部配置支持,配置服务器为各个不同微服务应用的所有环节提供了一个中心化的外部配置。
Spring Cloud Config 分为服务端和客户端两部分;
服务端也称为分布式配置中心,它是一个独立的微服务应用,用来连接配置服务器并为客户端提供获取配置信息,加密,解密信息等访问接口。
客户端则是通过指定的配置中心来管理应用资源,以及与业务相关的配置内容,并在启动的时候从配置中心获取和加载配置信息。配置服务器默认采用git来存储配置信息,这样就有助于对环境配置进行版本管理。并且可以通过git客户端工具来方便的管理和访问配置内容。
Config的优点
集中管理配置文件:不同环境,不同配置,动态化的配置更新,分环境部署,比如/dev /test/ /prod /beta /release
运行期间动态调整配置,不再需要在每个服务部署的机器上编写配置文件,服务会向配置中心统一拉取配置自己的信息。
当配置发生变动时,服务不需要重启,即可感知到配置的变化,并应用新的配置将配置信息以REST接口的形式暴露
快速开始-服务端
服务端的作用:
连接git远程仓库,读取配置文件
码云上新建远程仓库
在码云上新建远程仓库,并把它克隆到本地
在远程仓库中准备一个测试文件
创建项目导入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
<version>2.1.1.RELEASE</version>
</dependency>
编写配置,重点是连接远程仓库
server:
port: 3344
spring:
application:
name: config-server
# 连接远程仓库
cloud:
config:
server:
git:
uri: https://gitee.com/tu_xu_chen/net-flix-config.git # git上复制的https地址
启动服务
@EnableConfigServer //开启服务
@SpringBootApplication
public class ConfigApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigApplication.class,args);
}
}
之后就可以通过url+文件名即可访问到在远程仓库的配置文件了
访问远程配置的方式
官方提供以下几种方式来访问远程仓库中的配置文件
快速开始-客户端
客户端的作用:
通过连接config服务端,获取远程配置文件覆盖本地配置文件
远程仓库中上传测试配置文件
创建项目导入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
<version>2.1.1.RELEASE</version>
</dependency>
编写一个bootstrap.yml配置
# bootstrap.yml 是系统级的配置 application.yml是用户级别的配置
spring:
cloud:
config:
name: config-client # 此处写在git上读取的资源名称
uri: http://localhots:3344 # 注意 此处地址是config服务端
profile: dev # 拿哪个环境的配置
label: master # 从主分支拿
编写主启动类
@SpringBootApplication
public class ConfigClientApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigClientApplication.class,args);
}
}
启动以后,我们可以看到 config客户端通过我们配置的服务端地址获取到远程git仓库的配置文件 并覆盖了本地配置