spring cloud Alibaba

微信图片_20210920171736

Spring Cloud Alibaba入门

spring Cloud Alibaba版本说明

https://github.com/alibaba/spring-cloud-alibaba/wiki/%E7%89%88%E6%9C%AC%E8%AF%B4%E6%98%8E

组件版本关系

springcloud-springboot版本依赖关系

springcloud 的版本号是用伦敦地铁站站名标记的版本、因为错综复杂、用数字标记不是太友好

依赖关系

spring boot –> spring cloud –> spring cloud alibaba

Nacos服务治理

Nacos服务注册

  • 首先我们要先下载相应的Nacos服务、然后启动Nacos服务

Nacos服务启动

  • 引入父工程的相关依赖
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<dependencyManagement>
<dependencies>
<!-- Spring Cloud Hoxton -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Hoxton.SR3</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- Spring Cloud Alibaba -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.2.1.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
  • 创建provider子模块、引入相关依赖
1
2
3
4
5
6
7
8
9
10
11
12
13
<!--    继承父工程-->
<parent>
<groupId>com.dream.xiaobo</groupId>
<artifactId>springcloudalibaba</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>

<!-- 引入nacos发现依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<version>2.2.1.RELEASE</version>
</dependency>
  • 配置application.yml
1
2
3
4
5
6
7
8
9
10
11
spring:
cloud:
nacos:
discovery:
server-addr: localhost:8848 # 在nacos中注册、nacos地址

application:
name: provider # 服务名字

server:
port: 8082 # 端口号
  • 注册成功

Nacos注册成功

Nacos 服务发现

  • 创建consumer子模块、引入相关pom依赖
1
2
3
4
5
6
7
8
9
10
11
12
13
<!--    继承父工程-->
<parent>
<groupId>com.dream.xiaobo</groupId>
<artifactId>springcloudalibaba</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>

<!-- 引入nacos发现依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<version>2.2.1.RELEASE</version>
</dependency>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@RestController
public class ConsumerController {

/**
* DiscoveryClient是springCloud提供的一个发现Nacos的接口、直接将其注入到IOC容器即可
*/
@Autowired
private DiscoveryClient discoveryClient;

/**
* ServiceInstance是springCloud提供的一个接受服务的一个接口、直接用其接受即可
* @return
*/
@GetMapping("/instances")
public List<ServiceInstance> instances(){

//根据服务Id获取到服务、
List<ServiceInstance> provider = this.discoveryClient.getInstances("provider");

return provider;
}
}

Nacos 服务调用

  • consumerController
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
@RestController
@Slf4j
public class ConsumerController {

/**
* DiscoveryClient是springCloud提供的一个发现Nacos的接口、直接将其注入到IOC容器即可
*/
@Autowired
private DiscoveryClient discoveryClient;

//这里面spring boot没有提供RestTemplate、所以需要手动配置放到Bean中
@Autowired
private RestTemplate restTemplate;

/**
* ServiceInstance是springCloud提供的一个接受服务的一个接口、直接用其接受即可
* @return
*/
@GetMapping("/instances")
public List<ServiceInstance> instances(){

//根据服务Id获取到服务
List<ServiceInstance> provider = this.discoveryClient.getInstances("provider");

return provider;
}

@GetMapping(value = "/index")
public String index(){

//根据服务Id获取到服务
List<ServiceInstance> list = this.discoveryClient.getInstances("provider");

//生成一个随机数用于在不同服务之间访问
int index = ThreadLocalRandom.current().nextInt(list.size());

//获取到一个服务
ServiceInstance serviceInstance = list.get(index);

//获取到当前服务的URI
URI uri = serviceInstance.getUri();

//打印日志
log.info("调用的端口是:" + serviceInstance.getPort());

//返回
return "调用的端口是"+serviceInstance.getPort() + "uri是:" + serviceInstance.getUri();
}
}
  • ConsumerConfiguration
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Configuration
public class ConsumerConfiguration {

/**
* 注入到Bean中
* @return
*/
@Bean
public RestTemplate restTemplate(){

//直接返回RestTemplate对象
return new RestTemplate();
}
}

这里只实现了简单的调用、并没有太多的起到负载均衡、这里面的随机数相当于了负载均衡

Ribbon 负载均衡

Ribbon 不是spring Alibaba的组件、是Netfilx的、底层是RestTemplate、用的是轮询算法

  • ribbon的用法 @LoadBalanced
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Configuration
public class ConsumerConfiguration {

/**
* 注入到Bean中
* @return
*/
@Bean
@LoadBalanced
public RestTemplate restTemplate(){

//直接返回RestTemplate对象
return new RestTemplate();
}
}
  • controller
1
2
3
4
5
@GetMapping(value = "/ribbonIndex")
public String ribbonIndex(){

return this.restTemplate.getForObject("http://provider/index", String.class);
}

这是一种轮询算法

Ribbon之随机算法

1
2
3
4
5
6
7
server:
port: 8180

# Ribbon 随机算法
provider:
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

Ribbon之权重算法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
@Slf4j
public class NacosWeightedRule extends AbstractLoadBalancerRule {

@Autowired
private NacosDiscoveryProperties nacosDiscoveryProperties;

@Override
public void initWithNiwsConfig(IClientConfig iClientConfig) {
//读取配置文件
}

@Override
public Server choose(Object o) {
ILoadBalancer loadBalancer = this.getLoadBalancer();
BaseLoadBalancer baseLoadBalancer = (BaseLoadBalancer) loadBalancer;
//获取要请求的微服务名称
String name = baseLoadBalancer.getName();
//获取服务发现的相关API
NamingService namingService = nacosDiscoveryProperties.namingServiceInstance();
try {
Instance instance = namingService.selectOneHealthyInstance(name);
log.info("选择的实例是port={},instance={}",instance.getPort(),instance);
return new NacosServer(instance);
} catch (NacosException e) {
e.printStackTrace();
return null;
}
}
}
1
2
3
4
# Ribbon  权重算法
provider:
ribbon:
NFLoadBalancerRuleClassName: com.southwind.configuration.NacosWeightedRule

Sentinel 服务限流降级

雪崩效应

这里来说以下雪崩效应的理解、举个例子、就好比现在有A、B、C、D四块服务、现在项目中D需要调用C、C需要调用B、B需要调用A、但是由于A出现了一点点的小问题、导致B无法调用它、这样就会导致B内从增加、而导致B、C、D服务都不能正常工作、这样的问题就叫做雪崩效应

雪崩效应的解决方案

设置线程

这里可以设置线程、例如、B访问A时设置一个线程访问时间、如果在规定时间内没有获取到相应的线程就释放掉、这样就不会产生阻塞线程从而使得B的内存崩溃了

设置限流

例如、给A服务设置一个访问上限、假如给A设置10个访问上限、这样B来了10个访问线程之后就不会再有线程去访问、从而防止内存崩溃

熔断器 Sentienl Hystrix

  • 降级(应对服务自身的)

系统将某些不重要的接口功能进行降低、限制一些功能的使用、只提供部分功能、不提供全部功能

  • 限流(应对服务自身的)

只接受系统能够承载的访问量、超出即抛出异常

  • 熔断(应对服务外部的)

例如、B访问A时、A反应很慢、这样就会导致B反应也很慢、所以直接熔断、不去访问A了、直接返回错误

熔断器效果

sentinel大致历程

Sentinel的使用方法

下载相应的jar、用于启动Sentinel、然后运行下载的jar即可

sentinel启动

  • pom依赖
1
2
3
4
5
6
7
8
9
10
11
12
<!--        用于流量控制-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
<version>2.2.1.RELEASE</version>
</dependency>

<!-- 用于采集数据-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
  • application.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
spring:
cloud:
nacos:
discovery:
server-addr: localhost:8848 # 在nacos中注册、nacosURI 完成注册的(Nacos)
sentinel:
transport:
dashboard: localhost:8080 # 完成流量控制的 (Sentinel)
filter:
enabled: false # 用于Sentinel链路控制Service层的开关
application:
name: provider # 服务名字

server:
port: 8082 # 端口号

management:
endpoints:
web:
exposure:
include: "*" # 监控所有请求、用于Sentienel进行控制

效果图
sentinel控制台

流量规则

sentinel流控

直接流控

直接将其访问的方法加入阈值

sentinel直接阀值控制

关联流控

关联阈值是关联别的方法、简单点说就是别人做事我背锅、例如关联一个list方法、那么访问list方法时我就会被收到控制

1
2
3
4
5
6
7
8
9
10
11
public class Test {

static RestTemplate restTemplate = new RestTemplate();
public static void main(String[] args) throws Exception{

for (int i = 0; i < 1000; i++) {
restTemplate.getForObject("http://localhost:8082/list",String.class);
Thread.sleep(200);
}
}
}

sentinel关联模式

链路流控

链路流控其实就是控制service层、但是service不能直接被访问、所以要和调用的Controller进行关联

  • pom.xml
1
2
3
4
5
6
7
8
9
10
11
<!--        为Service做限流所用到的依赖-->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-core</artifactId>
<version>1.7.1</version>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-web-servlet</artifactId>
<version>1.7.1</version>
</dependency>
  • configuration
1
2
3
4
5
6
7
8
9
10
11
12
13
@Configuration
public class FilterConfiguration {

@Bean
public FilterRegistrationBean registrationBean(){
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
registrationBean.setFilter(new CommonFilter());
registrationBean.addUrlPatterns("/*");
registrationBean.addInitParameter(CommonFilter.WEB_CONTEXT_UNIFY,"false");
registrationBean.setName("sentinelFilter");
return registrationBean;
}
}
  • controller
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
@RestController
public class ProviderController {

@Autowired
private ProviderService providerService;

@Value("${server.port}")
private String port;

@GetMapping("/index")
public String index(){

return "端口号为:"+port;
}
@GetMapping(value = "list")
public String list(){

return "list";
}
@GetMapping(value = "/test1")
public String test1(){

providerService.test();

return "test1";
}
@GetMapping(value = "/test2")
public String test2(){

providerService.test();
return "test2";
}
}

  • service
1
2
3
4
5
6
7
8
9
10
@Service
public class ProviderService {

//声明Sentinel控制
@SentinelResource
public void test(){

System.out.println("test");
}
}

流量效果

直接失败

直接抛出异常、没什么附加功能

warm up

warm up就会在系统刚开始的性能比较低、举个例子就好比一个业务员刚上班、可能状态不是很好、所以他会在刚开始的时候只接受一个人办理业务、过了一会他可能状态适应了、会一个人接受多个人同时办理业务、这里大家可以想一下抢购、抢购业务用的可能就是这个

warm-up

排队等待

排队等待就是出现异常时不会直接抛出、会等待一下、等待下一个时间段请求、如果请求上了、就不会抛出异常、正常执行、否则会抛出异常

  • 失败
    Sentinel排队等待失败
1
2
3
4
5
6
7
8
9
10
11
public class Test {

static RestTemplate restTemplate = new RestTemplate();
public static void main(String[] args) throws Exception{

for (int i = 0; i < 1000; i++) {
restTemplate.getForObject("http://localhost:8082/index",String.class);
Thread.sleep(500);
}
}
}

排队等待失败

失败原因、以为0.5s+0.3s < 1s 所以在等待之后的请求当中还在阈值1s当中、所以不会请求成功、而会抛出异常

  • 成功
    Sentinel排队等待成功
1
2
3
4
5
6
7
8
9
10
11
public class Test {

static RestTemplate restTemplate = new RestTemplate();
public static void main(String[] args) throws Exception{

for (int i = 0; i < 1000; i++) {
restTemplate.getForObject("http://localhost:8082/index",String.class);
Thread.sleep(500);
}
}
}

排队等待成功

成功原因、因为0.5s + 0.5s = 1s、所以在等待之后阈值正好为1、所以后得到下一次的请求

降级规则

RT

单个请求的响应时间超过阈值、则进入准降级状态、接下来 1 S 内连续 5 个请求响应时间均超过阈值、就进行降级、持续时间为时间窗口的值

异常比例

每秒异常数量占通过量的比例大于阈值、就进行降级处理、持续时间为时间窗口的值

异常数

1 分钟内的异常数超过阈值就进行降级处理、时间窗口的值要大于 60S、否则刚结束熔断又进入下一次熔断了

热点规则

热点规则是流控规则的更细粒度操作、可以具体到对某个热点参数的限流、设置限流之后、如果带着限流参数的请求量超过阈值、则进行限流、时间为统计窗口时长

热点规则

1
2
3
4
5
6
7
8
@GetMapping(value = "/test")
@SentinelResource("test")
public String test(
@RequestParam(value = "num1",required = false) Integer num1,
@RequestParam(value = "num2", required = false) Integer num2
){
return num1 + "-" + num2;
}

授权规则

给指定的资源设置流控应用(追加参数)、可以对流控应用进行访问权限的设置、具体就是添加白名单和黑名单
授权

1
2
3
4
5
6
7
8
9
10
public class RequestOriginParserDefinition implements RequestOriginParser {
@Override
public String parseOrigin(HttpServletRequest httpServletRequest) {
String name = httpServletRequest.getParameter("name");
if(StringUtils.isEmpty(name)){
throw new RuntimeException("name is null");
}
return name;
}
}
1
2
3
4
5
6
7
public class SentinelConfiguration {

@PostConstruct
public void init(){
WebCallbackManager.setRequestOriginParser(new RequestOriginParserDefinition());
}
}

正确的开始、微小的长进、然后持续、嘿、我是小博、带你一起看我目之所及的世界……

-------------本文结束 感谢您的阅读-------------

本文标题:spring cloud Alibaba

文章作者:小博

发布时间:2021年09月22日 - 21:13

最后更新:2021年09月22日 - 21:16

原始链接:https://codexiaobo.github.io/posts/3456049725/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。