草庐IT

Spring-cloud-alibaba 系统搭建

秋叶华 2023-04-10 原文

Spring-cloud-alibaba 系统搭建

Spring-cloud-alibaba 系统架构图

SpringAlibabaCloud架构使用版本

注:springboot,spring-cloud,spring-cloud-alibaba相关jar有冲突,需要注意版本;

系统核心组件及架包

系统版本

Nacos中间件

1.1.4

Sentinel中间件

1.8.4

Zipkin-server 中间件

2.23.19

org.springframework.boot

2.2.4.RELEASE

spring-cloud-dependencies

Hoxton.SR1

spring-cloud-alibaba-dependencies

2.2.0.RELEASE

spring-cloud-starter-alibaba-nacos-discovery

1.5.0.RELEASE

spring-cloud-starter-alibaba-nacos-config

2.2.0.RELEASE

nacos-client

1.1.4

spring-cloud-starter-alibaba-sentinel

1.5.1.RELEASE

sentinel-datasource-nacos

1.7.1

sentinel-core

1.7.1

spring-cloud-starter-gateway

2.2.1.RELEASE

spring-cloud-starter-bootstrap

3.0.1

spring-boot-starter-webflux

2.2.4.RELEASE

spring-cloud-starter-zipkin

2.2.1.RELEASE

spring-cloud-starter-openfeign

2.2.1.RELEASE

创建SpringBoot项目 ddky-risk-cloud

同理创建子项目:

ddky-risk-generate:用于生成JDBC相关基础代码

ddky-risk-core : 用于基础对象,工具Util核心jar

ddky-risk-feign: 用于web服务调用封装

ddky-risk-products: 用于提供提供者服务

ddky-risk-web:用于提供消费者服务

ddky-risk-gateway: 用于网关转发服务

 Spring-cloud-alibaba-nacos 搭建

注册中心nacos单机安装

下载地址:https://github.com/alibaba/nacos/releases/tag/1.1.4

(版本兼容问题)

Windows 单机启动

cd D:\fills-tools\spring-cloud\nacos\bin

执行命令,单集群模式

startup.cmd -m standalone 

http://localhost:8848/nacos

name/password  -> nacos/nacos

ddky-risk-cloud  pom 父级依赖

<dependencyManagement>

    <dependencies>

        <!--spring cloud-->

        <dependency>

            <groupId>org.springframework.boot</groupId>

            <artifactId>spring-boot-starter-parent</artifactId>

            <version>2.2.4.RELEASE</version>

            <type>pom</type>

            <scope>import</scope>

        </dependency>

       <dependency>

            <groupId>org.springframework.cloud</groupId>

            <artifactId>spring-cloud-dependencies</artifactId>

            <version>Hoxton.SR1</version>

            <type>pom</type>

            <scope>import</scope>

        </dependency>

        <dependency>

            <groupId>com.alibaba.cloud</groupId>

            <artifactId>spring-cloud-alibaba-dependencies</artifactId>

            <version>2.2.0.RELEASE</version>

            <scope>import</scope>

            <type>pom</type>

        </dependency>

        <dependency>

            <groupId>com.alibaba.cloud</groupId>

          <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>

            <version>1.5.0.RELEASE</version>

        </dependency>

        <!--spring cloud-->

...... 其他依赖

</dependencyManagement>

ddky-risk-products  pom 依赖

<!-- 向注册中心进行服务注册 -->

<dependency>

        <groupId>com.alibaba.nacos</groupId>

        <artifactId>nacos-client</artifactId> <!--1.1.4-->

       <version>1.1.4</version>

</dependency>

<dependency>

      <groupId>com.alibaba.cloud</groupId>

      <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>

      <version>1.5.0.RELEASE</version>

</dependency>

<!-- 向注册中心进行服务注册 -->

ddky-risk-products  yml nacos配置

spring:

  application:

    name: ddky-risk-cloud-provider

  cloud:

    nacos:

      discovery:

        server-addr: 127.0.0.1:8848

ddky-risk-products  提供服务demo

@RestController

@RequestMapping("/riskConfig")

@Slf4j

public class RiskConfigServer {

    @Autowired

    private RiskConfigService riskConfigService;

    @RequestMapping(value="/getRiskConfig",method = {RequestMethod.GET,RequestMethod.POST})

    public RiskConfig getRiskConfig(String riskCode){

        log.info("请求参数:{}",riskCode);

        RiskConfig res = riskConfigService.queryRiskConfig(riskCode); // *service 服务

        log.info("响应结果:{}",JsonTools.writeValueAsString(res));

        return res;

    }

}

ddky-risk-web  pom 依赖

<!-- 向注册中心进行服务注册 -->

<dependency>

        <groupId>com.alibaba.nacos</groupId>

        <artifactId>nacos-client</artifactId> <!--1.1.4-->

        <version>1.1.4</version>

</dependency>

<dependency>

      <groupId>com.alibaba.cloud</groupId>

      <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>

      <version>1.5.0.RELEASE</version>

</dependency>

<!-- 向注册中心进行服务注册 -->

ddky-risk-web  yml 配置

spring:

  application:

    name: ddky-risk-cloud-consumer

  cloud:

    nacos:

      discovery:

        server-addr: 127.0.0.1:8848

ddky-risk-web访问服务端,手动RestTemplate访问

RestTemplate 手动实现访问服务端服务,只做了解

ServiceInstanceLoadBalancer 手动实现负载均衡,只做了解

实战应用场景参考:Spring-cloud-alibaba-feign 搭建

@RestController

@RequestMapping("riskConfig")

public class RiskConfigController extends BaseController {

    @Autowired

    protected ServiceInstanceLoadBalancer serviceInstanceLoadBalancer;

    @GetMapping(value = "/getRiskConfig", produces = {"application/json;charset=UTF-8"})

    @ResponseBody

    public ServiceResult<?> getRiskConfig(String riskCode) {

        try {

            ServiceResult result = new ServiceResult<>();

//serviceInstance = loadBalancerClient.choose("ddky-risk-cloud-provider");

            ServiceInstance serviceInstance = serviceInstanceLoadBalancer.getServiceInstance();

            String targetUrl = serviceInstance.getUri() + "/riskConfig/getRiskConfig";

            log.info("获取服务端请求地址"+targetUrl);

            LinkedMultiValueMap<String, Object> params = new LinkedMultiValueMap<String,Object>();

            params.add("riskCode",riskCode);

            Map<String,Object> objectMap = new HashMap<>();

            objectMap.put("riskCode",riskCode);

            RiskConfig config = restTemplate.postForObject(targetUrl,params,RiskConfig.class,objectMap);

            result.setResult(config);

            return  result;

        }catch (Exception e){

            log.error("保存异常",e);

            return new ServiceResult<>(ResultCodeEnum.failure.getIndex(),e.getMessage());

        }

    }

}

ServiceInstanceLoadBalancer 自定义负载均衡

ServiceInstanceLoadBalancer 自定义负载均衡也可以使用springcloud的LoadBalancerClient负载均衡客户端

只做了解

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.beans.factory.annotation.Value;

import org.springframework.cloud.client.ServiceInstance;

import org.springframework.cloud.client.discovery.DiscoveryClient;

import org.springframework.stereotype.Component;

import java.net.InetAddress;

import java.util.List;

import java.util.Random;

import java.util.concurrent.atomic.AtomicInteger;

/**

 * nacos 手动实现服务治理负责均衡 随机,轮询,Hash

 */

@Component

public class ServiceInstanceLoadBalancer {

    //nacos 提供者服务名称

    @Value("${server.cloud.name}")

    private String providerServer;

    //负载均衡策略,该配置可改成动态方式

    @Value("${server.instance.type:0}")

    private String instanceType; // 0-随机,1-轮询,2-Hash

    //随机

    private static final String RANDOM = "0";

    //轮询

    //private static final String POLL = "1";

    //Hash

    private static final String HASH = "2";

    //获取随机数

    private static final Random random = new Random();

    //nacos注册服务客户端

    @Autowired

    protected DiscoveryClient discoveryClient;

    //CAS 原子类

    private AtomicInteger poll = new AtomicInteger(0);

    //获取服务提供者

    public ServiceInstance getServiceInstance(){

        List<ServiceInstance> serviceInstanceList = discoveryClient.getInstances(providerServer);

        ServiceInstance serviceInstance =null;

        try {

            if (RANDOM.equals(instanceType)) {//随机

                serviceInstance = serviceInstanceList.get(random.nextInt(serviceInstanceList.size()));

            } else if (HASH.equals(instanceType)) {//IP Hash

                serviceInstance = serviceInstanceList.get(getIpHash() % serviceInstanceList.size());

            } else {//轮询,默认

                serviceInstance = serviceInstanceList.get(poll.getAndIncrement() % serviceInstanceList.size());

            }

        }catch (Exception e){

        }

        return serviceInstance;

    }

    //获取IP Hash

    private int getIpHash(){

        try {

            return InetAddress.getLocalHost().getHostAddress().hashCode();

        } catch (Exception e) {

            return 0;

        }

    }

}

属性字段解释

String providerServer : nacos 服务端提供者服务名称

String instanceType :负载均衡策略,该配置可改成动态方式(disconf,apollo,redis)

Random random :随机数轮询

AtomicInteger poll:CAS 原子类 用于轮询自增使用 

DiscoveryClient discoveryClient: nacos 提供者客户端获取所有服务

方法解释

public ServiceInstance getServiceInstance()

根据instanceType策略(0-随机,1-轮询,2-Hash)获取服务端server

private int getIpHash()

获取本地IP地址转为HashCode(int),用于Hash方式获取服务端server

演示效果

instanceType (0-随机)策略

instanceType (1-轮询)策略

instanceType (2-Hash)策略

 Spring-cloud-alibaba-feign 搭建

ddky-risk-feign pom 依赖

<dependency>

    <groupId>org.springframework.cloud</groupId>

    <artifactId>spring-cloud-starter-openfeign</artifactId>

<version>2.2.1-SNAPSHOT</version>

</dependency>

ddky-risk-feign yml 配置

注:Feign 配置可以忽略,可以针对线上环境具体配置

feignName:FeginClient的名称

connectTimeout : 建立链接的超时时长

readTimeout : 读取超时时长

loggerLevel: Fegin的日志级别

errorDecoder :Feign的错误解码器

retryer : 配置重试

requestInterceptors : 添加请求拦截器

decode404 : 配置熔断不处理404异常

feign:

  client:

    config:

      feignName: ##定义FeginClient的名称

        connectTimeout: 5000 # 链路链接超时时间

        readTimeout: 5000 # 读取超时时间

        # 配置Feign的日志级别,相当于代码配置方式中的Logger

        loggerLevel: full

ddky-risk-feign web -> web实现

ddky-risk-feign FeignClient 配置

value、name作用一样,配置nacos服务名称,用于服务发现

url用于配置指定服务的地址,相当于直接请求这个服务,不经过Ribbon的服务选择

path:定义当前FeignClient访问接口时统一前缀,例接口地址是/riskConfig/getRiskConfig, 定义了前缀是riskConfig, 同Spring的RequestMapping

contextId唯一标识,不想将所有的调用接口都定义在一个类中,手动指定不同的contextId解决冲突

decode404:请求报404错误时,值为true时执行decoder解码,否则抛出异常

configuration配置Feign配置类,在配置类中可以自定义Feign的Encoder、Decoder、LogLevel、Contract等

fallback:容错的处理类,也就是回退逻辑,fallback的类必须实现Feign Client的接口,无法知道熔断的异常信息。

fallbackFactory:容错的处理类,可以知道熔断的异常信息

ddky-risk-feign 接口封装

package com.ddky.risk.cloud.feign;

import com.ddky.risk.cloud.domain.RiskConfig;

import com.ddky.risk.cloud.response.ServiceResult;

import org.springframework.cloud.openfeign.FeignClient;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RequestParam;

@FeignClient(value="ddky-risk-cloud-provider",path ="/riskConfig")

public interface RiskConfigFeign {

    @RequestMapping("/getRiskConfig")

    public ServiceResult<RiskConfig> getRiskConfig(@RequestParam(value="riskCode") String riskCode);

}

ddky-risk-products 提供服务

服务端web服务和feign提供的接口保持一致

@RestController

@RequestMapping("/riskConfig")

@Slf4j

public class RiskConfigServer {

    @Autowired

    private RiskConfigService riskConfigService;

    @RequestMapping(value="/getRiskConfig",method = {RequestMethod.GET,RequestMethod.POST})

    @ResponseBody

    public ServiceResult<RiskConfig> getRiskConfig(HttpServletRequest request,String riskCode){

        log.info("请求参数:{}",riskCode);

        ServiceResult result = new ServiceResult();

        RiskConfig res = riskConfigService.queryRiskConfig(riskCode);

        log.info("响应结果:{}",JsonTools.writeValueAsString(res));

        result.setResult(res);

        return result;

    }

}

ddky-risk-web 消费服务

@Slf4j

@RestController

@RequestMapping("riskConfig")

public class RiskConfigController extends BaseController {

    

    @Autowired

    private RiskConfigFeign riskConfigFeign;

    @GetMapping(value = "/getRiskConfigFeign", produces = {"application/json;charset=UTF-8"})

    @ResponseBody

    public ServiceResult<?> getRiskConfigFeign(ServiceRequest<String> params) {

        try {

            ServiceResult<RiskConfig> result = riskConfigFeign.getRiskConfig(params.getData());

            return result;

        }catch (Exception e){

            log.error("保存异常",e);

            return new ServiceResult<>(ResultCodeEnum.failure.getIndex(),e.getMessage());

        }

    }

}

ddky-risk-feign 演示

 Gateway

Web

Products

Zipkin

 Spring-cloud-alibaba-sentienl 搭建

sentienl服务端安装

下载地址:https://github.com/alibaba/Sentinel/releases

启动脚本

java -jar D:/fills-tools/spring-cloud/sentinel-dashboard-1.8.1.jar --server.port=8881

或者:java -jar ./sentinel-dashboard-1.8.1.jar

用户名/密码   sentinel/sentinel

ddky-risk-products sentienl pom 配置

<!-- 向注册中心进行服务注册 -->

<dependency>

        <groupId>com.alibaba.nacos</groupId>

        <artifactId>nacos-client</artifactId><!--1.1.4-->

<version>1.1.4</version>

</dependency>

<dependency>

    <groupId>com.alibaba.cloud</groupId>

    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>

<version>1.5.1.RELEASE</version>

</dependency>

<dependency>

    <groupId>com.alibaba.cloud</groupId>

    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>

    <version>1.5.1.RELEASE</version>

</dependency>

<dependency>

    <groupId>com.alibaba.csp</groupId>

    <artifactId>sentinel-datasource-nacos</artifactId>

<version>1.7.1</version>

</dependency>

<dependency>

       <groupId>com.alibaba.csp</groupId>

       <artifactId>sentinel-core</artifactId>

       <version>1.7.1</version>

</dependency>

ddky-risk-products配置暴露/actuator/sentinel

#添加sentinel依赖后 暴露/actuator/sentinel

management:

  endpoints:

    web:

      exposure:

        include: '*'

查看actuator/sentinel配置

http://localhost:8882/actuator/sentinel

ddky-risk-products  yml  sentienl配置

spring:

  application:

    name: ddky-risk-cloud-provider

  cloud:

    nacos:

      discovery:

        server-addr: 127.0.0.1:8848

    sentinel:  # sentinel 接入配置

      eager: true

      transport:

        dashboard: 127.0.0.1:8080   #指定sentinel控制台的地址

        port: 8719

        clientIp: 127.0.0.1

      datasource:  #sentinel使用nacos接入持久化配置

        flow:

          nacos:

            serverAddr: 127.0.0.1:8848   

            dataId: ddky-risk-cloud-provider-flow

            groupId: DEFAULT_GROUP

            dataType: json

            ruleType: flow

ddky-risk-products 封装请求/响应参数

封装请求参数对象data

data为泛型,用于封装自定义sentinel处理器,入参统一

package com.ddky.risk.cloud.request;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

import java.io.Serializable;

@JsonIgnoreProperties(ignoreUnknown = true)

public class ServiceRequest <T> implements Serializable {

    private static final long serialVersionUID = -1L;

    private T data;

    public ServiceRequest(T data) {

        this.data = data;

    }

    public ServiceRequest() {

    }

    public T getData() {

        return data;

    }

    public void setData(T data) {

        this.data = data;

    }

}

封装响应参数对象result

result为泛型,用于封装自定义sentinel处理器,出参统一

package com.ddky.risk.cloud.response;

import com.ddky.risk.cloud.enums.ResultCodeEnum;

import com.ddky.risk.cloud.exception.BusinessException;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

import java.io.Serializable;

/**

 * 通用返回值

 */

@JsonIgnoreProperties(ignoreUnknown = true)

public class ServiceResult<T> implements Serializable {

   

   private static final long serialVersionUID = -394529804715984961L;

   private Integer code;

   private String msg;

   private T result;

   public ServiceResult() {

      this(ResultCodeEnum.Success);

   }

   public ServiceResult(ResultCodeEnum resultCode) {

      this.code = resultCode.getIndex();

      this.msg = resultCode.getMessage();

   }

   public ServiceResult(Integer code, String msg) {

      this.code = code;

      this.msg = msg;

   }

   public ServiceResult(BusinessException e) {

      this.code = e.getCode();

      this.msg = e.getMessage();

   }

...

   public Integer getCode() {

      return this.code;

   }

   public void setCode(Integer code) {

      this.code = code;

   }

    ...

}

自定义sentinel处理器

封装自定义处理器是因为sentinel 需要方法入参(参数最后多了一个异常)和出参与原方法保值一致才能拦截到sentinel阻断异常见:SentienlException

package com.ddky.risk.cloud.exception;

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.ddky.risk.cloud.enums.ResultCodeEnum;

import com.ddky.risk.cloud.request.ServiceRequest;

import com.ddky.risk.cloud.response.ServiceResult;

// 自定义sentinel处理器

public class SentienlException {

    /**

     * 系统异常时,捕获并返回错误

     * @param data

     * @param e

     * @return

     */

    public static ServiceResult errorException(ServiceRequest data,Throwable e){

        return new ServiceResult(ResultCodeEnum.failure.getIndex(),e.getClass().getName()+":"+e.getMessage());

    }

    /**

     * sentinel 限流异常时,封装并返回错误

     * @param data

     * @param e

     * @return

     */

    public static ServiceResult blockException(ServiceRequest data,BlockException e){

        if (e instanceof FlowException) {//限制异常

            return new ServiceResult(ResultCodeEnum.flow_error);

        } else if (e instanceof ParamFlowException) {//热点参数异常

            return new ServiceResult(ResultCodeEnum.hot_error);

        } else if (e instanceof DegradeException) {//降级异常

            return new ServiceResult(ResultCodeEnum.degrade_error);

        } else if (e instanceof AuthorityException) {//受权异常

            return new ServiceResult(ResultCodeEnum.auth_error);

        }

        //提供安全异常

        return new ServiceResult(ResultCodeEnum.system_block_error);

    }

}

应用示例

SentinelResource使用说明:

Fallback系统异常时回调方法

FallbackClass指定系统异常处理类,不配是默认当前类下

BlockHandler系统阻断时处理方法

BlockHandlerClass指定系统阻断处理类,不配是默认当前类下

package com.ddky.risk.cloud.webserver;

import com.alibaba.csp.sentinel.annotation.SentinelResource;

import com.ddky.risk.cloud.domain.RiskConfig;

import com.ddky.risk.cloud.exception.SentienlException;

import com.ddky.risk.cloud.request.ServiceRequest;

import com.ddky.risk.cloud.response.ServiceResult;

import com.ddky.risk.cloud.service.nacos.RiskConfigService;

import com.ddky.risk.cloud.util.JsonTools;

import lombok.extern.slf4j.Slf4j;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RequestMethod;

import org.springframework.web.bind.annotation.ResponseBody;

import org.springframework.web.bind.annotation.RestController;

/**

 * @author ysf

 * @version 1.0

 * @description: TODO

 * @date 2022/2/14 10:07

 */

@RestController

@RequestMapping("/riskConfig")

@Slf4j

public class RiskConfigServer {

    @Autowired

    private RiskConfigService riskConfigService;

    @RequestMapping(value="/getRiskConfig",method = {RequestMethod.GET,RequestMethod.POST})

    @ResponseBody

    @SentinelResource(value="/getRiskConfig",blockHandler = "blockException",blockHandlerClass = {SentienlException.class},fallback = "errorException",fallbackClass = {SentienlException.class})

    public ServiceResult<RiskConfig> getRiskConfig(ServiceRequest<String> riskCode){

        log.info("请求参数:{}",riskCode);

        ServiceResult result = new ServiceResult();

        RiskConfig res = riskConfigService.queryRiskConfig(riskCode.getData());

        log.info("响应结果:{}",JsonTools.writeValueAsString(res));

        result.setResult(res);

        return result;

    }

}

正常结果:

阻断结果:

异常结果

sentienl 监控配置方式(nacos配置中心)

从nacos服务端加载sentinel服务端的配置

配置数据实体对象参考:com.alibaba.cloud.sentinel.datasource.RuleType

Sentinel切面执行器:com.alibaba.csp.sentinel.annotation.aspectj

.SentinelResourceAspect

FLOW("flow", FlowRule.class),

DEGRADE("degrade", DegradeRule.class),

PARAM_FLOW("param-flow", ParamFlowRule.class),

SYSTEM("system", SystemRule.class),

AUTHORITY("authority", AuthorityRule.class),

GW_FLOW("gw-flow", "com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayFlowRule"),

GW_API_GROUP("gw-api-group", "com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiDefinition");

流控规则说明:FlowRule

Resource:资源名是限流规则的作用对象

LimitApp:流控针对的调用来源,若为 default 则不区分调用来源

Grade:限流阈值类型,QPS 模式(1)或并发线程数模式(0)

Count:限流阈值

Strategy:调用关系限流策略:直接-0、链路-1、关联-2

ControlBehavior:流量控制效果(直接拒绝-0、Warm Up-1、匀速排队-2)

ClusterMode:是否集群限流 是-true、否-false

[{

    "resource": "/getRiskConfig",

    "limitApp": "default",

    "grade": 1,

    "count": 1,

    "strategy": 0,

    "controlBehavior": 0,

    "clusterMode": false

}]

降级规则说明:DegradeRule

resource:资源名,

grade:熔断策略0-慢比例调用,1-异常比例,2-异常数,

count:grade=0,毫秒数;=1,比列阀值[0.0,1.0];=2,异常数,

slowRatioThreshold:grade=0,比例阈值[0.0,1.0],

timeWindow":熔断时长秒,

minRequestAmount:最小请求数,

statIntervalMs:统计时长(ms)

[{

  "resource": "/getRiskConfig",

  "grade": "0",

  "count": "1",

  "slowRatioThreshold": "0.1",

  "timeWindow": "1",

  "minRequestAmount": "1",

  "statIntervalMs": "1000"

}]

热点数据规则说明:ParamFlowRule

resource:资源名,

paramIdx:热点参数的索引,

count:单机阈值,

durationInSec:统计窗口时长(单位为 秒),

clusterMode":是否集群,

paramFlowItemList.classType:参数数据类型:int,double,byte,float,long,char,java.lang.String

paramFlowItemList.object:参数值

paramFlowItemList.count:限流阈值

注:该场景用于接口验证参数是基础数据,入参是引用对象不可用,所以不适用本次封装的请求对象

[{

  "resource": "/getRiskConfig",

  "paramIdx": "0",

  "count": "1",

  "durationInSec": "1",

  "clusterMode": false,

  "paramFlowItemList":[{

  "classType": "java.lang.String",

  "object": "10001",

  "count":"1"

  }]

}]

系统规则说明:systemRule

grade:0-LOAD,1-RT,2-线程数,3-入口QPS,4-CPU使用率

highestSystemLoad:LOAD

avgRt:RT

maxThread:线程数

qps:入口 QPS

highestCpuUsage:CPU 使用率

注:entryType = EntryType.IN 切面配置内部资源调用才会触发系统保护规则

@SentinelResource(value="/getRiskConfig",entryType= EntryType.IN,blockHandler = "blockException",blockHandlerClass = {SentienlException.class},fallback = "errorException",fallbackClass = {SentienlException.class})

[{

  "highestCpuUsage:CPU":1

}]

授权规则说明:AuthorityRule

resource:资源名

limitApp:流控应用,多个调用方名称用半角英文逗号(,)分隔

strategy:授权类型0-白名单,1-黑名单

[{

  "resource":"/getRiskConfig",

  "limitApp":"",

  "strategy":0

}]

Spring-cloud-alibaba-gateway 搭建

ddky-risk-gateway gateway pom 配置

<dependency>

    <groupId>com.alibaba.cloud</groupId>

    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>

<version>1.5.1.RELEASE</version>

</dependency>

<dependency>

    <groupId>com.alibaba.cloud</groupId>

    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>

<version>2.2.0.RELEASE</version>

</dependency>

<dependency>

    <groupId>org.springframework.cloud</groupId>

    <artifactId>spring-cloud-starter-gateway</artifactId>

<version>2.2.1.RELEASE</version>

</dependency>

<dependency>

    <groupId>org.springframework.cloud</groupId>

    <artifactId>spring-cloud-starter-bootstrap</artifactId>

    <version>3.0.1</version><!-- 使用nacos动态配置使用 -->

</dependency>

<dependency>

    <groupId>org.springframework.boot</groupId>

    <artifactId>spring-boot-starter-webflux</artifactId>

<version>2.2.4.RELEASE</version>

</dependency>

ddky-risk-gateway yml gateway非动态方式配置

注:该方式是写死在application.yml配置,每次需要新增修改,需要重新发布应用,只做了解不做使用

server:

  port: 8888

logging:

  config: classpath:logback.xml

  level:

    org:

      springframework:

        boot:

          autoconfigure: ERROR         # 日志不打印条件评估报告

spring:

  application:

    name: ddky-risk-cloud-getway # 应用名称

  cloud:

    nacos:

      discovery:

        server-addr: localhost:8848

    gateway:

      discovery:

        locator:

          enabled: true

      routes:

        - id: ddky-risk-cloud-consumer  #路由标识符,区别于其他 Route

          uri: lb://ddky-risk-cloud-consumer #路由指向的目的地 uri,即客户端请求最终被转发到的微服务

          predicates:  #断言,用于条件判断,只有断言都返回真,才会真正的执行路由

            - Path=/riskConfig/**

ddky-risk-gateway yml gateway nacos动态方式配置

注:该方式是需要通过application.yml和bootstrap.yml (gateway nacos 需要使用),每次只要在nacos配置中心新增修改,保存后即可实时刷新并应用

application.yml

server:

  port: 8888

logging:

  config: classpath:logback.xml

  level:

    org:

      springframework:

        boot:

          autoconfigure: ERROR         # 日志不打印条件评估报告

spring:

  application:

    name: ddky-risk-cloud-getway # 应用名称

bootstrap.yml

spring:

  cloud:

    nacos:

      discovery:

        server-addr: 127.0.0.1:8848

      config: #nacos config 配置

        server-addr: 127.0.0.1:8848

        file-extension: yaml #文件内容及格式

        group: DEFAULT_GROUP

        prefix: ddky-risk-cloud-getway  #nacos 动态配置前缀

nacos 配置中心

配置内容 spring.cloud.gateway.routes List集合

-id:# 路由唯一标识符

uri:# 路由目标地址,通过gateway转发到改地址 http原链接转发 或 lb://nacos 负载均衡

predicates:#断言 用于条件判断 List集合

- Path=/xxx/**

为一个独立子集,可以同时配置多个

ddky-risk-gateway 页面演示

 Html页面响应

例如:http://localhost:8888/riskConfig/index

注:gateway转发调转页面样式错乱

解决方案一:

需要在原页面指定具体css,js,image等静态资源的具体路径

例如:

<script src="${path}/static/js/other/select/dynamic-column.js" type="text/javascript"></script>

改为

<script src="http://localhost:8081/static/js/other/select/dynamic-column.js" type="text/javascript"></script>

解决方案二:

新增静态资源转发配置:ddky-risk-cloud-consumer-static

spring:

  cloud:

    gateway:

      discovery:

        locator:

          enabled: true

      routes:

        - id: ddky-risk-cloud-consumer  #路由标识符,区别于其他 Route

          uri: lb://ddky-risk-cloud-consumer #路由指向的目的地 uri,即客户端请求最终被转发到的微服务

          predicates:  #断言,用于条件判断,只有断言都返回真,才会真正的执行路由

            - Path=/riskConfig/**

        - id: ddky-risk-cloud-consumer-static  #路由标识符,区别于其他 Route

          uri: lb://ddky-risk-cloud-consumer #路由指向的目的地 uri,即客户端请求最终被转发到的微服务

          predicates:  #断言,用于条件判断,只有断言都返回真,才会真正的执行路由  

            - Path=/static/**

解决后效果:

API接口restful风格

以JSON对象返回结果集,建议统一入参和出参数据封装,避免接口不统一,影响阅读及风格不统一开发耗时

Spring-cloud-alibaba-sleuth+zipkin 搭建

Zipkin下载启动

官网地址

用于存储全链路调用链信息

https://zipkin.io/

下载链接 

https://repo1.maven.org/maven2/io/zipkin/zipkin-server/2.23.19/zipkin-server-2.23.19-exec.jar

启动不指定数据库:

java -jar zipkin-server-2.23.19-exec.jar

启动指定数据库

java -jar zipkin-server-2.23.19-exec.jar --STORAGE_TYPE=mysql --MYSQL_HOST=127.0.0.1 --MYSQL_TCP_PORT=3310 --MYSQL_DB=zipkin --MYSQL_USER=root --MYSQL_PASS=root

数据库脚本

CREATE TABLE IF NOT EXISTS zipkin_spans (

  `trace_id_high` BIGINT NOT NULL DEFAULT 0 COMMENT 'If non zero, this means the trace uses 128 bit traceIds instead of 64 bit',

  `trace_id` BIGINT NOT NULL,

  `id` BIGINT NOT NULL,

  `name` VARCHAR(255) NOT NULL,

  `remote_service_name` VARCHAR(255),

  `parent_id` BIGINT,

  `debug` BIT(1),

  `start_ts` BIGINT COMMENT 'Span.timestamp(): epoch micros used for endTs query and to implement TTL',

  `duration` BIGINT COMMENT 'Span.duration(): micros used for minDuration and maxDuration query',

  PRIMARY KEY (`trace_id_high`, `trace_id`, `id`)

) ENGINE=InnoDB ROW_FORMAT=COMPRESSED CHARACTER SET=utf8 COLLATE utf8_general_ci;

ALTER TABLE zipkin_spans ADD INDEX(`trace_id_high`, `trace_id`) COMMENT 'for getTracesByIds';

ALTER TABLE zipkin_spans ADD INDEX(`name`) COMMENT 'for getTraces and getSpanNames';

ALTER TABLE zipkin_spans ADD INDEX(`remote_service_name`) COMMENT 'for getTraces and getRemoteServiceNames';

ALTER TABLE zipkin_spans ADD INDEX(`start_ts`) COMMENT 'for getTraces ordering and range';

CREATE TABLE IF NOT EXISTS zipkin_annotations (

  `trace_id_high` BIGINT NOT NULL DEFAULT 0 COMMENT 'If non zero, this means the trace uses 128 bit traceIds instead of 64 bit',

  `trace_id` BIGINT NOT NULL COMMENT 'coincides with zipkin_spans.trace_id',

  `span_id` BIGINT NOT NULL COMMENT 'coincides with zipkin_spans.id',

  `a_key` VARCHAR(255) NOT NULL COMMENT 'BinaryAnnotation.key or Annotation.value if type == -1',

  `a_value` BLOB COMMENT 'BinaryAnnotation.value(), which must be smaller than 64KB',

  `a_type` INT NOT NULL COMMENT 'BinaryAnnotation.type() or -1 if Annotation',

  `a_timestamp` BIGINT COMMENT 'Used to implement TTL; Annotation.timestamp or zipkin_spans.timestamp',

  `endpoint_ipv4` INT COMMENT 'Null when Binary/Annotation.endpoint is null',

  `endpoint_ipv6` BINARY(16) COMMENT 'Null when Binary/Annotation.endpoint is null, or no IPv6 address',

  `endpoint_port` SMALLINT COMMENT 'Null when Binary/Annotation.endpoint is null',

  `endpoint_service_name` VARCHAR(255) COMMENT 'Null when Binary/Annotation.endpoint is null'

) ENGINE=InnoDB ROW_FORMAT=COMPRESSED CHARACTER SET=utf8 COLLATE utf8_general_ci;

ALTER TABLE zipkin_annotations ADD UNIQUE KEY(`trace_id_high`, `trace_id`, `span_id`, `a_key`, `a_timestamp`) COMMENT 'Ignore insert on duplicate';

ALTER TABLE zipkin_annotations ADD INDEX(`trace_id_high`, `trace_id`, `span_id`) COMMENT 'for joining with zipkin_spans';

ALTER TABLE zipkin_annotations ADD INDEX(`trace_id_high`, `trace_id`) COMMENT 'for getTraces/ByIds';

ALTER TABLE zipkin_annotations ADD INDEX(`endpoint_service_name`) COMMENT 'for getTraces and getServiceNames';

ALTER TABLE zipkin_annotations ADD INDEX(`a_type`) COMMENT 'for getTraces and autocomplete values';

ALTER TABLE zipkin_annotations ADD INDEX(`a_key`) COMMENT 'for getTraces and autocomplete values';

ALTER TABLE zipkin_annotations ADD INDEX(`trace_id`, `span_id`, `a_key`) COMMENT 'for dependencies job';

CREATE TABLE IF NOT EXISTS zipkin_dependencies (

  `day` DATE NOT NULL,

  `parent` VARCHAR(255) NOT NULL,

  `child` VARCHAR(255) NOT NULL,

  `call_count` BIGINT,

  `error_count` BIGINT,

  PRIMARY KEY (`day`, `parent`, `child`)

) ENGINE=InnoDB ROW_FORMAT=COMPRESSED CHARACTER SET=utf8 COLLATE utf8_general_ci;

Spring-cloud-alibaba-sleuth pom 配置

注:spring-cloud-starter-zipkin jar包含(spring-cloud-starter-sleuth

spring-cloud-sleuth-zipkin 

<dependency>

    <groupId>org.springframework.cloud</groupId>

    <artifactId>spring-cloud-starter-zipkin</artifactId>

<version>2.2.1-SNAPSHOT</version>

</dependency>

Spring-cloud-alibaba-sleuth yml 配置

spring:

  sleuth:

    web:

      client:

        enabled: true #开启链路采集

    sampler:

      probability: 1.0 #默认采集数据量 1-百分百,0.1-百分十

  zipkin:

    base-url: http://127.0.0.1:9411/  #制定链路日志收集地址

Spring-cloud-alibaba-微服务透传trace实现

Headers 封装

x-b3-spanid:一个工作单元(rpc 调用)的唯一标识

x-b3-parentspanid:当前工作单元的上一个工作单元,Root Span(请求链路的第一个工作单元)的值为空

x-b3-traceid:一条请求链条(trace) 的唯一标识

x-b3-sampled:是否被抽样为输出的标志,1 为需要被输出,0 为不需要被输出

Gateway|Http/Https -> web 实现trace透传

brave.servlet.TracingFilter#doFilter 实现TraceContextSpan创建并封装Headers实现trace透传

Web->Web openFeign 代理实现trace透传

依赖于openfeign框架实现,忽略 请参考 Spring-cloud-alibaba-feign 搭建 模块

Web -> Web RestTemplate手动实现trace透传

只做了解

HttpHeader封装trace信息:

从上一个web的request的Headers 获取X-B3-TraceIdX-B3-SpanIdX-B3-ParentSpanIdX-B3-Sampled

如果数据为空,从request.getAttribute("brave.propagation.TraceContext")对象信息

代码实现:

public ResponseEntity doPathUrl(HttpServletRequest request,String targetUrl,Object obj){

   //设置header信息

   Map map = MDC.getCopyOfContextMap();//获取trace信息

   HttpHeaders requestHandler = new HttpHeaders();

   String traceId = map.get("traceId")+"";

   String parentSpanId = map.get("spanId")+"";

   String spanId =  HexCodec.toLowerHex(nextId());

   String sampled = "1";

   requestHandler.add("X-B3-TraceId", traceId);

   requestHandler.add("X-B3-SpanId",spanId);

   requestHandler.add("X-B3-ParentSpanId", parentSpanId);

   requestHandler.add("X-B3-Sampled", sampled);

   MultiValueMap<String, Object> params = new LinkedMultiValueMap<>();

   params.add("riskCode",obj);

   HttpEntity<MultiValueMap> entity = new HttpEntity<>(params,requestHandler);

   return restTemplate.postForEntity(targetUrl,entity,ServiceResult.class);

}

效果展示

Gateway

Web

 Provider

 Zipkin

页面返回接口 Reseful json数据

有关Spring-cloud-alibaba 系统搭建的更多相关文章

  1. ruby-on-rails - 带 Spring 锁的 Rails 4 控制台 - 2

    我正在使用Ruby2.1.1和Rails4.1.0.rc1。当执行railsc时,它被锁定了。使用Ctrl-C停止,我得到以下错误日志:~/.rvm/gems/ruby-2.1.1/gems/spring-1.1.2/lib/spring/client/run.rb:47:in`gets':Interruptfrom~/.rvm/gems/ruby-2.1.1/gems/spring-1.1.2/lib/spring/client/run.rb:47:in`verify_server_version'from~/.rvm/gems/ruby-2.1.1/gems/spring-1.1.

  2. 电脑0x0000001A蓝屏错误怎么U盘重装系统教学 - 2

      电脑0x0000001A蓝屏错误怎么U盘重装系统教学分享。有用户电脑开机之后遇到了系统蓝屏的情况。系统蓝屏问题很多时候都是系统bug,只有通过重装系统来进行解决。那么蓝屏问题如何通过U盘重装新系统来解决呢?来看看以下的详细操作方法教学吧。  准备工作:  1、U盘一个(尽量使用8G以上的U盘)。  2、一台正常联网可使用的电脑。  3、ghost或ISO系统镜像文件(Win10系统下载_Win10专业版_windows10正式版下载-系统之家)。  4、在本页面下载U盘启动盘制作工具:系统之家U盘启动工具。  U盘启动盘制作步骤:  注意:制作期间,U盘会被格式化,因此U盘中的重要文件请注

  3. 【鸿蒙应用开发系列】- 获取系统设备信息以及版本API兼容调用方式 - 2

    在应用开发中,有时候我们需要获取系统的设备信息,用于数据上报和行为分析。那在鸿蒙系统中,我们应该怎么去获取设备的系统信息呢,比如说获取手机的系统版本号、手机的制造商、手机型号等数据。1、获取方式这里分为两种情况,一种是设备信息的获取,一种是系统信息的获取。1.1、获取设备信息获取设备信息,鸿蒙的SDK包为我们提供了DeviceInfo类,通过该类的一些静态方法,可以获取设备信息,DeviceInfo类的包路径为:ohos.system.DeviceInfo.具体的方法如下:ModifierandTypeMethodDescriptionstatic StringgetAbiList​()Obt

  4. kvm虚拟机安装centos7基于ubuntu20.04系统 - 2

    需求:要创建虚拟机,就需要给他提供一个虚拟的磁盘,我们就在/opt目录下创建一个10G大小的raw格式的虚拟磁盘CentOS-7-x86_64.raw命令格式:qemu-imgcreate-f磁盘格式磁盘名称磁盘大小qemu-imgcreate-f磁盘格式-o?1.创建磁盘qemu-imgcreate-fraw/opt/CentOS-7-x86_64.raw10G执行效果#ls/opt/CentOS-7-x86_64.raw2.安装虚拟机使用virt-install命令,基于我们提供的系统镜像和虚拟磁盘来创建一个虚拟机,另外在创建虚拟机之前,提前打开vnc客户端,在创建虚拟机的时候,通过vnc

  5. spring.profiles.active和spring.profiles.include的使用及区别说明 - 2

    转自:spring.profiles.active和spring.profiles.include的使用及区别说明下文笔者讲述spring.profiles.active和spring.profiles.include的区别简介说明,如下所示我们都知道,在日常开发中,开发|测试|生产环境都拥有不同的配置信息如:jdbc地址、ip、端口等此时为了避免每次都修改全部信息,我们则可以采用以上的属性处理此类异常spring.profiles.active属性例:配置文件,可使用以下方式定义application-${profile}.properties开发环境配置文件:application-dev

  6. ruby - 在没有基准或时间的情况下用 Ruby 测量用户时间或系统时间 - 2

    因为我现在正在做一些时间测量,我想知道是否可以在不使用Benchmark类或命令行实用程序time的情况下测量用户时间或系统时间。使用Time类只显示挂钟时间,而不显示系统和用户时间,但是我正在寻找具有相同灵active的解决方案,例如time=TimeUtility.now#somecodeuser,system,real=TimeUtility.now-time原因是我有点不喜欢Benchmark,因为它不能只返回数字(编辑:我错了-它可以。请参阅下面的答案。)。当然,我可以解析输出,但感觉不对。*NIX系统的time实用程序也应该可以解决我的问题,但我想知道是否已经在Ruby中实

  7. ruby - 以毫秒为单位获取当前系统时间 - 2

    在Ruby中,以毫秒为单位获取自纪元(1970)以来的当前系统时间的正确方法是什么?我试过了Time.now.to_i,好像不是我想要的结果。我需要结果显示毫秒并且使用long类型,而不是float或double。 最佳答案 (Time.now.to_f*1000).to_iTime.now.to_f显示包含十进制数字的时间。要获得毫秒数,只需将时间乘以1000。 关于ruby-以毫秒为单位获取当前系统时间,我们在StackOverflow上找到一个类似的问题:

  8. ruby-on-rails - 如何构建复杂的 Rails 系统 - 2

    关闭。这个问题需要更多focused.它目前不接受答案。想改进这个问题吗?更新问题,使其只关注一个问题editingthispost.关闭8年前。Improvethisquestion我们有以下(以及更多)系统,我们将数据从一个应用推送/拉取到另一个:托管CRM(InsideSales.com)Asterisk电话系统(内部)横幅广告系统(openx,我们托管)潜在客户生成系统(自行开发)电子商务商店(spree,我们托管)工作板(本土)一些工作网站抓取+入站工作提要电子邮件传送系统(如Mailchimp,自主开发)事件管理系统(如eventbrite,自主开发)仪表板系统(大量图表和

  9. ruby-on-rails - Rails 3,在RAILS_ROOT上方显示来自本地文件系统的jpg图片 - 2

    我正在尝试找出一种方法来显示来自不在RAILS_ROOT下(在RedHat或Ubuntu环境中)的已安装文件系统的图像。我不想使用符号链接(symboliclink),因为这个应用程序实际上是通过Tomcat部署的,而当我关闭Tomcat时,Tomcat会尝试跟随符号链接(symboliclink)并删除挂载中的所有图像。由于这些文件的数量和大小,将图像放在public/images下也不是一种选择。我查看了send_file,但它只会显示一张图片。我需要在一个格式良好的页面中显示6个请求的图像。由于膨胀,我宁愿不使用Base64编码,但我不知道如何将图像数据与呈现的页面一起传递下去。

  10. ruby-on-rails - Spring 不起作用。 [未初始化常量 Spring::SID::DL] - 2

    我无法运行Spring。这是错误日志。myid-no-MacBook-Pro:myid$spring/Users/myid/.rbenv/versions/1.9.3-p484/lib/ruby/gems/1.9.1/gems/spring-0.0.10/lib/spring/sid.rb:17:in`fiddle_func':uninitializedconstantSpring::SID::DL(NameError)from/Users/myid/.rbenv/versions/1.9.3-p484/lib/ruby/gems/1.9.1/gems/spring-0.0.10/li

随机推荐