Spring Cloud Alibaba旨在为微服务开发提供一站式解决方案。该项目包括开发分布式应用程序和服务所需的组件,以便开发人员可以使用Spring Cloud编程模型轻松开发分布式应用程序。使用Spring Cloud Alibaba,您只需要添加一些注释和配置,就可以为您的应用程序使用Alibaba的分布式解决方案,并使用Alibaba中间件构建自己的分布式系统。
Spring Cloud Alibaba其实是阿里的微服务解决方案,是阿里巴巴结合自身微服务实践,开源的微服务全家桶,在Spring Cloud项目中孵化成为Spring Cloud的子项目。第一代的Spring Cloud标准中很多组件已经停更,如:Eureak,zuul等。所以Spring Cloud Alibaba很有可能成为Spring Cloud第二代的标准实现,所以许多组件在业界逐渐开始使用,已有很多成功案例。
值得一提的是Spring Cloud Alibaba对Dubbo做了很好的兼容,同时也提供了一些强大的功能,如 Sentinel 流控 ,Seata 分布式事务,Nacos 服务发现与注册等等。
Spring Cloud Alibaba是阿里巴巴结合自身的微服务实践开源的微服务全家桶,我个人觉得其组件比Spring Cloud 中的组件更加好用和强大。并且对的Spring Cloud组件做了很好的兼容。比如在Spirng Cloud Alibaba中依然可以使用Feign作为服务调用方式,使用Eureak做服务注册发现等等。Spring Cloud Alibaba主要的功能如下:
流控制和服务降级:支持WebServlet,WebFlux,OpenFeign,RestTemplate,Dubbo访问限制和降级流的功能。它可以在运行时通过控制台实时修改限制和降级流的规则,并且还支持监视限制和降级度量标准。
服务注册和发现:可以注册服务,并且客户可以使用Spring托管的bean(自动集成功能区)发现实例。
分布式配置:支持分布式系统中的外部配置,配置更改时自动刷新。
Rpc服务:扩展Spring Cloud客户端RestTemplate和OpenFeign以支持调用Dubbo RPC服务。
事件驱动:支持构建与共享消息系统连接的高度可扩展的事件驱动微服务。
分布式事务:支持高性能且易于使用的分布式事务解决方案。
阿里云对象存储:大规模,安全,低成本,高度可靠的云存储服务。支持随时随地在任何应用程序中存储和访问任何类型的数据。
阿里云SchedulerX:准确,高度可靠,高可用性的计划作业调度服务,响应时间在几秒钟内。
阿里云短信:阿里云短信服务覆盖全球,提供便捷,高效,智能的通信功能,帮助企业快速联系客户。
Nacos和Eureka有着相同的能力,甚至更为强大,作为Dubbo 生态系统中重要的注册中心实现。官方对它有如下定义:
Nacos致力于帮助您发现,配置和管理微服务。它提供了一组简单有用的功能,使您能够实现动态服务发现,服务配置,服务元数据和流量管理。 Nacos使构建,交付和管理微服务平台变得更容易,更快捷。它是通过微服务或云原生方法支持以服务为中心的现代应用程序体系结构的基础架构。
这里我们看到Nacos不仅是服务发现组件,同时也是一个配置管理组件,也就是说它不仅可以用来取代Eureak作为注册中心, 也可以用来取代Spring Cloud Config 做配置统一管理。本篇文章意在探讨Nacos的服务注册与发现功能。
官方提供了Nacos的服务端供我们下载使用,我们启动Nacos后将我们的微服务注册进入Nacos即可。
下载地址:https://github.com/alibaba/nacos/releases
启动Nacos:解压后,
windows执行bin目录下的startup命令 :startup.cmd -m standalone
linux 执行 :sh startup.sh -m standalone
访问Nacos,端口8848:http://127.0.0.1:8848/nacos/index.html ,用户名和密码都是:nacos
我们这里要演示的案例是两个服务的通信,用户服务(user-server)作为服务提供者需要编写接口返回User实体对象,订单服务(order-server)作为消费者需要调用用户服务获取User实体对象,浏览器调用订单服务,订单服务调用用户服务或到User实体后返回给容器,用户和订单都注册到Nacos中,如下:
父工程搭建 搭建父工程springcloudalibaba-parent并管理相关依赖,Spring boot版本为2.1.3.RELEASE,Spring Cloud 版本为Greenwich.SR1,Alibaba版本为2.1.0.RELEASE ,父工程的pom如下:
UTF-8 UTF-8 1.8 org.springframework.boot spring-boot-starter-parent2.2.5.RELEASE com.alibaba.cloud spring-cloud-alibaba-dependencies2.2.1.RELEASE pom import org.springframework.cloud spring-cloud-dependenciesHoxton.SR3 pom import junit junit4.12
修改springcloudalibaba-service-user-1100导入服务发现依赖
com.alibaba.cloud spring-cloud-starter-alibaba-nacos-discoveryorg.springframework.boot spring-boot-starter-web
创建配置类加上@EnableDiscoveryClient注解开启服务发现功能,代码如下
//服务注册与发现 @SpringBootApplication @EnableDiscoveryClient public class UserServerApplication1010 { public static void main(String[] args) { SpringApplication.run(UserServerApplication1010.class) ; } }
配置文件主要配置端口,服务名,已经nacos注册中心地址
server: port: 1010 spring: application: name: user-server cloud: nacos: discovery: server-addr: 127.0.0.1:8848 #注册中心地址
启动服务提供者,观察Nacos服务列表 , user-server已经注册进去了
服务通信可以使用Ribbon,OpenFeign,甚至Dubbo,使用方式和在SpirngCloudNetflix中没有任何区别。
Nacos作为Spring Cloud Alibaba的一个重要组件,它不仅可以用作服务注册与发现,也可以用来替代Spring Cloud Config作为统一配置文件管理,而且他的使用更为简单和人性化。
第一步:打开Nacos监控面板 - 进入配置列表 -点击 “+” 图标添加配置 如下:
第二步:填写Data ID,选择YAML,编辑配置文件内容
这里定义了一个名字为application-user-dev.yaml的配置,使用的是YAML格式。
Data ID : 非常重要,可以看做是配置的文件的名字,在程序中拉取配置文件的时候需要指定Data ID。
Group : 分组,默认是 DEFAULT_GROUP , 可以针对不同的项目指定不同的配置组。
修改工程 springcloudalibaba-service-user-1100 ,添加配置中心依赖nacos-config,完整pom.xml如下。
com.alibaba.cloud spring-cloud-starter-alibaba-nacos-configcom.alibaba.cloud spring-cloud-starter-alibaba-nacos-discoveryorg.springframework.boot spring-boot-starter-weborg.example springcloudalibaba-user-common1.0-SNAPSHOT
下面的Controller用来做配置刷新测试,temp.notify对应了配置文件中的配置项目。@RefreshScope注解是用来做配置自动刷新。那么当我们修改了Nacos中的配置文件,Controller中读取到的配置temp.notify将会自动变化。
@RefreshScope //刷新配置 @RestController public class UserController { @Value("${temp.notify}") private String notify; @GetMapping("/user/{id}") public User getById(@PathVariable Long id){ System.out.println("测试配置notify="notify); return new User(id,"zs:"+id, "我是zs"); } }
注意,将原来的配置文件修改成bootstrap.yml,然后增加如下内容:
server: port: 1010 spring: profiles: active: dev application: name: service-user cloud: nacos: discovery: server-addr: localhost:8848 #注册中心 config: server-addr: localhost:8848 #配置中心 file-extension: yaml #配置文件格式 prefix: application-user #配置前缀 ,默认使用sring.application.name group: DEFAULT_GROUP #默认分组 #如何查找配置文件:application-user + dev + yaml=application-user-dev.yaml 正好和Nacos配置的DataId一致
启动Nacos,启动 springcloudalibaba-service-user 工程 , 修改Nacos中的配置文件内容,然后访问 http://localhost:1100/user/11 ,观察控制台打印的 “notify”的值会发生变化。
限流 , 限制流量,这里的流量我们可以理解成请求数量,其实就是限制服务器的请求并发数量,为什么要这么做?如果不做限流,那么在大量并发请求下我们的服务器会慢慢的变慢然后顶不住压力而挂掉(类似堵车)。并不是说并发越大越好,有的时候我们的项目规模和业务决定了我们不需要那么大的并发性,当大量的并发请求访问到服务器时我们需要把部分请求拒绝在外,这个是流量限制 - 限流。
熔断机制在在《Spring Cloud 极简入门》中有详细的解释,熔断机制是对服务调用链路的保护机制,如果链路上的某个服务不可访问,调用超时,发生异常等,服务会进行发熔断,触发降级返回托底数据。简单理解就是当服务器不可访问,可以返回一些预先准备好的兜底数据给用户,比如友好的提示信息,不至于直接向客户抛出异常。
Hystrix相比Sentinel来说它的线程池隔离(限流)会造成线程上下切换对资源的消耗比较大;Hystrix使用的信号量进行资源的隔离效果不错,但是无法对慢调用进行自动降级。
Sentinel诞生于阿里巴巴,其主要目标是流量控制和服务熔断,2018年,Sentinel演变为一个开源项目现如今成为了Spring Cloud Alibaba的一个子项目。Sentinel是通过限制并发线程的数量来减少不稳定资源的影响,而不是使用线程池,省去了线程切换的性能开销。
当资源的响应时间变长时,线程将开始被占用。当线程数累积到一定数量时,新的传入请求将被拒绝。反之亦然,当资源恢复并变得稳定时,占用的线程也将被释放,新请求将被接受。
除了限制并发性外,Sentinel可以根据响应时间降级不稳定资源也是保证可靠性的有效方法。当资源的响应时间太大时,将在指定的时间窗口中拒绝所有对该资源的访问。-- 熔断机制
此外,Sentinel支持的熔断降级维度更多,可对多种指标进行流控、熔断,且提供了实时监控和控制面板,功能更为强大。
Sentinel 提供了现成的服务端供我们使用,点我下载地址,下载之后通过命令行启动
java -jar -Dserver.port=1111 sentinel-dashboard-1.6.0.jar
访问:http://127.0.0.1:1111 进入控制台,使用 sentinel/sentinel登录。
修改用户服务 springcloudalibaba-service-user ,加入sentinel依赖
com.alibaba.cloud spring-cloud-starter-alibaba-sentinel
修改yml配置,添加senticel服务控制台地址
spring: cloud: sentinel: transport: dashboard: localhost:1111
Sentinel为我们提供了 @SentinelResource 注解标记需要限流的资源。 修改UserController,代码如下:
@GetMapping("/user/{id}") //限流降级 @SentinelResource(value="user",blockHandler="exceptionHandler") public User getById(@PathVariable Long id){ System.out.println(notify); return new User(id,"zs:"+id, "我是zs"); } // 限流与阻塞处理 : 参数要和 被降级的方法参数一样 public User exceptionHandler(@PathVariable Long id, BlockException ex) { ex.printStackTrace(); System.out.println("限流了..."); return new User(-1L,"限流了","限流了"); }
当然,也可以通过 blockHandlerClass 属性把降级方法写在一个专门的类中,如:
@SentinelResource(value="user",blockHandler="exceptionHandler" ,blockHandlerClass=ExceptionUtil.Class)
降级类
public final class ExceptionUtil { public static User exceptionHandler(Long id ,lockException ex) { //... } }
启动应用 springcloudalibaba-service-user-1100,然后通过浏览器访问 http://localhost:1100/user/11 ,然后登录Sentinel控制台,在“实时监控”列表中可以看到资源的相关监控信息的
在 “族点链路” 列表中可以看到资源的调用链 ,并且可以通过“流控”按钮设置流控规则
也可以在“流量控制”菜单中我们可以针对资源进行限流规则的设置。如下:
这里我添加了一个流控规则,资源名对应客户端 @SentinelResource(value="user".. 注解的资源,通过QPS限流(每秒请求数量),阈值是 1 ,意思是“user”这个资源每秒只能有1个请求进来,多余的请求会触发限流,返回降级数据。
通过浏览器频发访问 “user”资源,当QPS大于1就会触发限流,效果如下:
Spring Cloud Gateway 作为微服务的网关,它是微服务的访问入口,当请求的流量洪峰到来我们可以在Gateway网关层通过Sentinel对请求进行流控,把好第一道关。
com.alibaba.cloud spring-cloud-alibaba-sentinel-gatewaycom.alibaba.cloud spring-cloud-starter-alibaba-sentinel
spring: cloud: sentinel: transport: dashboard: localhost:1111
启动Gateway,登录sentinel控制台,对url资源进行流控限制,配置方式和前面的配置方式一样
@Configuration public class SentinelConfig { public SentinelConfig(){ GatewayCallbackManager.setBlockHandler(new BlockRequestHandler() { @Override public MonohandleRequest(ServerWebExchange serverWebExchange, Throwable throwable) { return ServerResponse.ok().body(Mono.just("限流啦,请求太频繁"),String.class); } }); } }
在前两章节我们学习了通过Sentinel的限流和熔断机制来保护微服务,提高系统的可用性,但是有一个问题,我们在Sentinel配置了限流,熔断策略,默认情况下Sentinel的数据是基于内存存储,当客户端断开,或者Sentinel重启数据就会丢失,这不是我们愿意看到的。所有我们需要的Sentinel做数据持久。 Sentinel 中支持5种持久化的方式:file、redis、nacos、zk和apollo,本片文章针对于Nacos进行持久化配置。
第一步:导入基础依赖,springcloudalibaba-service-user-1100为例子,修改pom增加Sentinel和Nacos持久化配置依赖 sentinel-datasource-nacos ,如下:
org.springframework.boot spring-boot-starter-weborg.springframework.cloud spring-cloud-starter-alibaba-sentinelcom.alibaba.csp sentinel-datasource-nacos1.5.2
第二步:配置持久化nacos地址
spring: application: name: user-server cloud: nacos: config: #配置中心 server-addr: localhost:8848 file-extension: yaml prefix: application-user sentinel: #限流服务器sentinel配置 transport: dashboard: localhost:1111 #====================持久化配置================================= datasource: flow: nacos: #限流持久配置 server-addr: localhost:8848 #使用nacos的持久 dataId: application-user-dev #获取限流的数据源的dataId groupId: DEFAULT_GROUP rule-type: flow #类型:限流 #===================================================== profiles: active: dev
第三步:编写测试用的Controller这个controller我们待会用来做限流测试
@RestController public class TempController { @GetMapping("/hello") public String hello() { return "测试数据"; } }
第一步:在配置列表增加配置如下:
[ { "resource": "/hello", "limitApp": "default", "grade": 1, "count": 10, "strategy": 0, "controlBehavior": 0, "clusterMode": false } ]
resource:对那个资源进行限流
limitApp:这个是流控的调用者,default 代表不区分调用者
grade:限流方式0是根据并发数量限流,1是表根据QPS来限流
count:限流阈值,达到这个阈值就被限流,触发降级。
strategy:基于调用链的流控制策略。0 直接,1 关联 2 链路
controlBehavior:流控效果,0 直接拒绝,1是Warm Up,2是匀速排队
clusterMode:是否为集群
上面的配置项目对应了 com.alibaba.csp.sentinel.slots.block.flow.FlowRule 限流规则类。程序启动,Sentinel通过 NacosDataSource 从Nacos中查找配置。具体效果如:
第二步:启动测试 ,启动springcloudalibaba-service-user-1100 ,向 /hello 资源发起访问,然后观察Sentinel控制台流控规则是否有了一条限流策略。
第一步:在Nacos配置列表增加文件 如:application-user-degrade-dev ,内容如下
[ { "resource": "GetUserByID", "grade": 0, "count": 10, "timeWindow": 5 } ]
resources : 资源名
grade : 慢调用比例 0 ;异常比例 1 ;异常数 2;
count : 最大RT,最大平均响应时间
timeWindow :时间窗口,即熔断时长
第二步:项目中增加配置
spring: application: name: service-user cloud: sentinel: datasource: flow: #限流的配置 nacos: #限流持久配置 server-addr: 127.0.0.1:8848 #使用nacos的持久 dataId: application-user-sentinal-dev #获取限流的数据源的dataId groupId: DEFAULT_GROUP rule-type: flow #类型:限流 ##================================================================== degrade: #降级的配置 nacos: server-addr: 127.0.0.1:8848 dataId: application-user-degrade-dev groupId: DEFAULT_GROUP rule-type: degrade
第三步:启动测试,观察sentinel的熔断规则列表
在上一章节我们探讨了Sentinel的流控(限流)功能,Sentinel除了流控还提供了服务熔断和降级机制,服务之间的调用关系错综复杂,微服务的调用链上的某些服务资源不稳定(宕机,异常,超时)可能会导致可能请求的失败和请求的堆积,调用链产生连锁反应可能会导致整个微服务架构瘫痪。服务熔断降级机制是保障高可用的重要措施之一。
Sentinel的服务熔断机制会对调用链上的某个不稳定(宕机,异常,超时)的资源,做出请求限制,快速失败,避免影响到其它的服务而导致级联错误。资源熔断后,在后续的一定时间(时间窗口)之内,对该服务的请求都自动熔断,抛出 DegradeException异常。
Sentinel拥有比Hystrix更强大和丰富的功能,能满足我们的各种应用场景,并且经历过淘宝双十一的考验,是微服务架构中熔断机制的不二选择。
// 限流降级 public User exceptionHandler(@PathVariable Long id, BlockException ex) { ex.printStackTrace(); System.out.println("限流了..."); return new User(-1L,"限流了","限流了"); } // 熔断降级,参数和返回值与源方法一致 public User getByIdfallback(@PathVariable Long id){ System.out.println(notify); return new User(id,"zs:"+id, "熔断托底了"); } @GetMapping("/user/{id}") //限流降级 @SentinelResource(value="user",blockHandler="exceptionHandler",fallback = "getByIdfallback") public User getById(@PathVariable Long id){ int i = 1 / 0; //方法异常,触发熔断 return new User(id,"zs:"+id, "我是zs"); }
在Sentinel控制台,在族点链路菜单中找到“user”资源,然后点击“降级”按钮添加降级策略,如下:
启动springcloudalibaba-service-user-1100工程,访问 http://localhost:1100/user/2 ,浏览器返回:
Spring Cloud Alibaba是Spring Cloud的一个子项目,OpenFeign是Spring Cloud的客户端负载均衡器,使用Spring Cloud Alibaba依然可以很方便的集成OpenFeign,如果要使用OpenFeign作为服务客户端负载均衡,那么我们需要考虑OpenFeign开启Sentinel进行服务熔断降级。
OpenFeign与Sentinel组件集成除了引入sentinel-starter依赖关系之外,还需要在属性文件中启用Sentinel支持:feign.sentinel.enabled=true
feign: sentinel: enabled: true #熔断
这里跟Feign开启Hystrix降级一样,还是可以使用fallback属性
@FeignClient(value = "user-server",fallback = UserClientFallback.class) public interface UserClient { @GetMapping("/user/{id}") User getById(@PathVariable Long id); }
@Component public class UserClientFallback implements UserClient { @Override public User getById(Long id) { return new User(-1L,"无此用户","无此用户"); } }