2021-04-23

springcloud

1.1简介

Spring Cloud是一系列框架的有序集合。它利用Spring Boot的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等,都可以用Spring Boot的开发风格做到一键启动和部署。Spring Cloud并没有重复制造轮子,它只是将目前各家公司开发的比较成熟、经得起实际考验的服务框架组合起来,通过Spring Boot风格进行再封装屏蔽掉了复杂的配置和实现原理,最终给开发者留出了一套简单易懂、易部署和易维护的分布式系统开发工具包。

==Spring Cloud从技术架构上降低了对大型系统构建的要求和难度==,使我们以非常低的成本(技术或者硬件)搭建一套高效、分布式、容错的平台,但Spring Cloud也不是没有缺点,小型独立的项目不适合使用。

1.2一般开发中存在的问题

provider_service:对外提供用户查询接口

consumer_service:通过RestTemplate访问接口查询用户数据

存在的问题:

  1. 在消费者服务中,访问提供者服务URL地址硬编码,万一地址端口变化了怎么办?提供者服务死掉了消费者怎么才能知道?

  2. 在消费者服务中,是不清楚服务提供者状态的!

  3. 为了增加服务并发访问量,我们搭建集群,集群的负载均衡怎么实现?

  4. 服务提供者如果出现故障,会不会向用户抛出异常页面,该不该抛出错误页面?

  5. RestTemplate这种请求调用方式是否还有优化空间?复用,管理,可读性角度来思考

  6. 多服务权限拦截如何实现?怎么保证所有微服务服务的安全性?

  7. 众多微服务的配置文件,每次都修改很多个,是不是很麻烦!?

其实上面说的部分问题,概括一下就是微服务架构必然面临的一些问题。

  • 服务管理:自动注册与发现、状态监管

  • 服务负载均衡

  • 熔断

  • 面向接口的远程调用

  • 网关拦截、路由转发

  • 统一配置修改

1.3注册中心 Spring Cloud Eureka

1.3.1整合注册中心Eureka

步骤分三步:

  • 第一步:搭建eureka服务,创建eureka_server工程

  • 第二步:服务提供者provider_service,注册到eureka注册中心

  • 第三步:服务消费者consumer_service,注册到eureka注册中心

 

eureka_server:

1.创建eureka_server的springboot工程。

2.勾选坐标

3.在启动类EurekaServerApplication声明当前应用为Eureka服务使用@EnableEurekaServer注解

4.编写配置文件application.yml

# 端口
server.port: 10086
# 应用名称,会在Eureka中作为服务的id标识(serviceId)
spring.application.name: eureka-server
# EurekaServer的地址,现在是自己的地址,如果是集群,需要写其它Server的地址。
eureka.client.service-url.defaultZone: http://127.0.0.1:10086/eureka

5.启动EurekaServerApplication

6.测试访问地址http://127.0.0.1:10086,如下信息代表访问成功

7.关闭注册自己

# 是否抓取注册列表
eureka.client.fetch-registry: false
# 是否注册服务中心Eureka
eureka.client.register-with-eureka: false

provider_service:

1.在服务提供者provider_service工程中添加Eureka客户端依赖

<!--eureka客户端starter-->
<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
</dependencies>
<!--SpringCloud,BOM,依赖清单导入,所有依赖管理的坐标-->
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Greenwich.SR3</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

2.在启动类上开启Eureka客户端发现功能@EnableDiscoveryClient

@SpringBootApplication
@EnableDiscoveryClient // 开启Eureka客户端发现功能
public class UserApplication {

    public static void main(String[] args) {
        SpringApplication.run(UserApplication.class,args);
    }
}

3.修改配置文件:spring.application.name指定应用名称,作为服务ID使用

# 端口
server.port: 9091
# DB 配置
spring.datasource.driver-class-name: com.mysql.cj.jdbc.Driver
spring.datasource.url: jdbc:mysql://127.0.0.1:3306/springcloud?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
spring.datasource.password: root
spring.datasource.username: root

# 应用名称
spring.application.name: user-service
# 注册中心地址
eureka.client.service-url.defaultZone: http://127.0.0.1:10086/eureka

4.完成之后重启项目

5.客户端代码会自动把服务注册到EurekaServer中,在Eureka监控页面可以看到服务注册成功信息

consum-service:

  1. 通过注册中心客户端对象DiscoveryClient,获取Eureka中注册的user-service实例列表

  2. 获取user-service服务实例对象

  3. 从实例对象中获取host地址和端口,拼接请求地址

  4. 使用RestTemplate发送请求

@RestController
@RequestMapping("/consumer")
public class ConsumerController {
    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private DiscoveryClient discoveryClient;

    @GetMapping("{id}")
    public User queryById(@PathVariable Long id){
        String url = String.format("http://localhost:9091/user/%d", id);

        //1、通过注册中心客户端对象DiscoveryClient,获取Eureka中注册的user-service实例列表
        List<ServiceInstance> serviceInstanceList = discoveryClient.getInstances("user-service");
        //2、获取user-service服务实例对象
        ServiceInstance serviceInstance = serviceInstanceList.get(0);
        //3、从实例对象中获取host地址和端口,拼接请求地址
        url = String.format("http://%s:%s/user/%d", serviceInstance.getHost(), serviceInstance.getPort(), id);
        //4.使用RestTemplate发送请求
        return restTemplate.getForObject(url,User.class);
    }
}
# 默认注册时使用的是主机名,想用ip进行注册添加如下配置
# ip地址
eureka.instance.ip-address: 127.0.0.1
# 更倾向于使用ip,而不是host名
eureka.instance.prefer-ip-address: true

服务续约: 

# 租约续约间隔时间,默认30秒
eureka.instance.lease-renewal-interval-in-seconds: 30 

获取服务中心 

# 每隔多久获取服务中心列表,(只读备份)
eureka.client.registry-fetch-interval-seconds: 30 

 失效剔除:

# 租约到期,服务时效时间,默认值90秒
eureka.instance.lease-expiration-duration-in-seconds: 90 

自我保护:Eureka会统计服务实例最近15分钟心跳续约的比例是否低于85%,如果低于则会触发自我保护机制。

#向Eureka服务中心集群注册服务
eureka.server.enable-self-preservation: false # 关闭自我保护模式(默认值是打开)

 1.3.2负载均衡 Spring Cloud Ribbon

实现步骤:

第一步:启动多个user_service服务

  1. 修改配置文件端口获取方式

  2. 编辑应用启动配置

  3. 启动两个提供者服务

  4. 在注册中心查询是否启动成功

第二步:开启消费者负载均衡

  1. 在RestTemplate的注入方法上加入@LoadBalanced注解

    @Bean
    @LoadBalanced//开启负载均衡
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }

     

  2. 修改调用请求的Url地址,改为服务名称调用

    @RequestMapping("/ribbonconsumer/{id}")
    public String queryByIdByRibbon(@PathVariable Integer id){
        String url = "http://user-service/user/findById?id="+id;
        String user = restTemplate.getForObject(url, String.class);
        return user;
    }

     

  3. 访问页面查看效果

# 修改服务地址轮询策略,默认是轮询,配置之后变随机,RoundRobinRule
user-service:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

 

1.3.3熔断器 Spring Cloud Hystrix

Hystrix被设计的目标是:

  • 对通过第三方客户端库访问的依赖项(通常是通过网络)的延迟和故障进行保护和控制。

  • 在复杂的分布式系统中阻止雪崩效应。

  • 快速失败,快速恢复。

  • 回退,尽可能优雅地降级。

目标:服务提供者的服务出现了故障,服务消费者快速失败给用户友好提示。体验==服务降级==

实现步骤:

  1. 引入熔断的starter依赖坐标

  2. 开启熔断的注解@EnableCircuitBreaker

  3. 编写服务降级处理的方法

  4. 配置熔断的策略

  5. 模拟异常代码

  6. 测试熔断服务效果

实现过程:

 

引入熔断的依赖坐标:

  • consumer_service中加入依赖

    <!--熔断Hystrix starter-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
    </dependency>

     

    开启熔断的注解

  • //注解简化写法:微服务中,注解往往引入多个,简化注解可以使用组合注解。@SpringCloudApplication =等同于@SpringBootApplication+@EnableDiscoveryClient+@EnableCircuitBreaker
    @SpringBootApplication
    @EnableDiscoveryClient//开启服务发现
    @EnableCircuitBreaker//开启熔断
    public class ConsumerApplication {
        @Bean
        @LoadBalanced//开启负载均衡
        public RestTemplate restTemplate(){
            return new RestTemplate();
        }
        public static void main(String[] args) {
            SpringApplication.run(ConsumerApplication.class,args);
        }
    }

    编写服务降级处理方法:使用@HystrixCommand定义fallback方法。

    @RequestMapping("/ribbonconsumer/{id}")
    @HystrixCommand(fallbackMethod ="queryByIdFallback")
    public String queryById(@PathVariable Long id){
        String url = String.format("http://user-service/user/%d", id);
        return restTemplate.getForObject(url,String.class);
    }
    
    public String queryByIdFallback(Long id){
        return "对不起,网络太拥挤了!";
    }

    配置熔断策略

  • 常见熔断策略配置

  • 熔断后休眠时间:sleepWindowInMilliseconds

  • 熔断触发最小请求次数:requestVolumeThreshold

  • 熔断触发错误比例阈值:errorThresholdPercentage

  • 熔断超时时间:timeoutInMilliseconds

  •  

    # 配置熔断策略:
    # 强制打开熔断器 默认false关闭的。测试配置是否生效
    hystrix.command.default.circuitBreaker.forceOpen: false
    # 触发熔断错误比例阈值,默认值50%
    hystrix.command.default.circuitBreaker.errorThresholdPercentage: 20
    # 熔断后休眠时长,默认值5秒
    hystrix.command.default.circuitBreaker.sleepWindowInMilliseconds: 60000
    # 熔断触发最小请求次数,默认值是20
    hystrix.command.default.circuitBreaker.requestVolumeThreshold: 5
    # 熔断超时设置,默认为1秒
    hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds: 2000

     

  • 方法上服务降级的fallback兜底方法

    • 使用HystrixCommon注解,定义

    • @HystrixCommand(fallbackMethod="queryByIdFallBack")用来声明一个降级逻辑的fallback兜底方法

  • 类上默认服务降级的fallback兜底方法

    • 刚才把fallback写在了某个业务方法上,如果方法很多,可以将FallBack配置加在类上,实现默认FallBack

    • @DefaultProperties(defaultFallback=”defaultFallBack“),在类上,指明统一的失败降级方法;

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值