javascript
Spring Cloud Alibaba——Nacos实现服务治理
引言
本博客總結微服務開發中各個微服務調用的實現,并使用 Nacos 完成服務注冊和發現。
文章中會涉及到 maven 的使用,以及 spring boot 的一些知識。開發工具采用 IDEA 2020.2。
設計一個電商訂單和商品購買微服務,實現微服務的注冊發現與調用。
一、模塊設計
本案例采用電商網站作為展示,涉及到的三個微服務有:shop-user、shop-product、shop-order,還有一個公共依賴模塊shop-common。他們的依賴、調用關系如下所示:
shop-user 是用戶微服務,端口是807x
shop-product 是商品微服務,端口是808x
shop-order 是訂單微服務,端口是809x
三個微服務之間可以通過HTTP請求相互調用業務邏輯。
二、創建Maven父工程
為了便于依賴的管理,和項目維護,在實際生產中,往往通過父工程來管理各個 maven 微服務模塊,和maven 依賴模塊。
(在這里我需要簡單說明一下這個大的maven 工程下面,如何理解各個子模塊的關系。案例中包含了三個微服務(shop-user/shop-product/shop-order),和一個公共依賴模塊(shop-common),它們都會作為一個 maven 子模塊存放到父工程目錄下,但實際上,在實際部署的時候,三個微服務是分開部署的,因為三個微服務之間的關系,除了通過父工程來統一維護一些依賴版本之外,沒有什么在代碼層面的耦合關系。而公共依賴模塊則在代碼層面耦合到各個模塊中,部署之后,也是你中有我的概念。)
首先 New ——> Project ——> Maven ,選擇好JDK 版本后,直接Next,跳過 archetype 選項。
填寫必要的項目名稱和存儲位置,maven坐標等信息,點擊finish:
idea可以快速為我們創建并打開新項目,由于? Maven 父工程只做版本管理,不需要寫任何代碼,因此一般都會直接刪除 src 目錄:
緊接著,我們需要修改父工程 pom 文件。它主要需要負責兩件事:1、指定父工程? ?2、依賴版本的鎖定
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>org.morty</groupId><artifactId>shop</artifactId><version>1.0-SNAPSHOT</version><!-- 指定父工程--><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.1.5.RELEASE</version></parent><properties><java.version>1.8</java.version><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><!-- 版本鎖定--><dependencyManagement><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>Greenwich.SR5</version><type>pom</type><scope>import</scope></dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-alibaba-dependencies</artifactId><version>2.1.1.RELEASE</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement> </project>下表展示了 Spring Cloud Alibaba & Spring Cloud & Spring Boot 兼容關系:
| ------- | ------- | ------- |
| Spring Cloud Hoxton | 2.2.x.RELEASE | 2.2.x.RELEASE |
| Spring Cloud Greenwich | 2.1.x.RELEASE | 2.1.x.RELEASE |
| Spring Cloud Finchley | 2.0.x.RELEASE | 2.0.x.RELEASE |
| Spring Cloud Edgware | 1.5.x.RELEASE | 1.5.x.RELEASE |
三、創建基礎依賴模塊
new——>Module...
添加必要的依賴:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>shop</artifactId><groupId>org.morty</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>shop-common</artifactId><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.58</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency></dependencies> </project>創建domain實體類,User、Product、Order,這樣,其他三個微服務可以依賴使用:
package com.morty.domain;import lombok.Data;import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id;@Entity(name = "shop_user") @Data public class User {@Id// 數據庫自增@GeneratedValue(strategy = GenerationType.IDENTITY)private Integer uid;private String username;private String password;private String telephone; } package com.morty.domain;import lombok.Data;import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id;@Data @Entity(name = "shop_product") public class Product {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Integer pid;private String pname;// 商品價格private Double pprice;// 庫存private Integer stock; } package com.morty.domain;import lombok.Data;import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id;@Data @Entity(name = "shop_order") public class Order {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Integer oid;private Integer uid;private String username;private Integer pid;private String pname;private Double pprice;/** 購買數量*/private Integer number; }四、創建微服務模塊
依次創建shop-user、shop-product、shop-order 三個微服務,并依賴 shop-common。篇幅有限,以 shop-product 為例。
1、和shop-common的創建方式一樣,新建一個 Module,并命名 shop-product,修改pom文件,添加 shop-common依賴和 web starter:
<dependencies><!-- 依賴基礎模塊--><dependency><groupId>org.morty</groupId><artifactId>shop-common</artifactId><version>1.0-SNAPSHOT</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency></dependencies>2、創建spring boot 啟動類:
@SpringBootApplication @Slf4j public class ProductApplication {public static void main(String[] args) {SpringApplication.run(ProductApplication.class);log.info("-----------啟動成功------------");} }3、修改配置文件:
server:port: 8081 spring:application:name: service-productdatasource:driver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://localhost:3306/shop?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&rewriteBatchedStatements=trueusername: rootpassword: 123456jpa:properties:hibernate:hbm2ddl:auto: update# InnoDB方言dialect: org.hibernate.dialect.MySQL5InnoDBDialect然后就是創建 controller、service、dao:
@Slf4j @RestController @RequestMapping("/product") public class ProductController {@Autowiredprivate ProductService productService;/*** 查詢訂單信息* @param pid* @return*/@GetMapping("/{pid}")public Product getProduct(@PathVariable("pid") Integer pid) {log.info("收到查詢商品信息請求,商品編號:{}", pid);Product product = productService.getProduct(pid);log.info("商品信息查詢成功:{}", JSON.toJSONString(product));return product;} } @Service public class ProductService {@Autowiredprivate ProductDao productDao;public Product getProduct(Integer productId) {return productDao.findById(productId).get();} } public interface ProductDao extends JpaRepository<Product, Integer> { }最后,手動創建 shop 數據庫,然后啟動服務,可以看到表已經自動創建好了,向 shop_product 表插入一條商品信息:
INSERT INTO `shop_product`(pname, pprice, stock) VALUES('皮大衣', '120', '20');打開瀏覽器,訪問接口,可以正常返回:
五、微服務調用
按照類似的步驟創建好了三個微服務之后,我們來實現訂單到商品的微服務調用。需要說明的是,任何兩個服務之間都是可以通過http請求進行調用,而不完全需要服務治理功能,也就是說,如果我們指定了ip和端口號,實際上就可以實現微服務的調用。
為了演示方便,這里只列出關鍵代碼,并去掉了Service的接口層。
提供必要的 restTemplate:
@Beanpublic RestTemplate restTemplate() {return new RestTemplate();}DAO:
public interface OrderDao extends JpaRepository<Order, Integer> { }Service:
@Service public class OrderService {@Autowiredprivate OrderDao orderDao;public void createOrder(Order order) {orderDao.save(order);} }Controller:
@Slf4j @RestController @RequestMapping("/order") public class OrderController {@Autowiredprivate RestTemplate restTemplate;@Autowiredprivate OrderService orderService;/**** 下單* @param pid* @return*/@GetMapping("/prod/{pid}")public Order order(@PathVariable("pid") Integer pid) {log.info("接收到{}號商品的下單請求,準備調用商品微服務", pid);// 調用商品微服務,查詢商品信息Product prod = restTemplate.getForObject("http://localhost:8081/product/" + pid, Product.class);log.info("查詢到{}號商品信息,內容是:{}", pid, JSON.toJSONString(prod));// 下單(即創建訂單并保存)Order order = new Order();order.setUid(1);order.setUsername("測試用戶");order.setPid(pid);order.setPname(prod.getPname());order.setPprice(prod.getPprice());order.setNumber(1);// 訂單入庫orderService.createOrder(order);log.info("創建訂單成功,訂單信息為:{}", JSON.toJSONString(order));return order;} }然后在配置文件中指定 8091 端口號,以及數據庫地址等必要信息。啟動 OrderApplication 和 ProductApplication,調用 /order/prod/{pid} 接口:
檢查控制臺打印的日志:
訂單微服務:
商品微服務:
同時數據庫也出現了剛才添加的訂單記錄:
六、服務治理
在前面的微服務調用案例中,我們通過 restTemplate 對象,配合 ip + port 的形式,實現了最簡單的訂單微服務到商品微服務的調用邏輯。
但這在實際生產中會存在較大的問題:
1、一旦服務提供者的地址發生變化,就不得不去修改服務調用者的代碼,即便是使用配置文件也治標不治本。
2、在高并發場景中,服務一般需要進行集群部署,會有多個服務提供者實例。那么就需要通過負載均衡調用不同的服務提供者,來分散單個服務實例的訪問壓力,上面這種調用方式顯然無法滿足負載均衡的要求。
3、一旦微服務變得越來越多,如果管理服務清單將會是一個大問題。
基于以上幾點,就有了服務治理的概念:
服務治理是微服務架構中最核心、最基本的模塊。用于實現各個微服務的自動化注冊和發現。
服務注冊:在服務治理框架中,都會構建一個注冊中心。每個服務單元向注冊中心登記自己提供服務的詳細信息。注冊中心會基于這些微服務的詳細信息,生成一張服務清單。注冊中心需要以心跳的方式檢測清單中服務是否可用,如果發現心跳異常的服務,會從服務清單中剔除不可用的服務。
服務發現:服務消費者向注冊中心咨詢服務,并獲取所有服務的實例清單,實現對具體服務的訪問。
常用的服務治理框架有:
ZooKeeper:是一個分布式服務框架,是Apache Hadoop 的一個子項目,它主要用來解決分布式應用中經常遇到的一些數據管理問題,如統一命名服務、狀態同步服務、集群管理、分布式應用配置項管理等。
Eureka:是Spring Cloud Netfix 中的重要組件,主要作用是做服務注冊和發現,但現在已經閉源。
Nacos:是一個更易于構建云原生應用的動態服務發現、配置管理和服務管理平臺。它是 Spring cloud Alibaba 的組件之一,負責服務注冊發現和服務配置,可以認為是 Eureka + Config 的組合升級版服務治理框架。
七、Nacos-discovery 實現微服務調用
7.1 啟動 Nacos 服務
首先,如果想使用 Nacos 注冊中心服務,必須到官網上下載啟動壓縮包。值得一提的是,原來的 Eureka 是通過 Spring boot 構建一個專門用于實現注冊發現的微服務,這需要我們手動去構建這樣一個重要的架構組件,但是 Nacos 則提供了獨立的啟動程序,讓開發者可以開箱即用,進一步提高了微服務部署的效率。
nacos 下載地址:https://nacos.io/zh-cn/docs/quick-start.html
不論你是在 Windows 環境上學習和練習,還是在 Linux 服務器上安裝部署,都只需要簡單的一鍵啟動即可。
啟動成功后,我們通過瀏覽器訪問控制臺,默認用戶名和密碼都是 nacos,下圖登錄成功后進入首頁:
7.2 將微服務注冊到 Nacos
以 shop-product 為例,演示如何將微服務注冊到 Nacos。
1、微服務中添加 nacos 客戶端依賴:
<!-- nacos 客戶端--><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-alibaba-nacos-discovery</artifactId></dependency>2、為主類添加@EnableDiscoveryClient 注解:
@Slf4j @EnableDiscoveryClient @SpringBootApplication public class ProductApplication {public static void main(String[] args) {SpringApplication.run(ProductApplication.class);log.info("-----------啟動成功------------");} }3、配置 Nacos Server 地址:
spring:cloud:nacos:discovery:server-addr: localhost:88484、啟動微服務,查看 Nacos 控制臺:
7.3 Nacos 實現微服務調用
針對前面第五節訂單到商品的微服務調用方式,我們調整一下restTemplate 代碼,以服務治理推薦的方式來實現微服務調用。
引入服務發現客戶端對象:
@Autowired private DiscoveryClient discoveryClient;修改代碼:
啟動 shop-order 、shop-product 微服務,它們會自動注冊到 Nacos 中。
重新調用下單接口,可以看到接口依然調用成功:
總結
微服務注冊中心的主要功能是負責服務注冊和發現,它會生成一張注冊服務清單,可以簡單理解為一個服務名稱和對應服務地址的對照表,服務消費者使用服務名稱調用服務提供者的接口時,會直接發送到對應地址:
微服務如果想要注冊到 Nacos Server,需要完成三件事:
1、添加 nacos-discovery 依賴
2、啟動服務發現客戶端,即添加 @EnableDiscoveryClient 注解到主類
3、配置 Nacos server 注冊中心地址和端口號
?
總結
以上是生活随笔為你收集整理的Spring Cloud Alibaba——Nacos实现服务治理的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java so jnienv_JNI初步
- 下一篇: controller接收json数据_S