目录
一、微服务的注册中心
1、注册中心的主要作用
(1)服务发现
(2)服务配置
(3)服务健康检测
2、 常见的注册中心
二、nacos简介
1、nacos实战入门
(1)搭建nacos环境
(2)将商品/订单等微服务注册到nacos
三、服务调用Ribbon入门
1、Ribbon概述
(1)什么是Ribbon
(2)Ribbon的主要作用
2、基于Ribbon实现订单调用商品服务
(1)坐标依赖
(2)具体实现
四、服务调用Ribbon高级
1、负载均衡概述
(1)什么是负载均衡
(2)客户端负载均衡与服务端负载均衡
2、基于Ribbon实现负载均衡
(2)负载均衡策略
五、Nacos配置管理
1、统一配置管理
(1)在nacos中添加配置文件
(2)从微服务拉取配置
2、配置热更新
(1)方式一
(2)方式二(硬编码方式)
3、配置共享
(1)同服务内配置共享
(2)不同微服务共享配置
(3)配置共享的优先级
一、微服务的注册中心
注册中心可以说是微服务架构中的"通讯录",它它记录了服务和服务地址的映射关系。在分布式架构中,服务会注册到这里,当服务需要调用其它服务时,就这里找到服务的地址,进行调用。
1、注册中心的主要作用
服务注册中心(下称注册中心)是微服务架构非常重要的一个组件,在微服务架构里主要起到了协调者的一个作用。注册中心一般包含如下几个功能:
(1)服务发现
- 服务注册/反注册:保存服务提供者和服务调用者的信息。
- 服务订阅/取消订阅:服务调用者订阅服务提供者的信息,最好有实时推送的功能服务路由(可选):具有筛选整合服务提供者的能力。
(2)服务配置
- 配置订阅:服务提供者和服务调用者订阅微服务相关的配置。
- 配置下发:主动将配置推送给服务提供者和服务调用者。
(3)服务健康检测
- 检测服务提供者的健康情况。
2、 常见的注册中心
Zookeeper:zookeeper它是一个分布式服务框架,是Apache Hadoop 的一个子项目,它主要是用来解决分布式应用中经常遇到的一些数据管理问题,如:统一命名服务、状态同步服务、集群管理、分布式应用配置项的管理等。简单来说zookeeper=文件系统+监听通知机制。
Eureka:Eureka是在Java语言上,基于Restful Api开发的服务注册与发现组件,Springcloud Netfix中的重要组件。
Consul:Consul是由HashiCorp基于Go语言开发的支持多数据中心分布式高可用的服务发布和注册服务软件,采用Raft算法保证服务的一致性,且支持健康检查。
Nacos:Nacos是一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。简单来说 Nacos 就是注册中心 + 配置中心的组合,提供简单易用的特性集,帮助我们解决微服务开发必会涉及到的服务注册与发现,服务配置,服务管理等问题。。Nacos 还是 Spring Cloud Alibaba 组件之一,负责服务注册与发现。
Eureka闭源影响:
在Euraka的GitHub上,宣布Eureka 2.x闭源。近这意味着如果开发者继续使用作为 2.x 分支上现有工作repo一部分发布的代码库和工件,则将自负风险。Nacos替换方案。
二、nacos简介
Nacos 致力于帮助您发现、配置和管理微服务。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据及流量管理。nacos的作用就是一个注册中心,用来管理注册上来的各个微服务。
1、nacos实战入门
(1)搭建nacos环境
下载完后启动nacos有两种操作:startup.cmd -m standalone 或者直接双击startup.cmd运行。
然后访问nacos:打开浏览器输⼊http://localhost:8848/nacos,即可访问服务, 默认密码是nacos/nacos。
还是订单管理服务平台,代码我就不重复展示了,就展示新知识点的代码。
(2)将商品/订单等微服务注册到nacos
我们就以商品模块为模板,开始修改 shop-product 模块的代码,将其注册到nacos服务上:
在pom.xml中添加nacos的依赖:
<!-- nacos客户端 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
在主类上添加@EnableDiscoveryClient注解:
@SpringBootApplication
@EnableDiscoveryClient
public class ProductApplication {
public static void main(String[] args) {
SpringApplication.run(ProductApplication.class);
}
}
@EnableDiscoveryClient 这个注解启用服务发现客户端功能,允许应用向服务注册中心(如 Eureka、Nacos)注册自身,并从中发现其他服务。使得应用能够作为服务消费者和生产者,支持服务注册和发现。这个项目中就是用order层来调用product层和user层服务的,和他们自身的注册。
在application.yml中添加nacos服务的地址:
server:
port: 8081
spring:
application:
name: service-product
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/springwork?serverTimezone=GMT
username: root
password: 123456
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
在yml中主要增加nacos服务地址,cloud是Spring Cloud 的根配置节点,nocos是指定 Nacos 的相关配置。discovery是节点配置与服务发现相关的设置,这个配置使得应用能够通过 Nacos 注册到服务注册中心,并从中发现其他服务。server-addr是配置 Nacos 服务器的地址。
启动服务,观察nacos的控制面板中是否有注册上来的商品/用户微服务:
显示商品和用户服务已经进行了注册。
那么最后再去shop_order模块中去调用控制器中的方法:
@RestController
public class OrderController {
@Autowired
private RestTemplate restTemplate;
@Autowired
private IOrderService orderService;
//获取nacos中服务的元数据
@Autowired
private DiscoveryClient discoveryClient;
//下单
@RequestMapping("/order/prod/{pid}")
public Order order(@PathVariable("pid") Integer pid) {
//从nacos中获取服务地址
ServiceInstance serviceInstance = discoveryClient.getInstances("service-product").get(0);
String url = serviceInstance.getHost() + ":" + serviceInstance.getPort();
//通过restTemplate调用商品微服务
Product product = restTemplate.getForObject( "http://" + url + "/product/" + pid, Product.class);
//下单(创建订单)
Order order = new Order();
order.setUid(1);
order.setUsername("测试用户");
order.setPid(pid);
order.setPname(product.getPname());
order.setPprice(product.getPprice());
order.setNumber(1);
orderService.createOrder(order);
return order;
}
}
这里和普通的调用不一样的是上次我们调用微服务是用"http://localhost:8081/product/" + pid,来执行服务方法和操作。
这次用的是通过discoveryClient对象来完成微服务注册中心的调用服务。通过getInstances("service-product")从Nacos中获取名为service-product的所有服务实例。
再通过拼接服务实例的主机名getHost()和获取端口号getPost()来构建服务的 URL。大概就为http://127.0.0.1:8091/product/4。
通过getForObject方法,调用商品服务的 /product/{pid} 接口,获取指定商品的详细信息,并将结果映射为 Product 对象。
三、服务调用Ribbon入门
经过以上的学习,已经实现了服务的注册和服务发现。当启动某个服务的时候,可以通过HTTP的形式将信息注册到注册中心,并且可以通过SpringCloud提供的工具获取注册中心的服务列表。但是服务之间的调用还存在很多的问题,如何更加方便的调用微服务,多个微服务的提供者如何选择,如何负载均衡等。
1、Ribbon概述
(1)什么是Ribbon
是 Netfixfa 发布的一个负载均衡器,有助于控制 HTTP 和 TCP客户端行为。在 SpringCloud 中Nacos一般配合Ribbon进行使用,Ribbon提供了客户端负载均衡的功能,Ribbon利用从Nacos中读取到的服务信息,在调用服务节点提供的服务时,会合理的进行负载。在SpringCloud中可以将注册中心和Ribbon配合使用,Ribbon自动的从注册中心中获取服务提供者的列表信息,并基于内置的负载均衡算法,请求服务。
(2)Ribbon的主要作用
服务调用:基于Ribbon实现服务调用,是通过拉取到的所有服务列表组成(服务名-请求路径的)映射关系。借助RestTemplate 最终进行调用。
负载均衡:当有多个服务提供者时,Ribbon可以根据负载均衡的算法自动的选择需要调用的服务地址。
2、基于Ribbon实现订单调用商品服务
(1)坐标依赖
在springcloud提供的服务发现的jar中以及包含了Ribbon的依赖。所以这里不需要导入任何额外的坐标。
(2)具体实现
首先在创建RestTemplate方法上添加 @LoadBalanced 注解:
@SpringBootApplication
@EnableDiscoveryClient
public class OrderApplication {
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class);
}
@Bean
@LoadBalanced//负载均衡
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
这里的@LoadBalanced是为 RestTemplate 添加负载均衡能力。Spring Cloud 会自动为这个 RestTemplate 实例配置一个负载均衡客户端(Ribbon),使其能够在调用其他服务时实现客户端的负载均衡。
使用 @LoadBalanced 的 RestTemplate 时,可以使用服务名而不是具体的 URL。例如:http://service-product/product/4,其中 service-product 是微服务的名称,而不是具体的 IP 和端口。
所以我们就可以通过服务名来使用其方法:
@RestController
public class OrderController {
@Autowired
private RestTemplate restTemplate;
@Autowired
private IOrderService orderService;
//Ribbon下单
@RequestMapping("/order/prod/{pid}")
public Order order(@PathVariable("pid") Integer pid) {
//通过restTemplate调用商品微服务
String url = "service-product";
Product product = restTemplate.getForObject( "http://"+url+"/product/" + pid, Product.class);
//下单(创建订单)
Order order = new Order();
order.setUid(1);
order.setUsername("测试用户");
order.setPid(pid);
order.setPname(product.getPname());
order.setPprice(product.getPprice());
order.setNumber(1);
orderService.createOrder(order);
return order;
}
}
里面直接定义了服务名称service-product,再用getForObject调用商品服务。
四、服务调用Ribbon高级
1、负载均衡概述
(1)什么是负载均衡
在搭建网站时,如果单节点的 web服务性能和可靠性都无法达到要求;或者是在使用外网服务时,经常担心被人攻破,一不小心就会有打开外网端口的情况,通常这个时候加入负载均衡就能有效解决服务问题。
负载均衡是一种基础的网络服务,其原理是通过运行在前面的负载均衡服务,按照指定的负载均衡算法,将流量分配到后端服务集群上,从而为系统提供并行扩展的能力。
负载均衡的应用场景包括流量包、转发规则以及后端服务,由于该服务有内外网个例、健康检查等功能,能够有效提供系统的安全性和可用性。
(2)客户端负载均衡与服务端负载均衡
服务端负载均衡:先发送请求到负载均衡服务器或者软件,然后通过负载均衡算法,在多个服务器之间选择一个进行访问;即在服务器端再进行负载均衡算法分配。
客户端负载均衡:客户端会有一个服务器地址列表,在发送请求前通过负载均衡算法选择一个服务器,然后进行访问,这是客户端负载均衡;即在客户端就进行负载均衡算法分配。
2、基于Ribbon实现负载均衡
通过idea再启动一个 shop-product 微服务,设置其端口为8082:
分别启动两次服务器验证效果,并查看两个控制台发现已轮询的方式调用了商品服务。
(2)负载均衡策略
Ribbon内置了多种负载均衡策略,内部负责复杂均衡的顶级接口为com.netflix.loadbalancer.IRue,实现方式如下:
- com.netflix.loadbalancer.RoundRobinRule9:以轮询的方式进行负载均衡。
- com.netflix.loadbalancer.RandomRue:随机策略com.netflix.loadbalancer.RetryRule :重试策略
- com.netflix.oadbalancer.WeightedResponseTimeRule:权重策略。会计算每个服务的权重,越高的被调用的可能性越大。
- com.netflix.loadbalancer.BestAvailableRule:最佳策略。遍历所有的服务实例,过滤掉故障实例,并返回请求数最小的实例返回。
- com.netflix.loadbalancer.AvailabilityFilteringRule:可用过滤策略。过滤掉故障和请 求数超过阈值的服务实例,再从剩下的实力中轮询调用。
- ZoneAvoidanceRule:以区域可用的服务器为基础进行服务器的选择。使用Zone对服务器进行分类,这个Zone可以理解为一个机房、一个机架等。而后再对Zone内的多个服务做轮询。
呢么根据刚才的实现代码,将shop_order模块中的pom加上负载均衡策略:
service-product:
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RoundRobinRule9
这里实现了轮询方式进行负载均衡,所以就是每次我调用呢个url就会在1号控制台中输出,然后是2号控制台,紧接着又是2号控制台,依次轮询。
还有可以设置自定义负载均衡策略:
service-product:
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRue
这里是使用RandomRue,意思是随机的去进行负载。
全局设置:
@Bean
public IRule randomRule(){
return new RandomRule();
}
局部设置:
#需要调⽤的微服务名称
service-product:
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
五、Nacos配置管理
Nacos除了可以做注册中心,同样可以做配置管理来使用。
1、统一配置管理
当微服务部署的实例越来越多,达到数十、数百时,逐个修改微服务配置就会让人抓狂,而且很容易出错。我们需要一种统一配置管理方案,可以集中管理所有实例的配置。
Nacos一方面可以将配置集中管理,另一方可以在配置变更时,及时通知微服务,实现配置的热更新。
在业界常见的服务配置中心,有下面这些:
- Apollo是由携程开源的分布式配置中心。特点有很多,比如:配置更新之后可以实时生效,支.持灰度发布功能,并且能对所有的配置进行版本管理、操作审计等功能,提供开放平台API。并且资料也写的很详细。
- Disconf是由百度开源的分布式配置中心。它是基于Zookeeper来实现配置变更后实时通知和生效的。
- SpringCloud Config这是Spring Cloud中带的配置中心组件。它和Spring是无缝集成,使用起来非常方便,并且它的配 置存储支持Git。不过它没有可视化的操作界面,配置的生效也不是实时的,需要重启或去刷新。
- Nacos这是SpingCloud alibaba技术栈中的一个组件,前面我们已经使用它做过服务注册中心。其实它也集成了服务配置的功能,我们可以直接使用它作为服务配置中心。
(1)在nacos中添加配置文件
注意:项目的核心配置,需要热更新的配置才有放到nacos管理的必要。基本不会变更的一些配置还是保存在微服务本地比较好。
(2)从微服务拉取配置
微服务要拉取nacos中管理的配置,并且与本地的application.yml配置合并,才能完成项目启动。但如果尚未读取application.yml,又如何得知nacos地址呢?因此spring引入了一种新的配置文件: bootstrap.yaml文件,会在application.yml之前被读取,流程如下:
配置实现步骤:
引入nacos-config依赖(在shop_product模块中导入坐标):
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
添加bootstrap.yaml:
不能使用原来的application.yml作为配置文件,而是新建一个bootstrap.yml作为配置文件配置文件优先级(由高到低):
bootstrap.properties ->bootstrap.yml ->application.properties -> application.yml
spring:
application:
name: service-product
cloud:
nacos:
config:
server-addr: 127.0.0.1:8848 #nacos中⼼地址
file-extension: yaml # 配置⽂件格式
profiles:
active: dev # 环境标识,开发环境
然后在nacos中添加配置。
2、配置热更新
我们最终的目的,是修改nacos中的配置后,微服务中无需重启即可让配置生效,也就是配置热更新。要实现配置热更新,可以使用两种方式:
配置中心添加配置:
config:
appName: product
(1)方式一
在@Value注⼊的变量所在类上添加注解@RefreshScope:
@RestController
@RefreshScope//只需要在需要动态读取配置的类上添加此注解就可以
public class NacosConfigController {
@Value("${config.appName}")
private String appName;
@GetMapping("/nacos-config-test1")
public String nacosConfingTest1() {
return appName;
}
}
@RefreshScope,这个注解来自 Spring Cloud,表示这个类中的配置可以在运行时动态刷新。只要在需要动态读取配置的类上添加此注解,Spring Cloud Config 配合 Nacos 就会在配置改变时自动更新该类中的配置属性。
@Value("${config.appName}"),这是一个 Spring 的注解,用来从配置文件,这里我们是从刚才配置的nacos服务中的yml文件中读取。
通过配置上面的代码就可以实现在nacos中修改服务时,不用重新启动也能获取更新。
(2)方式二(硬编码方式)
@RestController
public class NacosConfigController {
@Autowired
private ConfigurableApplicationContext applicationContext;
@GetMapping("/nacos-config-test2")
public String nacosConfingTest2() {
return applicationContext.getEnvironment().getProperty("config.appName");
}
}
这里在控制器中定义了一个ConfigurableApplicationContext实例,通过这个变量,可以访问 Spring 的环境配置和应用上下文。
后面的方法中用getEnvironment()方法获取Environment对象,然后再通过getProperty("config.appName")获取名为 config.appName 的属性值。
3、配置共享
当配置越来越多的时候,我们就发现有很多配置是重复的,这时候就考虑可不可以将公共配置文件提取出来。
(1)同服务内配置共享
现步骤:
- 新建一个以 spring.application.name 命名的配置文件,然后将其所有环境的公共配置放在里面。
- 新建一个名为service-product-test.yaml配置存放测试环境的配置。
- 新建一个名为service-product-dev.yaml配置存放开发环境的配置。
- 在两个环境文件中配置独有信息。
#多配置⼀段
config:
env: test
#多配置⼀段
config:
env: dev
添加测试的方法:
@RestController
@RefreshScope
public class NacosConfigController {
@Value("${config.env}")
private String env;
//3 同⼀微服务的不同环境下共享配置
@GetMapping("/nacos-config-test3")
public String nacosConfingTest3() {
return env;
}
}
(2)不同微服务共享配置
不同服务之间实现配置共享的原理类似于文件引入,就是定义一个公共配置,然后在当前配置中引入。
在nacos中定义一个DatalD为datasource.yaml的配置,用于所有微服务共享:
然后再去把配置好的service-product-dev服务配置内容进行对重复内容删减:
最后去修改bootstrap.yaml文件:
spring:
application:
name: service-product
cloud:
nacos:
config:
server-addr: 127.0.0.1:8848 #nacos中⼼地址
file-extension: yaml # 配置⽂件格式
shared-dataids: DataSource.yml # 配置要引⼊的配置
refreshable-dataids: DataSource.yml # 配置要实现动态配置刷新的配置
profiles:
active: dev # 环境标识,开发环境
其中shared-dataids就是要引入的配置,定义要从 Nacos 配置中心引入的共享配置文件。DataSource.yml 是文件的 ID,表示要引入的数据源配置,也就是公共配置。
refreshablee-dataids配置的是要实现动态配置刷新的配置,指定可以动态刷新的配置文件。DataSource.yml 表示当 Nacos 中该文件内容变化时,Spring 应用会自动刷新相关的配置。
最后启动商品微服务进行测试。
(3)配置共享的优先级
当nacos、服务本地同时出现相同属性时,优先级有高低之分: