前言 :本文主要阐述微服务架构中的服务治理,以及Nacos环境搭建、服务注册、服务调用,负载均衡以及Feign实现服务调用。
服务治理

这里还有一个必不可少的组件,就是服务注册中心,它是微服务架构非常重要的一个组件,在微服务架构里主要起到了协调者的一个作用。
常见的服务注册中心
Zookeeper:是一个分布式服务框架,主要用来解决分布式应用中经常遇到的数据管理问题,如:统一命名服务、状态同步服务、集群管理、分布式应用 配置项的管理等。
Eureka:Spring Cloud 微服务框架默认的也是推荐的服务注册中心,主要作用就是做服务注册和发现。主要面向分布式,服务化的系统提供服务注册、服务发现 和 配置管理的功能。
Nacos:Ailibab旗下的开源项目,是一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台,负责服务注册发现和服务配置。
对比总结
特性 | Eureka | Nacos | Zookeeper |
---|---|---|---|
一致性模型 | AP | AP/CP 可切换 | CP |
健康检查 | 心跳 | TCP/HTTP/自定义 | 心跳 |
配置管理 | 不支持 | 支持 | 支持(ZNode) |
多数据中心 | 不支持 | 支持 | 不支持 |
社区生态 | 停滞 | 活跃(阿里云) | 成熟(Apache) |
适用场景 | Spring Cloud 旧项目 | 全功能服务治理 | 强一致性协调服务 |
Nacos
Nacos(Dynamic Naming and Configuration Service)是阿里巴巴开源的一款集服务注册与发现、配置管理于一体的动态服务管理平台。它帮助开发者构建云原生应用和微服务架构,实现服务的动态发现、健康管理、配置统一管理等功能。
环境搭建
进入bin目录
启动Nacos
startup.cmd -m standalone
访问网址:127.0.0.1:8848/nacos
服务注册
1.添加依赖
<!--nacos 客户端-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
2.启动类注解标签
@EnableDiscoveryClient
3. 定义服务名,添加nacos服务地址
spring:
application:
name: service-order #服务名
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848 #nacos 地址
此时商品,订单,用户服务均已注册成功。
服务调用
@RestController
@RequestMapping("/order")
public class OrderController{
@Autowired
OrderService orderService;
@Autowired
DiscoveryClient discoveryClient;
@Autowired
RestTemplate restTemplate;
@RequestMapping("/create/{pid}/{uid}/{num}")
public Order createOrder(@PathVariable("pid") int pid, @PathVariable("uid")int uid, @PathVariable("num") int num){
ServiceInstance serviceInstance = discoveryClient.getInstances("service-product").get(0);
//ip + port
String purl = serviceInstance.getHost() + ":" + serviceInstance.getPort();
//使用
ServiceInstance userviceInstance = discoveryClient.getInstances("service-user").get(0);
//ip + port
String uurl = userviceInstance.getHost() + ":" + userviceInstance.getPort();
Product p = restTemplate.getForObject( "http://" + purl + "/product/get/" + pid, Product.class);
User u = restTemplate.getForObject( "http://" + uurl + "/user/get/" + uid, User.class);
Order order= null;
if(p!=null){
if(p.getStock()>=num){
if(u!=null){
order = orderService.saveorder(pid,uid,num);
}
}
}
return order;
}
}
与单一使用 RestTemplate 使用 http 方式远程访问相比,解决了很多繁琐的步骤与人工维护。
负载均衡
自定义实现
1.修改端口启动多个商品微服务
2.将获取服务的方式改为随机获取
核心代码:
//获取服务列表
List<ServiceInstance> instances =
discoveryClient.getInstances("service-product");
//随机生成索引
Integer index = new Random().nextInt(instances.size());
//获取服务
ServiceInstance productService = instances.get(index);
//获取服务地址
String purl = productService.getHost() + ":" +
productService.getPort();
Ribbon实现
Ribbon 是 Spring Cloud 的一个组件, 它可以让我们使用一个注解就能轻松的搞定负载均衡。
1.在 RestTemplate 的生成方法上添加@LoadBalanced 注解
2.修改服务调用的方法
Product p = restTemplate.getForObject( "http://service-product/product/get/" + pid, Product.class);
User u = restTemplate.getForObject( "http://service-user/user/get/" + uid, User.class);
Ribbon 支持的负载均衡策略 Ribbon 内置了多种负载均衡策略,内部负载均衡的顶级接口为 com.netflix.loadbalancer.IRule
3. 配置
ribbon:
ConnectTimeout: 2000 # 请求连接的超时时间
ReadTimeout: 5000 # 请求处理的超时时间
service-product: # 调用的提供者的名称
ribbon:
NFLoadBalancerRuleClassName:com.netflix.loadbalancer.RandomRule #负载均衡策略
Ribbon 的七种负载均衡策略
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RoundRobinRule
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.WeightedResponseTimeRule
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.BestAvailableRule
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.AvailabilityFilteringRule
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.ZoneAvoidanceRule
Feign
服务调用
1.添加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2.启动类添加Feign注解
@EnableFeignClients//开启 Fegin
3.创建Service接口,使用Feign实现服务调用
@FeignClient(name = "service-product")
public interface ProductService {
@GetMapping("/product/get/{id}")
Product findProductById(@PathVariable int id);
}
4.调用
//使用前要注入
@Autowired
ProductService productService;
//使用feign
Product p = productService.findProductById(pid);
//不使用feign
User u = restTemplate.getForObject( "http://service-user/user/get/" + uid, User.class);