Spring Cloud Alibaba致力于提供微服务开发的一站式解决方案。此项目包含开发分布式应用微服务的必需组件,方便开发者通过 Spring Cloud 编程模型轻松使用这些组件来开发分布式应用服务。
依托 Spring Cloud Alibaba,您只需要添加一些注解和少量配置
,就可以将 Spring Cloud 应用接入阿里微服务解决方案,通过阿里中间件来迅速搭建分布式应用系统。
简单来说:就是在以前的微服务搭建中,如果使用SpringCloudAlibaba,来替代以前的某些产品,那么开发SpringCloud应用会变得更加简单。
Sentinel:把流量作为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。
Nacos:一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。
RocketMQ:一款开源的分布式消息系统,基于高可用分布式集群技术,提供低延时的、高可靠的消息发布与订阅服务。
Dubbo:Apache Dubbo? 是一款高性能 Java RPC 框架。
Seata:阿里巴巴开源产品,一个易于使用的高性能微服务分布式事务解决方案。
Alibaba Cloud OSS: 阿里云对象存储服务(Object Storage Service,简称 OSS),是阿里云提供的海量、安全、低成本、高可靠的云存储服务。您可以在任何应用、任何时间、任何地点存储和访问任意类型的数据。
Alibaba Cloud SchedulerX: 阿里中间件团队开发的一款分布式任务调度产品,提供秒级、精准、高可靠、高可用的定时(基于 Cron 表达式)任务调度服务。
Alibaba Cloud SMS: 覆盖全球的短信服务,友好、高效、智能的互联化通讯能力,帮助企业迅速搭建客户触达通道。
只需要在SpringCloud的父项目中引入以下依赖即可
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.2.5.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
在接下来的子项目中根据需求添加依赖即可
Nacos 致力于帮助您发现、配置和管理微服务。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据及流量管理。
Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。 Nacos 是构建以“服务”为中心的现代应用架构 (例如微服务范式、云原生范式) 的服务基础设施。
简单来说:Nacos就是注册中心+配置中心的组合
,就是利用Nacos来代替之前学习的Eureka来做注册中心,代替SpringCloudConfig来做配置中心。
Nacos中文文档:
https://nacos.io/zh-cn/docs/what-is-nacos.html
CAP原则:指的是在一个分布式系统中,一致性(Consistency)、可用性(Availability)、分区容错性(Partition tolerance)。CAP 原则指的是,这三个要素最多只能同时实现两点,不可能三者兼顾。P原则是必须满足的,即自能又两种原则 CP或者 AP
CP原则:放弃了系统的高可用性,但保证了数据准确唯一
AP原则:维护了系统的高可用,但是得到的数据可能有缺陷,不唯一。
由上图可知Nacos同时支持了CP或者AP原则,对于两个原则,它是可变的,我们只需要启动发送一个命令即可切换(默认是AP)
curl -X PUT ‘nacos服务ip或者主机域名:8848/nacos/v1/ns/operator/switches?entry=serverMode&value=CP‘
CP和AP切换原则:
一般来说:
如果不需要存储服务级别的信息且服务实例是通过nacos-client注册,并能够保持心跳上报,那么就可以选择AP模式。当前主流的服务如Spring cloud和Dubbo服务 ,都适用于AP模式,AP模式为了服务的可用性而减弱了一致性,因此AP模式下只支持注册临时实例。
如果需要在服务级别编辑或者存储配置信息,那么CP是必须的,K8S服务和DNS服务则适用于CP模式
CP模式下则支持注册持久化实例,此时则是以Raft协议为集群运行模式,该模式下注册实例之前必须先注册服务,如果服务不存在,则会返回错误。
所有版本下载地址:https://github.com/alibaba/nacos/releases
Nacos-server2.0.1-windows版本下载地址:https://github.com/alibaba/nacos/releases/download/2.0.1/nacos-server-2.0.1.zip
Nacos-server2.0.1-linux版本下载地址:https://github.com/alibaba/nacos/releases/download/2.0.1/nacos-server-2.0.1.tar.gz
Nacos-server1.4.2-windows版本下载地址:https://github.com/alibaba/nacos/releases/download/1.4.2/nacos-server-1.4.2.zip
Nacos-server1.4.2-linux版本下载地址:https://github.com/alibaba/nacos/releases/download/1.4.2/nacos-server-1.4.2.tar.gz
安装:将下载的压缩包解压即可
启动:
修改解压目录的nacos下的config目录下的 application.yaml,将数据库的注释打开,如下
根据配置文件中的数据库名称建立数据库,默认叫nacos,linux有所不同,字符编码utf8 ,排序规则utf8_general_ci
将解压目录的nacos下的config目录下的nacos-mysql.sql的数据库脚本放到建立的数据中执行。
在nacos启动目录下的bin目录下,修改配置文件windows修改startup.cmd,linux修改startup.sh
# windows 将文件中的 set MODE="cluster" 改为 set MODE="standalone"
# linux 将文件中的 export MODE="cluster" 改为 export MODE="standalone"
执行启动文件windows 启动startup.cmd linux启动 startup.sh
然后访问:http://localhost:8848/nacos/,出现如下界面启动成功
注意
默认登录用户名和密码都是 nacos
微服务父项目搭建参考:https://www.cnblogs.com/Rampant/p/14770855.html
创建新模块 nacos-provider-9001
导入pom.xml依赖
<dependencies>
<!--Nacos 服务注册的依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--spring-boot-web 模块 常用的3个-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--热部署插件-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<!--测试插件-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
<scope>test</scope>
</dependency>
<!--lombok 依赖-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
配置application.yaml
server:
port: 9001 # 端口号
spring:
application:
name: cloud-alibaba-provider # 微服务名称
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848 # 连接的注册中心
management:
endpoints:
web:
exposure:
include: ‘*‘ #暴露端口
主启动类
package com.wyx.cloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class NacosProviderMain9001 {
public static void main(String[] args) {
SpringApplication.run(NacosProviderMain9001.class,args);
}
}
业务类
package com.wyx.cloud.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ProviderController {
@Value("${server.port}")
private String serverPort;
@GetMapping("/provider/{id}")
public String provider(@PathVariable String id){
return "使用Nacos服务注册中心,当前服务端口: "+serverPort+"\t"+"查询参数:"+id;
}
}
启动测试,访问:http://localhost:9001/provider/1
为了实现后面的负载均衡,我们在用相同的步骤搭建一个9002端口的服务
创建模块nacos-consumer-80
添加依赖
<dependencies>
<!--Nacos 服务注册的依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--spring-boot-web 模块 常用的3个-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--热部署插件-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<!--测试插件-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
<scope>test</scope>
</dependency>
<!--lombok 依赖-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
修改yaml
server:
port: 80 # 端口号
spring:
application:
name: cloud-alibaba-consumer # 微服务名称
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848 # 连接的注册中心
service-url:
nacos-service: http://cloud-alibaba-provider #将微服务提供者的名字放入配置文件,后面读取即可
主启动类
package com.wyx.cloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class NacosConsumerMain80 {
public static void main(String[] args) {
SpringApplication.run(NacosConsumerMain80.class,args);
}
}
业务类
RestTemplate注入
package com.wyx.cloud.config;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class RestTemplateConfig {
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
服务调用
package com.wyx.cloud.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
@RestController
public class ConsumerController {
@Value("${service-url.nacos-service}")
private String serviceUrl;
@Resource
RestTemplate restTemplate;
@GetMapping("/consumer/{id}")
public String getConsumer(@PathVariable String id){
return restTemplate.getForObject(serviceUrl+"/provider/"+id,String.class);
}
}
对于Nacos服务注册中心,天生集成了 ribbon
做负载均衡,
使用Ribbon做负载均衡,就是它默认给我们写了很多负载均衡类
1、随机策略——RandomRule
2、轮询策略——RoundRobinRule
注:Ribbon默认策略
3、重试策略——RetryRule
4、最低并发策略——BestAvailableRule
5、可用过滤策略——AvailabilityFilteringRule
过滤掉那些因为一直连接失败的被标记为circuit tripped的后端server,并过滤掉那些高并发的的后端server(active connections 超过配置的阈值)
性能仅次于最低并发策略。
6、响应时间加权策略——WeightedResponseTimeRule
每隔30秒计算一次服务器响应时间,以响应时间作为权重,响应时间越短的服务器被选中的概率越大。
7、区域权衡策略——ZoneAvoidanceRule
Ribbon的负载均衡策略使用建议
一般情况下,推荐使用最低并发策略,这个性能比默认的轮询策略高很多。
编写配置类
// 编写一个类注入负载均衡算法类,该类必须不能让springboot扫描到,不能放在同级,或者子包下面,必须放在其它地方
@Configuration
public class RibbonConfiguration {
@Bean
public IRule ribbonRule() {
// 负载均衡规则,改为随机,可以new的类,参考上面提供的类名,官方写好的的类,也可以自定义负载均衡类
return new RandomRule();
}
}
在RestTemplate注入配置类添加注解
package com.wyx.cloud.config;
import com.wyx.loadbalance.RibbonConfiguration;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.ribbon.RibbonClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
// name 是微服务的应用名
@Configuration
@RibbonClient(name = "cloud-alibaba-provider", configuration = RibbonConfiguration.class)
public class RestTemplateConfig {
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
其他配置不修改,启动即可。
当然如果对提供的负载均衡算法,不满意,也可以自定义负载均衡算法,只需要编写一个类,实现IRule
接口即可。
创建新模块nacos-config-3344
导入 pom.xml
<dependencies>
<!--Nacos 配置中心依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!--这个依赖,看版本来修改版本是20版之后的最好导入,因为在版后默认剔除了,不导入启动项目会出错-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
<!--Nacos 服务注册的依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--spring-boot-web 模块 常用的3个-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--热部署插件-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<!--测试插件-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
<scope>test</scope>
</dependency>
<!--lombok 依赖-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
添加application.yaml、bootstrap.yml
# application.yml
server:
port: 3344
spring:
profiles:
active: dev
# bootstrap.yml
spring:
application:
name: nacos-config-client
cloud:
nacos:
discovery:
server-addr: localhost:8848 #服务注册中心地址
config:
server-addr: localhost:8848 #配置中心地址
file-extension: yaml #指定文件后缀名,切记配置中心的后缀,必须一样,不能一个是yml 一个是yaml
主启动类
package com.wyx.cloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class NacosConfigMain3344 {
public static void main(String[] args) {
SpringApplication.run(NacosConfigMain3344.class,args);
}
}
业务类
package com.wyx.cloud.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RefreshScope //动态刷新功能,nacos修改后,不需要在发送什么命令,直接会自动刷新
public class ConfigClientController {
@Value("${config.info}")
private String configInfo;
@GetMapping("/config/info")
public String getConfigInfo() {
return configInfo;
}
}
文件名要求规则如下(dataId)即为文件名
在 Nacos Spring Cloud 中,dataId
的完整格式如下:
${prefix}-${spring.profiles.active}.${file-extension}
prefix
默认为 spring.application.name
的值,也可以通过配置项 spring.cloud.nacos.config.prefix
来配置。spring.profiles.active
即为当前环境对应的 profile,详情可以参考 Spring Boot文档。 注意:当 spring.profiles.active
为空时,对应的连接符 -
也将不存在,dataId 的拼接格式变成 ${prefix}.${file-extension}
file-exetension
为配置内容的数据格式,可以通过配置项 spring.cloud.nacos.config.file-extension
来配置。目前只支持 properties
和 yaml
类型。由文件命名规则可知,我们该项目的配置文件命令为:nacos-config-client-dev.yml
添加配置文件如下图
启动项目测试即可:访问,http://localhost:3344/config/info
在修改配置文件后继续访问,发现是动态刷新的,不在像 springcloud-config 一样需要实时的刷新配置。
对于SpringCloud-config一般情况下都是通过修改文件名字来实现生产环境,测试环境的使用,但是在Nacos中,利用了Java的包名类名管理思想。
它存在三级管理配置文件的功能,具体来说就是命名空间 + GROUP + Data ID
,三者之间的关系命名空间 > GROUP > Data ID,
下面我们来看一下如何创建命令空间
我们可以通过修改application.yaml来获取我们的命名空间,如下
spring:
cloud:
nacos:
discovery:
server-addr: localhost:8848 #服务注册中心地址
config:
server-addr: localhost:8848 #配置中心地址
file-extension: yaml #指定文件后缀名,切记配置中心的后缀,必须一样,不能一个是yml 一个是yaml
namespace: f50332a2-9b31-479c-9111-102c125d97d7 # 这个数字是刚刚创建时自动生成的命名空间ID
在新建配置的时候可以自定义组名
我们在配置中如何配置组
spring:
cloud:
nacos:
discovery:
server-addr: localhost:8848 #服务注册中心地址
config:
server-addr: localhost:8848 #配置中心地址
file-extension: yaml #指定文件后缀名,切记配置中心的后缀,必须一样,不能一个是yml 一个是yaml
namespace: f50332a2-9b31-479c-9111-102c125d97d7 # 这个数字是刚刚创建时自动生成的命名空间ID
group: DEV_GROUP # 指定组名
Data ID就是一个对应文件名的配置,上面已经解释过了。
官方集群架构部署图
可能开起来不是很理解,下面是根据官网修改后的集群部署图:
简单来说:
默认Nacos使用的是内嵌式数据库实现数据存储(derby)。如果采用集群配置,每个Nacos节点都有自己的配置,就会存在数据一致性的问题。为了解决这个问题,Nacos采用了集中式存储方式来支持集群化部署(目前只支持MySQL)。
切换默认的数据源
创建数据库nacos_devtest,字符编码utf8 ,排序规则utf8_general_ci
将在安装nacos的目录下的conf下的nacos-mysql.sql
文件复制到自己刚刚创建的数据库中执行SQL命令
修改在安装nacos的目录下的conf下的application.properties
文件,添加如下配置
#使用的数据源
spring.datasource.platform=mysql
# 数据库的数量
db.num=1
#连接的URL注意数据库名称
db.url.0=jdbc:mysql://127.0.0.1:3306/nacos_devtest?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC
#用户名
db.user.0=root
#密码
db.password.0=970699
重新启动即可。
特别注意,数据库的名字不能改变,必须使用 nacos_devtest
否则不能用
MySQL 8.0
,需要加上时区配置。
环境准备(3台虚拟机+阿里云服务器一台)
环境说明,由于服务器不够所以这里数据库就不集群了。其他的都集群配置
master 192.168.137.129
slave1 192.168.137.130
slave2 192.168.137.131
阿里云服务器 47.97.218.81
三台虚拟机上都先安装JDK,教程很多不在说明
准备Nginx
安装包,Nacos
安装包
下载地址:
Nginx(1.20.0版本):http://nginx.org/download/nginx-1.20.0.tar.gz
Nacos(nacos-server2.0.1版本):https://github.com/alibaba/nacos/releases/download/2.0.1/nacos-server-2.0.1.tar.gz
并将 Nginx和Nacos
放到三台虚拟机上
说明以下,这里三台服务器的Nacos安装教程都一样,只对一台讲解
解压配置上传的压缩包
# 我是安装在 /opt目录下
[root@localhost opt]# pwd
/opt
[root@localhost opt]# tar -xzvf nacos-server-2.0.1.tar.gz
配置MySQL数据源(我选用的是阿里云的服务器来配置数据源,如果条件不允许,可以自己用虚拟机来装MySQL也可以)
首先:
查看数据库配置文件在解压目录下的nacos 下的 conf目录下的数据库名称
[root@localhost opt]# vim /opt/nacos/conf/nacos-mysql.sql
使用navicat连接我的阿里云服务器的数据库建立数据库名为nacos_config,字符集为 utf8
,排序规则为utf8_general_ci
将刚刚我们查看的nacos-mysql.sql
脚本,拿到navicat中运行数据库脚本。具体简单,不在操作。
配置nacos目录下的conf目录下的application.properties
文件
# 首先将文件备份,防止修改错
[root@localhost conf]# cp application.properties application.properties.bk
# 修改文件
[root@localhost conf]# vim application.properties
在文件最后配置数据源的位置,就是在文件最后添加如下内容
#使用的数据源
spring.datasource.platform=mysql
# 数据库的数量
db.num=1
#连接的URL注意数据库名称,及其数据源的位置IP
db.url.0=jdbc:mysql://xxx.xxx.xxx.xxx:3306/nacos_config?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC
#用户名
db.user.0=root
#密码
db.password.0=970699
配置集群文件
# j将集群文件先复制一份,并改名为 cluster.conf
[root@localhost conf]# cp cluster.conf.example cluster.conf
# 编辑 cluster.conf
[root@localhost conf]# vim cluster.conf
上面修改的这个文件 3个服务器上都需要配置
在三台服务器上都启动nacos
# 启动命令,三台都要启动
[root@localhost conf]# sh /opt/nacos/bin/startup.sh
# 关闭防火墙,如果是阿里云服务器建议开启端口,并配置安全组规则不要关闭防火墙
systemctl stop firewalld.service
# 查看防火墙状态
firewall-cmd --state
访问:http://192.168.100.129:8848/nacos/
注意:
启动实在太慢了,需要多等一会。我3G
的运行内存启动差不多花了3分钟,这里可能是网络原因。所以记得等,如果等不了,使用如下命令查看启动日志
1G内存启动花了6分钟左右
# 默认就是安装目录下的logs下的start.out
[root@localhost bin]# vim /opt/nacos/logs/start.out
看到出现如下信息才算启动成功,看服务器配置启动时间。
全部启动成功后可以查看节点状态
两台服务器安装Nginx
安装教程参考:Nginx安装教程
这里使用192.168.100.129和192.168.100.130
来搭建Nginx
安装完成后测试访问没有问题后开始搭建
搭建过程如果看不到可以参考这里:https://www.cnblogs.com/Rampant/p/14785179.html 的反向代理模式中的负载均衡,和Nginx高可用
两个部分
修改Nginx启动配置文件
# 编辑配置文件
[root@localhost conf]# vim /usr/local/nginx/conf/nginx.conf
编辑后如下
upstream nacoscluster{
server 192.168.100.129:8848;
server 192.168.100.130:8848;
server 192.168.100.131:8848;
}
server {
listen 5000;
server_name 192.168.137.129;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
# root html;
# index index.html index.htm;
proxy_pass http://nacoscluster
}
另外一台也做配置
upstream nacoscluster{
server 192.168.100.129:8848;
server 192.168.100.130:8848;
server 192.168.100.131:8848;
}
server {
listen 5000;
# 只需要这里的IP是本机IP,其他不变
server_name 192.168.137.130;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
# root html;
# index index.html index.htm;
proxy_pass http://nacoscluster
}
参考:Nginx高可用搭建
安装 keeplived
# 安装命令
yum install keepalived
编辑配置文件
# 进入配置文件目录
cd /etc/keepalived/
# 编辑配置文件
vim keepalived.conf
! Configuration File for keepalived
## 两台服务器都要配置
global_defs {
notification_email { # keepalived服务宕机异常出现的时候,发送通知邮件 可以是多个
acassen@firewall.loc # 收件人邮箱1
failover@firewall.loc # 收件人邮箱2
sysadmin@firewall.loc # 收件人邮箱3
}
notification_email_from Alexandre.Cassen@firewall.loc #邮件发件人
smtp_server 192.168.200.1 # 邮件服务器地址
smtp_connect_timeout 30 # 超时时间
router_id LVS_DEVEL # 机器标识 局域网内唯一即可
vrrp_skip_check_adv_addr # 默认是不跳过检查。检查收到的VRRP通告中的所有地址可能会比较耗时,设置此命令的意思是,如果通告与接收的上一个通告来自相同的master路由器,则不执行检查(跳过检查)。
#vrrp_strict # 严格遵守VRRP协议。下列情况将会阻止启动Keepalived:1. 没有VIP地址。2. 单播邻居。3. 在VRRP版本2中有IPv6地址。
vrrp_garp_interval 0 # 小数类型,单位秒,在一个网卡上每组gratuitous arp消息之间的延迟时间,默认为0,一个发送的消息=n组 arp报文
vrrp_gna_interval 0 # 小数类型,单位秒, 在一个网卡上每组na消息之间的延迟时间,默认为0
}
# 检测 nginx 的活动状态
vrrp_script chk_http_port{
# 检测脚本路径
script "/etc/keepalived/nginx_chech.sh"
interval 2
weight 2
}
# vrrp实例 我们集群设置 多机配置,除了state和priority不一样,其他都一样
vrrp_instance VI_1 {
state MASTER # 服务器状态 MASTER是主服务器 BACKUP是备份服务器 主服务器的priority要比备份服务器大
interface ens33 # 通信端口 通过ip addr可以看到 根据自己的机器配置
virtual_router_id 51 # vrrp实例id keepalived集群,实例id必须一致
priority 100 # 权重比 主服务器的priority要比备份服务器大
advert_int 1 # 心跳间隔 单位秒 keepalived多机器集群 通过心跳检测,如果发送心跳没反应 就立刻接管;
authentication { # 服务器之间通信密码
auth_type PASS
auth_pass 1111
}
virtual_ipaddress { # 自定义虚拟IP
# 虚拟IP池,要求必须在一个网段内,必须192.168.100开头
192.168.100.80
}
}
配置检测脚本
#!/bin/bash
A=`ps -C nginx -no-header | wc -l`
if [$A -eq 0 ];then
/usr/local/neginx/sbin/nginx
sleep 2
if [`PS -C nginx --no-header |wc -1` -eq 0 ]; then
killall keepalived
fi
fi
访问:192.168.100.80:5000/nacos/测试,当主服务器192.168.100.129宕机后,测试访问依然成功,搭建完成。
随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。
简单来说:它是一个轻量级的流量控制、熔断降级的Java库,就是以前学习的Hystrix的加强版
。
中文官方文档
:SpringCloudalibaba Sentinel中文官方文档
Sentinel 分为两个部分:
下载Setinel
下载地址(全部版本):https://github.com/alibaba/Sentinel/releases
1.8.2版本:https://github.com/alibaba/Sentinel/releases/download/1.8.2/sentinel-dashboard-1.8.2.jar
启动,运行下载出来的jar包就可以了
# 运行jar包
java -jar Sentinel-dashboard-1.8.2.jar
访问:http://localhost:8080/ 如下启动成功
登录用户和密码都是 sentinel
创建新模块nacos-sentinel-service-9003
pom.xml
<dependencies>
<!--Sentinel 服务监控的依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!--Nacos 服务注册的依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--spring-boot-web 模块 常用的3个-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--热部署插件-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<!--测试插件-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
<scope>test</scope>
</dependency>
<!--lombok 依赖-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
application.yaml
server:
port: 9003
spring:
application:
name: nacos-sentinel-service
cloud:
nacos:
discovery:
server-addr: localhost:8848 #注册到nacos注册中心
sentinel:
transport:
dashboard: localhost:8080 #在8080d
port: 8719 #默认8719,假如被占用了会自动从8719开始依次+1扫描。直至找到未被占用的端口
management: #凡是涉及监控的都需要暴露端口
endpoints:
web:
exposure:
include: ‘*‘
主启动类
package com.wyx.cloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class SentinelServiceMain9003 {
public static void main(String[] args) {
SpringApplication.run(SentinelServiceMain9003.class,args);
}
}
业务类
package com.wyx.cloud.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class SentinelController {
private Integer contA=0;
private Integer contB=0;
@GetMapping("/getInfoA")
public String getInfoA(){
contA++;
return "提供A服务次数"+contA;
}
@GetMapping("/getInfoB")
public String getInfoB(){
contB++;
return "提供B服务次数"+contB;
}
}
访问 http://localhost:8080/ 查看监控信息,发现没有上面,是因为Sentinel使用懒加载模式
只有访问服务后才会进入监控列表。
我们访问 http://localhost:9003/getInfoA
再次查看监控信息
显示在一段时间内对服务的每个请求的访问量,并以秒吉显示出来
触电链路主要有两种显示方式 树状视图
和列表视图,主要功能就是显示某个服务的请求路径,并可用为其添加 流控、熔断、热点、授权
等规则
通过一定的规则来配置限流规则,来对服务提供一种保护作用,具体如何实现请看后面
也是一种限流规则,具体参考后面。
查看当前服务名下有多少台实例的服务。
在学习流控规则前,我们先来了解几个基本概念
QPS:单位时间类的请求如果超过设定的规则就返回失败
默认返回错误的页面,后期可用自定义
并发线程数:给定固定线程数,如果请求大于线程数的处理范围就快速失败
直接:针对自己的流控规则,满足规则就对自己限流。这个很简单不在解释
关联:将两个资源名进行关联,当关联资源达到限流规则时,来限流与之关联的资源。
简单理解:如下图,当/getInfoB
在单位时间内的访问次数超过2次以上,那么/getInfoA
将会被限流
,如果是并发线程数也是一样。当两个线程数处理不过来时,那么/getInfoA
限流。(适用于当支付模块处理不过来时,可以对下单模块限流)
链路:在微服务调用过程中,如果入口资源调用资源名的服务,满足限流规则,则开始限流。
简单来说:假设微服务之间互相调用,那么当/getIfoB
服务调用/getInfoA
满足单位时间内超过2次以上触发限流
流控效果只能针对QPS
模式,并发线程模式,只能时快速失败
快速失败:就是快速放回默认的错误信息如下图(可以自定义)。
Warm UP(缓慢唤醒):即预热/冷启动方式。当系统长期处于低水位的情况下,当流量突然增加时,直接把系统拉升到高水位可能瞬间把系统压垮。通过"冷启动",让通过的流量缓慢增加,在一定时间内逐渐增加到阈值上限,给冷系统一个预热的时间,避免冷系统被压垮。
简单理解如下:起始单机阈值是3(在源码WarmUpController类中)当请求量突然增大时,系统会自动的在5秒钟内将我们的单机阈值调到我们设定的最大值10。(使用场景:抢购东西时,避免一开始就出现系统死机的情况)
等待排队:等待排队利用的原理是漏桶算法,就是对所有请求都不返回错误(在不超时的情况下,超时也会返回错误),而是将请求拿过来后,经行排队,以此处理。什么是漏桶算法
熔断规则又称服务熔断
:但是这里的服务熔断和Hystrix
有区别,它并没有半开状态
,就只有两种状态可用,不可用。
慢比例调用:在设置的统计时间内,如果满足最小请求数,且响应时间(最大RT
)大于设定值的比例高于阈值就熔断设定的时长,当过了熔断时长,若接下来的一个请求响应时间小于设置的慢调用 RT 则结束熔断,若大于设置的慢调用 RT 则会再次被熔断。
下图的例子:/getInfoA
请求,如果在统计时长(1秒内)内,请求次数大于4次(最小请求数),并且响应时间大于50毫秒(最大RT)的比例大于0.4(比例阈值),就会进入熔断 10秒(熔断时长)。过了熔断时长就恢复访问。熔断界面为默认的出错界面,可用修改。
异常比例模式:当单位统计时长(statIntervalMs
)内请求数目大于设置的最小请求数目,并且异常的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。异常比率的阈值范围是 [0.0, 1.0]
,代表 0% - 100%。
例如,表示在一秒钟内,请求次数大于5次,并且出现异常的的次数大于请求次数的百分之四十,就会开启熔断,熔断时间过了后,如果请求还是异常继续熔断,等待下一次可用。
异常数模式:当单位统计时长内的异常数目超过阈值之后会自动进行熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。
何为热点?热点即经常访问的数据。很多时候我们希望统计某个热点数据中访问频次最高的 Top K 数据,并对其访问进行限制。比如:
热点参数限流会统计传入参数中的热点参数,并根据配置的限流阈值与模式,对包含热点参数的资源调用进行限流。热点参数限流可以看做是一种特殊的流量控制,仅对包含热点参数的资源调用生效。
Sentinel 利用 LRU 策略统计最近最常访问的热点参数,结合令牌桶算法来进行参数级别的流控。热点参数限流支持集群模式。
环境准备,在业务类新加一个请求
// 新增一个请求参数为非必须,这里只能用 SentinelResource,单独使用/hotKey是没效果的
@GetMapping("/hotKey")
@SentinelResource(value = "hotKey", blockHandler = "del_hotKet") //定义访问的资源名,和失败后走的处理方法
public String hotKet(@RequestParam(value = "p1", required = false) String p1,
@RequestParam(value = "p2", required = false) String p2){
return "热点访问成功";
}
// 失败后的处理方法
public String del_hotKet(String p1, String p2 , BlockException exception){
return "热点新闻访问失败!????????";
}
重启,添加热点规则
上面的规则代表当访问/hotKey
时,如果添加第一个参数(参数索引0开始),对应代码中的第一个参数为 p1,即当带有p1参数的访问在统计时间内,访问超过2次,就进行熔断。
效果如下
简单来说:对于上述的请求,当p1等于任何值是,只要单机访问超过2个QPS,那么他就会熔断,对于参数例外项配置,就是可用当p1等于特殊的某个值,进行重新的定义限流规则。
如下,即当我们请求的参数为第一个(对于代码中的p1)本来限流是每秒钟超过2次进行限流,但是现在如果请求参数 p1 = 5并且请求类型为String类型,那么他的限流就为200。
系统保护规则是从应用级别的入口流量进行控制,从单台机器的 load、CPU 使用率、平均 RT、入口 QPS 和并发线程数等几个维度监控应用指标,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。
简单来说:就是对我们之前定义的限流规则在外面包裹一层,来做新的限流规则,必须满足系统的限流规则,才能走到里面的限流规则
参考:系统自适应限流
系统规则支持以下的模式:(一般不是很常用,因为会如果配置不好,可能会导致下一层的一些规则失效不可用。导致系统瘫痪)
maxQps * minRt
估算得出。设定参考值一般是 CPU cores * 2.5
。用来配置访问资源名和达到限流规则后应该怎么处理
@GetMapping("/hotKey")
@SentinelResource(value = "hotKey", blockHandler = "del_hotKet") //定义访问的资源名,和失败后走的处理方法
public String hotKet(@RequestParam(value = "p1", required = false) String p1,
@RequestParam(value = "p2", required = false) String p2){
return "热点访问成功";
}
// 失败后的处理方法
public String del_hotKet(String p1, String p2 , BlockException exception){
return "热点新闻访问失败!????????";
}
当然也可用只用定义的访问资源名称,就算定义了资源名称,配置流控规则时依然可以使用URL来做资源名,就是请求地址,但是热点规则除外,不能使用URL
// 达到限流规则时默认走,系统默认的
@SentinelResource(value = "hotKey")
问题存在:
问题解决:
自定义一个类,用来写异常的方法
package com.wyx.cloud.myHandler;
import com.alibaba.csp.sentinel.slots.block.BlockException;
public class ConsumerHandler {
// 因为JVM 的加载机制只能使用 static 返回值和要处理的方法的返回值相同
public static String handlerEx(BlockException exception){
return "自定义异常处理方法";
}
}
在方法中调用自定义的异常处理
@GetMapping("/handlerEx")
// blockHandlerClass 指定处理异常的类, blockHandler 指定处理异常类中的那个方法,如果没有异常类就是在自己的类中找方法
@SentinelResource(value = "hotKey", blockHandlerClass = ConsumerHandler.class ,blockHandler = "handlerEx")
public String handlerEx(){
return "访问成功";
}
fallback:
// 参数中还有defaultFallback,代表默认的处理,当与fallback同时标注时,fallback优先级高于defaultFallback
@GetMapping("/fallBack")
@SentinelResource(value = "fallBack",fallback = "fallbackMethod")
public String fallBack(){
return "访问成功";
}
// 失败后的处理方法
public String fallbackMethod(Throwable exception){
return "运行时异常处理方法";
}
上面的配置方式还是存在代码膨胀的问题
我们这里也可以用控制台资源处理的方法来处理。即创建一个fallbackMethod的类,然后通过fallbackClass来处理
创建类ConsumerFallbackMethod
package com.wyx.cloud.myHandler;
public class ConsumerFallbackMethod {
// 因为JVM 的加载机制只能使用 static 返回值和要处理的方法的返回值相同
public static String fallback(Throwable exception){
return "自定义运行时异常处理方法";
}
}
在方法中调用
@GetMapping("/fallBack")
@SentinelResource(value = "fallBack", fallbackClass = ConsumerFallbackMethod.class, fallback = "fallback")
public String fallBack(){
int a=10/0;
return "访问成功";
}
特别说明:
当Java运行时异常和控制台限流规则同时配置,且同时生效时,优先使用控制台的限流或熔断处理方法
使用方法和在Hystrix中使用类似,有一点点微小差异(开启的yaml支持不一样),可以参考
OpenFeign的使用:OpenFeign使用流程
Hystrix中使用OpenFeign做服务降级:Hystrix配合OpenFeign使用服务降级
具体步骤如下:
微服务提供者搭建:(2个微服务提供者)
新建模块Nacos-Sentinel-OpenFeign-Provider-8001,Nacos-Sentinel-OpenFeign-Provider-8002,两个搭建的东西都一样改端口即可
pom.xml
<dependencies>
<!--Nacos 服务注册的依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--spring-boot-web 模块 常用的3个-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--热部署插件-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<!--测试插件-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
<scope>test</scope>
</dependency>
<!--lombok 依赖-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
yaml
server:
port: 8001 # 端口号
spring:
application:
name: nacos-sentinel-openfeign # 微服务名称
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848 # 连接的注册中心
management:
endpoints:
web:
exposure:
include: ‘*‘ #暴露端口
主启动类
package com.wyx.cloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class NacosSentinelOpenFeignProviderMain8001 {
public static void main(String[] args) {
SpringApplication.run(NacosSentinelOpenFeignProviderMain8001.class,args);
}
}
业务类
OpenFeign调用服务
package com.wyx.cloud.service;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
@Service
public class Provider {
@Value("${server.port}")
private String serverPort;
public String getService(){
return "提供服务成功,当前服务端口:"+serverPort;
}
}
控制层
package com.wyx.cloud.controller;
import com.wyx.cloud.service.Provider;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@RestController
public class ProviderController {
@Resource
Provider provider;
@GetMapping("/getServer")
public String getService(){
return provider.getService();
}
}
微服务消费者搭建:
创建新模块Nacos-Sentinel-OpenFeign-Consumer-80
pom.xml
<dependencies>
<!--添加 openfeign 的启动依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
<!--Sentinel 服务监控的依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!--Nacos 服务注册的依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--spring-boot-web 模块 常用的3个-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--热部署插件-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<!--测试插件-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
<scope>test</scope>
</dependency>
<!--lombok 依赖-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
yaml
server:
port: 80
spring:
application:
name: nacos-order-consumer
cloud:
nacos:
discovery:
server-addr: localhost:8848
sentinel:
transport:
dashboard: localhost:8080
port: 8719
service-url:
nacos-user-service: http://nacos-sentinel-openfeign
#对Feign的支持
feign:
sentinel:
enabled: true
主启动类
package com.wyx.cloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class NacosSentinelOpenFeignConsumerMain80 {
public static void main(String[] args) {
SpringApplication.run(NacosSentinelOpenFeignConsumerMain80.class,args);
}
}
业务类
OpenFeign调用接口
package com.wyx.cloud.service;
import com.wyx.cloud.fallback.ProviderFallBackImpl;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
@FeignClient(value = "nacos-sentinel-openfeign",fallback = ProviderFallBackImpl.class)
public interface ProviderService {
@GetMapping("/getServer")
public String getService();
}
出错处理类
package com.wyx.cloud.fallback;
import com.wyx.cloud.service.ProviderService;
import org.springframework.stereotype.Component;
@Component
public class ProviderFallBackImpl implements ProviderService {
@Override
public String getService() {
return "Nacos下Sentinel的程序运行出错方法调用";
}
}
控制层
package com.wyx.cloud.controller;
import com.wyx.cloud.service.ProviderService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@RestController
public class ConsumerController {
@Resource
private ProviderService provider;
@GetMapping("/getServer")
public String getServer(){
int a = 10/0;
return provider.getService();
}
}
启动测试即可
一旦我们重启应用,Sentinel规则将消失,生产环境需要将配置规则进行持久化。那么如何持久化呢?
导入依赖
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
添加yaml配置
spring:
cloud:
sentinel:
datasource:
ds1:
nacos:
server-addr: localhost:8848
dataid: ${spring.application.name}
groupid: DEFAULT_GROUP
data-type: json
rule-type: flow
在Nacos中添加配置Data Id配置文件名:是spring.application.name,服务名称
,类型为json
[
{
"resource": "/getInfoB",
"limitApp": "default",
"grade": 1,
"count": 1,
"strategy": 0,
"controlBehavior": 0,
"clusterMode": false
}
]
重启即可
原文:https://www.cnblogs.com/Rampant/p/15063358.html