浅谈springCloudAlibaba
第一章:微服务发展史
1、演变
单体应用架构--->垂直应用架构--->分布式架构--->SOA架构--->微服务架构
单体架构
在一台tomcat服务器上部署一个web项目
垂直应用架构
就是将原来的一个应用拆成互不相干的几个应用,以提升效率
分布式架构
它将把工程拆分成表现层和服务层两个部分,服务层中包含业务逻辑,表现层只需要处理和页面的交互
SOA架构
一个调度中心对集群进行实时管理,解决在分布式架构下服务越来越多的问题
微服务架构
在SOA基础上继续发展,分而治之
2、微服务架构介绍
微服务架构, 简单的说就是将单体应用进一步拆分,拆分成更小的服务,每个服务都是一个可以独立运行的项目
- 他们之间如何通讯?(restful rpc)
- 如何管理他们?(服务治理 )
- 客户端怎么访问他们?(网关)
- 应该如何自处理?(容错)
- 应该如何排错? (链路追踪)
服务治理
进行服务的自动化管理,其核心是服务的自动注册与发现。
- 服务注册
服务实例将自身服务信息注册到注册中心。
- 服务发现
服务实例通过注册中心获取到注册到其中的服务实例的信息
- 服务剔除
服务注册中心将出问题的服务自动剔除到可用列表之外,使其不会被调用到。
服务调用
多个服务之间的远程调用的需求。目前主流的远程调用技术有基于HTTP的RESTful接口以及基于TCP的RPC协议。
-
REST(Representational State Transfer):
这是一种HTTP调用的格式,更标准,更通用,无论哪种语言都支持http协议
-
RPC(Remote Promote Call):
一种进程间通信方式。允许像调用本地服务一样调用远程服务。
服务网关
将所有API调用统一接入到API网关层,由网关层统一接入和输出
服务容错
将出问题的服务自动剔除到可用列表之外
链路追踪
对一次请求涉及的多个服务链路进行日志记录,性能监控即链路追踪
3、微服务的解决方案——spring cloud
spring cloud是指通过spring boot整合其他工具快速构建微服务的一套规范,如解决服务治理、负载均衡、熔断器、全局锁等等问题,cloud netflix、cloud alibaba是规范的实现
阿里微服务
Dubbo+Nacos+Sentinel+RocketMQ+Seata+OSS+SchedulerX
第二章:spring Cloud的核心之Spring Boot
- IoC
把对象的生命周期交给Spring容器管理
- DI
依赖注入
Bean的装配方式
- @Component
@Component("componentBean")
public class ComponentBean {
}
- @Configuration
@Configuration
public class BeanConfig {
@Bean
public ConfigBean configBean() {
return new ConfigBean();
}
}
第三章:微服务架构下的服务治理
服务通信
首先各个服务之间要可以互相的访问
- RPC
即远程过程调用,通过访问 JAR 包的方式
- REST
直接使用HTTP做应用层协议
RPC框架
通过注册中心管理各个微服务,服务注册与监控是RPC架构的两个基本功能
- 服务注册
服务越多,本地配置的url维护成本越高,需要动态维护
- 监控
监控每个服务的调用量和使用时间
- 注册中心 :
保存所有服务的名字,服务提供者的IP列表,服务消费者的IP列表
- 服务提供者:
提供跨进程服务
- 服务消费者:
寻找服务并消费。
RPC框架
基本功能RPC通信
dubbo框架
可以集成其他主流框架
a、支持多种协议的服务发布,默认dubbo://,还支持rest://、webservice://等
b、支持不同的注册中心,如zookeeper、Nacos、Redis
服务治理
dubbo虽然作为一个rpc框架负责通信,但仍然具备其他注册中心基本的功能
- 集群容错
当服务消费方调用服务提供方的服务出现错误时候,缺省模式为failover,也就是失败重试
- 负载均衡
为了避免大量请求一直落到一个或几个服务提供方机器上,缺省为random,也就是每次随机调用一台服务提供者的机器。
- 动态维护
动态维护越来越多服务的url地址
- 监控服务
服务的调用量即响应时间
第四章:注册中心zookeeper
1、zookeeper
分布式协调中间件,主要解决分布式环境中各个服务进程访问控制,避免同一时刻有多个进程访问某一资源
注意:
a、基于本身的特性可以用作注册中心
b、由于apache官方推荐的关系,最早dubbo用zookeeper实现服务注册
a、conf目录下配置样例zoo_sample.cfg
b、修改为zoo.cfg,默认端口2181
c、zkCli.sh启动
文件系统
Zookeeper维护一个类似文件系统的数据结构:
a、每个子目录项如 NameService 都被称作为 znode(目录节点)
b、和文件系统一样,我们能够*的增加、删除znode
c、唯一的不同在于znode是可以存储数据的,维护了一个start状态信息,包含数据化的时间和版本等
-
PERSISTENT-持久节点
保存到磁盘,客户端与zookeeper断开连接后,该节点依旧存在
-
SEQUENTIAL-有序节点
递增序列,可以将持久节点、临时节点设为有序
-
EPHEMERAL-临时节点
客户端与zookeeper断开连接后,该节点被删除
Watcher监听通知机制
当目录节点发生变化(数据改变、被删除、子目录节点增加删除)时,zookeeper会通知客户端。
- getData
获得节点信息
- getChildren
获取所有子节点
- exists
判断节点是否存在
分布式锁
解决多个进程需要访问统一服务时的问题
- 获取锁的过程
每个客户端可以去ZooKeeper服务器上的/Exclusice_Locks节点下创建一个临时节点/lock,每次只能有一个客户端创建成功
- 释放锁的过程
客户端断开连接后自动删除
master选举
集群中某一节点(master)出现故障后选举其他节点作为master继续工作
a、多个客户端在zookeeper创建命名一致的临时节点,因为节点的唯一性,所以只会有一个创建成功,若该节点删除了再重新创建
b、所有客户端在zookeeper共同创建链式临时有序节点,后节点监听前节点的删除事件
2、boot+dubbo+zookeeper(单机部署)
当bubbo服务启动时会在zookeeper服务器下建立URL
- service:
服务接口全路径名称
- providrs:
表示提供者,dubbo://表示该服务发布的协议类型和访问地址(涉及集群、负载均衡、watcher监听)
- consumers:
消费者写入自己的URL
springboot-dubbo-server Dubbo 服务提供者工程
pom.xml 配置
application.properties 配置
## Dubbo 服务提供者配置
#应用名称
spring.dubbo.application.name=provider
#注册中心
spring.dubbo.registry.address=zookeeper://127.0.0.1:2181
#协议名称
spring.dubbo.protocol.name=dubbo
#协议端口
spring.dubbo.protocol.port=20880
#服务类包
spring.dubbo.scan=org.spring.springboot.dubbo
CityDubboServiceImpl.java
@Service 注解标识为 Dubbo 服务
// 注册为 Dubbo 服务
@Service(version = "1.0.0")
public class CityDubboServiceImpl implements CityDubboService {
public City findCityByName(String cityName) {
return new City(1L,2L,"温岭","是我的故乡");
}
}
City.java 城市实体类
实体类通过 Dubbo 服务之间 RPC 调用,则需要实现序列化接口
springboot-dubbo-client Dubbo 服务消费者工程
pom.xml 、 CityDubboService.java、City.java 没有改动
application.properties 配置
## 避免和 server 工程端口冲突
server.port=8081
## Dubbo 服务消费者配置
spring.dubbo.application.name=consumer
spring.dubbo.registry.address=zookeeper://127.0.0.1:2181
spring.dubbo.scan=org.spring.springboot.dubbo
CityDubboConsumerService.java
@Reference(version = “1.0.0”) 通过该注解,订阅该接口版本为 1.0.0 的 Dubbo 服务
@Component
public class CityDubboConsumerService {
@Reference(version = "1.0.0")
CityDubboService cityDubboService;
public void printCity() {
String cityName="温岭";
City city = cityDubboService.findCityByName(cityName);
System.out.println(city.toString());
}
}
ClientApplication.java 客户端启动类
@SpringBootApplication
public class ClientApplication {
public static void main(String[] args) {
// 程序启动入口
// 启动嵌入式的 Tomcat 并初始化 Spring 环境及其各 Spring 组件
ConfigurableApplicationContext run = SpringApplication.run(ClientApplication.class, args);
CityDubboConsumerService cityService = run.getBean(CityDubboConsumerService.class);
cityService.printCity();
}
}
第五章:注册中心nacos
1、界面
a、 下载地址
github地址: https://github.com/alibaba/nacos/releases
b、启动Nacos服务
- Linux/Unix/Mac
启动命令(standalone代表着单机模式运行,非集群模式)
启动命令:sh startup.sh -m standalone
- Windows
启动命令:cmd startup.cmd 或者双击startup.cmd运行文件。
访问:http://localhost:8848/nacos
用户名密码:nacos/nacos
2、基本使用
父工程dubbo-nacos-demo
<?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>dubbo-nacos-demo</artifactId>
<groupId>com.zmq</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>com.zmq</groupId>
<artifactId>dubbo-provide</artifactId>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<exclusions>
<!-- 排除自带的logback依赖 -->
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
<!--<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</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>
<!-- Dubbo -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
</dependency>
<!-- Dubbo Registry Nacos -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-registry-nacos</artifactId>
<version>2.7.3</version>
</dependency>
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
</dependency>
</dependencies>
<repositories>
<repository>
<id>apache.snapshots.https</id>
<name>Apache Development Snapshot Repository</name>
<url>https://repository.apache.org/content/repositories/snapshots</url>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
提供者dubbo-provide
<?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>dubbo-nacos-demo</artifactId>
<groupId>com.zmq</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>com.zmq</groupId>
<artifactId>dubbo-provide</artifactId>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<exclusions>
<!-- 排除自带的logback依赖 -->
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
<!--<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</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>
<!-- Dubbo -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
</dependency>
<!-- Dubbo Registry Nacos -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-registry-nacos</artifactId>
<version>2.7.3</version>
</dependency>
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
</dependency>
</dependencies>
<repositories>
<repository>
<id>apache.snapshots.https</id>
<name>Apache Development Snapshot Repository</name>
<url>https://repository.apache.org/content/repositories/snapshots</url>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
application.yml
nacos注册中心nacos.config.servier-addr
dubbo名称dubbo.application.name
dubbo注册中心dubbo.registry.address
dubbo路径dubbo.scan.base-packages
nacos:
config:
server-addr: localhost:8848
spring:
application:
name: dubbo-provide
dubbo:
application:
name: ${spring.application.name}
registry:
address: nacos://${nacos.config.server-addr}
scan:
base-packages: com.zmq.service
protocol:
name: dubbo
port: 20881
启动类
@SpringBootApplication
@EnableDubbo
public class DubboProvideApplication {
public static void main(String[] args) {
SpringApplication.run(DubboProvideApplication.class);
}
}
service接口
public interface ProvideService {
String sayHello(String word);
}
service接口实现类
@service注册dubbo服务
@Service
public class ProvideImpl implements ProvideService {
public String sayHello(String word) {
return word;
}
}
消费者dubbo-consumer
<?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>dubbo-nacos-demo</artifactId>
<groupId>com.zmq</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>com.zmq</groupId>
<artifactId>dubbo-consumer</artifactId>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<!-- 排除自带的logback依赖 -->
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</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>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
</dependency>
<!-- Dubbo Registry Nacos -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-registry-nacos</artifactId>
<version>2.7.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba.nacos/nacos-spring-context -->
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-spring-context</artifactId>
<version>0.3.1</version>
</dependency>
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
</dependency>
<dependency>
<groupId>com.zmq</groupId>
<artifactId>dubbo-provide</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
</dependencies>
<repositories>
<repository>
<id>apache.snapshots.https</id>
<name>Apache Development Snapshot Repository</name>
<url>https://repository.apache.org/content/repositories/snapshots</url>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
application.yml
server:
address:
port: 8081
spring:
application:
name: dubbo-consumer
nacos:
config:
server-addr: localhost:8848
dubbo:
registry:
address: nacos://${nacos.config.server-addr}
application:
name: ${spring.application.name}
启动类
@SpringBootApplication
public class dubboConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(dubboConsumerApplication.class);
}
}
controller调用服务
@RestController
public class ConsumerController {
@Reference
ProvideService provideService;
@RequestMapping("sayHello")
public String sayHello(){
return provideService.sayHello("我爱你");
}
}
浏览器
启动nacos后可在服务列表看到注册的服务
3、部署Nacos的生产集群环境
集群部署
a、用Nginx 来负载多个 Nacos 节点 IP
b、外部客户端直接通过域名访问就可
c、更换 IP 方便、可读性好
添加集群配置文件
nacos的conf目录下有配置文件cluster.conf
配置MySQL数据库
application.properties
nacos/conf/application
启动Nacos集群模式
在没有参数模式,是集群模式sh startup.sh,打开任何一个Nacos控制台都能看到节点列表
nginx配置
a、server_name 直接改成域名就行。
b、Nginx -s reload 重新加载配置后即可
项目
a、acos官方Spring Cloud Nacos Example的示例打开
b、Provider和Consumer两个项目中的application.properties
c、nacos server地址改成 Nginx中配置的server_name。
启动项目,就可以在nacos集群的任何一个节点的服务管理列表中看到里面已经有服务注册成功了
其实这个Example就是微服务和微服务之间的调用
4、配置中心
案例结构
- 服务端:
node08-nacos-server
- 客户端:
node08-nacos-clien
配置文件
配置内容如下:
DataID、文件格式、文件内容的配置。这里还配置了一个MySQL数据源。
服务端配置
- 核心依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<version>2.1.1.RELEASE</version>
</dependency>
- 配置文件
spring:
application:
name: node08-nacos-server
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
这里的name
配置和上面DataID
一致,就可以读取上述配置内容。
- 提供服务接口
@RestController
public class ServerWeb {
private static Logger logger = LoggerFactory.getLogger(ServerWeb.class) ;
@RequestMapping(value = "/web/getMsg",method = RequestMethod.GET)
public String getMsg (@RequestParam("name") String name){
logger.info("8001 服务被调用...");
return "Hello:" + name ;
}
}
- 启动类注解
@SpringBootApplication
// SpringCloud原生注解@EnableDiscoveryClient开启服务注册发现功能
@EnableDiscoveryClient
public class ApplicationServer {
public static void main(String[] args) {
SpringApplication.run(ApplicationServer.class,args) ;
}
}
客户端配置
- 核心依赖
加入基于Feign模式,访问上述服务端提供的接口服务 。
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<version>2.1.1.RELEASE</version>
</dependency>
<!-- Feign组件 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>2.1.3.RELEASE</version>
</dependency>
- 基于Rest接口访问
@Configuration
public class RestConfig {
@LoadBalanced
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
@RestController
public class ClientWeb {
@Resource
private RestTemplate restTemplate ;
@RequestMapping(value = "/web/getMsgV1/{name}",method = RequestMethod.GET)
public String getMsgV1 (@PathVariable String name){
String reqUrl = "http://node08-nacos-server:8001/web/getMsg/"+name ;
return restTemplate.getForObject(reqUrl,String.class) ;
}
}
- 基于Feign接口访问
Feign接口配置
@FeignClient("node08-nacos-server")
public interface MsgFeign {
@GetMapping("/web/getMsg")
String getMsg (@RequestParam(name = "name") String name);
}
请求方法
@RestController
public class ClientWeb {
@Resource
private MsgFeign msgFeign ;
@RequestMapping(value = "/web/getMsgV2/{name}",method = RequestMethod.GET)
public String getMsgV2 (@PathVariable String name){
return msgFeign.getMsg(name) ;
}
}
- 启动类配置
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients(basePackages={"cloud.nacos.client.feign"})
public class ApplicationClient {
public static void main(String[] args) {
SpringApplication.run(ApplicationClient.class,args) ;
}
}
第六章:sentinel微服务限流及熔断
- 限流:
限制并发量或请求量
- 熔断:
多个微服务调用会形成链式,当某个服务延迟或超时导致阻塞,为避免雪崩效应,将其隔离,直到恢复
- 降级
出于整体系统负荷考虑暂时隔离
1、基本应用
Sentinel实现限流
引入Sentinel的核心库
<!--引入Sentinel的核心库-->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-core</artifactId>
<version>1.7.2</version>
</dependency>
业务类方法
blockHandler 的值在触发限流之后调用
private static void doSomething() {
try (Entry entry = SphU.entry("doSomething")){
//业务逻辑处理
System.out.println("hello world"+System.currentTimeMillis());
} catch (BlockException ex){
//被流控处理的逻辑
}
}
//注释实现
@SentinelResource(value = "resourceName" ,blockHandler = "blockHandlerForString")
public String getName(String id){
//业务逻辑
return " ";
}
public String blockHandlerForString(String id,BlockException e){
//被限流后的处理方法
return " ";
}
针对该保护的资源定义限流规则;
private static void initFlowRules(){
ArrayList<FlowRule> rules = new ArrayList<>();
FlowRule rule = new FlowRule();
rule.setResource("doSomething");
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
rule.setCount(20);
rules.add(rule);
FlowRuleManager.loadRules(rules);
}
测试
public static void main(String[] args) {
initFlowRules();
while (true) {
doSomething();
}
}
我们需要去到日志文件观看(这个图显示了日志在什么位置):
Sentinel限流规则
private void initFlowQpsRule() {
ArrayList<FlowRule> rules = new ArrayList<>();
FlowRule rule = new FlowRule();
rule.setCount(20);
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
rule.setLimitApp("default");
rule.setStrategy(RuleConstant.STRATEGY_CHAIN);
rule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_DEFAULT);
rule.setClusterMode(false);
rules.add(rule);
FlowRuleManager.loadRules(rules);
}
- count:限流阈值
超过线程或qps的阀值触发限流
- Grade:限流阈值类型
QPS模式:一台服务器每秒能够响应的查询次数
并发线程数模式:服务不稳定或响应延迟造成阻塞
- limitApp: 是否需要针对调用来源进行限流
默认是default即不区分调用来源。
- controlBehavior: 流控行为
默认当超出阀值抛出FlowException
Sentinel熔断规则
三种策略:响应时间/异常比例/异常数量
private static void initDegradeRule() {
ArrayList<DegradeRule> rules = new ArrayList<>();
DegradeRule degradeRule = new DegradeRule();
degradeRule.setResource("key");
degradeRule.setCount(10);
degradeRule.setGrade(RuleConstant.DEGRADE_GRADE_RT);
degradeRule.setTimeWindow(10);
degradeRule.setMinRequestAmount(5);
degradeRule.setRtSlowRequestAmount(5);
rules.add(degradeRule);
DegradeRuleManager.loadRules(rules);
}
2、springCloud整合sentinel
Sentinel接入Spring Cloud
a、创建一个基于Spring Boot的项目,并集成Greenwich.SR2版本的Spring Cloud依赖。
b、添加Sentinel依赖包
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
<version>2.1.1.RELEASE</version>
</dependency>
c、创建一个REST接口,并通过@SentinelResource配置限流保护资源
@RestController
public class SentinelDemoController {
@SentinelResource(value = "hello", blockHandler = "blockHandlerHello")
@GetMapping("/hello")
public String hello() {
return "Hello Sentinel";
}
public String blockHandlerHello(BlockException e) {
return "限流了";
}
}
d、实现InitFunc接口,并在init方法中编写规则
public class FlowRuleInitFunc implements InitFunc {
@Override
public void init() throws Exception {
List<FlowRule> rules = new ArrayList<>();
FlowRule rule = new FlowRule();
rule.setCount(1);
rule.setResource("hello");
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
rule.setLimitApp("default");
rules.add(rule);
FlowRuleManager.loadRules(rules);
}
}
e、在resource目录下创建META-INF/services/com.alibaba.csp.sentinel.init.InitFunc文件,文件内容就是自定义扩展点的全路径
com.sentinel.springcloud.demo.FlowRuleInitFunc
f、启动服务后,访问http://localhost:8080/hello方法,当访问频率超过设定阈值的时候,就会触发限流。
基于Sentinel Dashboard来实现流控配置
a、启动Sentinel Dashboard
b、在application.yaml中增加如下配置:
spring.cloud.sentinel.transport.dashboard指向的是Sentinel Dashboard的服务器地址
spring:
application:
name: sentinel-spring-cloud-demo
cloud:
sentinel:
transport:
dashboard: localhost:7777
e、提供一个REST接口
@RestController
public class SentinelDashboardController {
@GetMapping("/dash")
public String dashboard() {
return "Hello Sentinel Dashboard";
}
}
f、启动服务后,此时访问http://localhost:8080/dash,不存在任何限流行为。
g、至此,Spring Cloud集成Sentinel的配置就完成了,接下来就可以进入Sentinel Dashboard去实现限流规则的配置。
h、针对/dash这个资源,点击最右边的操作栏中的“流控”按钮设置流控规则,如下图所示:
i、新增完成后,再次访问localhost:8080/dash,当超过设置的阈值的时候,就可以看到限流的效果,并获得如下输出:
自定义URL限流异常
a、在默认情况下,URL触发限流后会直接返回Blocked by Sentinel (flow limiting)
b、在实际应用中,大都采用JSON格式的数据,可以通过自定义限流异常来处理,实现UrlBlockHandler并重写blocked方法:
@Service
public class CustomUrlBlockHandler implements UrlBlockHandler {
@Override
public void blocked(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, BlockException e) throws IOException {
httpServletResponse.setHeader("Content-Type", "application/json;charset=UTF-8");
String message = "{\"code\":999,\"msg\":\"访问人数过多\"}";
httpServletResponse.getWriter().write(message);
}
}
c、当触发限流之后,我们希望直接跳转到一个降级页面,可以通过下面这个配置来实现:
spring.cloud.sentinel.servlet.block-page={url}
URL资源清洗
a、把每个不同的URL统一归类,通过UrlCleaner接口来实现资源清洗
b、例如对/clean/{id}这个URL,我们可以统一归集到/clean/*资源下
@Service
public class CustomUrlCleaner implements UrlCleaner {
@Override
public String clean(String s) {
if (StringUtils.isEmpty(s)) {
return s;
}
if (s.startsWith("/clean/")) {
return "/clean/*";
}
return s;
}
}
3、Sentinel集成Nacos实现动态流控规则
a、Sentinel的理念是只需要开发者设置流控规则,它默认会对资源进行流控
b、Sentinel Dashboard所配置的流控规则,都是保存在内存中的,一旦应用重启,这些规则都会被清除。
c、Sentinel支持Consul、Zookeeper、Redis、Nacos、Apollo、etcd等数据源的扩展
a、添加Nacos数据源的依赖包
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
<version>1.7.0</version>
</dependency>
b、创建一个REST接口,用于测试
@RestController
public class DynamicController {
@GetMapping("/dynamic")
public String dynamic() {
return "Hello Dynamic Rules";
}
}
c、在application.yml文件中添加数据源配置
spring:
application:
name: sentinel-spring-cloud-demo
cloud:
sentinel:
transport:
dashboard: 192.168.56.1:7777
datasource:
- nacos:
server-addr: 192.168.56.1:8848
data-id: ${spring.application.name}-sentinel
group-id: DEFAULT_GROUP
data-type: json
rule-type: flow
- datasource: 目前支持redis、apollo、zk、file、nacos,选什么类型的数据源就配置相应的key即可。
- data-id:可以设置成${spring.application.name},方便区分不同应用的配置。
- data-type:指配置项的内容格式,Spring Cloud Alibaba Sentinel提供了JSON和XML两种格式
- rule-type:表示数据源中规则属于哪种类型,如flow、degrade、param-flow、gw-flow等。
d、登陆Nacos控制台,创建流控配置规则:
e、登陆Sentinel Dashboard,找到执行项目名称菜单下的“流控规则”,就可以看到在Nacos上所配置的流控规则已经被加载了。
注意:
以上在Sentinel Dashboard上修改流控规则,无法同步到Nacos上
4、Sentinel Dashboard集成Nacos实现规则同步
a、源码改动忽略,只看应用程序的改动
b、data-id的命名要以-sentinel-flow结尾即可(看源码具体实现用的什么后缀)
spring:
application:
name: spring-cloud-sentinel-dynamic
cloud:
sentinel:
transport:
dashboard: 192.168.56.1:7777
datasource:
- nacos:
server-addr: 192.168.56.1:8848
data-id: ${spring.application.name}-sentinel-flow
group-id: DEFAULT_GROUP
data-type: json
rule-type: flow
5、Dubbo 集成 Sentinel 实现限流
Dubbo服务接入Sentinel
a、Sentinel提供了与Dubbo整合的模块Sentinel Apache Dubbo Adapter
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-apache-dubbo-adapter</artifactId>
<version>1.7.1</version>
</dependency>
b、关闭消费端的过滤器。
@Bean
public ConsumerConfig consumerConfig() {
ConsumerConfig consumerConfig = new ConsumerConfig();
consumerConfig.setFilter("-sentinel.dubbo.filter");
return consumerConfig;
}
Dubbo服务接入Sentinel Dashboard
a、spring-cloud-starter-alibaba-sentinel目前无法支持Dubbo服务的限流,
b、所以针对Dubbo服务的限流只能使用sentinel-apache-dubbo-adapter。
c、这个适配组件并没有自动接入sentinel dashboard,要引入sentinel-transport-simple-http依赖
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-transport-simple-http</artifactId>
<version>1.7.1</version>
</dependency>
a、添加启动参数
-Djava.net.perferIPv4Stack=true -Dcsp.sentinel.api.port=8720 -Dcsp.sentinel.dashboard.server=localhost:7777 -Dproject.name=spring-cloud-sentinel-dubbo-provider
b、登陆Sentinel Dashboard之后,进入"簇点链路",就可以看到资源信息
Dubbo服务限流规则配置
a、添加sentinel-datasource-nacos的依赖
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
<version>1.7.1</version>
</dependency>
b、通过Sentinel提供的InitFunc扩展点,实现Nacos数据源的配置
public class NacosDataSourceInitFunc implements InitFunc{
private String serverAddr="localhost:8848";
private String groupId="DEFAULT_GROUP";
private String dataId="spring-cloud.sentinel-dubbo.provider-sentinel-flow";
@Override
public void init() throws Exception {
loadNacosData();
}
private void loadNacosData(){
ReadableDataSource<String,List<FlowRule>> flowRuleDataSource=
new NacosDataSource<>(serverAddr, groupId, dataId, source -> JSON.parseObject(source, new TypeReference<List<FlowRule>>() {
}));
FlowRuleManager.register2Property(flowRuleDataSource.getProperty());
}
}
c、需要在resource目录下的META-INF/services中创建一个名称为com.alibaba.csp.sentinel.init.InitFunc的文件,内容为路径
d、访问Sentinel Dashboard,在针对资源创建流控规则的时候,这个规则会同步保存到Nacos配置中心。
e、而当Nacos配置中心发生变化的时候,也会触发事件机制通知Dubbo应用重新加载流控规则。
第七章:分布式事务seata
提供了AT、TCC、Sata、XA事务模式,AT模式是Seata主推的分布式事务解决方案
AT模式
- 事务协调器(TC):
维护全局事务和分支事务的状态
- 事务管理器(TM):
定义全局事务的范围:开始全局事务,提交或回滚全局事务。
- 资源管理器(RM):
管理正在处理的分支事务的资源,与TC对话以注册分支事务并报告分支事务的状态
a、TM(协调)——>要求TC(全局)开始一项新的全局事务,生成全局事务的XID。
b、RM(局部)本地事务——>在TC(全局)注册为全局事务XID的分支
c、TM(协调)——>要求TC(全局)提交XID相应全局事务下的所有分支
1、配置
a、配置注册中心动态维护
b、用数据库维护全局事务会话信息
file.cong
修改registry.cong文件
2、使用
在类或者方法上@GlobalTransactional
@GlobalTransactional
public void purchase(String userId, String commodityCode, int orderCount) {
}
XID 的传递
全局事务ID的跨服务传递,需要我们自己实现,这里通过拦截器的方式。每个服务都需要添加下面两个类。
@Component
public class SeataFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) servletRequest;
String xid = req.getHeader(RootContext.KEY_XID.toLowerCase());
boolean isBind = false;
if (StringUtils.isNotBlank(xid)) {
RootContext.bind(xid);
isBind = true;
}
try {
filterChain.doFilter(servletRequest, servletResponse);
} finally {
if (isBind) {
RootContext.unbind();
}
}
}
@Override
public void destroy() {
}
}
@Configuration
public class SeataRestTemplateAutoConfiguration {
@Autowired(
required = false
)
private Collection<RestTemplate> restTemplates;
@Autowired
private SeataRestTemplateInterceptor seataRestTemplateInterceptor;
public SeataRestTemplateAutoConfiguration() {
}
@Bean
public SeataRestTemplateInterceptor seataRestTemplateInterceptor() {
return new SeataRestTemplateInterceptor();
}
@PostConstruct
public void init() {
if (this.restTemplates != null) {
Iterator var1 = this.restTemplates.iterator();
while (var1.hasNext()) {
RestTemplate restTemplate = (RestTemplate) var1.next();
List<ClientHttpRequestInterceptor> interceptors = new ArrayList(restTemplate.getInterceptors());
interceptors.add(this.seataRestTemplateInterceptor);
restTemplate.setInterceptors(interceptors);
}
}
}
}
第八章:微服务网关Spring Cloud Gateway
为微服务架构提供一种简单有效的统一的 API 路由管理方式。
Spring Cloud Gateway 作为 Spring Cloud 生态系统中的网关,目标是替代 Netflix Zuul,其不仅提供统一的路由方式,并且基于 Filter 链的方式提供了网关基本的功能,例如:安全,监控/指标,和限流。
-
Route(路由):
这是网关的基本构建块。它由一个 ID,一个目标 URI,一组断言和一组过滤器定义。如果断言为真,则路由匹配。
-
Predicate(断言):
这是一个 Java 8 的 Predicate。输入类型是一个 ServerWebExchange。我们可以使用它来匹配来自 HTTP 请求的任何内容
-
Filter(过滤器):
这是org.springframework.cloud.gateway.filter.GatewayFilter的实例,我们可以使用它修改请求和响应。
a、客户端向 Spring Cloud Gateway 发出请求。
b、匹配路由
c、过滤器将请求发送到我们实际的服务执行业务逻辑
配置文件
- id:我们自定义的路由 ID
- uri:转发到目标服务地址
- predicates:路由条件
server:
port: 8080
spring:
application:
name: api-gateway
cloud:
gateway:
routes:
- id: gateway-service
uri: https://blog.csdn.net
predicates:
- Path=/meteor_93
1、路由规则
a、Predicate 来源于 Java 8,是 Java 8 中引入的一个函数,Predicate 接受一个输入参数,返回一个布尔值结果
b、Predicate 就是为了实现一组匹配规则,方便让请求过来找到对应的 Route 进行处理
表示在这个时间段可以进行路由,否则访问地址http://localhost:8080,页面会报 404 没有找到地址。
server:
port: 8080
spring:
application:
name: api-gateway
cloud:
gateway:
routes:
- id: gateway-service
uri: https://www.baidu.com
order: 0
predicates:
- Between=2019-01-01T00:00:00+08:00[Asia/Shanghai], 2019-07-01T00:00:00+08:00[Asia/Shanghai]
通过请求方式匹配
可以通过是 POST、GET、PUT、DELETE 等不同的请求方式来进行路由。
通过请求路径匹配
Path Route Predicate 接收一个匹配路径的参数来判断是否走路由
通过请求参数匹配
通过请求 ip 地址进行匹配
本文地址:https://blog.csdn.net/qq_36750352/article/details/107209617
上一篇: 用js实现拼图小游戏
下一篇: 微信小程序自定义tabbar组件