微服务入门:SpringCloud常用组件实操|青训营

68 阅读6分钟

Spring Cloud

微服务:将一个大的应用,拆分成多个小模块(“服务”),每个模块有自己的功能和职责,可以部署在不同的机器上,可进行交互。

集群:多个相互独立、同个高速网络互联的计算机构成一组,一起做相同的事,提供相同的服务。

Spring Cloud 是基于 Spring Boot 的、微服务系统架构的一站式解决方案

本文使用版本:

  • springboot:2.3.0.RELEASE
  • springcloud:Hoxton.SR12

常用组件:

  • 服务注册与发现:eureka、nacos、consul
  • 声明式服务调用:feign
  • 客户端负载均衡:ribbon
  • 网关:zuul
  • 容错:hystrix
  • 分布式配置:config

Eureka

服务治理:微服务架构中各微服务实例的快速上线或下线且保持各服务能正常通信的能力

服务注册:服务实例将自身服务信息注册到注册中心。 服务发现:服务实例通过注册中心,获取到注册到其中的服务实例的信息,通过这些信息去请求他们提供服务。 服务剔除:服务注册中心将出问题的服务自动剔除到可用列表之外,使其不会被调用到。

  • Eureka Server:eureka服务器 。维护一个服务注册表,存储所有可用服务节点的信息,可以在界面中直观看到。 @EnableEurekaServer

  • Eurake Client:eureka客户端。 @EnableDiscoveryClient

    • 消费者consumer:调用提供者接口实现业务,一般包含复杂业务逻辑和数据封装
    • 提供者provider:提供接口供其他服务调用,一般包含数据库操作和简单业务逻辑

操作:

  • 创建server:创建项目、添加依赖(eurekaServer)、启动类注解、yml配置信息、运行验证

  • 注册微服务(消费者、提供者)到注册中心:创建项目、添加依赖(eurekaClient、web)、启动类注解、配置信息(端口号、当前服务名称、服务端地址)、运行验证

  • 添加用户认证:

    • server:添加security依赖、配置文件中配置用户名密码
    • client:修改配置文件:在注册中心地址前加上“用户名:密码@”

CAP原则:一致性、可用性、分区容错性

zookeeper:CP 注重数据一致性

eureka:AP 注重高可用性

Feign

声明式REST接口调用,基于HTTP请求

遇到问题:

  • feign不支持“_” 将服务名称中的_改为 “-”即可
  • 提示get请求的方法不支持‘POST’请求,在消费者的feign接口的方法参数前加上 @RequestParam 注解使该方法强制调用get请求;那么如果出现post请求的方法不支持‘GET’请求这种报错,则加上 @RequestBody 注解使该方法强制调用post请求。

操作:

  • 在提供者服务添加类和方法
  • 在消费者服务中添加feign依赖(openfeign)
  • 启动类添加注解@EnableFeignClients
  • 创建feign接口(@FeignClients)并在属性name指定提供者服务的名称
  • 创建具体实现类和方法(将feign接口注入,调用其方法)

Hystrix

feign自动整合了Hystrix,所以不需要导入依赖

  • 在consumer中创建容错处理类,注入容器,实现feign接口,重写方法。
  • 修改feign接口的@FeignClients注解:添加属性fallback,值为容错处理类.class
  • 修改consumer的配置文件:添加feign.hystrix.enabled.true

Ribbon

服务端负载均衡:反向代理,把客户端请求分发到可用的服务器上。例:Nginx

客户端负载均衡:在客户端获取所有可用的服务节点,选择其中一个节点进行访问。

Ribbon:客户端负载均衡。可以直接从eureka server中获取所有服务提供者的节点地址,再根据指定的负载均衡策略选择某个节点进行访问。

策略:

  • 轮询
  • 响应时间越长,权重越低,被选中的可能性越小
  • 随机
  • 综合考虑性能和可用性
  • 重试
  • 选择并发请求最小的节点
  • 过滤掉请求失败以及高并发的节点

操作:

  • 因为eureka和feign都整合了ribbon,所以不需要添加依赖
  • 修改提供者的方法中的参数和实现(无参->带参),添加日志输出功能 @Slf4j (lombok注解)
@RestController
@Slf4j
public class UserService {
    @GetMapping("/login")
    public String login(@RequestParam("count") int count) throws Exception{
        log.info("login>>"+count+"user-provider-8082");
        return "用户登录(provider1)";
    }
}
  • 复制一份provider的模块,重命名为provider-second,修改配置信息中的端口号,服务名称不用变,将日志输出信息改为自己的
log.info("login>>"+count+"user-provider-second-8083");
  • 修改消费者的feign接口对应的抽象方法以及具体实现类的具体方法,多次调用feign接口的方法。
@FeignClient(name = "user-provider",fallback = UserFeignClientFallBack.class)
public interface UserFeignClient {
    @GetMapping("/login")
    public String login(@RequestParam("count") int count);
}
@RestController
public class LoginController {
    @Autowired
    private UserFeignClient userFeignClient;
    
    @GetMapping("/login")
    public String login(){
        for(int i=0;i<10;i++){
            userFeignClient.login(i);
        }
        return "ribbon负载均衡";
    }
}
  • 依次启动注册中心、提供者1、提供者2、消费者,访问消费者的方法接口,观察两个提供者的日志信息。默认负载均衡策略是轮询

image.png

image.png

  • 通过配置文件修改负载均衡策略:
user-provider: ##服务提供者名字
  ribbon:
    NFloadBalancerRuleClassName: com.netfilx.loadbalancer.RandomRule
  • 挂掉其中一个提供者,那么所有的请求都由另一个提供者承担

Zuul

zuul的核心是一系列过滤器,功能:身份认证和安全、审查与监控、动态路由、静态相应处理、弹性负载均衡。

操作:

  • 新建eureka client项目,添加zuul依赖
<dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
  • 配置文件信息:
server:
  port: 8086
spring:
  application:
    name: gateway-zuul
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8080/eureka/
  • 启动类添加注解:@EnableZuulProxy,声明这是zuul代理,默认使用ribbon进行负载均衡,Hystrix进行容错处理。
  • 路由配置:在配置文件中增加各个微服务的访问路径映射
zuul:
  routs:
    user-consumer: /user/**      ##微服务名:映射路径
    ##如果要访问user-consumer中的方法,需要在正常访问地址前增加前缀
    ##原来:http://localhost:8081/login
    ##现在:http://localhost:8081/user/login  此时访问改地址,就会被网关转发到原地址
  • 使用过滤器过滤请求:创建过滤器类,继承ZuulFilter,重写几个方法,在run()方法中编写过滤逻辑,比如:preFilter可以实现每次在zuul转发请求前根据请求地址结合自定的接口规则来判断是否需要验证token,如果不需要,就直接转发请求;如果需要,就获取请求头中的token,通过该token在数据库redis中查询,查询到则继续转发请求,查询不到就视为无效请求。
@Component
@Slf4j
public class PreFilter extends ZuulFilter {
    @Override
    public String filterType() {
        return "pre";
    }
    @Override
    public int filterOrder() {
        return 0;
    }
    @Override
    public boolean shouldFilter() {
        return true;
    }
    @Override
    public Object run() throws ZuulException {
        //
        return null;
    }
}
  • 在启动类中添加过滤器定义,注入容器(@bean
@SpringBootApplication
@EnableZuulProxy
public class GatewayZuulApplication {
​
    public static void main(String[] args) {
        SpringApplication.run(GatewayZuulApplication.class, args);
    }
    
    @Bean
    public PreFilter preFilter(){
        return new PreFilter();
    }
}
  • 禁用某个过滤器
zuul:
    PreFilter: ##过滤器名
        pre:   ##过滤器类型 pre、rout、post、error
            disable: true   

Config

分布式配置

Sleuth

分布式追踪:

  • Trace:一个 Trace 代表一个完整的请求流程,包括从客户端发起请求到服务器处理完毕并返回响应的整个过程。Trace 由一个或多个 Span 组成。
  • Span:一个 Span 代表一个独立的工作单元,通常对应一个特定的服务或操作。Span 是 Trace 的组成部分,用于表示请求在各个服务之间的执行路径。

操作:

  • 在提供者和消费者的pom.xml中添加sleuth依赖
<dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
  • 依次运行注册中心、提供者、消费者,可以看到日志中有追踪信息

image.png