
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 的版本号是用伦敦地铁站站名标记的版本、因为错综复杂、用数字标记不是太友好
依赖关系
spring boot  –>   spring cloud   –>   spring cloud alibaba
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>                          <dependency>                 <groupId>org.springframework.cloud</groupId>                 <artifactId>spring-cloud-dependencies</artifactId>                 <version>Hoxton.SR3</version>                 <type>pom</type>                 <scope>import</scope>             </dependency>                          <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>
   | 
 
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>
 
          <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
   | spring:   cloud:     nacos:       discovery:         server-addr: localhost:8848 
    application:     name: provider 
  server:   port: 8082 
   | 
 

Nacos 服务发现
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>
 
          <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 {
      
 
      @Autowired     private DiscoveryClient discoveryClient;
      
 
 
      @GetMapping("/instances")     public List<ServiceInstance> instances(){
                   List<ServiceInstance> provider = this.discoveryClient.getInstances("provider");
          return provider;     } }
   | 
 
Nacos 服务调用
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 {
      
 
      @Autowired     private DiscoveryClient discoveryClient;
           @Autowired     private RestTemplate restTemplate;
      
 
 
      @GetMapping("/instances")     public List<ServiceInstance> instances(){
                   List<ServiceInstance> provider = this.discoveryClient.getInstances("provider");
          return provider;     }
      @GetMapping(value = "/index")     public String index(){
                   List<ServiceInstance> list = this.discoveryClient.getInstances("provider");
                   int index = ThreadLocalRandom.current().nextInt(list.size());
                   ServiceInstance serviceInstance = list.get(index);
                   URI uri = serviceInstance.getUri();
                   log.info("调用的端口是:" + serviceInstance.getPort());
                   return "调用的端口是"+serviceInstance.getPort() + "uri是:" + serviceInstance.getUri();     } }
   | 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14
   | @Configuration public class ConsumerConfiguration {
      
 
 
      @Bean     public RestTemplate restTemplate(){
                   return new RestTemplate();     } }
   | 
 
这里只实现了简单的调用、并没有太多的起到负载均衡、这里面的随机数相当于了负载均衡
Ribbon 负载均衡
Ribbon 不是spring Alibaba的组件、是Netfilx的、底层是RestTemplate、用的是轮询算法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
   | @Configuration public class ConsumerConfiguration {
      
 
 
      @Bean     @LoadBalanced     public RestTemplate restTemplate(){
                   return new RestTemplate();     } }
   | 
 
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
 
  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();                  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
   |  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的使用方法
下载相应的jar、用于启动Sentinel、然后运行下载的jar即可

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>
 
  | 
 
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      sentinel:       transport:         dashboard: localhost:8080        filter:         enabled: false    application:     name: provider 
  server:   port: 8082 
  management:   endpoints:     web:       exposure:         include: "*" 
   | 
 
效果图

流量规则

直接流控
直接将其访问的方法加入阈值
  
关联流控
关联阈值是关联别的方法、简单点说就是别人做事我背锅、例如关联一个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);         }     } }
  | 
 

链路流控
链路流控其实就是控制service层、但是service不能直接被访问、所以要和调用的Controller进行关联
1 2 3 4 5 6 7 8 9 10 11
   |          <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>
 
  | 
 
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;     } }
   | 
 
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";     } }
 
   | 
 
1 2 3 4 5 6 7 8 9 10
   | @Service public class ProviderService {
           @SentinelResource     public void test(){
          System.out.println("test");     } }
   | 
 
流量效果
直接失败
直接抛出异常、没什么附加功能
warm up
warm up就会在系统刚开始的性能比较低、举个例子就好比一个业务员刚上班、可能状态不是很好、所以他会在刚开始的时候只接受一个人办理业务、过了一会他可能状态适应了、会一个人接受多个人同时办理业务、这里大家可以想一下抢购、抢购业务用的可能就是这个

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

 
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当中、所以不会请求成功、而会抛出异常
- 成功

 
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());     } }
  | 
 
正确的开始、微小的长进、然后持续、嘿、我是小博、带你一起看我目之所及的世界……