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
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
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实现负载均衡
- 虚拟机准备
- 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
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实现动态规则配置
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服务上
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链路追踪,安装包使用阿里云镜像地址
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
10.4、访问UI界面
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
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>
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");
}