Spring Cloud Alibaba相关记录

由 visionki 发布

原先做了个Spring Cloud的小项目(未完成),使用Spring的全家桶,其中注册中心用的是eureka,但目前2.X版本已经停止维护了。

最近刷到了Nacos相关的信息,去了解了下,是属于Spring Cloud Alibaba的组件,能当注册中心和配置中心使用。正好想体验下Spring Cloud Alibaba,于是就上手试试了。

摘一段Spring Cloud Alibaba与Spring Cloud的关系概述:

Spring Cloud Alibaba是依赖SpringCloud相关的标准实现的一套微服务的架构。
结合阿里巴巴的相关实践与阿里云的相关服务实现的一些组件得以更快的实现相关产品业务。

这篇文章是来记录几个体验过程中遇到的小坑,虽然大多数属于没有好好看文档导致的。

版本

使用Spring Cloud Alibaba需要配置对应的Spring Cloud和Spring Boot版本,不然可能会出现乱七八糟的错误。
官方的版本对应关系链接:Spring Cloud Alibaba版本说明
我这里用的版本:

  • Spring Cloud Alibaba:2.2.3.RELEASE
  • Spring Cloud:Hoxton.SR8
  • Spring Boot:2.3.2.RELEASE

另外提一句目前最新版的SpringBoot为2.4.1,但和Nacos的最新版本不兼容,等修复吧。(GitHub issues链接

配置中心

模块要使用配置中心,一开始在模块下建立了application.yml,并添加如下配置,进行读取远程配置,但启动后报错无法读取,查了下才知道需要把文件名改为bootstrap.yml,两者具体差别自行Google。

server:
  port: 6001
spring:
  profiles:
    active: dev
  application:
    name: demo-client
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
      config:
        server-addr: 127.0.0.1:8848 #配置中心地址
        file-extension: yaml

查看Nacos Spring Cloud文档有提到dataId的格式,也就是Nacos控制台对应的文件,默认格式为:

${prefix}-${spring.profiles.active}.${file-extension}
  • ${prefix}:默认是application.name,在我这个配置文件里就是demo-client。
  • ${spring.profiles.active}:这个值取的是spring.profiles.active,在我这是dev。
  • ${file-extension}:这个就是文件的后缀,默认是properties,我这里配置了yaml。
    结合上面,我这份配置文件会到Nacos的配置中心里,找到demo-client-dev.yaml这个配置进行读取,所以我们需要建立对应的文件存放配置。

网关限流

使用了Spring Cloud Gateway,配合sentinel进行限流。
maven:

        <!-- 限流熔断 -->
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-spring-cloud-gateway-adapter</artifactId>
        </dependency>

配置文件:

server:
  port: 8888
spring:
  application:
    name: server-gateway
  cloud:
    nacos:
      server-addr: localhost:8848
    gateway:
      routes:
        - id: server-source
          uri: lb://server-source
          predicates:
            - Path=/server-source/**
          filters:
            - StripPrefix=1

限流配置类

@Configuration
public class GatewayConfiguration {
    private final List<ViewResolver> viewResolvers;
    private final ServerCodecConfigurer serverCodecConfigurer;

    public GatewayConfiguration(ObjectProvider<List<ViewResolver>> viewResolversProvider, ServerCodecConfigurer serverCodecConfigurer) {
        this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
        this.serverCodecConfigurer = serverCodecConfigurer;
    }

    // 初始化一个限流的过滤器
    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public GlobalFilter sentinelGatewayFilter() {
        return new SentinelGatewayFilter();
    }

    // 配置初始化的限流参数
    @PostConstruct
    public void initGatewayRules() {
        Set<GatewayFlowRule> rules = new HashSet<>();
        rules.add(new GatewayFlowRule("server-source") //资源名称,对应路由id
                .setCount(1) // 限流阈值
                .setIntervalSec(1) // 统计时间窗口,单位是秒,默认是 1 秒
        );
        GatewayRuleManager.loadRules(rules);
    }

    // 配置限流的异常处理器
    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
        return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);
    }

    // 自定义限流异常页面
    @PostConstruct
    public void initBlockHandlers() {
        BlockRequestHandler blockRequestHandler = (serverWebExchange, throwable) -> {
            Map map = new HashMap<>();
            map.put("code", 0);
            map.put("message", "接口被限流了");
            return ServerResponse.status(HttpStatus.OK).
                    contentType(MediaType.APPLICATION_JSON).body(BodyInserters.fromValue(map));
        };
        GatewayCallbackManager.setBlockHandler(blockRequestHandler);
    }
}

默认路由覆盖导致限流失效

spring.cloud.gateway.discovery.locator.enabled=true时,网关会根据注册中心的服务自动生成默认路由规则,手动配置的路由断言与默认路由规则一致时,会优先使用默认生成的路由规则。例如路由到server-source服务配置为:

server:
  port: 8888
spring:
  application:
    name: server-gateway
  cloud:
    nacos:
      server-addr: localhost:8848
    gateway:
      discovery:
        locator:
          enabled: true
      routes:
        - id: server-source
          uri: lb://server-source
          predicates:
            - Path=/server-source/**
          filters:
            - StripPrefix=1

此时,http://localhost:8888/server-source/index的路由会被默认路由接管,配置文件内的这个路由是无效的。由于走了默认路由规则,限流中resourceId也就不是server-source了,因此限流也就失效了。

Linux上各类组件开机自启

上了一些组件,其中有ZipkinSentinelNacos,全部装在了虚拟机上,希望每次启动虚拟机的时候能够自启这些组件。
直接加入到/etc/rc.local文件内启动吧,在文件内添加如下内容:

# nacos开机自启
/usr/local/nacos/bin/startup.sh -m standalone
# zipkin开机自启
nohup /usr/local/java/jdk1.8.0_281/bin/java -jar /usr/local/zipkin/zipkin-server-2.23.2-exec.jar >> /usr/local/zipkin/nohup.out &
# sentinel开机自启
nohup /usr/local/java/jdk1.8.0_281/bin/java -jar /usr/local/sentinel/sentinel-dashboard.jar >> /usr/local/sentinel/nohup.out &

赋予/etc/rc.local权限:

chmod +x /etc/rc.local

注:/etc/rc.local文件执行命令的时候似乎不会加载环境,所以上面的java都替换成了绝对路径,在Nacos的startup.sh脚本中也需要替换一下脚本内的JAVA_HOME路径,把顶部一堆JAVA_HOME相关内容替换成这个绝对路径:

[ ! -e "$JAVA_HOME/bin/java" ] && JAVA_HOME=/usr/local/java/jdk1.8.0_281
[ ! -e "$JAVA_HOME/bin/java" ] && unset JAVA_HOME

重启测试即可


暂无评论

发表评论