目录
1.注册中心
1.1.nacos注册中心
1.2. 微服务注册和拉取注册中心的内容
2.3.修改订单微服务的代码
3.负载均衡组件
3.1.什么是负载均衡
3.2.什么是Ribbon
3.3.Ribbon 的主要作用
3.4.Ribbon提供的负载均衡策略
4.openfeign完成服务调用
4.1.什么是OpenFeign
4.2.完成openfeign的调用
继 微服务工程 文章扩展的注册中心及负载均衡
1.注册中心
服务治理是微服务架构中最核心最基本的模块。用于实现各个微服务的自动化注册与发现。
服务注册:在服务治理框架中,都会构建一个注册中心,每个服务单元向注册中心登记自己提供服务的详细信息。并在注册中心形成一张服务的清单,服务注册中心需要以心跳30s 90s的方式去监测清单中 的服务是否可用,如果不可用,需要在服务清单中剔除不可用的服务。
服务发现:服务调用方向服务注册中心咨询服务,并获取*所有服务*的实例清单,实现对具体服务实例的访问。
通过上面的调用图会发现,除了微服务,还有一个组件是服务注册中心,它是微服务架构非常重要的一个组件,在微服务架构里主要起到了协调者的一个作用。注册中心一般包含如下几个功能:
1. 服务发现:
服务注册:保存服务提供者和服务调用者的信息
服务订阅:服务调用者订阅服务提供者的信息,注册中心向订阅者推送提供者的信息
2. 服务配置:
配置订阅:服务提供者和服务调用者订阅微服务相关的配置
配置下发:主动将配置推送给服务提供者和服务调用者
3. 服务健康检测
检测服务提供者的健康情况,如果发现异常,执行服务剔除
1.1.nacos注册中心
官网nacos
nacos资源已上传
解压后打开
修改:
默认它启动模式为--集群模式---修改它为单机模式
修改后保存退出
访问:
http://localhost:8848/nacos 账号和密码: nacos
1.2. 微服务注册和拉取注册中心的内容
商品微服务:
引入依赖
<!--引入nacos的依赖--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency>
修改配置文件
#nacos注册中心的地址 spring.cloud.nacos.discovery.server-addr=localhost:8848 #为微服务定义名称 spring.application.name=qy165-product
发现:
2.3.修改订单微服务的代码
引入依赖
<!--引入nacos的依赖--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency>
修改配置文件
#nacos注册中心的地址 spring.cloud.nacos.discovery.server-addr=localhost:8848 #为微服务定义名称 spring.application.name=qy165-order
解决硬编码问题
package com.wqg.order.controller; import com.wqg.entity.Order; import com.wqg.entity.Product; import com.wqg.order.service.OrderService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.discovery.DiscoveryClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; import java.util.List; @RestController @RequestMapping("order") public class OrderController01 { @Autowired private OrderService orderService; @Autowired private RestTemplate restTemplate; //在springcloud依赖中存在一个类DiscoveryClient 该类可以从注册中心拉取指定的服务列表清单 @Autowired private DiscoveryClient discoveryClient; @GetMapping("insert") public String insert(Long pid, Integer num) { //创建订单--添加数据 Order order = new Order(); order.setUid(5L); order.setUsername("笔记本"); order.setNumber(num); List<ServiceInstance> instances = discoveryClient.getInstances("qy165-product"); ServiceInstance serviceInstance = instances.get(0); //根据服务实例对象获取相对应的ip和端口号 String path = serviceInstance.getUri().toString(); //商品信息 Product product = restTemplate.getForObject(path+"/product/getById/"+pid, Product.class); order.setPid(product.getPid()); order.setPname(product.getPname()); order.setPprice(product.getPprice()); int i = orderService.saveOrder(order); return i > 0 ? "下单成功" : "下单失败"; } }
3.负载均衡组件
3.1.什么是负载均衡
通俗的讲, 负载均衡就是将负载(工作任务,访问请求)进行分摊到多个操作单元(服务器,组件)上进行执行。
根据负载均衡发生位置的不同,一般分为服务端负载均衡和客户端负载均衡。
服务端负载均衡指的是发生在服务提供者一方,比如常见的nginx负载均衡
而客户端负载均衡指的是发生在服务请求的一方,也就是在发送请求之前已经选好了由哪个实例处理请求
我们在微服务调用关系中一般会选择客户端负载均衡,也就是在服务调用的一方来决定服务由哪个提供者执行.
演示:---手动完成负载均衡
模拟搭建商品微服务n台
手动实现负载均衡----随机负载均衡
修改OrderController订单代码
@RestController @RequestMapping("order") public class OrderController02 { @Autowired private OrderService orderService; @Autowired private RestTemplate restTemplate; @Autowired private DiscoveryClient discoveryClient; @GetMapping("insert") public String insert(Long pid, Integer num) { //创建订单--添加数据 Order order = new Order(); order.setUid(5L); order.setUsername("笔记本"); order.setNumber(num); List<ServiceInstance> instances = discoveryClient.getInstances("qy165-product"); int index = new Random().nextInt(instances.size()); ServiceInstance serviceInstance = instances.get(index); String s = serviceInstance.getUri().toString(); //商品信息 Product product = restTemplate.getForObject(s+"/product/getById/"+pid, Product.class); order.setPid(product.getPid()); order.setPname(product.getPname()); order.setPprice(product.getPprice()); int i = orderService.saveOrder(order); return i > 0 ? "下单成功" : "下单失败"; } }
上面通过手动完成了负载均衡的调用,存在的问题: 它采用的随机负载均衡,如何我想使用轮询负载均衡策略。
只能修改源代码。耦合。---springcloud提供了一个组件--可以灵活的完成负载均衡。--ribbon
3.2.什么是Ribbon
是 Netflix 发布的一个负载均衡器,有助于控制 HTTP 和 TCP 客户端行为。在 Springcloud中, nacos 一般配合 Ribbon 进行使用,Ribbon 提供了客户端负载均衡的功能,Ribbon 利用从 nacos 中读 取到的服务信息,在调用服务节点提供的服务时,会合理(策略) 的进行负载。在Springcloud 中可以将注册中心和Ribbon 配合使用,Ribbon 自动的从注册中心中获取服务提供者的 列表信息,并基于内置的负载均衡算法,请求服务。
3.3.Ribbon 的主要作用
(1)服务调用
基于 Ribbon 实现服务调用,是通过拉取到的所有服务列表组成 ( 服务名-请求路径的 ) 映射关系。借助 RestTemplate最终进行调用.
(2)负载均衡
当有多个服冬提供者时,Ribbon 可以根据负载均衡的算法自动的选择需要调用的服务地址
如何使用Ribbon实现负载均衡
在RestTemplate生成类上加入@LoadBalanced
修改OrderController订单代码
@RestController @RequestMapping("order") public class OrderController03 { @Autowired private OrderService orderService; @Autowired private RestTemplate restTemplate; @GetMapping("insert") public String insert(Long pid, Integer num) { //创建订单--添加数据 Order order = new Order(); order.setUid(5L); order.setUsername("笔记本"); order.setNumber(num); //商品信息 Product product = restTemplate.getForObject("http://qy165-product/product/getById/"+pid, Product.class); order.setPid(product.getPid()); order.setPname(product.getPname()); order.setPprice(product.getPprice()); int i = orderService.saveOrder(order); return i > 0 ? "下单成功" : "下单失败"; } }
测试
3.4.Ribbon提供的负载均衡策略
Ribbon内置了多种负载均衡策略,内部负载均衡的顶级接口为:com.netflix.loadbalancer.IRule,具体的负载策略如下所示:
策略名 策略描述 实现说明 BestAvailableRule 选中一个最小的并发请求的server 逐个考察Server,如果Server被 tripped了,则忽略,在选择其中ActiveRequestsCount最小的server RandomRule 随机选择一个server 在index上随机,选择index对应位置的server RoundRobinRule 轮询方式轮询选择 轮询index,选择index对应位置的 AvailabilityFilteringRule 过滤掉那些因为一直连接失败的被标记为circuittripped的后端server,并过滤掉 那些高并发的的后端server (activeconnections 超过配置的阈值) 使用一个AvailabilityPredicate来包含过滤server的逻辑,其实就是检查 status里记录的各个server的运行状态 WeightedResponseTimeRule 根据相应时间分配一个weight,相应时间越长,weight越小,被选中的可能性越低 一个后台线程定期的从status里面读取评价响应时间,为每个server计算一个weight。Weight的计算也比较简单responsetime减去每个server自己平均的responsetime是server的权重。当刚开始运行,没有形成statas时,使用roubine策略选择server。 RetryRule 对选定的负载均衡策略机上重试机制 在一个配置时间段内当选择server不成功,则一直尝试使用subRule的方式选择一个可用的server ZoneAvoidanceRule 复合判断server所在区域的性能和server的可用性选择server 使用ZoneAvoidancePredicate和AvailabilityPredicate来判断是否选择某个server,前一个判断判定一个zone的运行性能是否可用,剔除不可用的zone(的所有server),AvailabilityPredicate用于过滤掉 ribbon内置的负载均衡策略,默认轮询,也可以自定义负载均衡。
如何修改ribbon组件的负载均衡策略----修改配置文件
修改为随机:
#修改ribbon的负载均衡策略---随机 qy165-product.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RandomRule
4.openfeign完成服务调用
4.1.什么是OpenFeign
OpenFeign是Spring Cloud提供的一个声明式的伪Http客户端, 它使得调用远程服务就像调用本地方法一样简单, 只需要创建一个接口并添加一个注解即可。
Nacos很好的兼容了OpenFeign, OpenFeign负载均衡默认集成了 Ribbon, 所以在Nacos下使用OpenFeign默认就实现了负载均衡的效果。
4.2.完成openfeign的调用
订单微服务
(1)依赖
<!--openfeign依赖--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
(2)创建openfeign接口
@FeignClient(value = "qy165-product") public interface ProductFeign { //接口的方法 必须 和被调用者的接口的参数一致 @GetMapping("/product/getById/{id}") public Product getById(@PathVariable Long id); //springcloud 扫描到@FeignClient注解时--生产一个代理实现类. }
(3)开启openfeign注解驱动
(4)修改OrderController
@RestController @RequestMapping("order") public class OrderController04 { @Autowired private OrderService orderService; @Autowired private ProductFeign productFeign; @GetMapping("insert") public String insert(Long pid, Integer num) { //创建订单--添加数据 Order order = new Order(); order.setUid(5L); order.setUsername("笔记本"); order.setNumber(num); //商品信息 Product product = productFeign.getById(pid); order.setPid(product.getPid()); order.setPname(product.getPname()); order.setPprice(product.getPprice()); int i = orderService.saveOrder(order); return i > 0 ? "下单成功" : "下单失败"; } }