SpringCloud学习笔记 02、SpringCloud六大基础组件使用(二)

本文涉及的产品
传统型负载均衡 CLB,每月750个小时 15LCU
EMR Serverless StarRocks,5000CU*H 48000GB*H
应用型负载均衡 ALB,每月750个小时 15LCU
简介: SpringCloud学习笔记 02、SpringCloud六大基础组件使用(二)

四、实现负载均衡(Ribbon)


4.1、认识负载均衡


负载均衡类型


负载均衡两种类型:


客户端负载均衡:Ribbon

服务端负载均衡:Nginx

对于客户端:在调用的时能够看到对应的所有节点,我依次去调用即可,由我调用的人去考虑问题。


一般用于服务之间内部进行调用会使用Ribbon,而不是nginx(使用的话无非将我们的链路增长),

对于服务端:所有的请求先来到nginx,由它来进行分发转发


像用户来发送请求,统一Nginx收取进行分发。


认识策略


负载均衡策略三种


RandomRule:表示随机策略,每次都会随机调用

RoundRobinRule:表示轮询策略,表示一个个进行调用,比较好的能够平衡各个节点压力

ResponseTimeWeightedRule加权:根据每一个Server的平均响应时间动态加权。也就是说会进行评估,例如三个节点,有一个节点机器比较差,后两个节点机器比较好,使用该策略就会去进行动态评估,机器不好的会少给几个请求


4.2、实操配置ribbon


如何配置策略?


通过在yaml中添加Ribbon.NFLoadBalancerRuleClassName进行配置。

实操配置:例如当前course-price服务要远程调用course-list服务,此时我们可以进行配置ribbon配置策略


course-price服务的配置内容:


# 服务id=>命名空间=>配置属性
course-list:   # 当前远程调用的服务application名
  ribbon:
    NFLoadBanlancerRuleClassName: com.netflix.loadbalancer.RoundRobinRule  # 轮询策略


course-list服务配置:


ribbon:
  eureka:
    enabled: true



五、断路器Hystrix


5.1、认识断路器


进行远程调用的时候出现了延迟或者服务不可用就能够起到保护的功能。


当某一个单元发生故障的时候,就可以利用断路器把它隔离出去。帮助我们快速优雅的构建断路的功能,当访问异常的时候就返回默认的响应,而不用长时间的让用户去等待,避免在分布式系统中出现故障导致蔓延。


下面是某个请求调用多个服务时某个服务出现故障导致延迟一定时间;右边则是多个请求对同一个服务进行请求时,若是该服务故障则会导致连接数量急剧增多,容易导致服务器瘫痪。




5.2、集成Hystrix


前提:一般的话是集成好了Feign之后,我们才会对某个服务使用断路器。


配置:


1、引入依赖


<!--    引入断路器模块    -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<!--       SpringCloud指定版本,springboot2.1.x     -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-dependencies</artifactId>
    <version>Greenwich.SR5</version>
    <type>pom</type>
    <scope>import</scope>
</dependency>


2、yaml打开断路器


feign:
  hystrix:
    enabled: true  # 远程调用断路器


3、springboot启动器添加注解


@EnableCircuitBreaker    //打开断路器


4、对默认情况进行配置,找到指定client接口,对应的注解配置fallback指定类,该类则是调用异常默认返回的方法,这里写的就是发送错误时的方法



//指定fallback,也就是当远程调用的服务不可用时对应接口的默认返回
@FeignClient(value = "course-list",fallback = CourseListClientHystrix.class)   
public interface CourseListClient {
    @GetMapping("/course/list")
    List<Course> getList();
}
//1、同样实现CourseListClient接口,重写其中的对应的接口方法,该方法用于作为服务不可调用时返回的默认值
@Component
public class CourseListClientHystrix implements CourseListClient{
    @Override
    public List<Course> getList() {
        Course course = new Course();
        course.setId(0);
        course.setCourseId(0);
        course.setName("Java从入门到精通");
        course.setValid(0);
        return Collections.singletonList(course);
    }
}



效果:一旦getListz()接口远程调用能够访问就会返回调用远程接口返回的值,若是对应服务不可用或者其他问题时就会返回我们指定接口的默认值。



六、网关Zuul(统一管理)


为什么需要网关?


对于分布式远程调用,服务与服务之间都能够进行互相调用,若是我们在某个服务上做鉴权或者说单个自己开个服务用于鉴权,都是会有一定的问题的,单个服务上做鉴权,那么其他服务都需要额外再写一套;单个服务做鉴权,你还要考虑转发的问题。此时就会出现签名校验、登陆校验冗余等问题。

此时就出现了Zuul网关,用于统一管理多个服务,想要访问某个服务必须先要通过网关之后才能够访问到服务。



6.1、springboot集成Zuul网关


引入依赖:


<dependencies>
    <!--    用于服务注册     -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
    <!--    zuul网关     -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
    </dependency>
</dependencies>
<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>


添加一个启动器类:


import org.springframework.boot.SpringApplication;
import org.springframework.cloud.client.SpringCloudApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
/**
 * @ClassName ZuulGatewayApplication
 * @Author ChangLu
 * @Date 2021/10/5 8:27
 * @Description 网关启动类
 */
@EnableZuulProxy   //开启Zuul代理
@SpringCloudApplication  //包含springboot启动器注解、开启服务注册发现、开启断路器
public class ZuulGatewayApplication {
    public static void main(String[] args) {
        SpringApplication.run(ZuulGatewayApplication.class,args);
    }
}


配置文件:


spring:
  application:
    name: zuul-gateway  # 注册到服务中心的应用名称
server:
  port: 9000
# 指定注册的服务中心地址,一般与eureka-server中配置的对应,此时该服务启动就会将自己注册到服务中心
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8000/eureka/


此时我们就已经搭建了一个网关Zuul的服务,我们将项目启动:可以看到zuul网关也被注册到服务中心去了



此时我们就可以通过这个zuul网关来进行访问其他两个服务:


①http://localhost:9000/course-list/course/list:9000端口(网关)、服务名(application name)、uri接口路径



②http://localhost:9000/course-price/courseprice/courseprice:9000端口(网关)、服务名(application name)、uri接口路径



我们可以看到通过走9000端口的网关服务也能够去访问到同在注册中心的其他服务,在这里我们是没有对zuul服务的访问前缀作限制,这里就是/。


再说明一下,不走网关的话像之前一样只要你知道对应的ip地址端口号以及服务名你同样能够访问到该服务,这都是没有影响的:




6.2、配置路由地址(针对于服务)


在6.1中,我们通过搭建一个zuul网关服务将其注册到服务中心,此时我们就可以通过该网关来访问到其他的服务,默认访问官网服务是没有对应的前缀/xxx的,并且访问指定的服务需要根据在服务中心上注册的application name才能够进行访问到指定的服务,下面来进行配置zuul网关服务的前缀url以及对应其他服务的路由地址。


下面是在zuul服务的yaml配置中的内容:


# zuul的相关配置
zuul:
  prefix: /changlu   # 访问zuul网关的前缀url(由原来的/ => /changlu)
  routes:            # 路由配对,下面有两组服务
    course-list: 
      path: /list/**             # 2、指定的服务路由转换 (例如由原来的/course-list => /list)
      service-id: course-list    # 1、指定的服务名(application name):课程服务
    course-price:
      path: /price/**
      service-id: course-price


配置好之后看效果:


# 配置之前访问服务地址
http://localhost:9000/course-list/course/list
http://localhost:9000/course-price/courseprice/courseprice
# 配置之后访问服务地址
http://localhost:9000/changlu/list/course/list
http://localhost:9000/changlu/price/courseprice/courseprice


同样说明一下,不走网关直接访问服务也是ok的!



6.3、实现网关过滤器(统计请求时长)


介绍过滤器


首先介绍下面几个过滤器:


pre 过滤器在路由请求之前运行

route 过滤器可以处理请求的实际路由

post 路由请求后运行过滤器

error 如果在处理请求的过程中发生错误,则过滤器将运行


实现pre、post过滤器,统计请求执行时间



PreRequestFilter:前置请求过滤器


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;
/**
 * @ClassName PreRequestFilter
 * @Author ChangLu
 * @Date 2021/10/5 9:26
 * @Description 前置请求过滤器
 */
@Component
public class PreRequestFilter extends ZuulFilter {
    @Override
    public String filterType() {
        //过滤器类型
        return FilterConstants.PRE_TYPE;
    }
    @Override
    public int filterOrder() {
        //过滤器顺序
        return 0;  //0-1000 从小到大顺序依次执行,这里表示第一个执行
    }
    @Override
    public boolean shouldFilter() {
        return true;  //是否启动过滤器
    }
    //具体过滤器中执行的方法
    @Override
    public Object run() throws ZuulException {
        RequestContext currentContext = RequestContext.getCurrentContext();
        currentContext.set("startTime",System.currentTimeMillis());
        System.out.println("前缀过滤器pre已经记录时间");
        return null;
    }
}


PostRequestFilter:后置器请求过滤器


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;
/**
 * @ClassName PostRequestFilter
 * @Author ChangLu
 * @Date 2021/10/5 9:31
 * @Description 后置请求处理器
 */
@Component
public class PostRequestFilter extends ZuulFilter {
    @Override
    public String filterType() {
        return FilterConstants.POST_TYPE;
    }
    /**
     * filter执行顺序,值越小优先级越高
     * 官方推荐使用x-1方式优先排序
     * @return
     */
    @Override
    public int filterOrder() {
        return FilterConstants.SEND_RESPONSE_FILTER_ORDER-1;  //响应过滤器为1000,这里-1表示该过滤器越优先执行
    }
    @Override
    public boolean shouldFilter() {
        return true;
    }
    @Override
    public Object run() throws ZuulException {
        RequestContext currentContext = RequestContext.getCurrentContext();
        Long startTime = (Long) currentContext.get("startTime");
        Long duration = System.currentTimeMillis() - startTime;
        String uri = currentContext.getRequest().getRequestURI();
        System.out.println("uri:"+uri+",处理时长为:"+duration);
        return null;
    }
}


效果:统计访问一个请求时处理的时长!


相关实践学习
SLB负载均衡实践
本场景通过使用阿里云负载均衡 SLB 以及对负载均衡 SLB 后端服务器 ECS 的权重进行修改,快速解决服务器响应速度慢的问题
负载均衡入门与产品使用指南
负载均衡(Server Load Balancer)是对多台云服务器进行流量分发的负载均衡服务,可以通过流量分发扩展应用系统对外的服务能力,通过消除单点故障提升应用系统的可用性。 本课程主要介绍负载均衡的相关技术以及阿里云负载均衡产品的使用方法。
相关文章
|
1天前
|
监控 负载均衡 Java
5 大 SpringCloud 核心组件详解,8 张图彻底弄懂
本文图文详解 Spring Cloud 的五大核心组件,帮助深入理解和掌握微服务架构。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
5 大 SpringCloud 核心组件详解,8 张图彻底弄懂
|
4天前
|
负载均衡 算法 Java
除了 Ribbon,Spring Cloud 中还有哪些负载均衡组件?
这些负载均衡组件各有特点,在不同的场景和需求下,可以根据项目的具体情况选择合适的负载均衡组件来实现高效、稳定的服务调用。
17 5
|
1月前
|
负载均衡 Java API
【Spring Cloud生态】Spring Cloud Gateway基本配置
【Spring Cloud生态】Spring Cloud Gateway基本配置
37 0
|
3月前
|
负载均衡 监控 Java
SpringCloud常见面试题(一):SpringCloud 5大组件,服务注册和发现,nacos与eureka区别,服务雪崩、服务熔断、服务降级,微服务监控
SpringCloud常见面试题(一):SpringCloud 5大组件,服务注册和发现,nacos与eureka区别,服务雪崩、服务熔断、服务降级,微服务监控
SpringCloud常见面试题(一):SpringCloud 5大组件,服务注册和发现,nacos与eureka区别,服务雪崩、服务熔断、服务降级,微服务监控
|
3月前
|
Java Spring
【Azure Spring Cloud】Spring Cloud Azure 4.0 调用Key Vault遇见认证错误 AADSTS90002: Tenant not found.
【Azure Spring Cloud】Spring Cloud Azure 4.0 调用Key Vault遇见认证错误 AADSTS90002: Tenant not found.
|
3月前
|
Java Spring 容器
【Azure Spring Cloud】在Azure Spring Apps上看见 App Memory Usage 和 jvm.menory.use 的指标的疑问及OOM
【Azure Spring Cloud】在Azure Spring Apps上看见 App Memory Usage 和 jvm.menory.use 的指标的疑问及OOM
|
3月前
|
存储 Java Spring
【Azure Spring Cloud】Azure Spring Cloud服务,如何获取应用程序日志文件呢?
【Azure Spring Cloud】Azure Spring Cloud服务,如何获取应用程序日志文件呢?
|
3月前
|
SQL Java 数据库连接
【Azure Spring Cloud】Azure Spring Cloud connect to SQL using MSI
【Azure Spring Cloud】Azure Spring Cloud connect to SQL using MSI
|
3月前
|
Java 开发工具 Spring
【Azure Spring Cloud】使用azure-spring-boot-starter-storage来上传文件报错: java.net.UnknownHostException: xxxxxxxx.blob.core.windows.net: Name or service not known
【Azure Spring Cloud】使用azure-spring-boot-starter-storage来上传文件报错: java.net.UnknownHostException: xxxxxxxx.blob.core.windows.net: Name or service not known
|
3月前
|
NoSQL Java Redis
【Azure Spring Cloud】Java Spring Cloud 应用部署到Azure上后,发现大量的 java.lang.NullPointerException: null at io.lettuce.core.protocol.CommandHandler.writeSingleCommand(CommandHandler.java:426) at ... 异常
【Azure Spring Cloud】Java Spring Cloud 应用部署到Azure上后,发现大量的 java.lang.NullPointerException: null at io.lettuce.core.protocol.CommandHandler.writeSingleCommand(CommandHandler.java:426) at ... 异常
下一篇
无影云桌面