前言?:本文主要闡述微服務架構中的服務治理,以及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{@AutowiredOrderService orderService;@AutowiredDiscoveryClient discoveryClient;@AutowiredRestTemplate 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 + portString purl = serviceInstance.getHost() + ":" + serviceInstance.getPort();//使用ServiceInstance userviceInstance = discoveryClient.getInstances("service-user").get(0);//ip + portString 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.調用
//使用前要注入@AutowiredProductService productService;
//使用feignProduct p = productService.findProductById(pid);//不使用feignUser u = restTemplate.getForObject( "http://service-user/user/get/" + uid, User.class);