一。 Spring Cloud Alibaba介绍
spring Cloud Alibaba 致力于提供分布式应用服务开发的一站式解决方案。此项目包含开发分布式应用服务的必需组件,方便开发者通过 Spring Cloud 编程模型轻松使用这些组件来开发分布式应用服务。
依托 Spring Cloud Alibaba,您只需要添加一些注解和少量配置,就可以将 Spring Cloud 应用接入阿里分布式应用解决方案,通过阿里中间件来迅速搭建分布式应用系统。
主要功能
- 服务限流降级:默认支持为 HTTP 服务的提供限流保护,也支持添加注解实现方法的自定义限流降级,且支持动态修改限流降级规则。
- 服务注册与发现:适配 sprig cloud 服务注册与发现标准,默认集成了 Ribbon 的支持。
- 分布式配置管理:支持分布式系统中的外部化配置,配置更改时自动刷新。
- 阿里云对象存储:阿里云提供的海量、安全、低成本、高可靠的云存储服务。支持在任何应用、任何时间、任何地点存储和访问任意类型的数据。
组件:
Sentinel:把流量作为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。
Nacos:一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。
AliCloud OSS: 阿里云对象存储服务(Object Storage Service,简称 OSS),是阿里云提供的海量、安全、低成本、高可靠的云存储服务。您可以在任何应用、任何时间、任何地点存储和访问任意类型的数据。
二。Nacos使用示例
Nacos用于实现注册中心和配置中心
github源码 :https://github.com/alibaba/Nacos
官方文档:https://nacos.io/zh-cn/docs/cluster-mode-quick-start.html
1。安装nacos服务器
下载地址 zip包
解压 因为nacos默认的配置数据存储在derby文件数据库中(启动生成 data\derby-data数据),防止文件损坏(一般要求配置数据并需永久保存安全服务器,比如 mysql主从库中,注册信息 重启丢失了 注册服务器自动重连) |
所以 nacos提供了数据库的存储方式
参考自 https://nacos.io/zh-cn/docs/cluster-mode-quick-start.html
假设本机安装了 mysql数据库 (mysql最好事先设计好主从 否则数据库挂了 就无法使用nacos)
连接数据 执行 conf/nacos-mysql.sql 创建数据库 nacos_config
修改conf/application.properties 将后面db相关的配置打开 (放弃了 怎么配置都不写到数据库。。。还是先derby 官网文档渣渣 只能有时间分析源码了)
db.num=1
db.url.0=jdbc:mysql://localhost:3306/nacos_config?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true
db.user=nacos_devtest
db.password=youdontknow
启动nacos-server 点击 bin/startup.cmd
配置集群 起多个nacos-server 将每一台配置(懒得试了):
在nacos的解压目录nacos/的conf目录下,有配置文件cluster.conf,请每行配置成ip:port。
window安装curl https://curl.haxx.se/download.html linux直接使用
使用rest测试配置参数和获取参数
curl -X POST "http://127.0.0.1:8848/nacos/v1/cs/configs?dataId=example&group=DEFAULT_GROUP&content=useLocalCache=true"
获取参数:
C:\Users\Administrator>curl -X GET "http://127.0.0.1:8848/nacos/v1/cs/configs?dataId=example&group=DEFAULT_GROUP"
useLocalCache=true
2。使用springcloud获取配置数据
理解几个概念 dataid可以理解是一个springcloud配置中心文件的意思
在 Nacos Spring Cloud 中,dataId
的完整格式如下:
${prefix}-${spring.profile.active}.${file-extension}
prefix
默认为spring.application.name
的值,也可以通过配置项spring.cloud.nacos.config.prefix
来配置。spring.profile.active【注意这里是profiles 文档求规范】
即为当前环境对应的 profile,详情可以参考 Spring Boot文档。 __注意:当 __spring.profile.active
为空时,对应的连接符-
也将不存在,dataId 的拼接格式变成${prefix}
.${file-extension}
file-exetension
为配置内容的数据格式,可以通过配置项spring.cloud.nacos.config.file-extension
来配置。目前只支持properties
类型。
创建springboot项目 添加依赖
<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">
<modelVersion>4.0.0</modelVersion>
<groupId>cn.ps</groupId>
<artifactId>CLOUD_PUBLIC</artifactId>
<version>0.0.1-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.6.RELEASE</version>
</parent>
<dependencies>
<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.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Finchley.SR1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba</artifactId>
<version>0.2.0.BUILD-SNAPSHOT</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<repositories>
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/libs-snapshot-local</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
<releases>
<enabled>false</enabled>
</releases>
</repository>
</repositories>
</project>
bootstrap.properties
spring.cloud.nacos.config.server-addr=127.0.0.1:8848
application.properties
spring.application.name=example
spring.profiles.active=dev
spring.cloud.nacos.config.file-extension=properties
添加main测试类
package cn.ps;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class TestConf {
public static void main(String[] args) throws Exception {
SpringApplication.run(TestConf.class, args);
}
}
添加控制层:
package cn.ps;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/config")
@RefreshScope
public class ConfigController {
@Value("${useLocalCache:false}")
private boolean useLocalCache;
@RequestMapping("/get")
public boolean get() {
return useLocalCache;
}
}
使用cput添加一个配置数据
curl -X POST "http://127.0.0.1:8848/nacos/v1/cs/configs?dataId=example-dev.properties&group=DEFAULT_GROUP&content=useLocalCache=true"
浏览器访问路径测试
http://localhost:8080/config/get
发现输出结果为true
再次修改结果查看是否自动重载
2。使用springcloud配置注册和发现
新建一个生产者项目 注册到nacos-server 添加maven
<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">
<modelVersion>4.0.0</modelVersion>
<groupId>cn.ps</groupId>
<artifactId>CLOUD_PUBLIC</artifactId>
<version>0.0.1-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.6.RELEASE</version>
</parent>
<dependencies>
<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.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Finchley.SR1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba</artifactId>
<version>0.2.0.BUILD-SNAPSHOT</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<repositories>
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/libs-snapshot-local</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
<releases>
<enabled>false</enabled>
</releases>
</repository>
</repositories>
</project>
添加main方法
package cn.ps;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class TestPub {
public static void main(String[] args) throws Exception {
SpringApplication.run(TestPub.class, args);
}
}
添加控制层类 将来调用
package cn.ps;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@RequestMapping("/hello")
public String get() {
return "hello";
}
}
三。 Sentinel使用示例
sentinel完成 Spring Cloud 应用的限流管理
sentinel示例 参考 https://github.com/spring-cloud-incubator/spring-cloud-alibaba/blob/master/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/readme-zh.md
随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。
Sentinel 具有以下特征:
- 丰富的应用场景:Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、集群流量控制、实时熔断下游不可用应用等。
- 完备的实时监控:Sentinel 同时提供实时的监控功能。您可以在控制台中看到接入应用的单台机器秒级数据,甚至 500 台以下规模的集群的汇总运行情况。
- 广泛的开源生态:Sentinel 提供开箱即用的与其它开源框架/库的整合模块,例如与 Spring Cloud、Dubbo、gRPC 的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入 Sentinel。
- 完善的 SPI 扩展点:Sentinel 提供简单易用、完善的 SPI 扩展接口。您可以通过实现扩展接口来快速地定制逻辑。例如定制规则管理、适配动态数据源等。
Sentinel 的主要特性:
Sentinel 分为两个部分:
- 核心库(Java 客户端)不依赖任何框架/库,能够运行于所有 Java 运行时环境,同时对 Dubbo / Spring Cloud 等框架也有较好的支持。
- 控制台(Dashboard)基于 Spring Boot 开发,打包后可以直接运行,不需要额外的 Tomcat 等应用容器。
1。安装dashboard控制台
下载sentinel控制台jar包 参考 https://github.com/alibaba/Sentinel/wiki/%E6%8E%A7%E5%88%B6%E5%8F%B0
下载的1.4.1版本
下载jar包在某个目录后,启动该jar包
java -Dserver.port=8883 -Dcsp.sentinel.dashboard.server=localhost:8883 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.4.1.jar
启动后访问:http://localhost:8883 界面如下:
如果我们的程序连接上控制台,并且设置了, 左边菜单栏就会显示对应的限流项目的应用名称(spring.application.name)可以对程序进行限流控制
2。编写熔断或者降级程序
使用springboot和springcloud集成 参考wiki章节:主流框架的适配#spring-cloud。
https://github.com/alibaba/Sentinel/wiki/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6%E7%9A%84%E9%80%82%E9%85%8D#spring-cloud
参考文档
https://github.com/spring-cloud-incubator/spring-cloud-alibaba/wiki/Sentinel
添加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
如果依赖无法加载,添加spring的snapshot仓库
<repositories>
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/libs-snapshot-local</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
<releases>
<enabled>false</enabled>
</releases>
</repository>
</repositories>
如果你的应用是spring或者springmvc的环境 必须配置aspectj的环绕类,这个限流和降级的原理就是使用aop实现的
springcloud的程序控制层不需要添加该bean,如果是service层其他层的限流必须添加该bean否则无效
@Configuration
public class SentinelAspectConfiguration {
@Bean
public SentinelResourceAspect sentinelResourceAspect() {
return new SentinelResourceAspect();
}
}
可以打开SentinelResourceAspect这个类
application.properties内容:
management.endpoints.web.exposure.include=*
spring.application.name=sentinelexample
server.port=8882
spring.cloud.sentinel.transport.dashboard=localhost:8883 #连接sentinel控制台的ip和端口
1》熔断规则实现
Sentinel 以流量(qps[每秒的请求数],thread[最大线程数])为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。
熔断:如果流量达到某个设置的限度,调用方抛出一个错误信息(BlockException),调用方接受错误后处理,一般该功能无法使用,前端加载出错等异常。
降级:如果流量达到某个设置的限度,调用方调用其他的方法返回数据(并不是错误),主不达求其次。
1》》控制层的web请求熔断
添加一个控制层的方法(sentinel会将每个路径自动添加到资源集合中 ,资源的名字就是路径 /test1)假设端口是8882
@GetMapping("/test1")
public String test1(){
return "test1";
}
给资源添加流量限制规则:首先设置一个资源规则到sentinel dashboard控制台
@GetMapping("/setTest1FlowRule")
public String setRule(){
List<FlowRule> rules = new ArrayList<FlowRule>();//限流规则列表
FlowRule rule = new FlowRule(); //创建一个规则
rule.setResource("/test1"); //设置需要定义规则的名称
// set limit qps to 10
rule.setCount(1);//设置每秒的qps数量,为了演示效果使用1
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);//限制qps
rule.setLimitApp("default"); //设置允许的请求的来源默认 default允许所有请求过来
rules.add(rule);//添加到集合中
FlowRuleManager.loadRules(rules);//静态方法添加到sentinel控制台
//自定义控制层限流规则达到阀值后 自动出现错误 以下是自定义输出错误
WebCallbackManager.setUrlBlockHandler(new UrlBlockHandler() {
@Override
public void blocked(HttpServletRequest request, HttpServletResponse response, BlockException ex) throws IOException {
response.getWriter().print("<font color=red>error"+ex.toString()+"</font>");
}
});
return "1";
}
在浏览器上执行这个设置规则的路径 http://localhost:8082/setTest1FlowRule 回到sentinel控制台,查看是否有当前项目的监控项
出现
接下来访问 http://localhost:8082/test1
如果qps没有超过1 显示:test1 如果超过了就会自动进入UrlBlockHandler显示红色error和异常
2》其他层(service或者repository或则其他方法)的调用熔断
比如在控制层调用service层方法
@Autowired
private TestServiceImpl tsi;
@GetMapping("/test2")
public String test2(){
return tsi.getText();
}
TestServiceImpl内容:
@Service
public class TestServiceImpl {
//指定资源名称,熔断后调用的方法
@SentinelResource(value="text1",entryType=EntryType.IN,blockHandler = "exceptionHandler") //出现熔断后调用方法
public String getText() {
return "测试文本";
}
// Block 异常处理函数,参数最后多一个 BlockException,其余与原函数一致.
public String exceptionHandler( BlockException ex) {
return "block" ;
}
}
设置限流规则,注意资源名称是text1
@GetMapping("/setTest1FlowRule")
public String setRule(){
List<FlowRule> rules = new ArrayList<FlowRule>();
FlowRule rule1 = new FlowRule();
rule1.setResource("text1");
// set limit qps to 10
rule1.setCount(1);
rule1.setGrade(RuleConstant.FLOW_GRADE_QPS);
rule1.setLimitApp("default");
rules.add(rule1);
FlowRuleManager.loadRules(rules);
return "1";
}
使用浏览器 访问 http://localhost:8082/test2就会调用getText哪个text1资源方法,qps没有到达显示:测试文本,否则显示block
其他关于降级使用DegradeRule,系统规则使用SystemRule,权限规则使用AuthorityRule 具体参考官网
https://github.com/spring-cloud-incubator/spring-cloud-alibaba/wiki/Sentinel