">

springcloudalibaba入门

springcloudalibaba入门

1、父工程pom文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <modules>
        <module>order</module>
        <module>stock</module>
    </modules>

    <groupId>com.wanqi</groupId>
    <artifactId>springCloudAlibaba</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>springCloudAlibaba</name>
    <description>springCloudAlibaba</description>
    <packaging>pom</packaging>

    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>2021.0.3</spring-cloud.version>
        <spring-cloud.alibaba.version>2021.1</spring-cloud.alibaba.version>
        <spring-cloud.alibaba.nacos.version>2021.1</spring-cloud.alibaba.nacos.version>
        <spring-boot.version>2.7.2</spring-boot.version>
        <spring-cloud.loadbalancer.version>3.1.3</spring-cloud.loadbalancer.version>

    </properties>


    <dependencyManagement>
        <dependencies>
            <!-- 考虑到企业可能有自己的父工程,spring-boot父工程引用改到dependencyManagement -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-parent</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${spring-cloud.alibaba.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
                <version>${spring-cloud.alibaba.nacos.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!-- 高版本移除了Ribbon,改用loadbalancer -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-loadbalancer</artifactId>
                <version>${spring-cloud.loadbalancer.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
                <version>${spring-cloud.alibaba.nacos.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

1.1、nacos服务本地部署启动

1.1.1、github下载nacos服务
1.1.2、解压后修改启动文件改为单机nacos/bin/startup.sh
解压命令
tar -xvf nacos-server-2.1.0.tar.gz
# export MODE="cluster"
export MODE="standalone"
1.1.3、修改启动端口nacos/conf/application.properties

image.png

1.1.4、启动nacos通过nacos/bin/startup.sh
1.1.5、根据启动提示找到日志nacos/logs/start.out
#看到一下提示表示启动成功
INFO Nacos started successfully in stand alone mode. use embedded storage

image.png

1.1.6、找到日志中启动logo的Console: http://192.168.110.57:8848/nacos/index.html使用浏览器打开,输入默认用户名密码,均为:nacos

2、服务提供方pom文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>springCloudAlibaba</artifactId>
        <groupId>com.wanqi</groupId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>stock</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
         <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
    </dependencies>
</project>

2.1、application.yml配置文件

server:
  port: 8082
---
spring:
  cloud:
    nacos:
      server-addr: 39.105.101.111:12205
      discovery:
        ephemeral: true #是否临时实例,false表示永久实例,掉线也不会消失
  application:
    name: stock-service

2.2、 编写测试Controller

@RestController
@RequestMapping("/stock")
public class StockController {

    @Value("${server.port}")
    private String port;

    @RequestMapping("/add")
    public String add(){
        return "ok---" + port;
    }
}

3、 服务调用方pom文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>springCloudAlibaba</artifactId>
        <groupId>com.wanqi</groupId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>order</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
         <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!-- 高版本移除了Ribbon,改用loadbalancer -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-loadbalancer</artifactId>
        </dependency>
    </dependencies>

</project>

3.1、application.yml配置文件

server:
  port: 8081
spring:
  cloud:
    nacos:
      server-addr: 39.105.101.111:12205
      discovery:
        ephemeral: true #是否临时实例,false表示永久实例,掉线也不会消失
  application:
    name: order-service

3.2、配置类,调用方注册RestTemplate

@Configuration
public class AppConfig {
    @Bean
    @LoadBalanced //解决 java.net.UnknownHostException
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

3.3、controller使用RestTemplate

@RestController
@RequestMapping("/order")
public class OrderController {

    @Autowired
    private RestTemplate restTemplate;

    @GetMapping("/add")
    public String add(){
        return restTemplate.getForObject("http://stock-service/stock/add",String.class);
    }

}

4、Nacos集群部署,并使用nginx实现负载均衡

  • 虚拟机准备

image.png

  • mysql准备,安装并创建nacos库
  • nginx安装

4.1、github下载nacos服务

4.1.1、解压nacos并修改nacos/conf/application.properties文件
  • 修改端口号,配置放开并修改数据库相关数据
server.port=8849
#*************** Config Module Related Configurations ***************#
### If use MySQL as datasource:
spring.datasource.platform=mysql

### Count of DB:
db.num=1

### Connect URL of DB:
db.url.0=jdbc:mysql://39.105.101.111:3306/nacos?characterEncoding=utf-8&useSSL=true&serverTimezone=Asia/Shanghai
db.user.0=wq
db.password.0=123456

4.2、数据库表相关sql,nacos/conf/nacos-mysql.sql

4.3、修改启动脚本nacos/bin/startup.sh

    # *根据服务器实际内存情况酌情修改*
    JAVA_OPT="${JAVA_OPT} -server -Xms256m -Xmx256m -Xmn128m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=320m"
    #JAVA_OPT="${JAVA_OPT} -server -Xms2g -Xmx2g -Xmn1g -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=320m"
    JAVA_OPT="${JAVA_OPT} -XX:-OmitStackTraceInFastThrow -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=${BASE_DIR}/logs/java_heapdump.hprof"
    JAVA_OPT="${JAVA_OPT} -XX:-UseLargePages"
     # *新增以下参数设置本机ip地址,云服务器如果不修改会默认多一个使用网卡ip注册的节点*
    JAVA_OPT="${JAVA_OPT} -Dnacos.server.ip=114.67.111.165"

4.5、在nacos/conf下新建cluster.conf文件配置集群

  • 一台机器模拟端口最好分散一点不容易翻车,多台的话默认8848即可
#单台机器模拟
114.67.111.165:8849
114.67.111.165:8851
114.67.111.165:8853
#多台虚拟机
172.16.156.134:8848
172.16.156.135:8848
172.16.156.136:8848

4.5、启动并验证是否成功参考单机模式

4.6、启动成功后把这个nacos再复制2个修改端口然后启动即可

4.7、nginx配置新增在http下

    upstream  nacosServer{
      #nacos集群ip与端口
         server 114.67.111.165:8849;
         server 114.67.111.165:8851;
         server 114.67.111.165:8853;
    }
    server {
      #监听端口
       listen       12205;
        #nginx服务器ip
       server_name  39.105.101.111;
       location /nacos{
            proxy_pass http://nacosServer/nacos;
       }
    # 静态资源处理
    location ~ .* {
                proxy_pass      http://nacosServer;
                proxy_set_header Host $http_host;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Fonwarded-For $proxy_add_x_forwarded_for;
         }

    }

4.8、访问nginx配置的监听端口与请求

http://39.105.101.111:12205/nacos

image.png

5、集成openfeign

5.1、服务调用方导入依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter</artifactId>
        </dependency>       
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <dependency>
          <groupId>org.springframework.cloud</groupId>
          <artifactId>spring-cloud-loadbalancer</artifactId>
        </dependency>

5.2、使用示例

5.2.1、服务提供方Controller
@RestController
public class StockController {
    @Autowired
    StockMapper stockMapper;

    @PostMapping("/add")
    public int add(@RequestParam("orderId") Long id) {
        Stock select = stockMapper.select();
       
        int x =  stockMapper.update(id);
        System.out.println(select);
        return x;
    }

    @PostMapping(value = "/sqlFile")
    public String genSqlFile(@RequestParam("sqlId")String sqlId,@RequestParam("sql")String sql){
        MyTest test = new MyTest(sqlId,sql);
        System.out.println(test);
        return test.toString();
    }

}
5.2.2、调用方Feign接口
/**
 * name 指定调用服务提供方接口所对应的服务名
 * path 指定调用接口所在StockController指定的@RequestMapping("/stock"),如果没有则不需要
 * contextId 多个feign接口使用@FeignClient注解调用同一个名称的微服务时增加contextId属性,
 * 确保每个feignclient的contextId唯一
 */
@FeignClient(name = "stock-db",contextId = "stock-db")
public interface StockFeignService {
    
    @PostMapping("/add")
    public int add(@RequestParam("orderId") Long orderId);

    @PostMapping(value = "/sqlFile")
    public String genSqlFile(@RequestParam("sqlId")String sqlId,@RequestParam("sql")String sql);

5.2.3、使用@EnableFeignClients开启Feign
@SpringBootApplication
@EnableDiscoveryClient //高版本可省略
@EnableFeignClients
public class OrderApplication {
    public static void main(String[] args) {
        SpringApplication.run(OrderApplication.class);
    }
}
5.2.4、调用方service
@RestController
public class OrderController {

    @Autowired
    StockFeignService stockFeignService;


    @GetMapping("add2/{orderId}")
    public int add2(@PathVariable("orderId") Long orderId) {
        return stockFeignService.add(orderId);
    }


    @PostMapping(value = "/sqlFile")
    public String genSqlFile(@RequestParam("sqlId")String sqlId,@RequestParam("sql")String sql){
        MyTest test = new MyTest(sqlId,sql);
        String msg = stockFeignService.genSqlFile(test.getSqlId(),test.getSql());
        System.out.println(msg + "调用成功啦!!!");
        return msg;
    }
}

5.5、openfeign日志配置示例

5.5.1、使用配置文件
feign:
  client:
    config:
      # 全局使用default,指定feign默认使用feignName,如果配置了contextId必须使用contextId
      stock: #@FeignClient(name = "stock-service",path = "/stock",contextId = "stock")
        # 连接超时时间,默认2s
        connectTimeout: 5000
        # 请求处理超时时间,默认5秒
        readTimeout: 3000
        # 指定feign拦截器
        requestInterceptors[0]: com.wanqi.interceptor.FeignInterceptor
        # 指定日志级别,需要开启spring日志
        loggerLevel: BASIC
# 开启Spring日志        
logging:
  level:
    com.wanqi.feign: debug  #指定feign包的日志级别为debug
5.5.2、使用注解
  • 全局配置直接使用@Configuration
/**
 * 全局配置直接使用 @Configuration
 * 局部配置配合@FeignClient使用:configuration = FeignConfig.class
 */
@Configuration
public class FeignConfig {
    /**
     * NONE【性能最佳,适用于生产】:不记录任何日志(默认值)
     * BASIC【适用于生产环境追踪问题】:仅记录请求方法、URL、响应状态代码以及执行时间。
     * HEADERS:记录BASIC级别的基础上,记录请求和响应的neader。
     * FULL【比较适用于开发及测试环境定位问题】:记录请求和响应的header、body和元数据。
     */
    @Bean
    public Logger.Level feignLoggerLevel(){
        return Logger.Level.FULL;
    }
}
  • 局部配置,去掉FeignConfig配置类上的@Configuration注解,在需要指定的FeignClient属性上加上configuration = FeignConfig.class(FeignConfig配置类不要加@Configuration注解,否则这将是一个全局配置)。
/**
 * name 指定调用rest接口所对应的服务名
 * path 指定调用接口所在StockController指定的@RequestMapping("/stock")
 * contextId 多个feign接口使用@FeignClient注解调用同一个名称的微服务时增加contextId属性,
 * 确保每个feignclient的contextId唯一
 * configuration 引入配置类
 */
@FeignClient(name = "stock-service",path = "/stock"
        ,contextId = "stock"
        ,configuration = FeignConfig.class
)
public interface StockFeignService {
    // 接口方法对应调用服务的方法,即对应服务Controller里面的方法名和参数一一对应
    @RequestMapping("/add2")
    String add2();

  /*  @RestController
    @RequestMapping("/stock")
    public class StockController {

        @Value("${server.port}")
        private String port;

        @RequestMapping("/add2")
        public String add2(){
            System.out.println("add2");
            return "add2---" + port;
        }
    */
}

5.6、feign自定义拦截器,实现RequestInterceptor接口重写apply方法,注册bean

  • 自定义拦截器
public class FeignInterceptor implements RequestInterceptor {
    Logger logger = LoggerFactory.getLogger(this.getClass());
    @Override
    public void apply(RequestTemplate requestTemplate) {
        logger.info("--------------FeignInterceptor---------------" + requestTemplate.path());
        logger.info("--------------FeignInterceptor---------------" + requestTemplate.request().url());
        logger.info("--------------FeignInterceptor---------------" + requestTemplate.url());

    }
}
  • 配置类@Bean注册,或者直接在自定义拦截器上加上@Component注解(全局配置)
/**
* 自定义拦截器
*/
@Bean
public FeignInterceptor feignInterceptor(){
    return new FeignInterceptor();
    }
  • application.yml配置文件注册(可以指定具体FeignClient)
feign:
  client:
    config:
      # 全局使用default,指定feign默认使用feignName,如果配置了contextId必须使用contextId
      stock: #@FeignClient(name = "stock-service",path = "/stock",contextId = "stock")
        # 指定feign拦截器
        requestInterceptors[0]: com.wanqi.interceptor.FeignInterceptor
  • 使用FeignClient属性configuration配置(可以指定具体FeignClient)
/**
 * name 指定调用rest接口所对应的服务名
 * path 指定调用接口所在StockController指定的@RequestMapping("/stock")
 * contextId 多个feign接口使用@FeignClient注解调用同一个名称的微服务时增加contextId属性,
 * 确保每个feignclient的contextId唯一
 * configuration 引入配置类
 */
@FeignClient(name = "stock-service",path = "/stock"
        ,contextId = "stock"
        ,configuration = {FeignConfig.class, FeignInterceptor.class}
)
public interface StockFeignService {
    // 接口方法对应调用服务的方法,即对应服务Controller里面的方法名和参数一一对应
    @RequestMapping("/add2")
    String add2();

  /*  @RestController
    @RequestMapping("/stock")
    public class StockController {

        @Value("${server.port}")
        private String port;

        @RequestMapping("/add2")
        public String add2(){
            System.out.println("add2");
            return "add2---" + port;
        }
    */
}

5.7、feign超时时间配置

  • 配置类的方式
   /**
     * 超时时间配置
     */
    @Bean
    public Request.Options options(){
        return new Request.Options(5, TimeUnit.SECONDS,10,TimeUnit.SECONDS,true);
    }
  • application.yml配置文件
feign:
  client:
    config:
      # 全局使用default,指定feign默认使用feignName,如果配置了contextId必须使用contextId
      product:
        # 连接超时时间,默认2s
        connectTimeout: 5000
        # 请求处理超时时间,默认5秒
        readTimeout: 3000

6、Nacos-config配置使用

  • 建议所有配置文件的名字即data-id都加上文件扩展名如test.properties,test.yml等

6.1、pom文件导入依赖

         <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>
        <!--   新版nacos-config要使用bootstrap.yml必须引入     -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-bootstrap</artifactId>
        </dependency>

6.2、编写bootstrap.yml文件

6.2.1、推荐模式根据namespace来控制不同环境的配置
spring:
  cloud:
    nacos:
      config:
        server-addr: 172.16.156.137:8847
        # 指定命名空间,不明确配置的话,默认是public
        namespace: dev
        # 指定文件名即配置的Data ID
        name: com.wanqi.config-mac.yml
        username: nacos
        password: nacos
        # 配置文件类型
        file-extension: yml
6.2.2、支持profile粒度的配置
配置文件名com.wanqi.config-mac.yml,必须显示的指定文件格式
profile粒度的配置dataid即文件名格式:${spring.application.name}-${profile}.${file-extension:properties}
${spring.application.name}对应:com.wanqi.config,属性名spring.cloud.nacos.config.name
${profile}对应:mac,属性名springprofiles.active
${file-extension:properties}对应:yml,属性名spring.cloud.nacos.config.file-extension
spring:
  cloud:
    nacos:
      config:
        server-addr: 172.16.156.137:8847
        # 指定命名空间,不明确配置的话,默认是public
        namespace: dev
        #配置文件名即Data ID为com.wanqi.config-mac.yml
        # 指定文件名${spring.application.name}=com.wanqi.config
        name: com.wanqi.config
        username: nacos
        password: nacos
        # 配置文件类型${file-extension:properties}=yml
        file-extension: yml
  # profile粒度${profile}=mac
  profiles:
    active: mac
6.2.3、多配置、共享配置bootstrap.yml
spring:
  cloud:
    nacos:
      config:
        server-addr: 172.16.156.137:8847
        # 指定命名空间,不明确配置的话,默认是public
        namespace: test
        # 指定文件名 
#        name: com.wanqi.config
        username: nacos
        password: nacos
        # 配置文件类型
        file-extension: yml
#        shared-configs[0]:
#          data-id: test.properties
#          refresh: true
#        shared-configs[1]:
#          data-id: test01.properties
#          refresh: true
        shared-configs:
          - data-id: test.properties
#            不明确配置的话,默认是 DEFAULT_GROUP。
#            group: DEFAULT_GROUP
          # refresh是否支持应用中可动态刷新, 感知到最新的配置值。默认是不支持的。
            refresh: true
#          - data-id: test01.properties
#           refresh: true
        extension-configs:
          - data-id: test01.properties
            refresh: true

6.3、使用

6.3.1、硬编码
@SpringBootApplication
public class NacosConfigApplication {
    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(NacosConfigApplication.class, args);
        String name = context.getEnvironment().getProperty("wq.name");
        System.out.println(name);
    }
}
6.3.2、注解@RefreshScope和 @Value
@Controller
@RefreshScope
public class NacosController {

    @Value("${wq.name}")
    private String name;
    @Value("${wq.age}")
    private int age;
    @Value("${wq.msg}")
    private String msg;

    @ResponseBody
    @RequestMapping("nacos")
    public String nacos(){
        return name + msg;
    }
}

6.4、配置的优先级

Spring Cloud Alibaba Nacos Config 目前提供了三种配置能力从 Nacos 拉取相关的配置。
A: 通过 spring.cloud.nacos.config.shared-configs[n].data-id 支持多个共享 Data Id 的配置
B: 通过 spring.cloud.nacos.config.extension-configs[n].data-id 的方式支持多个扩展 Data Id 的配置
C: 通过内部相关规则(应用名、应用名+ Profile )自动生成相关的 Data Id 配置
当三种方式共同使用时,他们的一个优先级关系是:A < B < C

  • 多个 Data Id 同时配置时,他的优先级关系是 spring.cloud.nacos.config.extension-configs[n].data-id 其中 n 的值越大,优先级越高。

7、sentinel集成

7.1、普通spring boot项目使用sentinel

7.1.1、引入依赖
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--   sentinel核心库     -->
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-core</artifactId>
            <version>1.8.4</version>
        </dependency>
        <!--   sentinel注解支持     -->
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-annotation-aspectj</artifactId>
            <version>1.8.4</version>
        </dependency>
        <!--   spring aop配合sentinel注解支持     -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
7.1.2、定义规则可使用@PostConstruct注解
    private static final String SENTINEL = "sentinel";
    private static final String HELLO = "hello";
    private static final String QIFENG = "qifeng";

    @PostConstruct
    private void initFlowRules(){
        List<FlowRule> rules = new ArrayList<>();
        FlowRule rule = new FlowRule();
        //流控的资源
        rule.setResource(SENTINEL);
        //流控规则为QPS
        rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
        // 设置QPS
        rule.setCount(1);
        rules.add(rule);

        rule = new FlowRule();
        //流控的资源
        rule.setResource(HELLO);
        //流控规则为QPS
        rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
        // 设置QPS
        rule.setCount(1);
        rules.add(rule);
        FlowRuleManager.loadRules(rules);
        initDegradeRule();
    }
    private void initDegradeRule() {
        List<DegradeRule> rules = new ArrayList<>();
        DegradeRule rule = new DegradeRule();
        rule.setResource(HELLO);
        //设置规则,熔断策略,支持慢调用比例/异常比例/异常数策略
        rule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT);
        // 熔断时长,单位为 s, 10 ms
        rule.setTimeWindow(10);
        //熔断触发的最小请求数,请求数小于该值时即使异常比率超出阈值也不会熔断
        rule.setMinRequestAmount(2);
        //统计时长(单位为 ms),如 60*1000 代表分钟级
        rule.setStatIntervalMs(60*1000);
        //慢调用比例模式下为慢调用临界 RT(超出该值计为慢调用);异常比例/异常数模式下为对应的阈值
        rule.setCount(2);
        rules.add(rule);
        DegradeRuleManager.loadRules(rules);
    }
7.1.3、定义资源
7.1.3.1、抛出异常的方式定义资源
    //抛出异常的方式定义资源
    @GetMapping("sentinel")
    @ResponseBody
    public String helloSentinel(){
        try (Entry entry = SphU.entry(SENTINEL)) {
            // 被保护的逻辑
            return "hello sentinel";
        } catch (BlockException ex) {
            // 处理被流控的逻辑
            return "请求被流控啦!!!!";
        }

    }
7.1.3.2、注解方式定义资源
 //注解方式定义资源
    // 原函数
    @GetMapping("qifeng/{age}")
    @ResponseBody
    @SentinelResource(value = QIFENG, blockHandler = "exceptionHandler", fallback = "helloFallback")
    public QiFeng qifeng(@PathVariable("age") int age) {
        return new QiFeng("齐丰",age);
    }

    // Fallback 函数,异常处理,函数签名与原函数一致或加一个 Throwable 类型的参数.
    public QiFeng helloFallback(int age,Throwable throwable) {
        throwable.printStackTrace();
        return new QiFeng("异常啦!!!!", age);
    }


    // Block 异常处理函数,参数最后多一个 BlockException,其余与原函数一致.
    public QiFeng exceptionHandler(int age, BlockException ex) {
        // Do some log here.
        ex.printStackTrace();
        return new QiFeng("请求被流控啦!!!",age);
    }


    //注解方式定义资源
    @GetMapping("hello")
    @ResponseBody
    @SentinelResource(value = HELLO,blockHandler = "hellBlockHandler")
    public String hell(String name){
        int x = 1/0;
        return "hello DegradeRule!!!";
    }

    // Block 异常处理函数,参数最后多一个 BlockException,其余与原函数一致.
    public String hellBlockHandler(String name, BlockException ex) {
        // Do some log here.
        ex.printStackTrace();
        return "熔断降级啦!!!!";
    }
7.1.3.3、注解需要将SentinelResourceAspect注册一个为Spring Bean
    @Bean
    public SentinelResourceAspect sentinelResourceAspect() {
        return new SentinelResourceAspect();
    }
  • 更多规则定义参考官方文档

7.2、Spring Cloud整合控制台sentinel、nacos、openfeign

  • 官方文档
7.2.1、下载控制台jar包并启动
java -Dserver.port=8080 -jar sentinel-dashboard.jar
7.2.2、引入依赖
 <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-datasource-nacos</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!-- 解决 java.net.UnknownHostException -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-loadbalancer</artifactId>
        </dependency>
7.2.3、yaml配置
server:
  port: 7779
spring:
  main:
    allow-circular-references: true
  cloud:
    sentinel:
      transport:
        # sentinel控制台地址
        dashboard: 172.16.156.139:9999
        port: 8720
      web-context-unify: false # 关闭默认调用链路收敛
      # sentinel持久化配置
      datasource:
        flowrule: #可以自定义
         nacos:
          serverAddr: 172.16.156.139:8847
          username: nacos
          password: nacos
          groupId: SENTINEL_GROUP
          # nacos上配置文件的dataId
          dataId: order-feign-sentinel-win-flowrule
          # 规则分类
          RuleType: flow
    nacos:
      server-addr: 172.16.156.139:8847
      discovery:
        ephemeral: true #是否临时实例,false表示永久实例,掉线也不会消失
      username: nacos
      password: nacos
  application:
    name: order-feign-sentinel
---
feign:
  client:
    config:
      # 全局使用default,指定feign默认使用feignName,如果配置了contextId必须使用contextId
      stock:
        # 连接超时时间,默认2s
        connectTimeout: 5000
        # 请求处理超时时间,默认5秒
        readTimeout: 3000
        # 指定feign拦截器
#        requestInterceptors[0]: com.wanqi.interceptor.FeignInterceptor
        loggerLevel: Full
  sentinel:
  # 打开 Sentinel 对 Feign 的支持
    enabled: true

---
logging:
  level:
    com.wanqi.feign: debug
---
7.2.4、示例代码
7.2.4.1、feign接口配置与回调
public class FeignConfig {
    @Bean
    public StockFeignServiceFallback stockFeignServiceImpl(){
        return new StockFeignServiceFallback();
    }
}

/**
* name 指定调用rest接口所对应的服务名
* path 指定调用接口所在StockController类上指定的@RequestMapping("/stock")
* contextId 多个feign接口使用@FeignClient注解调用同一个名称的微服务时增加contextId属性,
* 确保每个feignclient的contextId唯一
* configuration 引入配置类
*/
@FeignClient(name = "stock-service", path = "/stock"
             , contextId = "stock"
             , fallback = StockFeignServiceFallback.class
             , configuration = {FeignConfig.class}
            )
    public interface StockFeignService {

        @RequestMapping("/test1")
        String test1();
        @RequestMapping("/test2")
        String test2();
        @RequestMapping("/get/{id}")
        public String getById(@PathVariable("id") int id);
    }
public class StockFeignServiceFallback implements StockFeignService{
    @Override
    public String test1() {
        return "test1熔断降级啦!!!!";
    }

    @Override
    public String test2() {
        return "test2熔断降级啦!!!!";
    }

    @Override
    public String getById(int id) {
        return "接口异常熔断降级啦!!!!";
    }
}
7.2.4.2、controller层
@RestController
public class OrderController {
    @Autowired
    private StockFeignService stockFeignService;

    @GetMapping("/test1")
    public String test1(){
        return stockFeignService.test1();
    }

    @GetMapping("/test2")
    public String test2(){
        return stockFeignService.test2();
    }

    /**
     * 热点参数流控须要使用Sentinel
     * @param id
     * @return
     */
    @RequestMapping("/get/{id}")
    @SentinelResource(value = "getById",blockHandler = "getByIdBlockHandler")
    public String getById(@PathVariable("id") int id){
        return stockFeignService.getById(id);
    }

    public String getByIdBlockHandler(int id, BlockException e){
        return "getByIdBlockHandler--热点异常处理" + id;
    }

}
7.2.4.3、启动类
@SpringBootApplication
// 开启nacos
@EnableDiscoveryClient
// 开启feign
@EnableFeignClients
public class OrderFeignSentinelApplication {
    public static void main(String[] args) {
        SpringApplication.run(OrderFeignSentinelApplication.class,args);
    }
}
7.2.4.4、nacos实现动态规则配置

image.png

7.2.4.4.1、yaml配置增加
spring:
  cloud:
    sentinel:
      datasource:
        flowrule: #可以自定义
          nacos:
            serverAddr: 172.16.156.139:8847
            username: nacos
            password: nacos
            groupId: SENTINEL_GROUP
            dataId: order-feign-sentinel-win-flowrule
            RuleType: flow
    @GetMapping("/sentinel/nacos")
    @SentinelResource(value = "sentinelNacos",blockHandler = "sentinelNacosBlockHandler"
            , fallback ="sentinelNacosFallback")
    public String sentinelNacos(){
        return "sentinelNacos正常返回!!!";
    }

    // Fallback 函数,异常处理,函数签名与原函数一致或加一个 Throwable 类型的参数.
    public String sentinelNacosFallback(Throwable throwable) {
        return "Fallback: "+ throwable.getMessage();
    }

    // Block 异常处理函数,参数最后多一个 BlockException,其余与原函数一致.
    public String sentinelNacosBlockHandler(BlockException ex) {
        // Do some log here.
        return "BlockHandler: "+ ex.getMessage();

    }

8、Spring Cloud Gateway

  • 可以使用nginx实现负载均衡

8.1、引入依赖

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <!--spring cloud gateway-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>

        <!--    spring cloud gateway整合sentinel的依赖-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
        </dependency>
        <!--    sentinel的依赖-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!-- 解决 java.net.UnknownHostException -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-loadbalancer</artifactId>
        </dependency>

8.2、yaml配置

server:
  port: 9527
spring:
  application:
    name: api-gateway
  cloud:
    ## 整合sentinel,配置sentinel控制台的地址
    sentinel:
      transport:
        ## 指定控制台的地址,默认端口8080
        dashboard: 172.16.156.139:9999
        port: 8722
    nacos:
      ## 注册中心配置
      discovery:
        # nacos的服务地址,nacos-server中IP地址:端口号
        server-addr: 172.16.156.139:8847
        username: nacos
        password: nacos
    gateway:
      ## 路由
      routes:
        ## id只要唯一即可,名称任意
        - id: gateway-provider
          # 需要转发的地址
          #lb://service-name
          #lb:uri 的协议,表示开启 Spring Cloud Gateway 的负载均衡功能。
          #service-name:服务名,Spring Cloud Gateway 会根据它获取到具体的微服务地址。
          uri: lb://stock-service
          ## 配置断言
          predicates:
            # Path Route Predicate Factory断言,满足/stock-service/**这个请求路径的都会被路由到stock-service这个服务中
            # 自定义前缀避免接口重复 
            - Path=/stock-service/**
            # 过滤器,转发之前过滤掉第一层路径即stock-service/
            # http://localhost:9527/stock-service/stock/get/1 转发到stock-service服务上,http://stock-service/stock/get/1
          filters:
            - StripPrefix=1

8.3、访问http://localhost:9527/stock-service/stock/get/1会自动路由到stock-service服务上

image.png
image.pngimage.png

8.4、自定义全局流控异常

@Configuration
public class GatewayConfig {

    @PostConstruct
    public void init(){
        BlockRequestHandler blockRequestHandler = new BlockRequestHandler() {
            @Override
            public Mono<ServerResponse> handleRequest(ServerWebExchange serverWebExchange, Throwable throwable) {
                Map<String,Object> map = new HashMap<>();
                map.put("code", HttpStatus.TOO_MANY_REQUESTS.value());
                map.put("msg", "请求太多,限流了");
                return ServerResponse.status(HttpStatus.OK)
                        .contentType(MediaType.APPLICATION_JSON)
                        .bodyValue(map);
            }
        };
        GatewayCallbackManager.setBlockHandler(blockRequestHandler);
    }
}

9、seata使用

9.1、部署steata服务并启动

9.1.1、数据库准备
  • 资源地址
  • client

存放client端sql脚本 (包含 undo_log表) ,参数配置

  • config-center

各个配置中心参数导入脚本,config.txt(包含server和client,原名nacos-config.txt)为通用参数文件

  • server

server端数据库脚本 (包含 lock_table、branch_table 与 global_table) 及各个容器配置

9.1.2、下载seata服务
9.1.3、执行sql脚本seata/script/server/db/mysql.sql
-- -------------------------------- The script used when storeMode is "db" --------------------------------
-- the table to store GlobalSession data
CREATE TABLE IF NOT EXISTS `global_table`
(
    `xid`                       VARCHAR(128) NOT NULL,
    `transaction_id`            BIGINT,
    `status`                    TINYINT      NOT NULL,
    `application_id`            VARCHAR(32),
    `transaction_service_group` VARCHAR(32),
    `transaction_name`          VARCHAR(128),
    `timeout`                   INT,
    `begin_time`                BIGINT,
    `application_data`          VARCHAR(2000),
    `gmt_create`                DATETIME,
    `gmt_modified`              DATETIME,
    PRIMARY KEY (`xid`),
    KEY `idx_status_gmt_modified` (`status` , `gmt_modified`),
    KEY `idx_transaction_id` (`transaction_id`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8mb4;

-- the table to store BranchSession data
CREATE TABLE IF NOT EXISTS `branch_table`
(
    `branch_id`         BIGINT       NOT NULL,
    `xid`               VARCHAR(128) NOT NULL,
    `transaction_id`    BIGINT,
    `resource_group_id` VARCHAR(32),
    `resource_id`       VARCHAR(256),
    `branch_type`       VARCHAR(8),
    `status`            TINYINT,
    `client_id`         VARCHAR(64),
    `application_data`  VARCHAR(2000),
    `gmt_create`        DATETIME(6),
    `gmt_modified`      DATETIME(6),
    PRIMARY KEY (`branch_id`),
    KEY `idx_xid` (`xid`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8mb4;

-- the table to store lock data
CREATE TABLE IF NOT EXISTS `lock_table`
(
    `row_key`        VARCHAR(128) NOT NULL,
    `xid`            VARCHAR(128),
    `transaction_id` BIGINT,
    `branch_id`      BIGINT       NOT NULL,
    `resource_id`    VARCHAR(256),
    `table_name`     VARCHAR(32),
    `pk`             VARCHAR(36),
    `status`         TINYINT      NOT NULL DEFAULT "0" COMMENT "0:locked ,1:rollbacking",
    `gmt_create`     DATETIME,
    `gmt_modified`   DATETIME,
    PRIMARY KEY (`row_key`),
    KEY `idx_status` (`status`),
    KEY `idx_branch_id` (`branch_id`),
    KEY `idx_xid_and_branch_id` (`xid` , `branch_id`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8mb4;

CREATE TABLE IF NOT EXISTS `distributed_lock`
(
    `lock_key`       CHAR(20) NOT NULL,
    `lock_value`     VARCHAR(20) NOT NULL,
    `expire`         BIGINT,
    primary key (`lock_key`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8mb4;

INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ("AsyncCommitting", " ", 0);
INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ("RetryCommitting", " ", 0);
INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ("RetryRollbacking", " ", 0);
INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ("TxTimeoutCheck", " ", 0);
9.1.4、修改配置文件seata/conf/application.yml
server:
  port: 7091

spring:
  application:
    name: seata-server

logging:
  config: classpath:logback-spring.xml
  file:
    path: ${user.home}/logs/seata
#  extend:
#    logstash-appender:
#      destination: 127.0.0.1:4560
#    kafka-appender:
#      bootstrap-servers: 127.0.0.1:9092
#      topic: logback_to_logstash

console:  
  user:
    username: seata
    password: seata

seata:
  config:
    # support: nacos, consul, apollo, zk, etcd3
    type: nacos
    nacos:
      server-addr: 172.16.156.139:8847
      namespace: 170ee694-566d-4c3a-b316-fe233d984d43
      group: SEATA_GROUP
      username: nacos
      password: nacos
      ##if use MSE Nacos with auth, mutex with username/password attribute
      #access-key: ""
      #secret-key: ""
#      data-id: seataServer.properties
  registry:
    # support: nacos, eureka, redis, zk, consul, etcd3, sofa
    type: nacos
#    preferred-networks: 30.240.*
    nacos:
      application: seata-server
      server-addr: 172.16.156.139:8847
      group: SEATA_GROUP
      namespace: 170ee694-566d-4c3a-b316-fe233d984d43
      cluster: default
      username: nacos
      password: nacos
  store:
    # support: file 、 db 、 redis
    mode: db
#  server:
#    service-port: 8091 #If not configured, the default is "${server.port} + 1000"
  security:
    secretKey: SeataSecretKey0c382ef121d778043159209298fd40bf3850a017
    tokenValidityInMilliseconds: 1800000
    ignore:
      urls: /,/**/*.css,/**/*.js,/**/*.html,/**/*.map,/**/*.svg,/**/*.png,/**/*.ico,/console-fe/public/**,/api/v1/auth/login
9.1.5、修改seata/script/config-center/config.txt文件中数据库连接
# 改为db
store.mode=db
store.lock.mode=db
store.session.mode=db
# 改为对应的数据库连接地址
store.db.driverClassName=com.mysql.cj.jdbc.Driver
store.db.url=jdbc:mysql://114.67.111.175:3306/seata_server?useUnicode=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&useSSL=false
store.db.user=root
store.db.password=123456
9.1.6、进入seata/script/config-center/nacos执行脚本上传配置到nacos
./nacos-config.sh -h 172.16.156.139 -p 8847 -g SEATA_GROUP -t 170ee694-566d-4c3a-b316-fe233d984d43 -u nacos -w nacos
  • -h: 注册注册中心的ip
  • -p:注册中心的端口
  • -g: 注册到注册中心的Group
  • -t: 注册到注册中心的命名空间
  • -u: 注册中心的账号
  • -w: 注册中心的密码
9.1.7、进入seata/bin启动seata服务
./seata-server.sh -h 127.0.0.1 -p 8091
  • -h:seata服务地址
  • -p:监听端口,从8091开始

9.2、客户端client

  • 准备在需要开启分布式事务的各数据库新建undo_log表,主要通过 BeforeImage 和 AfterImage 保存前后逻辑 , 用于回退处理,使用at模式
-- for AT mode you must to init this sql for you business database. the seata server not need it.
CREATE TABLE IF NOT EXISTS `undo_log`
(
    `branch_id`     BIGINT       NOT NULL COMMENT "branch transaction id",
    `xid`           VARCHAR(128) NOT NULL COMMENT "global transaction id",
    `context`       VARCHAR(128) NOT NULL COMMENT "undo_log context,such as serialization",
    `rollback_info` LONGBLOB     NOT NULL COMMENT "rollback info",
    `log_status`    INT(11)      NOT NULL COMMENT "0:normal status,1:defense status",
    `log_created`   DATETIME(6)  NOT NULL COMMENT "create datetime",
    `log_modified`  DATETIME(6)  NOT NULL COMMENT "modify datetime",
    UNIQUE KEY `ux_undo_log` (`xid`, `branch_id`)
) ENGINE = InnoDB
  AUTO_INCREMENT = 1
  DEFAULT CHARSET = utf8mb4 COMMENT ="AT transaction mode undo table";
9.2.1、导入依赖
9.2.1.1、服务提供方
 <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.2.2</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.2.11</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>io.seata</groupId>
            <artifactId>seata-spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>io.seata</groupId>
                    <artifactId>seata-spring-boot-starter</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>
9.2.1.2、服务调用方
<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.2.2</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.2.11</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-loadbalancer</artifactId>
        </dependency>
        <dependency>
            <groupId>io.seata</groupId>
            <artifactId>seata-spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>io.seata</groupId>
                    <artifactId>seata-spring-boot-starter</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>
9.2.2、配置文件
9.2.2.1、服务提供方
server:
  port: 6062
spring:
  main:
    allow-circular-references: true
  application:
    name: stock-db
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://114.67.111.175:3306/test?allowPublicKeyRetrieval=true&useSSL=false&serverTimezone=Asia/Shanghai
    username: root
    password: 123456
  cloud:
    nacos:
      server-addr: 172.16.156.139:8847
      username: nacos
      password: nacos
    alibaba:
      seata:
        # 事务分组,可自定义,对应属性 service.vgroupMapping.default_tx_group=default
        tx-service-group: default_tx_group
---
mybatis:
  type-aliases-package: com.wanqi.pojo
  mapper-locations: classpath:mapper/*.xml
---
seata:
  tx-service-group: default_tx_group
  registry:
    type: nacos # 配置seata的注册中心,告诉seata client如何访问seata server
    nacos:
      server-addr: 172.16.156.139:8847 # seata server注册的nacos中心
      group: SEATA_GROUP # seata server注册的分组
      application: seata-server # seata server注册的服务名
      namespace: 170ee694-566d-4c3a-b316-fe233d984d43 # seata server注册的命名空间
      cluster: default # seata server集群名称
      username: nacos # nacos账号
      password: nacos # nacos密码
  config:
    type: nacos
    nacos:
      server-addr: 172.16.156.139:8847 # seata配置注册的nacos中心
      group: SEATA_GROUP # 配置注册的分组
      namespace: 170ee694-566d-4c3a-b316-fe233d984d43 # 配置注册的命名空间
      username: nacos # nacos账号
      password: nacos # nacos密码

9.2.2.2、服务调用方,在需要开启事务的方法上使用@GlobalTransactional开启全局事务
server:
  port: 6061
spring:
  main:
    allow-circular-references: true
  application:
    name: order-db
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://39.104.101.11:3306/test
    username: wq
    password: 123456
  cloud:
    nacos:
      server-addr: 172.16.156.139:8847
      password: nacos
      username: nacos
    alibaba:
      seata:
        # 事务分组,可自定义,对应属性 service.vgroupMapping.default_tx_group=default
        tx-service-group: default_tx_group

---
mybatis:
  type-aliases-package: com.wanqi.pojo
  mapper-locations: classpath:mapper/*.xml
---
feign:
  client:
    config:
      default:
        loggerLevel: Full
        connectTimeout: 6000
        readTimeout: 6000
---
logging:
  level:
    com.wanqi.feign: debug
---
seata:
  tx-service-group: default_tx_group
  registry:
    type: nacos
    nacos:
      server-addr: 172.16.156.139:8847 # seata服务注册的nacos中心
      group: SEATA_GROUP # 注册的分组
      application: seata-server # 注册的服务名
      namespace: 170ee694-566d-4c3a-b316-fe233d984d43 # 注册的命名空间
      cluster: default # 集群名称
      username: nacos # nacos账号
      password: nacos # nacos密码
  config:
    type: nacos
    nacos:
      server-addr: 172.16.156.139:8847 # seata配置注册的nacos中心
      group: SEATA_GROUP # 配置注册的分组
      namespace: 170ee694-566d-4c3a-b316-fe233d984d43 # 配置注册的命名空间
      username: nacos # nacos账号
      password: nacos # nacos密码
9.2.3、client接口与调用
9.2.3.1、服务提供方接口
@RestController
public class StockController {
    @Autowired
    StockMapper stockMapper;

    @PostMapping("/add")
    public int add(@RequestParam("orderId") Long id) {
        System.out.println(id);
        Stock select = stockMapper.select();
        int x =  stockMapper.update(id);
        System.out.println(select);
        return x;
    }

    @PostMapping(value = "/sqlFile")
    public String genSqlFile(@RequestParam("sqlId")String sqlId,@RequestParam("sql")String sql){
        MyTest test = new MyTest(sqlId,sql);
        System.out.println(test);
        return test.toString();
    }

}
9.2.3.2、调用方接口
@FeignClient(name = "stock-db",contextId = "stock-db")
public interface StockFeignService {

    @PostMapping("/add")
    public int add(@RequestParam("orderId") Long orderId);

    @PostMapping(value = "/sqlFile")
    public String genSqlFile(@RequestParam("sqlId")String sqlId,@RequestParam("sql")String sql);
}
@RestController
public class OrderController {
    @Autowired
    OrderService orderService;
    @Autowired
    StockFeignService stockFeignService;

    @GetMapping("add/{name}")
    public String add(@PathVariable("name") String name){
        System.out.println(name);
        orderService.add(name);
        return "ok";
    }

    @GetMapping("add2/{orderId}")
    public int add2(@PathVariable("orderId") Long orderId) {
        return stockFeignService.add(orderId);
    }


    @PostMapping(value = "/sqlFile")
    public String genSqlFile(@RequestParam("sqlId")String sqlId,@RequestParam("sql")String sql){
        MyTest test = new MyTest(sqlId,sql);
        String msg = stockFeignService.genSqlFile(test.getSqlId(),test.getSql());
        System.out.println(msg + "调用成功啦!!!");
        return msg;
    }
}
@Service
public class OrderService {

    @Autowired
    StockFeignService stockFeignService;
    @Autowired
    OrderMapper orderMapper;
    //注解开启全局事务
    @GlobalTransactional
    public String add(String name) {
        orderMapper.save(name);

        stockFeignService.add(Long.valueOf("999"));
        int a = 1/0;
        return "ok";
    }
}

10、SkyWalking链路追踪,安装包使用阿里云镜像地址

image.png

10.1、解压后修改为mysql模式,apache-skywalking-apm-bin/config/application.yml

  • 设置为mysql,默认是h2
storage:
  selector: ${SW_STORAGE:mysql}
  • 新建数据库swtest,修改jdbcUrl地址为自己的数据库地址
  mysql:
    properties:
      jdbcUrl: ${SW_JDBC_URL:"jdbc:mysql://114.67.111.165:3306/swtest?rewriteBatchedStatements=true"}
      dataSource.user: ${SW_DATA_SOURCE_USER:root}
      dataSource.password: ${SW_DATA_SOURCE_PASSWORD:123456}

10.2、修改web端口,apache-skywalking-apm-bin/webapp/webapp.yml

  • 可选操作,默认端口8080使用频率较高避免重复
server:
  port: 8868

10.3、启动服务,apache-skywalking-apm-bin/bin/startup.sh

image.png

10.4、访问UI界面

image.png

10.5、idea接入,配置启动参数然后启动即可

-DSW_AGENT_NAME=api-gateway
-DSW_AGENT_COLLECTOR_BACKEND_SERVICES=172.16.156.139:11800
-javaagent:/Users/wandaren/Downloads/Compressed/skywalking-agent/skywalking-agent.jar

image.png

10.6、logback日志集成

10.6.1、引入依赖
        <dependency>
            <groupId>org.apache.skywalking</groupId>
            <artifactId>apm-toolkit-logback-1.x</artifactId>
            <version>8.11.0</version>
        </dependency>
10.6.2、修改agent配置增加以下内容
  • 文件:skywalking-agent/config/agent.config
plugin.toolkit.log.grpc.reporter.server_host=${SW_GRPC_LOG_SERVER_HOST:172.16.156.139}
plugin.toolkit.log.grpc.reporter.server_port=${SW_GRPC_LOG_SERVER_PORT:11800}
plugin.toolkit.log.grpc.reporter.max_message_size=${SW_GRPC_LOG_MAX_MESSAGE_SIZE:10485760}
plugin.toolkit.log.grpc.reporter.upstream_timeout=${SW_GRPC_LOG_GRPC_UPSTREAM_TIMEOUT:30}
10.6.3、编写logback日志配置,文件名logback-spring.xml
  • 如果不是使用的logback-spring.xml文件名,需要在配置文件中指application.yml定
logging:
  # 如果不想配置必须使用文件名:logback-spring.xml
  config: classpath:logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false">
    <!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径-->
    <property name="LOG_HOME" value="/data/log" />
    <!-- 控制台输出 -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
        </encoder>
    </appender>
    <!-- GRPCLogClientAppender处理器上传日志到skywalking -->
    <appender name="gpr-log" class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.log.GRPCLogClientAppender">
        <!-- 日志输出编码 -->
        <encoder>
            <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n
            </pattern>
        </encoder>
    </appender>

    <!--mybatis log configure-->
    <logger name="com.apache.ibatis" level="TRACE"/>
    <logger name="java.sql.Connection" level="DEBUG"/>
    <logger name="java.sql.Statement" level="DEBUG"/>
    <logger name="java.sql.PreparedStatement" level="DEBUG"/>

    <!-- 日志输出级别 -->
    <root level="INFO">
        <appender-ref ref="STDOUT" />
        <appender-ref ref="gpr-log"/>
        </root>
</configuration>

image.png

10.7、自定义链路追踪

10.7.1、引入依赖
        <dependency>
            <groupId>org.apache.skywalking</groupId>
            <artifactId>apm-toolkit-trace</artifactId>
            <version>8.11.0</version>
        </dependency>
10.7.2、使用注解指定方法,示例
    @Trace
    @Tag(key = "select",value = "returnedObj")
    public String select(){
        return stockFeignService.select();
    }

   @PostMapping(value = "/myTest")
    @Trace
    @Tags({@Tag(key = "sqlId",value = "arg[0]"),
            @Tag(key = "sql",value = "arg[1]"),
            @Tag(key = "sqlId",value = "returnedObj.sqlId"),
            @Tag(key = "sql",value = "returnedObj.sql")})
    public MyTest myTest(@RequestParam("sqlId")String sqlId,@RequestParam("sql")String sql){
        return new MyTest(sqlId + "111",sql + "222");
    }

image.png
image.png

10.8、告警参考官网

hmoban主题是根据ripro二开的主题,极致后台体验,无插件,集成会员系统
自学咖网 » springcloudalibaba入门