SpringCloud学习笔记2----高级特性

关于springcloud学习笔记,用于谨记提示自己!

本篇代码(包括片段)基于上个笔记基础上 

注:springCloud是一种模式,其组件并非没有替换技术,甚至某些组件对另外组件功能也有不同实现,可以灵活在其中使用

Eurekahttps://github.com/Netflix/eureka

 注册中心Eurek:

云端服务发现,一个基于 REST 的服务,用于定位服务,以实现云端中间层服务发现和故障转移。

搭建环境:按上一篇中,搭建环境。

EurekaServer集群问题:

Eureka中集群是在每个EurekaServer中将自身服务相互注册即可集群

server: #server相关
  port: 8000 #对应相同的3份端口,8000,8001,8002

spring:
  application:
    name: eureka-server

eureka:
  client:
    register-with-eureka: true
    serviceUrl:
      defaultZone: http://192.168.8.128:8000/eureka,http://192.168.8.128:8001/eureka,http://192.168.8.128:8002/eureka

 其他参数相同即可,搭建3份,效果如下:

 以上是将服务注册到一份Eureka中,得到的集群效果,集群自动同步到所有存活集群EurekaServer服务中,可以通过简单配置实现高可用。

Eureka注册服务细节:

笔记参考:小码的小坑

EurekaClient启动时,会将自身服务信息发送到EurekaServer。然后进行向EurekaServer拉取注册表中服务信息,保存到EurekaClient中。当服务间相互调用其它服务时,在EurekaClient中获取服务信息(如服务地址,端口等)后,根据信息直接调用服务。(注:服务的调用通过http(s)调用),当某个服务只调用其他服务,自身不提供服务调用时。在EurekaClient启动后会拉取EurekaServer拉取注册表中服务信息,需要调用时,在EurekaClient的本地缓存中获取信息,调用服务。

EurekaClient会向EurekaServer发送心跳(默认每30秒)来续约服务的, 注册信息和续订被复制到集群中的EurekaServe所有节点。 以此来确保当前服务还“存活”,可以被调用。如果客户端持续不能续约,那么它将在一段时间(默认90秒)从服务器注册表中剔除,但是EurekaServer并不是立即剔除服务,而是将其加入剔除清单,默认每60s剔除一次。默认90s是最短剔除时间,可能因为剔除周期,或者自我保护影响。自我保护是,当服务心跳续约异常时,未按约定续约,EurekaServer会统计15分钟内心跳比例是否低于85%,用于判断是否剔除,保证容错。

来自任何区域的EurekaClient都可以查找注册表信息(每30秒发生一次),以此来确保调用“存活”服务。并且当某个服务被更新或者新加进来,也可以调用到新的服务。

EurekaClient拉取EurekaServer细节参考(Eureka的注册表拉取及多级缓存机制简析_LO_YUN的博客-CSDN博客)

服务注册:

#手动配置服务端口
server.port=8888
#配置服务名
spring.application.name=eureka-service
#服务注册中心地址
eureka.client.serviceUrl.defaultZone=http://192.168.8.129:8003/eureka

服务续约:

eureka.instance.lease-renewal-interval-in-seconds=30 #默认30s进行一次续约

服务清除:

eureka.instance.lease-expiration-duration-in-seconds=90 #默认续约失败90s进行清除

服务拉取:

eureka.client.registry-fetch-interval-seconds=30 #默认定时拉取周期30s

服务器剔除周期:

eureka.server.eviction-interval-timer-in-ms=1000 #剔除周期,默认60*1000ms

服务自我保护:

eureka.server.enable-self-preservation=true #是否打开自我保护,默认打开

目前服务相互调用可以使用://以下为代码片段,不可直接运行,是从上一篇(SpringCloud学习笔记_hmiaoerdai的博客-CSDN博客)抽取

        /*
            需要配置注入RestTemplate (spring整合的一个http客户端)
        */
        @Bean
        public RestTemplate restTemplate(){
            return new RestTemplate();
        }


        /*
            注入相关类
        */
        @Autowired
        RestTemplate restTemplate;
        @Autowired
        DiscoveryClient discoveryClient;

        /*
            调用逻辑
        */
        //从缓存注册列表信息获取服务信息
        List<ServiceInstance> instances = discoveryClient.getInstances("test-service");
        //获取该服务信息中的一个节点(服务集群可能会有多个节点)
        ServiceInstance serviceInstance = instances.get(0);
        //获取该节点的url
        URI uri = serviceInstance.getUri();
        //通过restTemplate调用特定方法,将获取信息以String输出,本质是通过http(s)协议交互
        String user = restTemplate.getForObject(uri+"/test",String.class);
        //控制台输出该user
        System.out.println(user);

该方法可以进行调用,但是有一定缺陷,并且略微繁琐,比如获取到了的List,可以以一定算法,进行复杂均衡,并且同时进行封装等,使代码高效且简洁可靠,springCloud已经做了这一部分事情,Ribbon(负载均衡)。

Ribbonhttps://github.com/Netflix/ribbon

负载均衡Ribbon:

提供云端负载均衡,有多种负载均衡策略可供选择,可配合服务发现和断路器使用。

简单使用:

添加依赖

<!-- ribbon启动器依赖坐标 -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>

简单使用,手动负载均衡:

    //注入
    @Autowired
    RibbonLoadBalancerClient ribbonClient;

    //调用缓存注册表信息,区别DiscoveryClient,获取的List<ServiceInstance>,负载均衡后仅获取一个
    ServiceInstance choose = ribbonClient.choose("test-service");                          
    System.out.println(restTemplate.getForObject(choose.getUri()+"/test",String.class));

正常使用,注解自动负载均衡:

    /*
        在配置注入RestTemplate时,添加@LoadBalanced注解
    */
    @Bean
    @LoadBalanced //该注解后,会通过负载均衡拦截器拦截RestTemplate的HTTP请求
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }


    /*
        调用服务逻辑,自动负载均衡底层和手动原理相同
    */
    //注解自动拦截restTemplate的HTTP请求,并负载均衡
    String url = "http://test-service/test";
    String userStr = restTemplate.getForObject(url, String.class);
    System.out.println(userStr);

结果:

 注意:如果开启注解自动均衡的话,默认会通过RibbonLoadBalancerClient去查找注册中心的instances,意味着所有都将会这样做,所以不能使用该restTemplate进行其他http访问,否则IllegalStateException: No instances available for xxx,如果确实需要可以结合@Qualifier(“XxxBean”)进行再装配一个不进行拦截负载均均衡的restTemplate

负载均衡细节:

负载均衡内部提供多种负载均衡算法,并且支持配置负载均衡算法和自定义算法。默认是进行轮询算法。

配置负载均衡算法:

#test-service服务名,RandomRule随机,将test-service负载均衡算法改为随机

test-service.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RandomRule

配置连接超时时间和请求处理超时时间

ribbon:
  ConnectTimeout: 5000 #请求连接的超时时间,默认时间为1秒
  ReadTimeout: 5000 #请求处理的超时时间

Hystrixhttps://github.com/Netflix/hystrix

熔断器Hystrix:

熔断器,容错管理工具,旨在通过熔断机制控制服务和第三方库的节点,从而对延迟和故障提供更强大的容错能力。

简单使用:

添加依赖坐标:

<!-- 熔断器依赖坐标 -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>

配置注解:在springboot入口中添加

//添加熔断降级注解
@EnableCircuitBreaker//熔断降级
@EnableDiscoveryClient//客户端注册,兼容多个注册中心
@SpringBootApplication//springBoot
//或者添加
@SpringCloudApplication//该注解包含上面3个注解,官方提供的标准springCloud注解

启用熔断降级服务:

import com.netflix.hystrix.contrib.javanica.annotation.DefaultProperties;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import top.mypapa.demo.mapper.TestTKMapper;

@RestController
@DefaultProperties(defaultFallback = "fallback")//配置默认降级方法
public class TestController {
    @Autowired
    TestTKMapper testMapper;

    @GetMapping("test")
    @HystrixCommand//开启熔断器服务
    //@HystrixCommand(commandProperties = {
    //    @HystrixProperty(name =     
    //    "execution.isolation.thread.timeoutInMilliseconds",value = "4000")
    //})//配置超时处理属性,从预设1000ms配置为3000ms
    //@HystrixCommand(fallbackMethod = "fallback")//开启熔断器服务,并配置单独降级方法,单独的降级方法
    public String test() throws Exception {
        try {Thread.sleep(3000);}catch (Exception e){e.printStackTrace();}//进行人为超时模拟
        return testMapper.selectByPrimaryKey(7).toString();
    }

    /*
    通用fallback,没有参数,返回值统一

    单独fallback,必须要参数和返回值与原方法完全一致
    
    因为一般返回交互基本都是json,所以可以进行返回值String,也可以使用专用返回对象,将其json化返回
     */
    public String fallback(){
        return "抱歉,服务器阵亡了!";
    }
}

测试用例:

    //测试直接查询,返回正常
    User user = testMapper.selectByPrimaryKey(7);
    System.out.println(user);

    //注解自动负载均衡,由于人为模拟超时,触发降级,返回执行降级方法
    String userStr = restTemplate.getForObject("http://test-service/test", String.class);
    System.out.println(userStr);

测试结果: 成功触发降级

熔断器细节:

配置细节在com.netflix.hystrix包下HystrixCommandProperties配置类中,可以参阅。

降级机制:服务超时进行,进行降级处理,进行降级,调用降级方法,结束等待,以保证服务活性

默认超时时长:1000ms

//default_executionTimeoutInMilliseconds可以通配置execution.isolation.thread.timeoutInMilliseconds属性改变

private static final Integer default_executionTimeoutInMilliseconds = 1000; // default => executionTimeoutInMilliseconds: 1000 = 1 second

所以上面人为进行线程3000ms睡眠,会造成超时,触发降级,返回->"抱歉,服务器阵亡了!"

 添加注解,并使用 @HystrixProperty进行配置execution.isolation.thread.timeoutInMilliseconds为3000

/*
    该注解作用在方法上,@DefaultProperties也可以使用相同方式配置作用域为类的配置
*/
@HystrixCommand(commandProperties = {
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "3000")
    })

效果如下:使用时间3007ms,依旧超时

 配置为4000ms,响应成功,没有触发降级,效果如下:

 Hystrix全局超时时长配置:

#在application.yml配置文件中添加该配置属性,可更改全局超时时长属性,单位ms
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=3000
#default位置可以配置相同类型作用范围,例如:test-service(服务),test(方法)等同样生效
hystrix.command.[作用范围名].execution.isolation.thread.timeoutInMilliseconds=3000

熔制机制:熔断器有三个状态,关闭,打开,半开,在服务正常进行时,超时仅仅会触发降级,熔断器关闭,如果失败超过阈值,熔断器将会进入打开状态,该状态所有方法直接熔断,返回fallback方法值,5s后进入半开状态,会通过部分请求,测试通过后关闭熔断,否则继续打开,等待下一个观察时间窗循环操作

熔断阈值:默认是失败比例的阈值50%,请求次数不低于20次

休眠时间:默认5s

 配置熔断和配置降级相同,只是属性不同:

//可以按照上面降级同样方式进行其他阈,或者application.yml配置
@HystrixCommand(commandProperties = {
    //启动熔断最低次数
    @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold",value = "20"),
    //配置观察时间窗,单位ms
    @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds",value = "5000"),
    //配置失败阈值
    @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage",value = "50")
    })

Feignhttps://github.com/OpenFeign/feign

伪装Feign:

Feign是一种声明式、模板化的HTTP客户端。

feign也是负载均衡处理器,是基于ribbon的,是在 Ribbon的基础上进行了一次改进,是一个使用起来更加方便的 HTTP 客户端。采用接口的方式, 只需要创建一个接口,然后在上面添加注解即可 ,将需要调用的其他服务的方法定义成抽象方法即可, 不需要自己构建http请求。然后就像是调用自身工程的方法调用,而感觉不到是调用远程方法,使得编写 客户端变得非常容易。

简单使用:

添加依赖坐标:

<!-- feign依赖坐标 -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

springBoot入口中配置启用feign注解:

@EnableFeignClients //配置使用feign

创建伪装申明类:(以springMVC注解形式伪装远程调用成申明式)

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;


/*
    通过springMVC形式伪装成申明式,完成远程调用
*/
@FeignClient("test-service")//服务名称
public interface UserClient {

    @GetMapping("test")
    String test();
}

注意:由于Feign底层使用Ribbon调用请求,Ribbon的默认超时时间为1s,所以超过1s就报错,需要向上面Ribbon超时配置一样配置较长一点时间

Feign细节:

使用Feign可以不用引入Ribbon和Hystrix了,因为Feign是基于Ribbon,所以不用引入Ribbon,并且集成有Hystrix,但是和springCloud组件流程不大相同,可以都实现,但是没必要,Feign流程是先Ribbon,在Hystrix,所以涉及一个Ribbon的超时重试机制,和Hystrix熔断降级机制的相互配合问题,一般是Ribbon<Hystrix,因为如果Ribbon超时过长,将会触发、Hystrix降级,执行降级逻辑,直接返回了,那么Ribbon重试就无效了。

开启Feign内置的Hystrix:默认关闭

feign.hystrix.enabled=true #开启feign熔断,默认关闭

配置降级方法:先配置fallback参数

@FeignClient(value = "test-service",fallback = UserClientFallback.class)//服务名称

实现声明伪装接口UserClient:UserClientFallback 中实现对应降级逻辑

import org.springframework.stereotype.Component;

@Component
public class UserClientFallback implements UserClient {

    @Override
    public String test() {
        return "查询失败,熔断触发!";
    }
}

 Hystrix的application.yml方式配置依旧有效,但是java注解配置和Hystrix不同

Zuulhttps://github.com/Netflix/zuul

网关Zuul:

Zuul 是在云平台上提供动态路由,监控,弹性,安全等边缘服务的框架。Zuul 相当于是设备和 Netflix 流应用的 Web 网站后端所有请求的前门。

简单使用:

新建maven工程,参考上一篇配置环境。

导入依赖:由于需要拉取eurekaServer中的

<!-- zuul网关依赖坐标 -->        
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>

<!-- eureka-client客户端依赖坐标 -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

springBoot入口添加注解:

@EnableZuulProxy

在application.yml配置中添加:大概作用是从EurekaServer中拉取信息做映射,注释中有配置详情

server: #server相关
  port: 7000

spring:
  application:
    name: gateway

#配置客户端,可以从EurekaServer中拉取注册表,进行映射配置
eureka:
  client:
    serviceUrl:
      defaultZone: http://192.168.8.129:8003/eureka
    registry-fetch-interval-seconds: 2 #拉取周期

#配置具体映射规则
zuul:
  routes:
    #配置映射
    test:
      path: /test/**
      serviceId: test-service
      #去除匹配前缀,zuul下配置,作用域为全局
      strip-prefix: false
    #简化配置
    test-service: /test-service1/**
  #排除映射,自动会将所有EurekaServer中服务名进行路径映射
  ignored-services:
    - eureka-server

效果演示:访问网关,将路径映射到test-service服务,并调用成功

 

zuul网关细节:

 zuul服务中的模式流程:

 在zuul中默认开启hystrix和ribbon,添加application.yml配置如下:

#hystrix超时时长
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=6000

#配置ribbon
ribbon.ConnectTimeout=5000 #请求连接的超时时间,默认时间为1秒
ribbon.ReadTimeout=5000 #请求处理的超时时间

配置过滤器:

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;

@Component
public class TestZuulFilter extends ZuulFilter {
    @Override
    public String filterType() {//过滤器类型,类型分为前置,后置,路由,错误
        return FilterConstants.PRE_TYPE;
    }

    @Override
    public int filterOrder() {//过滤级别
        return FilterConstants.PRE_DECORATION_FILTER_ORDER-1;
    }

    @Override
    public boolean shouldFilter() {//是否过滤
        return true;
    }

    @Override
    public Object run() throws ZuulException {//过滤逻辑
        RequestContext ctx = RequestContext.getCurrentContext();//获取上下文
        HttpServletRequest request = ctx.getRequest();//获取到请求
        System.out.println("拦截成功,打印request:========================================================================================================================"+request);
        if(false){
            ctx.setResponseStatusCode(403);//通过上下文返回状态码
            ctx.setSendZuulResponse(false);//通过上下文返回拦截
        }
        return null;
    }
}

过滤器效果:启用成功 ,并且正常输出拦截信息

做了基本的关于springCloud微服务的学习和分析,分析一下基本访问流程,用户从一个http请求,一般是从某个域名,域名服务器进行解析成ip,从而找到指定代理服务器(以nginx为例),nginx可以负载均衡,反向代理,和存放静态资源,非常有用的3个功能,代理服务器先返回静态资源,用户端解析静态资源,通过静态资源中的逻辑,进行异步交互(例如AJAX),请求再次到达nginx服务器,服务器会进行负载均衡,和反向代理,访问一个良好的zuul,zuul网关是后端逻辑的入口,正式进入后端逻辑,一般网关会进行鉴权,判断是否有该权限,没有拦截登录,有放行等等,然后zuul进行拉取EurekaServer注册表信息,也会负载均衡选择良好的EurekaServer,通过注册表信息进行负载均衡选择良好的服务节点,进行调用业务逻辑,其中可能会触发熔断降级等,因为网关存在该功能,可以用于保证系统生态,在调用业务逻辑中也可能会调用其他服务,也存在负载均衡和熔断器,可以通过Feign进行申明式伪装,Feign也存在负载均衡和熔断器,可以自我选择其一通过拉取注册表信息进行调用其他逻辑,从而完成整体业务逻辑,后返回。该流程实现前后端分离,微服务,部署可以对微服务部署docker,高可用,高并发,低耦合,拓展性强,利于部署维护等等,但是不太利于小业务开发,因为架构庞大,部署开发流程复杂,随然各种工具已经做了很多,并且系统复杂度提高了,整体效率等等也会带来相应负担等等其他的。

仅仅是因为学习过程中的思考,如有问题,敬请指正。

——2021.12.27

xiaochen

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值