学习目标:
- Nacos注册中心
- Nacos配置中心
- Nacos集群和持久化
- 负载均衡Ribbon
- 声明式服务调用Feign
Nacos注册中心
一、nacos的安装和启动
1.解压
[root@localhost ~]# cd /usr/upload
[root@localhost upload]# tar -zxvf nacos-server-1.4.1.tar.gz -C /usr/local
2.启动和关闭
启动:
[root@localhost local]# cd nacos/bin/
[root@localhost bin]# ./startup.sh -m standalone #非集群模式启动
关闭:
[root@localhost bin]# ./shutdown.sh
二、Nacos注册中心
注册中心主要有三部分组成:
Ø Nacos-Server:注册中心
提供服务的注册和发现。
Ø Nacos-Provider:服务提供方
把自身的服务实例注册到 Nacos Server 中
Ø Nacos-Consumer:服务调用方
通过 Nacos Server 获取服务列表,消费服务。
1.服务提供者: nacos_provide
1. pom.xml文件
<!--nacos客户端-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
2. application.yml
spring:
cloud:
nacos:
discovery:
server-addr: 192.168.216.133:8848 #nacos服务的地址
application:
name: nacos-provider #向注册中心注册的名字
3.App(启动类)
@SpringBootApplication
@EnableDiscoveryClient//向注册中心注册该服务,并可以获取其他服务的调用地址
public class ProviderApp {
public static void main(String[] args) {
SpringApplication.run(ProviderApp.class,args);
}
}
2.服务消费者:nacos_consumer
1.pom.xml
<!--nacos客户端-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
2.application.yml
spring:
cloud:
nacos:
discovery:
server-addr: 192.168.216.133:8848 #nacos服务的地址
application:
name: nacos-consumer #向注册中心注册的名字
3.App
@SpringBootApplication
@EnableDiscoveryClient//向注册中心注册该服务,并可以获取其他服务的调用地址
public class ConsumerApp {
public static void main(String[] args) {
SpringApplication.run(ConsumerApp.class,args);
}
}
3.为什么要使用注册中心
-
地址硬编码
不能负载均衡
Nacos配置中心
一、nacos——config
1. pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--nacos注册中心的启动器-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--nacos配置中心的启动器-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>ccom.zzcsy</groupId>
<artifactId>springcloud_common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
2. bootstrap.yml
spring:
cloud:
nacos:
config:
server-addr: 192.168.216.133:8848
file-extension: yaml #后缀名,只支持 properties 和 yaml 类型
prefix: nacos-config #文件名,如果没有配置则默认为 ${spring.appliction.name}
3. 在nacos中创建配置文件
Data ID:
${spring.cloud.nacos.config.prefix}.${spring.cloud.nacos.config.file-extension}
配置格式:yaml或properties
spring.cloud.nacos.config.prefix:默认是当前服务的服务名称
spring.cloud.nacos.config.file-extension:配置文件的格式(后缀),目前只支持yaml和properties
例如:
spring:
cloud:
nacos:
config:
server-addr: 192.168.216.133:8848 #配置中心的地址
file-extension: yaml #配置文件扩展名只支持properties和yaml
prefix: nacos-config #文件名,默认是spring.application.name
二、为什么要使用配置中心
- 集中管理配置文件
- 动态更新配置文件
三、隔离模型
Namespace Group DataId介绍:
- Namespace: 代表不同的环境的配置隔离 ,如:开发、测试、生产等
- Group: 可以代表某个项目,如health、JD
-
DataId: 每个项目下的工程名
获取配置集需要指定:
-
nacos服务地址,必须指定
-
namespace,如不指定默认public
-
group,如不指定默认 DEFAULT_GROUP
-
dataId,必须指定
持久化
一、修改conf/application.properties文件
### If use MySQL as datasource:
spring.datasource.platform=mysql
### Count of DB:
db.num=1
### Connect URL of DB:
db.url.0=jdbc:mysql://192.168.216.130:3306/nacos?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC
db.user.0=root
db.password.0=1111
二、建库建表
创建nacos库 注意:库名和application.properties中的库名保持一致
建表:找到conf/nacos-mysql.sql文件并执行
测试
1、重启nacos
2、新建配置文件
3、观察配置文件是否持久化到mysql中
集群
一、节点规划
节点 | 端口 |
---|---|
192.168.204.156 | 8848 |
192.168.204.156 | 8849 |
192.168.204.156 | 8850 |
二、集群搭建
1、找到conf/cluster.conf.example ,将其改名为 conf/cluster.conf
# ip:port
192.168.216.133:8848
192.168.216.133:8849
192.168.216.133:8850
2、复制三份Nacos
[root@localhost bin]# cd /usr/local
[root@localhost java]# mkdir nacos_cluster
[root@localhost java]# cp -r nacos nacos_cluster/nacos_8848
[root@localhost java]# cp -r nacos nacos_cluster/nacos_8849
[root@localhost java]# cp -r nacos nacos_cluster/nacos_8850
3、将 conf/application.properties
中的端口号分别改为:
server.port=8848
server.port=8849
server.port=8850
三、配置代理服务
- 安装ngnix
- 配置ngnix代理nacos
- 测试
- 启动nacos集群
- 启动ngnix
- 将微服务注册到nacos集群
- 访问nacos集群
负载均衡Ribbon
一、什么是Ribbon
ribbon是基于netflix 实现的一个工作在consumer端的负载均衡工具,提供了很多负载均衡策略:轮询、随机等。
二、实现自定义负载均衡
1、创建服务提供者
1、创建工程provider
2、application.yml
server:
port: 9090
spring:
cloud:
nacos:
discovery:
server-addr: 192.168.216.133:8848
application:
name: ribbon-provider
server:
port: 9091
spring:
cloud:
nacos:
discovery:
server-addr: 192.168.216.133:8848
application:
name: ribbon-provider
2、创建服务消费者
1、创建工程nacos_consumer
2、application.yml
server:
port: 80
spring:
cloud:
nacos:
discovery:
server-addr: 192.168.216.133:8848
application:
name: ribbon-consumer
3、controller
@RestController
@RequestMapping("/consumer")
public class ConsumerController {
@Autowired
private RestTemplate restTemplate;
@Autowired
private DiscoveryClient discoveryClient;//发现服务的工具类
private int index;
@RequestMapping("/getUserById/{id}")
public User getUserById(@PathVariable Integer id) {
List<String> serviceList = discoveryClient.getServices();
//随机方式获得服务
int currentIndex = new Random().nextInt(2);
//轮询方式获得服务
//index = index + 1;
//int currentIndex =(index)% serviceList.size();
获取nacos中注册的指定服务信息
ServiceInstance instance = discoveryClient.getInstances("ribbon-provider").get(currentIndex);
String url = "http://" + instance.getHost() + ":" + instance.getPort() + "/provider/getUserById/" + id;
return restTemplate.getForObject(url, User.class);
}
}
二、什么是负载均衡
负载均衡就是将负载(工作任务,访问请求)进行分摊到多个操作单元(服务器,组件)上进行执行。
1.开启ribbon负载均衡
@Bean
@LoadBalanced//开启ribbon负载均衡,默认是轮询策略
public RestTemplate restTemplate(){
return new RestTemplate();
}
添加了@LoadBalanced注解之后,Ribbon会给restTemplate请求添加一个拦截器,在拦截器中获取 注册中心的服务列表,并使用Ribbon内置的负载均衡算法从服务列表里选中一个服务,通过获取到的服务信息 (ip,port)替换 serviceId 实现负载请求。
2、指定负载均衡的策略
//随机策略
@Bean
public IRule iRule() {
return new RandomRule();
}
负载均衡实现 | 策略 |
---|---|
随机策略:RandomRule | 从服务提供者的列表中随机选择一个服务实例 |
轮询策略:RoundRobinRule | 按照一定的顺序依次调用服务实例 |
可用敏感性策略:AvailabilityFilteringRule | 先过滤掉由于多次访问故障的服务,以及并发连接数超过阈值的服务,然后对剩下的服务按照轮询策略进行访问 |
权重策略:WeightedResponseTimeRule | 根据平均响应时间计算所有服务的权重,响 应时间越快服务权重就越大被选中的概率即越高,如果服务刚启动时统计信息不足,则 使用RoundRobinRule策略,待统计信息足够会切换到该WeightedResponseTimeRule策略 |
重试负载均衡策: RetryRule |
先按照 RoundRobinRule 策略获取 provider,若获取失败,则在指定的时限内重试。默认的时限为 500 毫秒。 |
最小连接数策略:BestAvailableRule | 先过滤掉由于多次访问故障的服务,然后选择一个并发量最小的服务 |
区域敏感策略:ZoneAvoidanceRule | 综合判断服务节点所在区域的性能和服务节点的可用性,来决定选择哪个服务 |
3、发送请求
@RestController
@RequestMapping("/consumer")
public class ConsumerController {
@Autowired
private RestTemplate restTemplate;
@Autowired
private DiscoveryClient discoveryClient;//发现服务的工具类
@RequestMapping("/getUserById/{id}")
public User getUserById(@PathVariable Integer id) {
String url = "http://ribbon-provider/provider/getUserById/"+id;
return restTemplate.getForObject(url, User.class);
}
}
三、ribbon存在的问题
url和参数还需要拼接,效率太低,不利于维护。
声明式服务调用Feign
一、背景
前文我们已经学到,当我们通过RestTemplate调用其它服务的API时,所需要的参数须在请求的URL中进行拼接,如果参数少的话或许我们还可以忍受,一旦有多个参数的话,这时拼接请求字符串就会效率低下,并且显得好傻。
那么有没有更好的解决方案呢?答案是确定的有,Netflix已经为我们提供了一个框架:Feign。
二、Feign概述
Feign是Spring Cloud提供的声明式、模板化的HTTP客户端, 它使得调用远程服务就像调用本地服务一样简单,只需要创建一个接口并添加一个注解即可。工作在consumer端。
Spring Cloud集成Feign并对其进行了增强,使Feign支持了Spring MVC注解;Feign默认集成了Ribbon,所以Fegin默认就实现了负载均衡的效果。
ribbon + restTemplate 优化后 = feign
三、Fegin入门
1、创建工程
1、 拷贝ribbon_provider_1
2、application.yml
server:
port: 9090
spring:
cloud:
nacos:
discovery:
server-addr: 192.168.216.133:8848
application:
name: feign-provider
2、创建feign接口
1、创建工程
2、pom.xml
<dependencies>
<!--Spring Cloud OpenFeign Starter -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>com.bjpowernode</groupId>
<artifactId>springcloud_common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
3、feign
@FeignClient("feign-provider")
@RequestMapping("/provider")
public interface UserFeign {
@RequestMapping("/getUserById/{id}")
public User getUserById(@PathVariable("id") Integer id);
}
3、创建服务消费者
1.创建工程
2、pom.xml
<!--feign接口-->
<dependency>
<groupId>com.zzcsy</groupId>
<artifactId>feign_interface</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
3、controller
@RestController
@RequestMapping("/consumer")
public class ConsumerController {
@Autowired
private UserFeign userFeign;//代理类
@RequestMapping("/getUserById/{id}")
public User getUserById(@PathVariable Integer id){
System.out.println(userFeign.getClass());
return userFeign.getUserById(id);
}
}
4、App
四、feign原理
1、将Feign接口代理类注入到Spring容器中
@EnableFeignClients开启feign注解扫描,调用FeignClientsRegistrar.registerFeignClients()方法扫描@FeignClient注解的接口生成代理类,并把接口和代理类交给Spring的容器管理。
2、为接口的方法创建RequestTemplate
当consumer调用feign代理类时,代理类会调用SynchronousMethodHandler.invoke()创建RequestTemplate(url,参数)
3、发起请求
代理类会通过RequestTemplate创建Request,然后client(URLConnetct、HttpClient、OkHttp)使用Request发送请求
五、feign参数传递
传参方式:
-
restful风格:
@PathVarible
【拼接restful形式的url】
-
?传参
@RequestParam
【拼接?形式的url】
-
pojo参数
@RequestBody User user
【获取请求体中的json串】