一、背景

  • 身为Java程序员,微服务是必须要掌握的一种架构。Spring Cloud作为提供微服务架构的完整技术生态链,给我们提供了非常多的框架与组件。其中的重要成员Spring Cloud Netflix也形成了一系列的技术栈:包括服务注册与发现(Eureka),断路器(Hystrix),智能路由(Zuul)和客户端负载平衡(Ribbon)等。
  • 但不幸的是Spring Cloud Netflix的技术栈相继宣布进行维护阶段:



二、初识Spring Cloud Alibaba

  • 做为国内互联网大厂的阿里巴巴,在开源领域的成就有目共睹。
  1. 2016 年,阿里全面拥抱 Spring Boot;
  2. 2017 年 12 月,Spring Cloud Alibaba 立项并顺利进入 Spring Cloud 孵化器。
  3. 2019 月 10 月 3 日,Spring Cloud Alibaba 正式 "挂牌" Spring 官方。

    关于Spring Cloud Alibaba的孵化过程具体可参考:《Spring Cloud Alibaba 从孵化到 "挂牌" 之旅》

同 Spring Cloud 一样,Spring Cloud Alibaba 也是一套微服务解决方案,包含开发分布式应用微服务的必需组件,方便开发者通过 Spring Cloud 编程模型轻松使用这些组件来开发分布式应用服务。

(图片来源:阿里云云栖号)

  • 做为微服务生态圈中冉冉升起的一颗新星,我们有理由去了解并掌握Spring Cloud Alibaba的各个技术栈。本文也将通过项目工程演练的方式对Spring Cloud Alibaba中的服务治理组件Nacos与高可用防护组件Sentinel进行基础实践。

三、Nacos的基础实践

  • 在2018年 6 月份 Aliware 技术行上海站 Dubbo 开发者沙龙上,阿里巴巴高级技术专家郭平 (坤宇) 宣布了阿里巴巴的一个新开源项目 Nacos。

Nacos 支持几乎所有主流类型的“服务”的发现、配置和管理:

  1. Kubernetes Serviceg
  2. RPC & Dubbo RPC Service
  3. Spring Cloud RESTful Service

    Nacos生态图(来自Nacos官网)

3.1 安装Nacos并启动服务

  • 获取Nacos安装文件并进行解压
# 下载nacos最新版
wget https://github.com/alibaba/nacos/releases/download/1.3.2/nacos-server-1.3.2.tar.gz
# 解压文件
tar -xvf nacos-server-1.3.2.tar.gz
# 通过nacos-mysql.sql脚本建立数据库
cd nacos/conf
vim nacos-mysql.sql
  • 建立Nacos配置数据库
 /******************************************/
/* 数据库全名 = nacos_config */
/* 表名称 = config_info */
/******************************************/
CREATE TABLE `config_info` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
`data_id` varchar(255) NOT NULL COMMENT 'data_id',
`group_id` varchar(255) DEFAULT NULL,
`content` longtext NOT NULL COMMENT 'content',
`md5` varchar(32) DEFAULT NULL COMMENT 'md5',
`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
`src_user` text COMMENT 'source user',
`src_ip` varchar(20) DEFAULT NULL COMMENT 'source ip',
`app_name` varchar(128) DEFAULT NULL,
`tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段',
`c_desc` varchar(256) DEFAULT NULL,
`c_use` varchar(64) DEFAULT NULL,
`effect` varchar(64) DEFAULT NULL,
`type` varchar(64) DEFAULT NULL,
`c_schema` text,
PRIMARY KEY (`id`),
...

  • 修改配置文件
 cd nacos/conf
# 编辑配置文件
vim application.properties #*************** Spring Boot Related Configurations ***************#
### Default web context path:
server.servlet.contextPath=/nacos
### Default web server port:
server.port=8848 #*************** Network Related Configurations ***************#
### If prefer hostname over ip for Nacos server addresses in cluster.conf:
# nacos.inetutils.prefer-hostname-over-ip=false ### Specify local server's IP:
# nacos.inetutils.ip-address= #*************** Config Module Related Configurations ***************#
### If use MySQL as datasource:
spring.datasource.platform=mysql ### Count of DB:
db.num=1 ### Connect URL of DB:
db.url.0=jdbc:mysql://127.0.0.1:3306/nacos_config?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC
db.user=root
db.password=root
  • 运行nacos
cd nacos/bin
# 单机运行
sh startup.sh -m standalone
  • 登录nacos控制台

3.2 建立微服务并向Nacos注册服务

  • 建立微服务工程项目



  • 勾选Nacos Service Discovery依赖

  • 打开pom.xml,下载依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.9.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>nacos.democonsumer</groupId>
<artifactId>sentinel</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>sentinel</name>
<description>Demo project for Spring Boot</description> <properties>
<java.version>1.8</java.version>
<spring-cloud-alibaba.version>2.2.1.RELEASE</spring-cloud-alibaba.version>
</properties> <dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</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-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies> <dependencyManagement>
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring-cloud-alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement> <build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build> </project>
  • 设置项目配置文件:application.yml
# 端口
server:
port: 8083 spring:
application:
name: goods-service
cloud:
# nacos服务注册
nacos:
discovery:
server-addr: 172.16.109.118:8848
  • 通过 Spring Cloud Alibaba原生注解 @EnableDiscoveryClient 开启服务注册发现功能
// 通过 Spring Cloud 原生注解 @EnableDiscoveryClient 开启服务注册发现功能
@EnableDiscoveryClient
@SpringBootApplication
public class DemoServiceApplication { public static void main(String[] args) { SpringApplication.run(DemoServiceApplication.class, args);
} }
  • 建立HTTP接口的商品信息微服务,模拟返回商品列表
/**
* 商品信息微服务-模拟返回商品列表
*/
@RestController
@RequestMapping("api/goods")
public class GoodsService {
public static final Logger logger = LoggerFactory.getLogger(GoodsService.class);
// 返回商品列表
@GetMapping
public List<Goods> getAllGoods(HttpServletRequest httpServletRequest) {
List<Goods> goods = new ArrayList<>();
goods.add(new Goods("电脑", 10));
goods.add(new Goods("手机", 20));
goods.add(new Goods("书籍", 30));
logger.info("服务被调用:"+httpServletRequest.getRequestURI());
return goods;
} }
  • 启动微服务程序

  • 查看Nacos控制台的服务中心列表,可以看到商品信息微服务已在Nacos注册成功

3.3 建立微服务消费者进行服务调用

  • 仿照以上3.2小节建立微服务提供者步骤,建立服务消费者工程项目;
  • 打开pom.xml,下载依赖
...
<!-- 加入Nacos Discovery Client 依赖 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
...
  • 项目配置:application.yml
# 端口
server:
port: 8090
# Spring配置
spring:
application:
name: user-consumer
cloud:
nacos:
discovery:
server-addr: 172.16.109.118:8848
enabled: true # 调用微服务超时时间设置
ribbon:
ConnectTimeout: 5000
ReadTimeout: 5000 # feign日志以什么级别监控哪个接口
logging:
level:
nacos.democonsumer.GoodService : debug
# 商品微服务地址
service:
url=http://goods-service/
  • 通过 Spring Cloud Alibaba原生注解 @EnableDiscoveryClient 开启服务发现功能,并向Spring注册一个RestTemplate Bean
@EnableDiscoveryClient
@SpringBootApplication
public class DemoConsumerApplication { // 向Spring注册一个RestTemplate Bean
@Bean
// 负载均衡
@LoadBalanced
RestTemplate restTemplate(){
return new RestTemplate();
} public static void main(String[] args) {
SpringApplication.run(DemoConsumerApplication.class, args);
}
}
  • 创建Restful测试接口,通过该测试接口可发现并调用Nacos中注册的商品信息微服务
/**
* 用户消费者--调用nacos服务中心的商品信息微服务,并对外提供RestFul接口测试
*/
@RestController
@RequestMapping("user/")
public class UserConsumer { @Autowired
private RestTemplate restTemplate; @Value("${service.url}")
private String url; @GetMapping("/goods")
public User getUserGoods() {
User user = new User();
// 调用商品微服务
Object response = restTemplate.getForEntity(url + "api/goods", Object.class).getBody();
try {
user.setName("jack");
user.setGoods((List<GoodsDTO>) response);
} catch (Exception e){
throw new RuntimeException(e.getMessage());
}
return user;
}
}
  • 运行服务消费者程序,并打开HttpClient工具进行测试



3.4 Nacos小结

  • Spring Cloud Alibaba 的Nacos组件可以完美取代Eureka做为微服务发现及注册的基础框架。
  • 通过Nacos特性大图中,我们还可以了解到,Nacos除了服务发现的框架,还能做到配置管理,DNS服务等功能。

四、Sentinel的基础实践

4.1 安装Sentinel监控

 # 下载服务端
wget https://github.com/alibaba/Sentinel/releases/download/v1.8.0/sentinel- dashboard-1.8.0.jar
# 启动服务(默认端口为8080)
java -jar sentinel-dashboard-1.8.0.jar
  • 登录控制台,默认用户名与密码为sentinel



4.2 通过Sentinel对微服务提供方进行流量控制

  • 对原有商品信息微服务提供者增加Sentinel依赖
<project>
...
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
...
</project>
  • 修改项目配置文件application.yml增加Sentinel控制台地址
server:
port: 8083 spring:
application:
name: goods-service
cloud:
# nacos服务注册
nacos:
discovery:
server-addr: 172.16.109.118:8848
# sentinel服务
sentinel:
transport:
dashboard: 172.16.109.118:8080
  • 运行微服务程序,通过Nacos控制台观察微服务注册信息

  • 我们再通过HttpClient工具访问一下微服务的Api端口,并进入Sentinel控制台进行监控:在控制台中,我们发现了服务名称,及该服务下的各种规则设置菜单。

4.2.1 通过JMeter模拟高并发流量

  • 设置20000个并发请求

  • 设置HTTP请求地址:

  • 设置报告输出

  • 启动JMeter,观察Sentinel控制台,可以看到QPS的实时状况。

4.2.2 设置流控规则进行流量控制

  • 对Sentinel控制台中服务的资源增加流量控制规则

  • 给微服务接口的QPS设置阈值



  • 再次启动JMeter进行高并发测试,在控制台中进行观察,可以看到服务接口的QPS被限制在阈值以下。

  • JMeter结果列表中可以观察到异常信息。

4.2.3 设置降级规则进行流量控制

  • 对Sentinel控制台中服务的资源增加熔断降级规则

慢调用比例 (SLOW_REQUEST_RATIO):选择以慢调用比例作为阈值,需要设置允许的慢调用 RT(即最大的响应时间),请求的响应时间大于该值则统计为慢调用。当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且慢调用的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求响应时间小于设置的慢调用 RT 则结束熔断,若大于设置的慢调用 RT 则会再次被熔断。

  • 在实时监控界面可以看到请求被拒绝,证明熔断降级规则生效

  • 在JMeter结果表格中也出现了大量失败的调用请求

4.3 通过Sentinel对微服务调用方进行流量控制

  • Sentinel流程控制组件除了可以在微服务端进行必要的流量控制外,也可以在服务调用方的客户端进行控。,
  • 微服务调用方加入OpenFeign组件
<-- pom.xml -->
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-openfeign -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>2.2.5.RELEASE</version>
</dependency>
  • 项目配置
server:
port: 8090 spring:
application:
name: user-consumer
cloud:
nacos:
discovery:
server-addr: 172.16.109.118:8848
# sentinel服务
sentinel:
transport:
dashboard: 172.16.109.118:8080 # 调用微服务超时时间设置
ribbon:
ConnectTimeout: 5000
ReadTimeout: 5000 # feign日志以什么级别监控哪个接口
logging:
level:
nacos.democonsumer.GoodService : debug # 启用sentinel
feign:
sentinel:
enabled: true
  • 主启动类增加注解
/**
* 主启动类
*/
// 启用Feign组件
@EnableFeignClients
@EnableDiscoveryClient
@SpringBootApplication
public class DemoConsumerApplication { public static void main(String[] args) {
SpringApplication.run(DemoConsumerApplication.class, args);
}
}
  • 参照Nacos中注册的服务名,在服务调用者程序中映射微服务接口, 并通过@FeignClient调用微服务,同时定义服务熔断时如何处理(fallback)

/**
* 映射商品微服务接口
*/
@Component
// 增加服务容错处理,指定服务熔断时处理的类名
@FeignClient(value="goods-service",fallback =FallBackService.class )
public interface GoodService { @GetMapping(value="/api/goods")
List<GoodsDTO> getGoods(); } /**
* 服务熔断处理:返回空值
*/
@Component
public class FallBackService implements GoodService {
private final static Logger logger= LoggerFactory.getLogger(FallBackService.class) ; @Override
public List<GoodsDTO> getGoods() {
logger.info("服务已熔断...");
return new ArrayList<>();
}
}
  • 服务调用者调用程序无需变化
/**
* 用户消费者--调用nacos服务中心的商品服务,并对外提供RestFul接口测试
*/
@RestController
@RequestMapping("user/")
public class UserConsumer {
// 注入商品微服务接品
@Autowired
private GoodService goodService; @GetMapping("/goods")
public User getUserGoods() {
User user = new User();
// 通过GoodsService接口调用商品微服务
try {
List<GoodsDTO> goods = goodService.getGoods();
user.setName("jack");
user.setGoods(goods);
} catch (Exception e){
throw new RuntimeException(e.getMessage());
}
return user;
} }
  • 接下来启动微服务调用者,通过HttpClient工具进行测试,调用正常

  • 进入到Sentinel控制台,同样可以看到消费者的Api接口

4.3.1 对服务调用者中的服务提供方进行流量控制

  • 对Sentinel控制台中服务的资源增加流量控制规则,在FeignClient中,Sentinel为Feign调用生成了资源名策略定义,定义规则为 [httpmethod :protocol://requesturl](比如 GET:http://goods-service/api/goods)

  • 为便于测试,故意将QPS的单机阈值设为0



  • 使用HttpClient工具再次测试,由于我们在流量控制规则中已对QPS做了限制,服务调用请求已无法通过,故触发fallback,返回空值。

  • 服务调用者日志信息提示服务已熔断..

4.4 Sentinel实践小结

  • Sentinel与Hystrix相比,更加轻量级:Sentinel对主流框架提供适配的 API,来定义需要保护的资源,并提供设施对资源进行实时统计和调用链路分析。
  • Sentinel 提供了更加多样化的流量控制,熔断降级和系统负载保护手段。
  • Sentine具备完善的实时监控和控制台。

随机推荐

  1. allegro蛇形线

    蛇形线设置: 设置之后,框选你要修改的线即可: 修线: --------------------------------

  2. Spark系列(一)Spark1.0.0源码编译及安装

    最近想对自己学的东西做些回顾,想到写博客是个不错的方式,方便他人也有利自己,刚开始写不足之处大家多担待. 编译前需要安装JDK1.6以上.scala.Maven.Ant.hadoop2.20 如下图( ...

  3. jqGrid插件的重载表格的解决方案

    jqGrid插件的重载表格的解决方案 $("#table_list_1").empty();// 清空表格内容 var parent=$("#gbox_table_lis ...

  4. .Net 第三方工具包整理

    抓取数据 Jumony (http://www.jumony.net/)是一个基于 .NET 技术,用 C# 编写的一个 HTML 引擎,其可以用来分析解读 HTML 文档中的数据,也可以修改和绑定数 ...

  5. Computed Observable的参数

    构造计算监控(Constructing a computed observable) 1. ko.computed( evaluator [, targetObject, options] ) eva ...

  6. Python推荐算法学习1

    1.闵可夫斯基距离 闵可夫斯基距离可以概括曼哈顿距离与欧几里得距离.  其中r越大,单个维度差值大小会对整体产生更大的影响.这个很好理解,假设当r=2时一个正方形对角线长度,永远是r=3时正方体对角线 ...

  7. 1170 - BLOB/TEXT column &#39;CustomerName&#39; used in key specification without a key length

    [DTF] Data Transfer 企管宝_2_CRM start[DTF] Getting tables[DTF] Analyzing table: `CustomerInfo`[DTF] Ge ...

  8. 8、JVM--虚拟机字节码执行引擎

    8.1.概述 执行引擎是Java虚拟机最核心的组成部分之一.“虚拟机”是一个相对于“物理机”的概念,这两种机器都有代码执行能力,其区别是物理机的执行引擎是直接建立在处理器.硬件.指令集和操作系统层面上 ...

  9. Enums and Lookup Tables with EF Code First

    With EntityFramework’s support for enums, there is no longer any need to include lookup tables in th ...

  10. hibernate+spring整合增删改事务错误

    org.springframework.dao.InvalidDataAccessApiUsageException: Write operations are not allowed in read ...