Springcloud+Spring Alibaba学习笔记

概述:最近学完了尚硅谷阳哥的Springcloud第二季,特此记下笔记。通过此笔记,你可以大致的了解Springcloud全家桶与SpringAlibaba在微服务中的作用。

首先,上一张springcloud迭代图。
Springcloud+Spring Alibaba学习笔记_第1张图片
Eureka(飞机):作为服务注册中心,可以及时的响应微服务启动并将其注册进入其中。作为ACP原则中的AP(高可用性(当微服务挂掉的时候,Eureka并不会立马抹去微服务),分区性(Eureka集群模式)),可以显示当前启动的微服务、以及它们的所在服务器和显示ip。Eureka自带负载均衡功能,本身与Rribbon相结合,通过restTemplate与@LoadBlance注解实现负载均衡。默认的负载模式是轮询负载。这一点可以从Eureka的依赖中看出,如图:
Springcloud+Spring Alibaba学习笔记_第2张图片
Nacos(飞机):作为阿里的开源项目,微服务注册中心(当然,也可以作为微服务的配置中心,后面会讲)的后起之秀。在ACP原则中,它既可以作为AP,也可以作CP。Eureka有的作用Nacos同样也有,例如可视化界面、服务监听等。 配置通常较为简单,如图:

spring:
  application:
    name: nacos-payment-provider
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848

还有一点,别忘记在启动类上加上@EnableDiscoveryClient注解,标识注册中心。
Zookeeper(飞机):同样的,服务注册中心也可以是ZK,但是比起前面两种,ZK并没有可视化界面。作为ACP中的CP原则,当微服务挂掉的时候,ZK上的service下的微服务名称节点立马挂掉。配置如图:

spring:
  application:
    name: payment-zk-service
  cloud:
    zookeeper:
      connect-string: 10.201.7.113:2181

ZK的默认端口为2181,有一点需要注意的是,搭建ZK环境的服务器至少要有3台,这是由它内部的选举机制决定的。
Ribbon(飞机):作为微服务调用负载工具,可以有效的减缓服务器端的压力,防止流量定点直冲,造成服务雪崩。自带轮询负载,当然也可以通过自定义设置负载模式。
OpenFeign(飞机):作为Feign的取代者。Feign有的功能OpenFeign同样也有。由于Feign已经停止维护,所以需使用OpenFeign实现微服务的便捷调用。为什么要使用OpenFeign这个工具?举个例子:现有订单微服务和库存微服务。通用逻辑是下订单->减库存。现库存微服务在3台服务器上运行着(真实环境就是如此,高可用),那在订单微服务中如何调?指定Ip和端口?这样不能负载。所以,需要通过OpenFeign中@FeignClient注解再结合Eureka实现多台服务器的轮询调用,达到负载目的。如图:

@ComponentScan
@FeignClient(value = "PAYMENT-SERVICE") //指定微服务名称->对应Spring application name
public interface FeignService {
     

    @RequestMapping("/select/{id}") //对应上面服务名下的接口
    CommonResponse<Payment> select(@PathVariable("id") Long id);
}

Hystrix(飞机):简称豪猪哥。是一款当服务挂掉时(运行异常、超时、宕机),给用户反馈一个友好信息。拥有服务降级、熔断等功能。

服务降级:当客户端调用接口的接口出现异常时,为避免长时间等待或者出现不合适的响应信息时,使用使用@HystrixCommand注解,进入指定指定方法,自定义响应信息。

降级代码如图:

@RestController
//@DefaultProperties(defaultFallback = "commonFallBack")  //全局服务降级通配标签
public class ConsumerController {
     

    @Autowired
    private ConsumerService consumerService;

    @RequestMapping("/ok")
    //服务降级(客户端超过最大等待时间3s或此方法执行出错,都将进入兜底方法okHanel)
    @HystrixCommand(fallbackMethod = "okHandel", commandProperties =
            {
     @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000")})
    public String ok() {
     
        return consumerService.ok();
    }

    public String okHandel() {
     
        return "您好,系统繁忙,请稍等重试~";
    }
}

其实,客户端的每个接口方法都有一个降级方法没必要,可以通过上图中的相关配置实现全局降级。

服务熔断:当调用目的接口达到一定的失败率的时候,进行服务熔断,并阻止外部调用,熔断器处于半开状态

通过熔断,可以有效的阻挡外部客户端再次调用微服务,防止出现服务出问题仍在调用的情况。有效代码如图:

@RestController
public class PaymentHystrixController {
     

    @Autowired
    private PaymentService paymentService;

    @RequestMapping("/testBreak/{id}")
    @HystrixCommand(fallbackMethod = "testBreakHandel",
            commandProperties = {
     
                    @HystrixProperty(name = "circuitBreaker.enabled", value = "true"), //熔断服务是否开启
                    @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"), //请求次数
                    @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "10000"), //时间范围
                    @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "60")}) //失败率
    public String testBreak(@PathVariable("id") Long id) {
     
        if (id < 0) {
     
            throw new RuntimeException("id不能为负数");
        }
        return "恭喜调用成功,此次服务的流水号为:" + UUID.randomUUID().toString();
    }

    //此处方法的参数不可不传,必须需要降级的方法保持一致,否则报错
    public String testBreakHandel(@PathVariable("id") Long id) {
     
        return "本次请求id:" + id + " 正在进行服务熔断,请稍后重试~";
    }

}

其中的@HystrixProperty属性可以控制熔断是否开启并设置熔断相关属性配置,已达到限流目的。
Getway(飞机):俗称网关。由于Zuul也已经停止维护,所以取而代之的是Getway。在网关中,有三个重要的概念:断言、路由、过滤。所谓路由就是微服务的唯一访问id(实际上就是域名),通常与断言(接口映射地址)一起使用,最后通过过滤层实现接口参数相关的过滤。yml配置如图(包含断言和路由配置):

spring:
  application:
    name: gateway-9527-service
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true
      routes:
        - id: payment-routh #路由的ID,没有固定规则但要求唯一,建议配合服务名
          uri: lb://payment-service #匹配后提供服务的路由地址 gateway与eureka通过微服务名称实现负载均衡
          predicates:
            - Path=/select/** #断言,路径相匹配的进行路由
            - After=2020-04-16T11:25:18.381+08:00[Asia/Shanghai] #表示在这个时段范围后才能访问上面的接口

过滤层实现如图:

@Service
public class GateWayFilter implements GlobalFilter, Ordered {
     
    @Override
    public Mono<Void> filter(ServerWebExchange serverWebExchange, GatewayFilterChain gatewayFilterChain) {
     

        //获取请求的参数
        String name = serverWebExchange.getRequest().getQueryParams().getFirst("name");

        //如果name为null,拒绝访问
        if (name == null) {
     
            System.out.println("用户名name为空,拒绝访问~");
            serverWebExchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
            return serverWebExchange.getResponse().setComplete();
        }
        return gatewayFilterChain.filter(serverWebExchange);
    }

    @Override
    public int getOrder() {
     
        return 0;
    }
}

Config(飞机):简称配置中心,可细分为服务端配置和客户端配置。主要对各个微服务子moudel里面的配置文件如yml进行配置。有一点可以了解下,配置中心可以在github、gitlab、gitee等代码托管中心。可根据自身喜好进行迁移。通过配置,指定托管中心,指定配置文件,服务配置如图:

spring:
  application:
    name: config-3344-service
  cloud:
    config:
       server:
        git:
          uri: git@gitee.com:chenghuanqing/springcloud-config.git #项目地址
          search-paths: - spring-cloud-config #仓库地址
       label: master
management:
  endpoints:
    web:
      exposure:
        include: 'bus-refresh' #暴露消息动态刷新点

客户端配置如图:

spring:
  application:
    name: config-client-3355-service
  cloud:
    config:
      label: master #分支名称
      name: conf #配置头
      profile: test #配置后缀
      uri: http://localhost:3344 #相当于访问http://localhost:3344/master/conf-test.yml

默认情况下,配置中心的配置一旦更改,服务端配置会立马刷新,而客户端的配置需要手动启动微服务刷新。这样就带来一个问题,加入微服务工程底下有几十个微服务,重启40下?接下来,介绍消息总线Bus。
Bus(飞机):作为消息总线,可以全方面覆盖进行了相关配置的微服务,做到配置一次刷新,处处生效的效果。一般来说,需要结合消息中间件例如RabbitMQ、Kafka结合使用。服务端配置如图:

spring:
  application:
    name: config-3344-service
  cloud:
    config:
       server:
        git:
          uri: git@gitee.com:chenghuanqing/springcloud-config.git #项目地址
          #uri: git@github.com:chq19970719/spring-cloud-config.git
          search-paths: - spring-cloud-config #仓库地址
       label: master
  rabbitmq: #新增消息中间件
        host: localhost
        port: 5672
        username: guest
        password: guest
management: 
  endpoints:
    web:
      exposure:
        include: 'bus-refresh' #暴露动态刷新点

客户端配置如下:

spring:
  application:
    name: config-client-3355-service
  cloud:
    config:
      label: master #分支名称
      name: conf #配置头
      profile: test #配置后缀
      uri: http://localhost:3344 #相当于访问http://localhost:3344/master/conf-test.yml
  rabbitmq: #新增消息中间件
        host: localhost
        port: 5672
        username: guest
        password: guest
        
#动态更新配置客户端
management:
  endpoints:
    web:
      exposure:
        include: "*"

通过配置,使用命令curl -X POST "http://localhost:3344/actuator/bus-refresh"即可实现消息的全局生效。
Nacos(飞机):上面说到Nacos作为服务注册中心的作用,同样的,Nacos也可以作为服务的配置中心。说白了,配置中心的作用就是将配置文件挂载到配置中心点上,以至于实现配置云端管理。目前来说,本人接触到的配置中心有Disconf、Nacos这两种。基于Nacos有这样的功能,所以也就替代了Springcloud中的Config+Bus组合。配置也是简单易懂,如图:

spring:
  application:
    name: sentinel-provider
  cloud:
    nacos:
      discovery:
        server-addr: 10.201.7.175:8848,10.201.7.176:8848,10.201.7.177:8848 #Nacos集群模式
    sentinel:
      transport:
        dashboard: localhost:8080
        port:
      datasource: #sentinel持久化配置,将配置信息放入nacos中的mysql
        d1:
          nacos:
            server-addr: 10.201.7.175:8848,10.201.7.176:8848,10.201.7.177:8848
            dataId: sentinel-provider
            groupId: DEFAULT_GROUP
            data-type: json
            rule-type: flow
management: #动态刷新配置
  endpoints:
    web:
      exposure:
        include: '*'

有一点需要说明,Nacos上的配置文件yaml等,数据默认是放在Nacos自带的数据库Derby上的。通常来说,实际开发中,需要将配置信息数据迁移到持久层框架Mysql中去,而且Mysql有主从库,可以有效防止数据丢失。
Sentinel(飞机):作为服务降级、熔断、限流的框架。Hystrix有的功能Sentinel同样也有,且配置更为人性化,不需要你在写配置代码,只需在Sentinel的可视化界面中进行相关配置即可。配置如下:

@RestController
public class ProviderController {
     
    @Value("${service.port}")
    String port;

    @RequestMapping("testSentinel/{id}")
    //降级、熔断、限流配置注解
    @SentinelResource(value = "testSentinel", blockHandler = "dealTestSentinel", fallback = "globalHandel",
            exceptionsToIgnore =RuntimeException.class) 
            //剔除指定异常造成的降级现象、直接出现ErrorPage
    public String testSentinel(@PathVariable String id) {
     
        if ("2".equals(id)) {
     
            throw new RuntimeException("非法id");
        }
        return "hi i am sentinel ,i am from " + " " + port;
    }

    //针对sentinel配置页面的限流降级配置所触发
    //当两者都配置时,此方法优先执行
    public String dealTestSentinel(@PathVariable String id,BlockException execption) {
     
        return "开始限流 " + execption.getMessage();
    }

    //针对java代码运行时异常触发
    public String globalHandel(@PathVariable String id) {
     
        return "兜底了";
    }
}

上图中,@SentinelResource注解是核心,其中的value是Sentinel页面配置上出现的资源名,它与访问映射只差了一个/,这点需要注意。后面的blockHandler意思是当超出Sentinel页面的限流配置例如QPS(每秒访问量)大于1,即触发服务降级。而当服务执行的时候发生异常时(比如上面的id为2)服务便会走fallback指定的方法。特别注意,如果同时出现QPS大于1,并且id=2的时候,那么此时,只会走限流方法dealTestSentinel,并没有走globalHandel方法。还有一点需要声明一下,Sentinel配置持久化的问题。例如,当你的微服务手动停止的时候,Sentinel上的所有的有关此微服务的配置全部失效。必须要重新配置。那么问题来了,灵魂拷问:微服务有40个,重新配置40个?且每个微服务下面都有不同环境的例如product、dev、test这样的环境,那不得配死人?所以,Sentinel的配置必须持久化,在上图中的yml文件中,我已经将持久化配置展示出来。配置之后,及时你重启微服务,Sentinel上的配置依然生效。

好了,以上就是最新版微服务架构讲解说明了,声明一下:这里并没有给出具体的各个框架的搭建,只是蜻蜓点水、告诉大家SringCloud全家桶与SpringAlibaba在微服务中的作用。具体的相关配置,如有不懂,请留言,我会逐一解答。

你可能感兴趣的:(java,spring)