Sentinel限流熔断应用实践
idea连接nacos
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-51LXMZlF-1635341419470)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20211027090456692.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vc2rW4Fy-1635341419477)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20211027090520621.png)]
9:44;
package com.cy;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
* 课后练习:基于ScheduledExecutorService对象完成一个
* 多线程任务的调度,在nacos注册中心发送定时心跳
* 以及nacos配置中心数据定时拉取(pull)
*/
public class ScheduledExecutorServiceUtils {
public static void main(String[] args) {
//构建一个负责任务调度的线程池对象,池中最多三个线程;
ScheduledExecutorService ses =
Executors.newScheduledThreadPool(3);
//构建任务对象
Runnable take = new Runnable() {
@Override
public void run() {
String tName = Thread.currentThread().getName();
System.out.println(tName+"->"+System.currentTimeMillis());
}
};
//执行任务调度(定时任务调度):1秒后开始执行,每隔5秒执行一次
ses.scheduleAtFixedRate(take,
1,//初始延迟
5,//每隔5秒执行一次(与任务是否执行无关)
TimeUnit.SECONDS);//时间单位
}
}
一、读写锁简介
现实中有这样一种场景:对共享资源有读和写的操作,且写操作没有读操作那么频繁。在没有写操作的时候,多个线程同时读一个资源没有任何问题,所以应该允许多个线程同时读取共享资源;但是如果一个线程想去写这些共享资源,就不应该允许其他线程对该资源进行读和写的操作了。
ConcurrentHashMap,线程安全map,查;独占锁,排它锁;锁商场试衣间;
package com.jt.common.thread;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* 简易服务注册中心测试(基于此,思考Nacos中服务的注册和发现)
* 1)测试服务的注册
* 2)测试服务的发现
*/
public class RegistryTests {
//存储服务信息的容器(可以简单理解为nacos中存储服务信息的对象)
private static Map<String,String> registryMap=new HashMap<>();
//private static Map<String,String> registryMap=new ConcurrentHashMap<>();
//读写锁,悲观写,乐观读 Segment对象守护--分段锁
private static final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();//悲观写对象
//服务的注册,将服务信息存储到map
public static void doRegist(String serviceId,String host){//悲观写
readWriteLock.writeLock().lock();
try {
registryMap.put(serviceId, host);
}finally {
readWriteLock.writeLock().unlock();
}
}
//服务的发现,从map中基于key获取服务实例
public static String doLookup(String serviceId){//乐观读
readWriteLock.readLock().lock();
try {
return registryMap.get(serviceId);
}finally {
readWriteLock.readLock().unlock();
}
}
public static void main(String[] args) {
//1.构建服务名,服务地址,服务名与服务地址有一一对应关系
//1.1服务名
String[] serviceIds=new String[100];
//1.2服务地址
String[] hostIds=new String[100];
//1.3数据初始化
for(int i=0;i<100;i++){
serviceIds[i]="Serivce-"+i;
hostIds[i]="Host-"+i;
}
//2.构建线程对象,模拟服务注册和发现
Thread t1=new Thread(){
@Override
public void run() {
for(int i=0;i<25;i++){
doRegist(serviceIds[i],hostIds[i]);
}
}
};
Thread t2=new Thread(){
@Override
public void run() {
for(int i=25;i<50;i++){
doRegist(serviceIds[i],hostIds[i]);
}
}
};
Thread t3=new Thread(){
@Override
public void run() {
for(int i=50;i<75;i++){
doRegist(serviceIds[i],hostIds[i]);
}
}
};
Thread t4=new Thread(){
@Override
public void run() {
for(int i=75;i<100;i++){
doRegist(serviceIds[i],hostIds[i]);
}
}
};
t1.start();
t2.start();
t3.start();
t4.start();
//2.构建线程对象,模拟服务注册和发现
}
}
ReentrantReadWriteLock读写锁详解
1.jar包下载地址
https://github.com/alibaba/Sentinel/releases
2.启动命令
java -Dserver.port=8180 -Dcsp.sentinel.dashboard.server=localhost:8180 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.0.jar
Sentinel限流入门
添加jar包
<!-- 添加Sentinel依赖,添加此依赖以后,会在项目中添加一个拦截器对象,这个对象会此服务发出的请求,
进行拦截,拦截到请求以后会与Sentinel控制台定义的限流规则进行比对,假如在允许范围对,则继续访问,
否则进行限流或者降级操作-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
服务提供方添加配置
spring:
cloud:
sentinel:
transport:
dashboard: localhost:8180 # 指定sentinel控制台地址。
创建一个用于演示限流操作的Controller对象,例如:
package com.cy.provider.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/provider")
public class ProviderSentinelController {
@GetMapping("/sentinel01")
public String doSentinel01(){
return "sentinel 01 test ...";
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9vyWNHp8-1635341419482)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20211027150002615.png)]
设置限流模式
Sentinel的流控模式代表的流控的方式,默认【直接】,还有关联,链路。
直接模式
Sentinel默认的流控处理就是【直接->快速失败】。
关联模式
当关联的资源达到阈值,就限流自己。例如设置了关联资源为/ur2时,假如关联资源/url2的qps阀值超过1时,就限流/url1接口(是不是感觉很霸道,关联资源达到阀值,是本资源接口被限流了)。这种关联模式有什么应用场景呢?我们举个例子,订单服务中会有2个重要的接口,一个是读取订单信息接口,一个是写入订单信息接口。在高并发业务场景中,两个接口都会占用资源,如果读取接口访问过大,就会影响写入接口的性能。业务中如果我们希望写入订单比较重要,要优先考虑写入订单接口。那就可以利用关联模式;在关联资源上面设置写入接口,资源名设置读取接口就行了;这样就起到了优先写入,一旦写入请求多,就限制读的请求。例如
第一步:在ProviderSentinelController中添加一个方法,例如:
@GetMapping("/sentinel02")
public String doSentinel02(){
return "sentinel 02 test ...";
}
https://jmeter.apache.org/changes.html