0.曾经的官网https://spring.io/projects/sprinq-cloud-alibaba#overview
1.中文版官网https://github.com/alibaba/spring-cloud-alibaba/blob/master/README-zh.md
2.英文版官网https://spring-cloud-alibaba-group.github.io/github-pages/greenwich/spring-cloud-alibaba.html、https://github.com/alibaba/spring-cloud-alibaba
1.为什么叫Nacos?
2.是什么?
就是注册中心+配置中心
Nacos = Eureka + Config + Bus
3.下载地址https://github.com/alibaba/Nacos
官网https://nacos.io/zh-cn/index.html
参考文档https://spring-cloud-alibaba-group.github.io/github-pages/greenwich/spring-cloud-alibaba.html#_spring_cloud_alibaba_nacos_discovery
4.各注册中心比较
1.建modal cloudalibaba-provider-payment9001
2.改pom
<dependencies>
<!--SpringCloud ailibaba nacos -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- SpringBoot整合Web组件 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--日常通用jar包配置-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
3.写yml
server:
port: 9002
spring:
application:
name: nacos-provider-payment
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
management:
endpoints:
web:
exposure:
include: '*'
4.主启动@EnableDIscoveryClient
5.业务类
controller
package com.atguigu.springcloud.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class PaymentController {
@Value("${server.port}")
private String serverPort;
@GetMapping("/payment/nacos/{id}")
public String getPayment(@PathVariable("id") Long id) {
return "nacos registry,serverport:" + serverPort + "\tid:" + id;
}
}
6.测试
①先启动nacos
②启动9001 发送http://localhost:9001/payment/nacos/55
按照payment9001的方法创建payment9002
如果想取巧不想新建重复劳动,也可以直接拷贝虚拟端口映射
7.模块cloudalibaba-consumer-nacos-order83 懂得都懂
server:
port: 83
spring:
application:
name: nacos-order-consumer
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
service-url:
nacos-user-service: http://nacos-provider-payment
8.业务类
配置类,获取RestTemplate
package com.atguigu.springcloud.config;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class ApplicationContextConfig {
@Bean
@LoadBalanced
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
}
controller
package com.atguigu.springcloud.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@RestController
public class OrderNacosController {
@Autowired
private RestTemplate restTemplate;
@Value("${service-url.nacos-user-service}")
public String SERVER_URL;
@GetMapping("/consumer/payment/nacos/{id}")
public String paymentInfo(@PathVariable("id") Long id) {
return restTemplate.getForObject(SERVER_URL + "/payment/nacos/" + id, String.class);
}
}
9.测试 http://localhost:83/consumer/payment/nacos/55
1.建modal cloudalibaba-config-nacos-client3377
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>cloud2020</artifactId>
<groupId>com.atguigu.springcloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloudalibaba-config-nacos-client3377</artifactId>
<dependencies>
<!--nacos-config-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!--nacos-discovery-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--web + actuator-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--一般基础配置-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
server:
port: 3377
spring:
application:
name: nacos-config-client
cloud:
nacos:
discovery:
server-addr: localhost:8848 #nacos作为服务注册中心
config:
server-addr: localhost:8848 #nacos作为配置中心
file-extension: yaml #指定yaml格式的配置
# ${prefix}-${spring.profile.active}.${file-extension}默认为
# ${spring.application.name}-${spring.profile.active}.${file-extension}
# nacos-config-client-dev.yaml
application.yml
spring:
profiles:
active: dev #表示开发环境
4.主启动
package com.atguigu.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class NacosConfigClientMain3377 {
public static void main(String[] args) {
SpringApplication.run(NacosConfigClientMain3377.class, args);
}
}
5.业务类
package com.atguigu.springcloud.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RefreshScope //支持nacos动态刷新
public class ConfigClientController {
@Value("${config.info}")
private String configInfo;
@GetMapping("/config/info")
public String getConfigInfo() {
return configInfo;
}
}
6.在nacos的配置列表中添加yaml文件,添加规则:
7.测试http://localhost:3377/config/info
8.修改配置列表中的配置文件,重新访问http://localhost:3377/config/info 发现直接自动刷新
1.问题:多环境多项目管理
2.nacos图形化管理界面
3.
1.DataID方案-----------最常用的,就是上面使用的
2.Group方案
1.建不同group的配置文件
2.在config下增加
3.Namespace方案
1.新建dev/test的Namespace
2.回到服务管理服务列表里查看
3.按照域名配置填写
4.bootstrap.yml与application.yml
读取顺序:namespace下的group中的${spring.application.name}-${spring.profile.active}.${file-extension}
5.测试:http://localhost:3377/config/info
得到的的确是namespace下的group中的${spring.application.name}-${spring.profile.active}.${file-extension}
中的配置信息
1.https://nacos.io/zh-cn/docs/cluster-mode-quick-start.html
2.对官网的翻译
3.说明
按照官网的说明 我们需要mysql数据库
1.nacos默认自带的是嵌入式数据库derby
https://github.com/alibaba/nacos/blob/develop/config/pom.xml
因为每个nacos都自带一个derby嵌入式数据库,所以集群就会造成数据一致性问题
2.derby到MySQL切换配置步骤
①nacos-server-1.1.4\nacos\conf目录下找到sql文件nacos-mysql.sql
在mysql中执行语句sql文件的语句(要先创建数据库nacos_config 再use config)
内容:https://github.com/alibaba/nacos/blob/master/distribution/conf/nacos-mysql.sql
这样改了以后,nacos的配置将会从自带的嵌入式derby迁到MySQL
②nacos-server-1.1.4\nacos\conf目录下找到properties文件application.properties
.修改conf/application.properties文件,增加支持mysql数据源配置(目前只支持mysql),添加mysql数据源的url、用户名和密码。
如下:
spring.datasource.platform=mysql
db.num=1
db.url.0=jdbc:mysql://127.0.0.1:3306/nacos_config?
characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true
db.user=root
db.password=root
③重启nacos
发现之前的yaml文件、namespace命名空间都没了,表示切换数据库成功
1.预计需要 1个Nginx+3个nacos注册中心+1个MySQL
2.Nacos下载Linux版本
https://github.com/alibaba/nacos/releases/tag/1.1.4
下载nacos-server-1.1.4.tar.qz
解压后安装
Linux服务器上MySQL数据库配置
1.SQL语句脚本在哪,进行copy
2.去自己的MySQL下执行
application.properties配置
1.位置 命令
2.内容
spring.datasource.platform=mysql
db.num=1
db.url.0=jdbc:mysql://127.0.0.1:3306/nacos_config?
characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true
db.user=root
db.password=root
Linux服务器上nacos的集群配置cluster.config
1.复制cluster.config备份
2.修改cluster.config内容
注意:这个IP不能写127.0.0.1,要写Linux命令 hostname -i能识别的IP
编辑Nacos的启动脚本startup.sh,使它能够接受不同的启动端口
1.位置:
2.内容:
3.执行
Nginx修改,由它作为负载均衡器
1.位置
2.内容
3.按照指定配置启动
截至到此,1个Nginx+3个nacos注册中心+1个MySQL
1.测试,通过nginx访问nacos http://192.168.111.144:1111/nacos/#/login
再nacos中新建一个配置,再MySQL中能发现插入了一条数据 成功
测试
微服务cloudalibaba-provider-payment9002启动注册进入集群
高可用小总结
官网https://github.com/alibaba/Sentinel
中文官网https://github.com/alibaba/Sentinel/wiki/介绍
下载地址https://github.com/alibaba/Sentinel/releases
能干嘛
1.下载(上面有)
2.运行命令
前提:java8环境OK+8080端口不被占用
命令:java -jar .\sentinel-dashboard-1.7.0.jar
3.访问Sentinel管理界面
http://localhost:8080
与nacos一样套路,用户名密码均为sentinel
1.启动nacos8848成功(startup.cmd)
2.建modal cloudalibaba-sentinel-service8401
pom
<dependencies>
<dependency><!-- 引入自己定义的api通用包,可以使用Payment支付Entity -->
<groupId>com.atguigu.springcloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>${project.version}</version>
</dependency>
<!--SpringCloud ailibaba nacos -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--SpringCloud ailibaba sentinel-datasource-nacos 后续做持久化用到-->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
<!--SpringCloud ailibaba sentinel -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!--openfeign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- SpringBoot整合Web组件+actuator -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--日常通用jar包配置-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>4.6.3</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
yml
server:
port: 8401
spring:
application:
name: cloudalibaba-sentinel-service
cloud:
nacos:
discovery:
#Nacos注册中心
server-addr: localhost:8848
sentinel:
transport:
#配置Sentinel dashboard地址
dashboard: localhost:8080
#默认端口就是8719,接入8719端口被占用会自动从8719开始依次+1扫描直到找到未被占用的端口
port: 8719
management:
endpoints:
web:
exposure:
include: '*'
主启动
package com.atguigu.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class MainApp8401 {
public static void main(String[] args) {
SpringApplication.run(MainApp8401.class, args);
}
}
业务类
package com.atguigu.springcloud.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class FlowLimitController {
@GetMapping("/testA")
public String testA() {
return "-----testA";
}
@GetMapping("/testB")
public String testB() {
return "-----testB";
}
}
3.启动Sentinel8080:运行:java -jar sentinel-dashboard-1.7.0.jar
4.启动微服务8401
5.启动后查看sentinel控制台
啥都没有,因为sentinel采用的是懒加载机制
执行一次访问即可http://localhost:8401/testA
第一种:直接->快速失败
①QPS
表示1秒钟内查询一次就OK,超过就直接->快速失败,报默认错误:Blocked by Sentinel (flow limiting)
问题:直接报默认错误,技术方面OK,但是应该要有类似fallback的兜底方法
②线程数
(还没弄懂)
源码:com.alibaba.csp.sentinel.slots.block.flow.controller.DefaultController
公式:阈值÷coldFactor(默认是3),经过预热时长后才会到达阈值
官网:https://github.com/alibaba/Sentinel/wiki/限流—冷启动
源码:com.alibaba.csp.sentinel.slots.block.flow.controller.WarmUpController
源码:com.alibaba.csp.sentinel.slots.block.flow.controller.RateLimiterController
https://github.com/alibaba/Sentinel/wiki/%E7%86%94%E6%96%AD%E9%99%8D%E7%BA%A7
注意:sentinel断路器是没有半开状态的
平均响应时间 (DEGRADE_GRADE_RT):当 1s 内持续进入 N 个请求,对应时刻的平均响应时间(秒级)均超过阈值(count,以 ms 为单位),那么在接下的时间窗口(DegradeRule 中的 timeWindow,以 s 为单位)之内,对这个方法的调用都会自动地熔断(抛出 DegradeException)。注意 Sentinel 默认统计的 RT 上限是 4900 ms,超出此阈值的都会算作 4900 ms,若需要变更此上限可以通过启动配置项 -Dcsp.sentinel.statistic.max.rt=xxx 来配置。
代码:
配置:
jmete压力测试:
测试结果:
服务熔断了
停止压力测试后重新访问:
@GetMapping("/testE")
public String testE()
{
log.info("testE 测试异常数");
int age = 10/0;
return "------testE 测试异常数";
}
https://github.com/alibaba/Sentinel/wiki/热点参数限流
@SentinelResource
)com.alibaba.csp.sentinel.slots.block.BlockException
@SentinelResource
属性value:资源名,没啥要求,除了唯一,一般是GetMapping的value去掉“/”
属性blockHandler:与Sentinel的配置不对应时的执行的函数
@GetMapping("/testHotKey")
@SentinelResource(value = "testHotKey",blockHandler = "deal_testHotKey")
public String testHotKey(@RequestParam(value = "p1",required = false) String p1,
@RequestParam(value = "p2",required = false) String p2)
{
//int age = 10/0;
return "------testHotKey";
}
public String deal_testHotKey (String p1, String p2, BlockException exception)
{
return "------deal_testHotKey,o(╥﹏╥)o"; //sentinel系统默认的提示:Blocked by Sentinel (flow limiting)
}
注意:这第0个第1个参数看的不是URL中的第0、第1而是代码中的参数
@GetMapping("/testHotKey")
@SentinelResource(value = "testHotKey",blockHandler = "deal_testHotKey")
public String testHotKey(@RequestParam(value = "p1",required = false) String p1,
@RequestParam(value = "p2",required = false) String p2)
{
int age = 10/0;
return "------testHotKey";
}
public String deal_testHotKey (String p1, String p2, BlockException exception)
{
return "------deal_testHotKey,o(╥﹏╥)o"; //sentinel系统默认的提示:Blocked by Sentinel (flow limiting)
}
访问 http://localhost:8401/testHotKey?p1=a
https://github.com/alibaba/Sentinel/wiki/系统自适应限流
步骤:
1.启动Nacoc
2.启动Sentinel
3.modul
4.pom
5.yml
6.主启动
7.业务类
package com.atguigu.springcloud.controller;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.atguigu.springcloud.entieies.CommonResult;
import com.atguigu.springcloud.entieies.Payment;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @auther zzyy
* @create 2020-02-25 15:04
*/
@RestController
public class RateLimitController
{
@GetMapping("/byResource")
@SentinelResource(value = "byResource",blockHandler = "handleException")
public CommonResult byResource()
{
return new CommonResult(200,"按资源名称限流测试OK",new Payment(2020L,"serial001"));
}
public CommonResult handleException(BlockException exception)
{
return new CommonResult(444,exception.getClass().getCanonicalName()+"\t 服务不可用");
}
}
7.Sentinel配置流控规则
8.额外问题:微服务关闭,Sentinel控制台刷新,流控规则消失-----------临时的
1.通过访问URL地址限流,返回Sentinel自带的默认限流处理信息
2.业务类
@GetMapping("/rateLimit/byUrl")
@SentinelResource(value = "byUrl")
public CommonResult byUrl()
{
return new CommonResult(200,"按url限流测试OK",new Payment(2020L,"serial002"));
}
https://editor.csdn.net/md?articleId=106291288#_1247
业务类:
@GetMapping("/rateLimit/customerBlockHandler")
@SentinelResource(value = "customerBlockHandler",
blockHandlerClass = CustomerBlockHandler.class,
blockHandler = "handlerException2")
public CommonResult customerBlockHandler()
{
return new CommonResult(200,"按客戶自定义",new Payment(2020L,"serial003"));
}
与豪猪哥Hystrix一样,方法的返回值要一样
、但参数的要多有一个BlockException exception(所有blockHandle都要多一个BlockException exception)*
package com.atguigu.springcloud.myhandler;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.atguigu.springcloud.entieies.CommonResult;
/**
* @auther zzyy
* @create 2020-02-25 15:32
*/
public class CustomerBlockHandler
{
public static CommonResult handlerException(BlockException exception)
{
return new CommonResult(4444,"按客戶自定义,global handlerException----1");
}
public static CommonResult handlerException2(BlockException exception)
{
return new CommonResult(4444,"按客戶自定义,global handlerException----2");
}
}
https://github.com/alibaba/Sentinel/wiki/注解支持
Sentinel三个核心API(了解)
1.SphU定义资源
2.Tracer定义统计
3.ContetxUtil定义上下文
总:sentinel整合Ribbon、OpenFeign、fallback
1.启动Nacos+Sentinel
2.新建cloudalibaba-provider-payment9003\9004两个服务类
3.pom
<dependencies>
<!--SpringCloud ailibaba nacos -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency><!-- 引入自己定义的api通用包,可以使用Payment支付Entity -->
<groupId>com.atguigu.springcloud</groupId>
<artifactId>cloud-api-common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!-- SpringBoot整合Web组件 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--日常通用jar包配置-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
4.yml
server:
port: 9003
spring:
application:
name: nacos-payment-provider
cloud:
nacos:
discovery:
server-addr: localhost:8848 #配置Nacos地址
management:
endpoints:
web:
exposure:
include: '*'
5.主启动
package com.atguigu.springcloud.alibaba;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
/**
* @auther zzyy
* @create 2020-02-25 16:10
*/
@SpringBootApplication
@EnableDiscoveryClient
public class PaymentMain9003
{
public static void main(String[] args) {
SpringApplication.run(PaymentMain9003.class, args);
}
}
6.业务类
package com.atguigu.springcloud.alibaba.controller;
import com.atguigu.springcloud.entieies.CommonResult;
import com.atguigu.springcloud.entieies.Payment;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
/**
* @auther zzyy
* @create 2020-02-25 16:11
*/
@RestController
public class PaymentController
{
@Value("${server.port}")
private String serverPort;
public static HashMap<Long,Payment> hashMap = new HashMap<>();
static
{
hashMap.put(1L,new Payment(1L,"28a8c1e3bc2742d8848569891fb42181"));
hashMap.put(2L,new Payment(2L,"bba8c1e3bc2742d8848569891ac32182"));
hashMap.put(3L,new Payment(3L,"6ua8c1e3bc2742d8848569891xt92183"));
}
@GetMapping(value = "/paymentSQL/{id}")
public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id)
{
Payment payment = hashMap.get(id);
CommonResult<Payment> result = new CommonResult(200,"from mysql,serverPort: "+serverPort,payment);
return result;
}
}
7.消费微服务cloudalibaba-consumer-nacos-order84
8.pom,yml,主启动
9.业务类
①RestTemplate
package com.atguigu.springcloud.alibaba.config;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
/**
* @auther zzyy
* @create 2020-02-25 16:06
*/
@Configuration
public class ApplicationContextConfig
{
@Bean
@LoadBalanced
public RestTemplate getRestTemplate()
{
return new RestTemplate();
}
}
②controller
package com.atguigu.springcloud.alibaba.controller;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.atguigu.springcloud.alibaba.service.PaymentService;
import com.atguigu.springcloud.entieies.CommonResult;
import com.atguigu.springcloud.entieies.Payment;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
/**
* @auther zzyy
* @create 2020-02-25 16:05
*/
@RestController
@Slf4j
public class CircleBreakerController
{
public static final String SERVICE_URL = "http://nacos-payment-provider";
@Resource
private RestTemplate restTemplate;
@RequestMapping("/consumer/fallback/{id}")
//@SentinelResource(value = "fallback") //没有配置
//@SentinelResource(value = "fallback",fallback = "handlerFallback") //fallback只负责业务异常
//@SentinelResource(value = "fallback",blockHandler = "blockHandler") //blockHandler只负责sentinel控制台配置违规
@SentinelResource(value = "fallback",fallback = "handlerFallback",blockHandler = "blockHandler",
exceptionsToIgnore = {IllegalArgumentException.class})
public CommonResult<Payment> fallback(@PathVariable Long id)
{
CommonResult<Payment> result = restTemplate.getForObject(SERVICE_URL + "/paymentSQL/"+id,CommonResult.class,id);
if (id == 4) {
throw new IllegalArgumentException ("IllegalArgumentException,非法参数异常....");
}else if (result.getData() == null) {
throw new NullPointerException ("NullPointerException,该ID没有对应记录,空指针异常");
}
return result;
}
//本例是fallback
public CommonResult handlerFallback(@PathVariable Long id,Throwable e) {
Payment payment = new Payment(id,"null");
return new CommonResult<>(444,"兜底异常handlerFallback,exception内容 "+e.getMessage(),payment);
}
//本例是blockHandler
public CommonResult blockHandler(@PathVariable Long id,BlockException blockException) {
Payment payment = new Payment(id,"null");
return new CommonResult<>(445,"blockHandler-sentinel限流,无此流水: blockException "+blockException.getMessage(),payment);
}
//==================OpenFeign
@Resource
private PaymentService paymentService;
@GetMapping(value = "/consumer/paymentSQL/{id}")
public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id)
{
return paymentService.paymentSQL(id);
}
}
目的:
fallback属性管运行时异常
blockHandler管配置违规
exceptionsToIgnore忽略异常,不在兜底方案
测试地址: http://localhost:84/consumer/fallback/1
一、controller的@SentinelResource没有任何配置
给客户的error界面,不友好
二、controller的@SentinelResource只配置fallbcak
运行时出错,友好了
三、controller的@SentinelResource只配置blockHandle属性
只管配置违规,不管是否运行时异常
四、fallback和blockHandle都配置
很有可能会冲突,呐最后听谁的?
五、忽略属性exceptionsToIgnore
1.修改84模块
84消费者调用提供者9003
Feign组件一般在消费者一端
2.pom
<!--SpringCloud openfeign -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
3.yml
# 激活Sentinel对Feign的支持
feign:
sentinel:
enabled: true
之间和豪猪哥整合是
feign:
Hystrix:
enabled: true
4.主启动
多个@EnableFeignClients
5.业务类
众所周知,OpenFeign是接口+实现类
service接口
package com.atguigu.springcloud.alibaba.service;
import com.atguigu.springcloud.entieies.CommonResult;
import com.atguigu.springcloud.entieies.Payment;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
/**
* @auther zzyy
* @create 2020-02-25 18:15
*/
@FeignClient(value = "nacos-payment-provider",fallback = PaymentFallbackService.class)
public interface PaymentService
{
@GetMapping(value = "/paymentSQL/{id}")
public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id);
}
sevice接口实现类
切记@Componment
package com.atguigu.springcloud.alibaba.service;
import com.atguigu.springcloud.entieies.CommonResult;
import com.atguigu.springcloud.entieies.Payment;
import org.springframework.stereotype.Component;
/**
* @auther zzyy
* @create 2020-02-25 18:30
*/
@Component
public class PaymentFallbackService implements PaymentService
{
@Override
public CommonResult<Payment> paymentSQL(Long id)
{
return new CommonResult<>(44444,"服务降级返回,---PaymentFallbackService",new Payment(id,"errorSerial"));
}
}
controller
//==================OpenFeign
@Resource
private PaymentService paymentService;
@GetMapping(value = "/consumer/paymentSQL/{id}")
public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id)
{
return paymentService.paymentSQL(id);
}
测试: http://localhost:84/consumer/paymentSQL/1
一旦重启sentinel客户端或者微服务modal,sentinel规则将消失,生产环境想要将配置规则持久化
将限流规则保存到Nacos中(数据库、文件等持久化文件都行,但是官方要求Nacos),(以8401modal为例子)只要刷新8401某个rest地址,sentinel控制台的流控规则就能看到,只要Nacos里面的配置不删除,针对8401上sentinel上的流控规则持久有效
1.pom
<!--SpringCloud ailibaba sentinel-datasource-nacos 后续做持久化用到-->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
2.yml
server:
port: 8401
spring:
application:
name: cloudalibaba-sentinel-service
cloud:
nacos:
discovery:
#Nacos注册中心
server-addr: localhost:8848
sentinel:
transport:
#配置Sentinel dashboard地址
dashboard: localhost:8080
#默认端口就是8719,接入8719端口被占用会自动从8719开始依次+1扫描直到找到未被占用的端口
port: 8719
datasource:
dsl:
nacos:
server-addr: loalhost://8848
dataId: cloudalibaba-sentinel-service
groupId: DEFAULT_GROUP
data-type: json
rule-type: flow
management:
endpoints:
web:
exposure:
include: '*'
[
{
"resource": "/rateLimit/byUrl",
"limitApp": "default",
"grade": 1,
"count": 1,
"strategy": 0,
"controlBehavior": 0,
"clusterMode": false
}
]
5.快速访问测试 http://localhost:8401/rateLimit/byUrl
6.停止8401再看sentinel
7.重启8401再看sentinel
测试http://localhost:8401/rateLimit/byUrl 降级规则等业务规则又有了
官网:http://seata.io/zh-cn,
分布式处理过程分为一ID+三组件模型
一ID:Transaction ID XID:全局唯一的事务ID
三组件:
TC - 事务协调者 维护全局和分支事务的状态,驱动全局事务提交或回滚。
TM - 事务管理器 定义全局事务的范围:开始全局事务、提交或回滚全局事务。
RM - 资源管理器 管理分支事务处理的资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。
处理过程
下载:https://github.com/seata/seata/releases
怎么玩:
本地@Transactional
全局@GrobalTransactional
1.修改conf目录下的file.conf配置文件
①先备份file.conf文件
②主要修改:自定义事务组名称+事务日志存储模式为db+数据库连接信息
③service模块
store模块
④在MySQL只建数据库seata
⑤在seata数据库中建表,间表的
⑥修改config目录下的registry.conf
⑦启动nacos
⑧启动seata
1.以下演示要保证先启动Nacos在启动Seata
2.分布式事务业务说明
3.创建业务数据库
4.按照上面3个数据库创建对应的表
5.按照上述3库分别创建对应回滚日志表
订单-库存-账户3个库下都需要建各自的回滚日志表:
conf目录下的db_undo_log.sql
业务需求:下订单-》减库存-》改余额-》改(订单)状态
(暂时写到这)
@Override
@GlobalTransactional(name = "fsp-create-order",rollbackFor = Exception.class)
public void create(Order order) {
//1.新建订单
log.info("------>开始创建订单");
orderDao.create(order);
//2.扣减库存
log.info("------>的单位服务调用库存,做扣减count");
storageService.decrease(order.getProductId(), order.getCount());
log.info("------>的单位服务调用库存,做扣减end");
//3.扣减账户
log.info("------>的单位服务调用账户,做扣减money");
accountService.decrease(order.getUserId(),order.getMoney());
log.info("------>的单位服务调用账户,做扣减end");
//4.修改订单状态
log.info("------>修改订单状态开始");
orderDao.update(order.getUserId(),0);
log.info("------>修改订单状态结束");
log.info("------>下单结束");
}