文章目录
1.什么是SpringCloud
SpringCloud是基于SpringBoot的一整套实现微服务的框架
Spring Cloud是一系列框架的有序集合。它利用Spring Boot的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册、配置中心、智能路由、消息总线、负载均衡、断路器、数据监控等,都可以用Spring Boot的开发风格做到一键启动和部署。Spring Cloud并没有重复制造轮子,它只是将各家公司开发的比较成熟、经得起实际考验的服务框架组合起来,通过Spring Boot风格进行再封装屏蔽掉了复杂的配置和实现原理,最终给开发者留出了一套简单易懂、易部署和易维护的分布式系统开发工具包。
2.服务注册和发现是什么意思?
Spring Cloud 如何实现?当我们开始一个项目时,我们通常在属性文件中进行所有的配置。随着越来越多的服务开发和部署,添加和修改这些属性变得更加复杂。有些服务可能会下降,而某些位置可能会发生变化。手动更改属性可能会产生问题。 Eureka 服务注册和发现可以在这种情况下提供帮助。由于所有服务都在 Eureka 服务器上注册并通过调用 Eureka 服务器完成查找,因此无需处理服务地点的任何更改和处理。
3.负载平衡的意义什么?
负载平衡旨在优化资源使用,最大化吞吐量,最小化响应时间并避免任何单一资源的过载。使用多个组件进行负载平衡而不是单个组件可能会通过冗余来提高可靠性和可用性。负载平衡通常涉及专用软件或硬件,例如多层交换机或域名系统服务器进程。
4.什么是 Hystrix?它如何实现容错?
Hystrix 是一个延迟和容错库,旨在隔离远程系统,服务和第三方库的访问点,当出现故障是不可避免的故障时,停止级联故障并在复杂的分布式系统中实现弹性。
5. Spring Cloud断路器的作用
当一个服务调用另一个服务由于网络原因或自身原因出现问题,调用者就会等待被调用者的响应,当更多的服务请求到这些资源导致更多的请求等待,发生连锁效应(雪崩效应)断路器有完全打开状态:一段时间内达到一定的次数无法调用并且多次监测没有恢复的迹象断路器完全打开那么下次请求就不会请求到该服务半开:短时间内有恢复迹象断路器会将部分请求发给该服务,正常调用时断路器关闭
关闭:当服务一直处于正常状态能正常调用
6.什么是Spring Cloud Config?
在分布式系统中,由于服务数量巨多,为了方便服务配置文件统一管理,实时更新,所以需要分布式配置中心组件。在Spring Cloud中,有分布式配置中心组件spring cloud config ,它支持配置服务放在配置服务的内存中(即本地),也支持放在远程Git仓库中。在spring cloud config 组件中,分两个角色,一是 config server,二是config client。使用:(1)添加pom依赖(2)配置文件添加相关配置(3)启动类添加注解@EnableConfigServer
7.什么是Spring Cloud Gateway?
Spring Cloud Gateway是Spring Cloud官方推出的第二代网关框架,取代Zuul 网关。网关作为流量的,在微服务系统中有着非常作用,网关常见的功能有路由转发、权限校验、限流控制等作用。使用了一个RouteLocatorBuilder的bean去创建路由,除了创建路由RouteLocatorBuilder可以让你添加各种predicates和filters,predicates断言的意思,顾名思义就是根据具体的请求的规则,由具体的route去处理,filters 是各种过滤器,用来对请求做各种判断和修改。
8Eureka注册中心
服务提供者启动时向eureka注册自己的信息,消费者根据服务名称向eureka拉取提供者信息。
如果服务者有多个,利用负载均衡算法从列表中挑选一个
服务者每隔30s向eurekaServer发送心跳请求报告健康状态,eureka更新服务列表信息,心跳不正常会被踢出
搭建EurekaServer
1引入eureka-server依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
2编写启动类,添加@EnableEurekaServer注解
@SpringBootApplication
@EnableEurekaServer
public class CenterApplication {
public static void main(String[] args) {
SpringApplication.run(CenterApplication.class, args);
System.out.println("rc-ms-registry Start success!");
}
}
3配置yml
server:
port: 8761 #端口
application:
name: eurekaserver #服务名
service:
#ip-address: 192.168.1.18
ip-address: 127.0.0.1
eureka:
client:
service-url: #eureka地址
defaultZone: http://${service.ip-address}:8761/eureka/
服务注册,发现
1引入eureka-client依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
server:
port: 9012
application:
name: eurekaservice #服务名
service:
# ip-address: 192.168.1.245
ip-address: 127.0.0.1
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:8761/eureka/
9Ribbon负载均衡
spring cloud ribbon基于Netflix Ribbon实现的一套客户端负载均衡的工具
将用户请求平摊到多个服务器上,从而达到系统的高可用
常见的负载均衡软件nginx
1在客户端引入依赖
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-ribbon -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<!--eureka客户端-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
2 ribbon的注解使用 @LoadBalanced
@Configuration//注解方式装配bean,相当于applicationContext.xml
public class ConfigBean {
@Bean
@LoadBalanced
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
3例:
使用ribbon,服务之间的请求调用不用写ip地址和端口号
package com.jxw.springcloud.controller;
import com.jxw.springcloud.pojo.TaskImplement;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
import java.util.List;
/**
* Created by jixinwei on 2022/2/28 22:45
*/
@RestController
public class TestFeignController {
@Autowired
private RestTemplate restTemplate;
private static final String REST_URL_PERFIX = "http://localhost:8001";
private static final String REST_URL_PERFIX2 = "http://provider";
@Autowired
private DiscoveryClient client;
/*不同服务的http调用*/
/*1 resTemplate的使用:
* 1配置bean
* 2restTemplate.getForObject(url,返回类)*/
@RequestMapping("/testRestTemplate/{id}")
public TaskImplement testFeign(@PathVariable("id")Long id){
return restTemplate.getForObject(REST_URL_PERFIX+"/get/" + id, TaskImplement.class);
}
/*测试ribbon,用服务名调用不同服务的请求*/
@RequestMapping("/testRibbon/{id}")
public TaskImplement testRibbon(@PathVariable("id")Long id){
return restTemplate.getForObject(REST_URL_PERFIX2+"/get/" + id, TaskImplement.class);
}
}
4自定义负载均衡算法
ribbon采用轮询访问,算法通过IRule接口实现
public interface IRule {
Server choose(Object var1);
void setLoadBalancer(ILoadBalancer var1);
ILoadBalancer getLoadBalancer();
}
choose
AvailabilityFilteringRule:过滤跳闸故障的服务,剩下的进行轮询
RoundRobinRule:轮询
RandomRule:随机
RetryRule:轮询服务,如果服务获取失败,在指定的时间内重试
自定义的负载均衡不要和主启动类同级,会被扫描到
主启动类
//自定义负载均衡规则,在主启动类写ribbon注解,在微服务启动的时候,自动加载自定义配置
@RibbonClient(name = "provider",configuration = MyRuleConfig.class)
@EnableDiscoveryClient
@EnableEurekaClient
@SpringBootApplication
public class ConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class, args);
}
}
自定义负载均衡规则
@Configuration
public class MyRuleConfig {
@Bean
public IRule myRule(){
return new RandomRule();
}
}
默认采用懒加载,第一次访问才会创建LoadBalanceClient,请求会很长
饥饿加载会在项目启动时创建,降低第一次访问的时间,通过以下方式配置饥饿加载
ribbon:
ReadTimeout: 60000
ConnectTimeout: 60000
eager-load:
enabled: true
clients: userservice #指定懒加载的服务名
10Feign
代替RestTemplate
String url = "http://userservice/user/"+order.getUserId();
User user = restTemplate.getForObject(url,User.class);
Feign是一个声明式的http客户端
Feign集成了Ribbon
在Feign的实现下,只需要创建一个接口并使用注解的方式来配置它(类似于Dao接口上的@Mapper注解,只需要在微服务接口上面标注Feign注解即可)
使用Feign的步骤
1引入openfeign依赖
<!-- feign -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2编写Feign接口
@Component
@FeignClient(value = "provider")//value为服务名
public interface TestFeignClientService {
@GetMapping("/get/{id}")
TaskImplement testRibbon(@PathVariable("id")Long id);
}
3客户端启动类加注解@EnableFeignClients
@SpringBootApplication
@EnableFeignClients(basePackages = "com.rsi.rc")
public class BusApplication{
public static void main(String[] args) {
SpringApplication.run(BusApplication.class, args);
System.out.println("rc-bus-service start success");
}
}
4使用Feign
@RestController
public class TestFeignController {
@Autowired
private TestFeignClientService clientService;
/*测试feign*/
@RequestMapping("/testFeign/{id}")
public TaskImplement testRibbon(@PathVariable("id")Long id){
return clientService.testRibbon(id);
}
}
Feign的最佳实践
将FeignClient抽取为独立模块,并且把接口有关pojo,默认的Feign配置都放到这个模块中,提供给消费者使用
11 Hystrix服务熔断
Hystrix是一个用于处理分布式系统的延迟和容错的开源库,保证在一个依赖出错的情况下不会导致整体服务失败,避免级联故障,提高分布式系统的弹性
“断路器”本身是一种开关装置,当某个服务单元发生故障之后,通过断路器的故障监控,向调用方返回一个服务预期的、可处理的备选响应(FallBack)而不是长时间的等待或者抛出调用方法无法处理的异常,这样就可以保证了服务调用方的线程不会被长时间、不必要的占用,避免了故障在分布式系统中的蔓延和雪崩
服务熔断
当失败的调用到一定阈值,5秒内20次调用失败就会启动熔断机制。熔断机制的注解是@HystrixCommand,熔断该节点微服务的调用,快速返回错误的响应信息。
1依赖
<!--hystrix-->
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-netflix-hystrix -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
<version>2.2.2.RELEASE</version>
</dependency>
2启动类
@EnableEurekaClient //启动后自动注册到eureka中
@SpringBootApplication
@EnableCircuitBreaker//添加服务熔断的支持
public class HystrixApplication {
public static void main(String[] args) {
SpringApplication.run(HystrixApplication.class, args);
}
}
3测试
@HystrixCommand(fallbackMethod = “hystrix”)服务异常调用备选方法
@RestController
public class TestController {
@Autowired
private TestService testService;
@GetMapping("/get/{id}")
@HystrixCommand(fallbackMethod = "hystrix")
public TaskImplement getById(@PathVariable("id")Long id){
TaskImplement taskImplement = testService.getById(id);
if (taskImplement==null) throw new RuntimeException("id" + id + "信息无法找到");
return taskImplement;
}
//备选方法
public TaskImplement hystrix(@PathVariable("id")Long id){
return TaskImplement.builder().implementId(id).implementDesc("not exist").build();
}
}
服务降级
服务端配置
#客户端开启服务降级
feign:
hystrix:
enabled: true
降级配置
@Component
@FeignClient(value = "provider",fallbackFactory = TestFeignClientFactory.class)//value为服务名
public interface TestFeignClientService {
@GetMapping("/get/{id}")
TaskImplement testRibbon(@PathVariable("id")Long id);
}
//服务降级
@Component
public class TestFeignClientFactory implements FallbackFactory {
public TestFeignClientService create(Throwable throwable) {
return new TestFeignClientService() {
public TaskImplement testRibbon(Long id) {
return TaskImplement.builder().implementId(id).implementDesc("客户端提供了降级服务,这个服务被关闭").build();
}
};
}
}
Dashboard流量监控
依赖
<!--服务监控-->
<!-- 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.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
<version>1.4.7.RELEASE</version>
</dependency>
监控配置
启动类
@EnableHystrixDashboard //开启监控页面
@SpringBootApplication
@EnableHystrixDashboard //开启监控页面
public class ConsumerDashboardApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerDashboardApplication.class, args);
}
}
http://localhost:9001/hystrix
输入端口号获得监控页面
被监控的配置
<!-- 监控-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-cloud-starter-actuator</artifactId>
</dependency>
@EnableEurekaClient //启动后自动注册到eureka中
@SpringBootApplication
public class ProviderApplication {
public static void main(String[] args) {
SpringApplication.run(ProviderApplication.class, args);
}
// 添加一个Servlet
@Bean
public ServletRegistrationBean registrationBean (){
ServletRegistrationBean registrationBean = new ServletRegistrationBean(new HystrixMetricsStreamServlet());
registrationBean.addUrlMappings("/actuator/hystrix.stream");//访问路径
return registrationBean;
}
}