之前我講過 Nacos文章 的內容,想要深入瞭解的 朋友的話,可以去看看 ,我們繼續承接上篇講下去 --> 第二章 : 微服務環境搭建
3.1 服務治理介紹
先來思考一個問題
通過上一章的操作,我們已經可以實現微服務之間的調用。但是我們把服務提供者的網絡地址(ip,端口)等硬編碼到了代碼中,這種做法存在許多問題:
- 一旦服務提供者地址變化,就需要手工修改代碼
- 一旦是多個服務提供者,無法實現負載均衡功能
- 一旦服務變得越來越多,人工維護調用關係困難
那麼應該怎麼解決呢, 這時候就需要通過註冊中心動態的實現服務治理。
什麼是服務治理
服務治理是微服務架構中最核心最基本的模塊。用於實現各個微服務的自動化註冊與發現。
-
服務註冊: 在服務治理框架中,都會構建一個註冊中心,每個服務單元向註冊中心登記自己提供服務的詳細信息。並在註冊中心形成一張服務的清單,服務註冊中心需要以心跳的方式去監測清單中的服務是否可用,如果不可用,需要在服務清單中剔除不可用的服務。
-
**服務發現:**服務調用方向服務註冊中心諮詢服務,並獲取所有服務的實例清單,實現對具體服務實例的訪問。
通過上面的調用圖會發現,除了微服務,還有一個組件是服務註冊中心,它是微服務架構非常重要的一個組件,在微服務架構裏主要起到了協調者的一個作用。註冊中心一般包含如下幾個功能:
1. 服務發現:
- **服務註冊:**保存服務提供者和服務調用者的信息
- **服務訂閱:**服務調用者訂閱服務提供者的信息,註冊中心向訂閱者推送提供者的信息
2. 服務配置:
- 配置訂閱: 服務提供者和服務調用者訂閱微服務相關的配置
- 配置下發: 主動將配置推送給服務提供者和服務調用者
3. 服務健康檢測
- 檢測服務提供者的健康情況,如果發現異常,執行服務剔除
常見的註冊中心
- Zookeeper
zookeeper 是一個分佈式服務框架,是Apache Hadoop 的一個子項目,它主要是用來解決分佈式應用中經常遇到的一些數據管理問題,如:統一命名服務、狀態同步服務、集羣管理、分佈式應用配置項的管理等。
-
Eureka
Eureka是Springcloud Netflix中的重要組件,主要作用就是做服務註冊和發現。但是現在已經閉源
-
Consul
Consul是基於GO語言開發的開源工具,主要面向分佈式,服務化的系統提供服務註冊、服務發現和配置管理的功能。Consul的功能都很實用,其中包括:服務註冊/發現、健康檢查、Key/Value存儲、多數據中心和分佈式一致性保證等特性。Consul本身只是一個二進制的可執行文件,所以安裝和部署都非常簡單,只需要從官網下載後,在執行對應的啓動腳本即可。
- Nacos
Nacos是一個更易於構建雲原生應用的動態服務發現、配置管理和服務管理平臺。它是 Spring Cloud Alibaba 組件之一,負責服務註冊發現和服務配置,可以這樣認爲nacos=eureka+config
。
3.2 nacos簡介
Nacos 致力於幫助您發現、配置和管理微服務。Nacos 提供了一組簡單易用的特性集,幫助您快速
實現動態服務發現、服務配置、服務元數據及流量管理。
從上面的介紹就可以看出,nacos的作用就是一個註冊中心,用來管理註冊上來的各個微服務。
3.3 nacos實戰入門
接下來,我們就在現有的環境中加入nacos,並將我們的兩個微服務註冊上去。
3.3.1 搭建nacos環境
第1步: 安裝nacos
下載地址: https://github.com/alibaba/nacos/releases
下載zip格式的安裝包,然後進行解壓縮操作
第2步: 啓動nacos
#切換目錄
cd nacos/bin
#命令啓動
startup.cmd -m standalone
第3步: 訪問nacos
打開瀏覽器輸入http://localhost:8848/nacos,即可訪問服務, 默認密碼是nacos/nacos
3.3.2 將商品微服務註冊到nacos
接下來開始修改shop-product
模塊的代碼, 將其註冊到nacos服務上
1 在pom.xml中添加nacos的依賴
<!--nacos客戶端-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
2 在主類上添加@EnableDiscoveryClient註解
@SpringBootApplication
@EnableDiscoveryClient
public class ProductApplication
3 在 application.yml
中添加nacos服務的地址
spring:
cloud:
nacos:
discovery:
server-addr: localhost:8848
4 啓動服務, 觀察nacos的控制面板中是否有註冊上來的商品微服務
3.3.3 將訂單微服務註冊到nacos
接下來開始修改shop_order
模塊的代碼, 將其註冊到nacos服務上
1. 在pom.xml中添加nacos的依賴
<!--nacos客戶端-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
2. 在主類上添加@EnableDiscoveryClient註解
@SpringBootApplication
@EnableDiscoveryClient
public class OrderApplication
3. 在 application.yml
中添加nacos服務的地址
spring:
cloud:
nacos:
discovery:
server-addr: localhost:8848
4 修改OrderController, 實現微服務調用
@RestController
@Slf4j
public class OrderController {
@Autowired
private RestTemplate restTemplate;
@Autowired
private OrderService orderService;
@Autowired
private DiscoveryClient discoveryClient;
//準備買1件商品
@GetMapping("/order/prod/{pid}")
public Order order(@PathVariable("pid") Integer pid) {
log.info(">>客戶下單,這時候要調用商品微服務查詢商品信息");
//從nacos中獲取服務地址
ServiceInstance serviceInstance =
discoveryClient.getInstances("service-product").get(0);
String url = serviceInstance.getHost() + ":" +
serviceInstance.getPort();
log.info(">>從nacos中獲取到的微服務地址爲:" + url);
//通過restTemplate調用商品微服務
Product product = restTemplate.getForObject(
"http://" + url + "/product/" + pid, Product.class);
log.info(">>商品信息,查詢結果:" + JSON.toJSONString(product));
Order order = new Order();
order.setUid(1);
order.setUsername("測試用戶");
order.setPid(product.getPid());
order.setPname(product.getPname());
order.setPprice(product.getPprice());
order.setNumber(1);
orderService.save(order);
return order;
}
}
DiscoveryClient是專門負責服務註冊和發現的,我們可以通過它獲取到註冊到註冊中心的所有服務
5 啓動服務, 觀察nacos的控制面板中是否有註冊上來的訂單微服務,然後通過訪問消費者服務驗證調用是否成功
3.4 實現服務調用的負載均衡
3.4.1 什麼是負載均衡
通俗的講, 負載均衡就是將負載(工作任務,訪問請求)進行分攤到多個操作單元(服務器,組件)上進行執行。
根據負載均衡發生位置的不同,一般分爲服務端負載均衡和客戶端負載均衡。
服務端負載均衡指的是發生在服務提供者一方,比如常見的nginx負載均衡
而客戶端負載均衡指的是發生在服務請求的一方,也就是在發送請求之前已經選好了由哪個實例處理請求。
我們在微服務調用關係中一般會選擇客戶端負載均衡,也就是在服務調用的一方來決定服務由哪個提供者執行。
3.4.2 自定義實現負載均衡
1 通過idea再啓動一個shop-product
微服務,設置其端口爲8082
2 通過nacos查看微服務的啓動情況
3 修改shop-order 的代碼,實現負載均衡
@RestController
@Slf4j
public class OrderController {
@Autowired
private RestTemplate restTemplate;
@Autowired
private OrderService orderService;
@Autowired
private DiscoveryClient discoveryClient;
//準備買1件商品
@GetMapping("/order/prod/{pid}")
public Order order (@PathVariable("pid") Integer pid){
log.info(">>客戶下單,這時候要調用商品微服務查詢商品信息");
//從nacos中獲取服務地址
//自定義規則實現隨機挑選服務
List<ServiceInstance> instances = discoveryClient.getInstances("serviceproduct");
int index = new Random().nextInt(instances.size());
ServiceInstance serviceInstance = instances.get(index);
String url = serviceInstance.getHost() + ":" +
serviceInstance.getPort();
log.info(">>從nacos中獲取到的微服務地址爲:" + url);
//通過restTemplate調用商品微服務
Product product = restTemplate.getForObject("http://" + url +
"/product/" + pid, Product.class);
log.info(">>商品信息,查詢結果:" + JSON.toJSONString(product));
Order order = new Order();
order.setUid(1);
order.setUsername("測試用戶");
order.setPid(product.getPid());
order.setPname(product.getPname());
order.setPprice(product.getPprice());
order.setNumber(1);
orderService.save(order);
return order;
}
}
第4步:啓動兩個服務提供者和一個服務消費者,多訪問幾次消費者測試效果
3.4.3 基於Ribbon實現負載均衡
Ribbon是Spring Cloud的一個組件, 它可以讓我們使用一個註解就能輕鬆的搞定負載均衡
第1步:在RestTemplate 的生成方法上添加**@LoadBalanced**註解
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
第2步:修改服務調用的方法
@RestController
@Slf4j
public class OrderController {
@Autowired
private RestTemplate restTemplate;
@Autowired
private OrderService orderService;
//準備買1件商品
@GetMapping("/order/prod/{pid}")
public Order order(@PathVariable("pid") Integer pid) {
log.info(">>客戶下單,這時候要調用商品微服務查詢商品信息");
//直接使用微服務名字, 從nacos中獲取服務地址
String url = "service-product";
//通過restTemplate調用商品微服務
Product product = restTemplate.getForObject(
"http://" + url + "/product/" + pid, Product.class);
log.info(">>商品信息,查詢結果:" + JSON.toJSONString(product));
Order order = new Order();
order.setUid(1);
order.setUsername("測試用戶");
order.setPid(product.getPid());
order.setPname(product.getPname());
order.setPprice(product.getPprice());
order.setNumber(1);
orderService.save(order);
return order;
}
}
Ribbon支持的負載均衡策略
Ribbon內置了多種負載均衡策略,內部負載均衡的頂級接口爲
com.netflix.loadbalancer.IRule
, 具體的負載策略如下圖所示:
們可以通過修改配置來調整Ribbon的負載均衡策略,具體代碼如下
service-product: # 調用的提供者的名稱
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
3.5 基於Feign實現服務調用
3.5.1 什麼是Feign
Feign是Spring Cloud提供的一個聲明式的僞Http客戶端, 它使得調用遠程服務就像調用本地服務一樣簡單, 只需要創建一個接口並添加一個註解即可。
Nacos很好的兼容了Feign, Feign默認集成了 Ribbon, 所以在Nacos下使用Fegin默認就實現了負載均衡的效果。
3.5.2 Feign的使用
1 加入Fegin的依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2 在主類上添加Fegin的註解
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients//開啓fegin的客戶端
public class OrderApplication {
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class);
}
3 創建一個service, 並使用Fegin實現微服務調用
@FeignClient("service-product")//聲明調用的提供者的name
public interface ProductService {
//指定調用提供者的哪個方法
//@FeignClient+@GetMapping 就是一個完整的請求路徑 http://serviceproduct/product/{pid}
@GetMapping(value = "/product/{pid}")
Product findByPid(@PathVariable("pid") Integer pid);
}
4 修改controller代碼,並啓動驗證
@RestController
@Slf4j
public class OrderController {
@Autowired
private OrderService orderService;
@Autowired
private ProductService productService;
//準備買1件商品
@GetMapping("/order/prod/{pid}")
public Order order(@PathVariable("pid") Integer pid) {
log.info(">>客戶下單,這時候要調用商品微服務查詢商品信息");
//通過fegin調用商品微服務
Product product = productService.findByPid(pid);
log.info(">>商品信息,查詢結果:" + JSON.toJSONString(product));
Order order = new Order();
order.setUid(1);
order.setUsername("測試用戶");
order.setPid(product.getPid());
order.setPname(product.getPname());
order.setPprice(product.getPprice());
order.setNumber(1);
orderService.save(order);
return order;
}
}
5 重啓order微服務,查看效果