从eureka到nacos配置中心注册中心,从hystrix到sentinel(springcloud alibaba2.2.3)

一.nacos与apollo/springcloud config

1.nacos集配置中心中心与注册中心与一体,部署相当简单,单机版可以直接用内置数据库存储,也可以配置mysql数据库存储,参考Nacos支持三种部署模式,而apollo需要分别部署configserver,adminserver,portal,mysql脚本,客户端还需要设置环境等参数;

2.nacos也支持多环境集中处理,支持实时刷新及配置变更监听,支持历史回退,权限控制等,项目持续火热;

3.性能上上nacos也是略胜一筹,其它详细对比参考Nacos、Apollo、Spring Cloud Config微服务配置中心对比_延宝小白马的博客-CSDN博客

二/从eureka到nacos nacos官网文档github demo

1.下载解压1.3.1 

2.config/application.properties修改端口,启动sh bin/startup.sh -m standalone (默认使用内置的derby数据库,可使用外置mysql数据库),或docker部署,参数都通过环境变量指定的

docker run -p 8170:8848  --name nacos  -d \
 -e PREFER_HOST_MODE=hostname \
 -e MODE=standalone \
 -e SPRING_DATASOURCE_PLATFORM=mysql \
 -e NACOS_AUTH_ENABLE=true \
 -e MYSQL_SERVICE_HOST=4x.xx.xx.xx \
 -e MYSQL_SERVICE_PORT=3306 \
 -e MYSQL_SERVICE_DB_NAME=nacos \
 -e MYSQL_SERVICE_USER=xxxx\
 -e MYSQL_SERVICE_PASSWORD=xxxx \
 nacos/nacos-server

3.登录http://localhost:8170 默认账号密码:nacos/nacos,可以新建一条配置,用于springcloud项目来读取并测试即时刷新与监听,如项目spring.application.name==xxx,spring.profile.active=dev,使用yaml格式配置,则配置dataid=xxx.dev.yaml;也可为同时配置一个xxx.yaml。namespace(默认public)>group(DEFAULT_GROUP)>data id(一般为配置文件名),项目较多,多环境时可以充分利用namespace,group区分。

4.springcloud项目集成nacos同时将eureka切换为nacos

加入依赖,就是两个jar,一个支持配置中心的一个支持注册中心的,可以单独使用配置中心、注册中心

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

bootstrap.yml 配置配置中心nacos的地址及文件后缀yaml/properties,(需要根据高优先级的bootstarp.yml配置的nacos信息远程读取到配置进行spring初始化)。需要使用配置的类@Value(value = "${test.key1:12345}")注入并在类上加入注解@RefreshScope即可获取nacos的配置并支持即时刷新。有时也需要监听配置更新进行一个业务逻辑,如动态变更日志级别,类似apollo;

spring:
  application:
    name: payment
  cloud:
    nacos:
      config:
        server-addr: 127.0.0.1:8170  #注意不要http://,nacaos使用的是raft协议
        file-extension: yaml
        namespace: public            #默认public,生产环境配个其它的prod,nacos配置管理权限就是基于namepace来设置的

application-dev.yml配置nacos中心中心的url,并将启动类的@EnableEurekaClient改为@EnableDiscoveryClient,并注释掉pom配置的eureka的jar(spring-cloud-starter-netflix-eureka-client)

spring:
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8170 #注意不要http://,nacaos使用的是raft协议

监听nacos配置动态修改日志案例

@Component
public class LoggingSystemConfigListener {
    
    private static final String LOGGER_TAG = "logging.level.";

    @Autowired
    private LoggingSystem loggingSystem;

    @NacosConfigListener(dataId = "${nacos.config.data-id}", type = ConfigType.YAML, timeout = 5000)
    public void onChange(String newLog) throws Exception {
        Map<String, Object> map = new YamlJsonParser().parseMap(newLog);
        for (Object t : map.keySet()) {
            String key = String.valueOf(t);
            // 如果是 logging.level 配置项,则设置其对应的日志级别
            if (key.startsWith(LOGGER_TAG)) {
                Object val = map.get(key);
                String strLevel = val!=null&&val.toString()!=""?val.toString():"info";
                LogLevel level = LogLevel.valueOf(strLevel.toUpperCase());
                loggingSystem.setLogLevel(key.replace(LOGGER_TAG, ""), level);
            }
        }
    }
}

nacos配置分享>>>

spring:
  application:
    name: message
  profiles:
    active: @package.environment@
  cloud:
    nacos:
      config:
        server-addr: @package.nacos.addr@         #注意不要http://,nacaos使用的是raft协议
        file-extension: yml                       #后缀
        namespace: @package.environment@          #配置命名空间,默认public
        shared-configs:
          - data-id: common.yml                #配置所有工程共享的配置,注意里面的配置默认不能动态刷新,需要时可配置自动刷新
            refresh: true
        password: @package.nacos.username@        #nacos 1.3.X才支持
        username: @package.nacos.password@
        context-path: /nacos
        group: DEFAULT_GROUP                      #使用默认组.如果使用namespace区分项目,则可以考虑group区分环境如DEV_GROUP
      discovery:
        password: @package.nacos.username@
        username: @package.nacos.password@
        server-addr: @package.nacos.addr@          #注意不要http://,nacaos使用的是raft协议
        namespace: @package.environment@           #服务命名空间,默认public

集群方案

参考官方,集群部署一般3节点,bootstarp.yml配置文件配置server-addr改为nginx监听的地址,由nignx转发到真正的nacos实例。注意每个nacos 都需要修改cluster.conf配置3个实例地址,每个实例不能使用内置的derby数据库,需要集中到同一个mysql库。

三/从hystrix到sentinel  文档地址

1.sentinel较hystrix更轻量级高性能,除了支持滑动时间窗口熔断降级,还支持接口基于QPS的限流,支持黑白名单,支持基于系统load,cpu使用率等全局降级,这些都是可以动态修改的,并且还有完美的中文界面。

2.下载安装sentinel 1.8.0 (dashboard)

java -Dserver.port=8101  -Dcsp.sentinel.dashboard.server=localhost:8101  -Dproject.name=sentinel-dashboard -Dauth.username=sentinel -Dauth.password=sentinel -Dlogging.file=/var/sentinel.log  -jar sentinel-dashboard-1.8.0.jar 

3.docker安装

docker run --name sentinel -d -p 8101:8858 -p 8719:8719 -d bladex/sentinel-dashboard

4.谷歌浏览器访问localhost:8101 账号密码sentinel/sentinel

5.在springcloud项目加入sentinel依赖,maven中央长裤找的,跟springboot大版本一致

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>

6.配置sentinel连接地址等

springcloud:
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8170
    sentinel:
      transport:
        dashboard: 127.0.0.1:8101
      enabled: true

测试:dashboard新增流控/降级规则,资源名写uri即可 

7.流控降级

  • 直接模式:QPS/并发线程数(直接设置流控阈值0,1进行测试)
  • 关联模式:下单/create-order关联支付/pay接口,支付接口触发流控使上游的下单接口也被流控(jmeter/postman/ab压测/pay接口后,再访问下单接口)
  • 链路模式:这个是大伙避而不谈的一种模式,确实比较麻烦,参考3-3服务容错sentinel-1流控规则_hzp-CSDN博客
  • 快速失败: 直接失败,抛出异常
  • Warm Up:当系统长期处于一个低负载的情况下,或服务刚刚启动,这种资源没有加载完成时。warm up冷启动+预热模式,开始的阈值是最大QPS阈值的1/3,然后慢慢增长,在配置时间内达到我们配置的阈值上限,达到保护系统的作用。高峰期后,可能会发生类卸载等,故该机制会重置QPS阈值,准备迎接下一波冲击
  • 排队等待:匀速+排队,会给触发阈值的请求一个排队机会,排队超时才抛出异常

触发时抛出异常Blocked by Sentinel (flow limiting),http状态码429 too manay request,  一般需要自定义流控降级blockHandler,注意降级方法出入参方法修饰符

8.熔断降级

熔断降级原理与效果基本同hystrix,阈值触发时,同流控抛出异常Blocked by Sentinel (flow limiting),http状态码429 too manay request,  一般需要自定义流控降级blockHandler,注意降级方法出入参方法修饰符

设置RT(response time)超过1ms超时,统计滑动时间窗口1s内,达到2个请求并且触发RT比例超过50%即会进入熔断,3s后进入半开,放过一个请求试探,通过则关闭熔断器,否则继续熔断,3s后再次进入半开。。。

注意:低版本sentinel没有半开状态,(sentinel异常统计逻辑在全局异常处理之后)被全局异常处理捕获的异常将不会被计入统计

9.热点规则

热点规则是一种基于方法参数配置的一种降级手段,带@SentinelResource注解的请求中有userId这个参数的请求进行流控,其参数例外项还可以配置如userId值为1时设定特别的限流值 。

    @GetMapping("/test3")
    @SentinelResource(value = "test3",
            blockHandler = "exceptionHandler",
            blockHandlerClass = SentinelHandler.class,
            fallback = "fallbackHandler",
            fallbackClass = SentinelHandler.class)
    public ResultEntity test3(@RequestParam(required = false) String userId, @RequestParam(required = false) String entpId) {
        int aa = 1 / 0;
        return ResultEntity.success();

    }
package com.construn.vehicle.payment.controller;

import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.construn.vehicle.common.base.entity.ResultEntity;
import lombok.extern.slf4j.Slf4j;

import javax.servlet.http.HttpServletRequest;

@Slf4j
public class SentinelHandler {
    /**
     * 熔断降级处理方法参数可以最后多一个 BlockException,其余入参出参类型与原函数一致,方法public static.
     * @param a
     * @param b
     * @param e
     * @return
     */
    public static ResultEntity  exceptionHandler(String a,String b  , BlockException e) {
        log.error("调用SentinelExceptionUtil中的exceptionHandler方法->{}",e.getMessage());
        return ResultEntity.fail("9999","降级处理");
    }

    /**
     * 流控规则检验在前,如果触发流控规则,则不会进入@SentinelResource方法,也就不会进入fallbackHandler
     * @param a
     * @param b
     * @param e
     * @return
     */
    public static ResultEntity  fallbackHandler( String a,String b,Throwable e ) {
        log.error("调用SentinelExceptionUtil中的fallbackHandler方法->{}",e.getMessage() );
        return  ResultEntity.fail("9999","异常处理");
    }

}

几个注意点:

     - 建议使用@SentinelResource注解的value值配置各种规则(流控,降级规则资源名可以是path或@SentinelResource的value值),如果根据path配置,触发规则只会抛出异常不会进入SentinelHandler进行处理,如果没有blockHandler没有定义则抛出5XX异常。

  • 如果程序中抛出了runtime异常则不会计入流控统计,如果程序正常触发阈值则抛出com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowException (区别其它流控,这里抛出500异常,而不是429异常——Blocked by Sentinel (flow limiting))。
  • 如果配置有降级处理方法,如@SentinelResource(value = "test3",  blockHandler = "exceptionHandler",blockHandlerClass = SentinelExceptionUtil.class,fallback = "fallbackHandler",fallbackClass = SentinelExceptionUtil.class) ,但同时如果系统有全局异常处理将com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowException提前给捕获了,sentinel则认为未触发流控规则,故不会进入降级方法。可以考虑不捕获ParamFlowException异常或改为网关进行捕获
  • 这里的blockHandler不仅仅适用于热点规则,也适用于流控规则,熔断降级规则(如果像上例定义了fallbackHandler,即把异常处理了,那么sentinel感知不到异常,不会触发熔断降级规则,固不会进入blockHandler)。

10.系统规则

  可以从LOAD  /RT /线程数 /入口 QPS /CPU 使用率 等方面保护系统,触发阈值时抛出异常Blocked by Sentinel (flow limiting),http状态码429 too manay request。系统规则无法像接口一样自定义blockHandler,但可以让程序跳到一个更友好的页面,或返回更友好的json

11. 每个接口单独配置@SentinelResource指定blockHandler,callback比较麻烦,可如下全局sentinel异常处理。其实全局异常处理也不一定好。个人赶脚最好的处理方式是:微服务内部feign调用,调用方自己写fallback;如果是网关调用微服务,则网关统一处理异常

参考springcloud gataway整合sentinel,nacos


import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.BlockExceptionHandler;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityException;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowException;
import com.alibaba.csp.sentinel.slots.system.SystemBlockException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Data;
import org.springframework.stereotype.Component;
 
import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
/**
 * 自定义sentinel异常返回信息
 */
 
@Component
public class CustomerBlockHandler implements BlockExceptionHandler {
 
    @Override
    public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, BlockException e) throws Exception {
        SentinelErrorMsg sentinelErrorMsg = new SentinelErrorMsg();
        if (e instanceof FlowException) {
            sentinelErrorMsg.setMsg("接口限流了");
            sentinelErrorMsg.setStatus(101);
        } else if (e instanceof DegradeException) {
            sentinelErrorMsg.setMsg("服务降级了");
            sentinelErrorMsg.setStatus(102);
        } else if (e instanceof ParamFlowException) {
            sentinelErrorMsg.setMsg("热点参数限流了");
            sentinelErrorMsg.setStatus(103);
        } else if (e instanceof SystemBlockException) {
            sentinelErrorMsg.setMsg("系统规则(负载/...不满足要求)");
            sentinelErrorMsg.setStatus(104);
        } else if (e instanceof AuthorityException) {
            sentinelErrorMsg.setMsg("授权规则不通过");
            sentinelErrorMsg.setStatus(105);
        }
        // http状态码
        httpServletResponse.setStatus(500);
        httpServletResponse.setCharacterEncoding("utf-8");
        httpServletResponse.setHeader("Content-Type", "application/json;charset=utf-8");
        httpServletResponse.setContentType("application/json;charset=utf-8");
        // spring mvc自带的json操作工具,叫jackson
        new ObjectMapper()
                .writeValue(
                        httpServletResponse.getWriter(),
                        sentinelErrorMsg
                );
    }
 
    @PostConstruct
    public void init() {
        new CustomerBlockHandler();
    }
 
    @Data
    static class SentinelErrorMsg {
        private Integer status;
        private String msg;
    }
}

12.配置持久化存储方案

单纯使用sentinel,规则无法进行持久化,在关闭、重启工程后,所配置的规则会丢失。需要自己进行额外的持久化操作,可以持久化到Nacos或是本地文件

  <dependency>
     <groupId>com.alibaba.csp</groupId>
     <artifactId>sentinel-datasource-nacos</artifactId>
   </dependency>

spring:
  cloud:
    sentinel:
      transport:
        dashboard: 127.0.0.1:8118
      enabled: true
      datasource: #持久化配置指定nacos
        ds1:
          nacos:
            server-addr: @package.nacos.addr@
            dataId: ${spring.application.name}
            groupId: SENTINEL_GROUP
            namespace: test    #这里没使用默认的PUBLIC 
            data-type: json
            rule-type: flow
            username: nacos   #开启了权限验证则需要配置账户密码
            password: nacos

比较麻烦的是需要在nacos配,不能将sentinel dashboard的所有配置copy到nacos??

可以F12  在/rules这个接口的 data内容(一个json array)copy到nacos 配置内容里

这样重启微服务即可从nacos读取到sentinel规则,但是sentinel dashboard还是没有流控规则,这时需要访问test3这个资源时sentinel dashboard才可再次看到。在sentinel修改规则立即生效但不会同步到nacos,如果从nacos修改即可持久化并立即生效

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值