简介

Spring Cloud Alibaba是阿里巴巴结合自身的微服务实践开源的微服务全家桶,我个人觉得其组件比Spring Cloud 中的组件更加好用和强大。并且对的Spring Cloud组件做了很好的兼容。比如在Spirng Cloud Alibaba中依然可以使用Feign作为服务调用方式,使用Eureak做服务注册发现等等。

主要功能

1.服务注册和发现(nacos):可以注册服务,并且客户可以使用Spring托管的bean(自动集成功能区)发现实例。注册中心。

2.分布式配置(nacos):支持分布式系统中的外部配置,配置更改时自动刷新。 配置中心

3.流控制和服务降级(Sentinel ):支持WebServlet,WebFlux-->(比Springmvc更高级)OpenFeign,RestTemplate,Dubbo访问限制和降级流的功能。它可以在运行时通过控制台实时修改限制和降级流的规则,并且还支持监视限制和降级度量标准。 - 服务熔断限流hystrix

4.Rpc服务:扩展Spring Cloud客户端RestTemplate(ribbon)和OpenFeign以支持调用Dubbo RPC服务。

5.分布式事务(seata):支持高性能且易于使用的分布式事务解决方案。

6.事件驱动:支持构建与共享消息系统连接的高度可扩展的事件驱动微服务。

7.阿里云对象存储:大规模,安全,低成本,高度可靠的云存储服务。支持随时随地在任何应用程序中存储和访问任何类型的数据。

8.阿里云SchedulerX:准确,高度可靠,高可用性的计划作业调度服务,响应时间在几秒钟内。

9.阿里云短信:阿里云短信服务覆盖全球,提供便捷,高效,智能的通信功能,帮助企业快速联系客户。

与奈飞对比

注册中心nacos

什么是nacos

Nacos致力于帮助您发现,配置和管理微服务。它提供了一组简单有用的功能,使您能够实现动态服务发现,服务配置,服务元数据和流量管理。Nacos使构建,交付和管理微服务平台变得更容易,更快捷。它是通过微服务或云原生方法支持以服务为中心的现代应用程序体系结构的基础架构。说的通俗一些,就是承担了奈飞框架中的Eureka的功能,相当于注册中心,但比Eureka更加智能与便捷。

如何安装nacos

官方提供了Nacos的服务端供我们下载使用,我们启动Nacos后将我们的微服务注册进入Nacos即可。

下载地址:[https://github.com/alibaba/nacos/releases]

启动nacos

nacos的启动也十分方便,在下载好的jar包目录下执行

- windows执行bin目录下的startup命令 :startup.cmd -m standalone 

- linux 执行 :sh startup.sh -m standalone

启动成功页面如下所示

 nacos的默认端口为8848,在启动成功后,用户即可访问nacos,访问地址为:(本地单机模式)http://127.0.0.1:8848/nacos/index.html

 登录的账号和密码均为:nacos

登录成功页面如图所示(笔者这里已经注册好了几个服务,故会有信息,第一次登录且未将服务注册到nacos的话,这里是没有信息的)

服务架构简单搭建

举例服务项目结构

微服务调用流程

Order-Service-20010提供订单的查询服务,Order-Client-30010调用Order-Service-20010提供的服务查询自身的订单信息,Order-Common作为公共服务,提供了相关实体类以及对应的无参有参构造方法

项目搭建

父工程的pom.xml

<!--公共的一些配置-->
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        
    </properties>

   <!--SpringBoot-->
    <parent>
        <groupId> org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.5.RELEASE</version>
    </parent>

    <!--SpringCloud-->
    <dependencyManagement>
        <dependencies>
            <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>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Hoxton.SR3</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
        <!--导入lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.12</version>
        </dependency>
    </dependencies>

服务注册到nacos

Order-Service-20010配置

添加依赖
 <dependency>
     <groupId>com.alibaba.cloud </groupId>
     <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
编写启动类 
@SpringBootApplication
@EnableDiscoveryClient
public class OrderServerStart {
    public static void main(String[] args) {
        SpringApplication.run(OrderServerStart.class);
    }
}
 编写配置文件yml
server:
  port: 20010
spring:
  application:
    name: Order-server
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
    

Order-Client-30010配置

添加依赖
<dependency>
     <groupId>com.alibaba.cloud </groupId>
     <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
编写启动类
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class OrderClientStart
{
    public static void main( String[] args )
    {
        SpringApplication.run(OrderClientStart.class);
    }
}
编写配置文件yml
server:
  port: 30010
spring:
  application:
    name: Order-client
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848

启动成功后,nacos当中便会看见注册成功的服务 

Nacos配置中心

客户端接入配置中心

概述

在《SpringCloud极简入门》中我们通过Spring Cloud Config作为统一配置文件管理中心,其实我们总结一下发现Spring Cloud Config使用起来总归比较麻烦。Nacos作为Spring Cloud Alibaba的一个重要组件,它不仅可以用作服务注册与发现,也可以用来替代Spring Cloud Config作为统一配置文件管理,而且他的使用更为简单和人性化。

如何实现

点击页面左上角的"+"按钮即可添加新的配置,不过需要注意的是,编写的后缀改为yaml,在项目中要将application.yml,修改为bootstrap.yml,并在内部进行相关的配置

导入依赖

<dependencies>
 <!--        配置中心客户端-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>
        
        <!-- 服务注册与发现-->
        <dependency>
            <groupId>com.alibaba.cloud </groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.example</groupId>
            <artifactId>springcloudalibaba-user-common</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>

配置Controller

@RefreshScope  //刷新配置
@RestController
public class UserController {

    @Value("${temp.notify}")
    private String notify;

    @GetMapping("/user/{id}")
    public User getById(@PathVariable Long id){
        User user = new User(id,"root"+notify ,null);
        return user;
    }
}

修改yml配置

以修改order-client的yml为例

server:
  port: 30010
spring:
  application:
    name: Order-client
  profiles:
    active: dev
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
      config:
        server-addr: 127.0.0.1:8848
        file-extension: yaml
        prefix: application-user
        group: DEFAULT_GROUP

测试

 root后多了一个1234,为什么呢?

因为笔者在nacos当中的配置文件中,定义了notify的值为1234,这样就表示配置中心配置成功

Sentinel限流控制

Sentinel和Hystrix

限流和熔断

限流 , 限制流量,这里的流量我们可以理解成请求数量,其实就是限制服务器的请求并发数量,为什么要这么做?如果不做限流,那么在大量并发请求下我们的服务器会慢慢的变慢然后顶不住压力而挂掉(类似堵车)。并不是说并发越大越好,有的时候我们的项目规模和业务决定了我们不需要那么大的并发性,当大量的并发请求访问到服务器时我们需要把部分请求拒绝在外,这个是流量限制 - 限流。

熔断机制在在[《Spring Cloud 极简入门》)中有详细的解释,熔断机制是对服务调用链路的保护机制,如果链路上的某个服务不可访问,调用超时,发生异常等,服务会进行发熔断,触发降级返回托底数据。简单理解就是当服务器不可访问,可以返回一些预先准备好的兜底数据给用户,比如友好的提示信息,不至于直接向客户抛出异常。

Hystrix的熔断和资源隔离

其实在[《Spring Cloud 极简入门》]中我们已经学习过Hystrix的熔断和资源隔离机制,它的资源隔离可以通过线程池隔离和信号量隔离两种方式来实现对流量的控制。Hystrix相比Sentinel来说它的线程池隔离(限流)会造成线程上下切换对资源的消耗比较大;Hystrix使用的信号量进行资源的隔离效果不错,但是无法对慢调用进行自动降级。

Sentinel定义

Sentinel诞生于阿里巴巴,其主要目标是流量控制和服务熔断,2018年,Sentinel演变为一个开源项目现如今成为了Spring Cloud Alibaba的一个子项目。Sentinel是通过限制并发线程的数量来减少不稳定资源的影响,而不是使用线程池,省去了线程切换的性能开销。

当资源的响应时间变长时,线程将开始被占用。当线程数累积到一定数量时,新的传入请求将被拒绝。反之亦然,当资源恢复并变得稳定时,占用的线程也将被释放,新请求将被接受。

除了限制并发性外,Sentinel可以根据响应时间降级不稳定资源也是保证可靠性的有效方法。当资源的响应时间太大时,将在指定的时间窗口中拒绝所有对该资源的访问。-- 熔断机制

此外,Sentinel支持的熔断降级维度更多,可对多种指标进行流控、熔断,且提供了实时监控和控制面板,功能更为强大。

Sentinel客户端接入

导入依赖

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

添加yml配置

spring:
  cloud:
    sentinel:
      transport:
        dashboard: localhost:1111

资源限流实现 

在Controller中添加一个Sentinelresource注解

 @SentinelResource(value = "getUser",blockHandler = "LimitResource")

value表示要进行限流的方法,blockHandler表示限流之后系统调用的方法

 完整代码:

@RefreshScope
@RestController
@RequestMapping("/user")
public class UserController {
    @Value("${temp.notify}")
    private String notify;
    @Autowired
    private OrderOpenFeignClient feignClient;
    //限制的资源
    @SentinelResource(value = "getUser",blockHandler = "LimitResource")
//    给资源取名user,后续通过名字来进行限流
    @GetMapping("/{id}")
    public User getUser(@PathVariable("id") Long id){
        //发起远程调用
        List<Order> orders =feignClient.getList(id);
        int i=new Random().nextInt(2);
        System.out.println(1/i);
        User user = new User(id,"root"+notify ,orders);
        return user;
    }
   
       public User LimitResource(@PathVariable("id") Long id,BlockException e){
           e.printStackTrace();
             return new User(-1L,"限流了",null);
   }
  
}

 如何设置限流

在sentinel的当前页面,点击对应资源的流控按钮,进行流控策略的配置。

 

这里单机阈值设置为1,表示1s内的访问量超过一次,则会触发限流效果。 系统便会执行自己设定的LimitResource方法,笔者这里便不附上运行截图了,配置十分简单,配置完成也不需要重启服务,直接进行接口访问压测即可。

Sentinel流控效果

快速失败

快速失败:(RuleConstant.CONTROL_BEHAVIOR_DEFAULT)是默认的流控方式,当流量达到阀值直接返回异常,QPS达到任何规则阈值后,后续请求就会立即拒绝,并抛出FlowException 异常。简单理解:并发太高,直接请求拒绝

warmup预热

Warm Up预热:(RuleConstant.CONTROL_BEHAVIOR_WARM_UP)方式,根据codeFactor(默认3)的值,从(阀值/codeFactor)为初始阀值,经过预热时长,才到达设置的QPS的阀值,即预热/冷启动方式。简单理解:慢慢的增大处理并发的能力

排队等待

排队等待(RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER),忽然增加的请求并发量达到了限流阈值后续请求会被拒绝,有时候我们可能更希望后续的请求可以加入队列进行排队,慢慢执行,而不是直接拒绝请求,这种方式后严格控制请求通过的时间间隔,也即是让请求以均匀的速度通过,对应的是漏桶算法,这种方式主要用于处理间隔性突发的流量,例如消息队列。 简单理解:突发流量处理不过来,让请求排队。

Sentinel熔断

概述

什么是熔断

Sentinel除了流控还提供了服务熔断和降级机制,服务之间的调用关系错综复杂,微服务的调用链上的某些服务资源不稳定(宕机,异常,超时)可能会导致可能请求的失败和请求的堆积,调用链产生连锁反应可能会导致整个微服务架构瘫痪。服务熔断降级机制是保障高可用的重要措施之一。

Sentinel熔断

Sentinel的服务熔断机制会对调用链上的某个不稳定(宕机,异常,超时)的资源,做出请求限制,快速失败,避免影响到其它的服务而导致级联错误。资源熔断后,在后续的一定时间(时间窗口)之内,对该服务的请求都自动熔断,抛出 DegradeException异常。Sentinel拥有比Hystrix更强大和丰富的功能,能满足我们的各种应用场景,并且经历过淘宝双十一的考验,是微服务架构中熔断机制的不二选择。

熔断规则

平均响应RT

平均响应时间 (DEGRADE_GRADE_RT):当资源的平均响应时间超过阈值(DegradeRule 中的 count,以 ms 为单位)之后,资源进入准降级状态。如果接下来 1s 内持续进入 5 个请求(即 QPS >= 5),它们的 RT 都持续超过这个阈值,那么在接下的时间窗口(DegradeRule 中的 timeWindow,以 s 为单位)之内,对这个方法的调用都会自动地熔断(抛出 DegradeException)。注意 Sentinel 默认统计的 RT 上限是 4900 ms,超出此阈值的都会算作 4900 ms,若需要变更此上限可以通过启动配置项 -Dcsp.sentinel.statistic.max.rt=xxx 来配置。

异常比例 

异常比例(DEGRADE_GRADE_EXCEPTION_RATIO):每秒请求量 > 5 ,当资源的每秒异常总数占通过量的比值超过阈值(DegradeRule 中的 count)之后,资源进入降级状态,即在接下的时间窗口(DegradeRule 中的 timeWindow,以 s 为单位)之内,对这个方法的调用都会自动地返回。异常比率的阈值范围是 [0.0, 1.0],代表 0% - 100%。

异常数 

异常数 (DEGRADE_GRADE_EXCEPTION_COUNT):当资源近 1 分钟的异常数目超过阈值之后会进行熔断。注意由于统计时间窗口是分钟级别的,若 timeWindow 小于 60s,则结束熔断状态后仍可能再进入熔断状态。

慢调用比例

熔断策略慢调用比例是以慢调用数量的比例作为阈值,首先需要设置最大 RT(即最大的响应时间,用于鉴定是否是慢调用),请求的响应时间大于该值则统计为慢调用。当单位统计时长(statIntervalMs)内请求数大于设置的最小请求数,并且慢调用的比例大于比例阈值,则接下来的请求会自动熔断,熔断时间为设置的熔断时长。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若在HALF-OPEN状态下有一个请求响应时间小于 最大RT 则结束熔断,否则继续熔断。

熔断实战示例

导入依赖

 <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

配置yml

feign:
  sentinel:
    enabled: true #熔断

配置OpenFeign

接口

@FeignClient(value = "Order-server")
public interface OrderOpenFeignClient {
    @GetMapping("/order/{id}")
    public List<Order> getList(@PathVariable("id") Long id);
}

 熔断返回fallback

@Component
public class UserFallBack implements FallbackFactory<OrderOpenFeignClient> {
   @Override
   public OrderOpenFeignClient create(Throwable throwable) {
       return id ->Arrays.asList(new Order(-2L,"服务暂时不可用","请您稍后再试"));
    }
}

修改Controller

在SentinelResource中添加相关属性值

Controller完整代码

@RefreshScope
@RestController
@RequestMapping("/user")
public class UserController {
    @Value("${temp.notify}")
    private String notify;
    @Autowired
    private OrderOpenFeignClient feignClient;
    //限制的资源
    @SentinelResource(value = "getUser",blockHandler = "LimitResource",blockHandlerClass = UserFallback.class,
    fallback = "Error")
//    给资源取名user,后续通过名字来进行限流
    @GetMapping("/{id}")
    public User getUser(@PathVariable("id") Long id){
        //发起远程调用
        List<Order> orders =feignClient.getList(id);
        int i=new Random().nextInt(2);
        System.out.println(1/i);
        User user = new User(id,"root"+notify ,orders);
        return user;
    }
    //方案1
//    public User LimitResource(@PathVariable("id") Long id,BlockException e){
//        e.printStackTrace();
//        return new User(-1L,"限流了",null);
//    }
    public User Error(@PathVariable("id") Long id){
        return new User(-1L,"熔断数据集",null);
    }
}

因为在这里,写了一个Error方法,并且在SentinelResource中添加了fallback="Error"所以fallback返回的将是Error的内容。 

测试结果:

写在最后:

SpringCloudAlibaba是一款优秀的微服务架构,在市面上有着广泛的应用。这篇文章介绍了SpringCloudAlibaba的一些基本使用,适合初学者,希望能够给大家带来帮助。笔者小,中,大厂均有面试经验,目前正在从事全栈开发工作,坚持每日分享java全栈开发知识与相关的面试真题,希望能够给大家带来帮助,同大家共同进步 

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐