微服務是一種軟件架構風格,它是以專注于單一職責的很多小型項目為基礎,組合出復雜的大型應用。 (對應的是單體架構風格)
一、認識微服務
1、單體架構
單體架構:將業務的所有功能集中在一個項目中開發,打成一個包部署
優:架構簡單、部署成本低
缺:團隊協作成本高、系統發布效率低、系統可用性差
2、微服務
微服務架構:是服務化思想指導下的一套最佳實踐架構方案。服務化,就是把單體架構中的功能模塊拆分為多個獨立項目。?
3、SpringCloud
SpringCloud集成了各種微服務功能組件,并基于SpringBoot實現了這些組件的自動裝配,從而提供了良好的開箱即用體驗。
二、微服務拆分
1、服務拆分原則
什么時候拆分:
????????創業型項目:先采用單體架構,快速開發,快速試錯。隨著規模擴大,逐漸拆分。
????????確定的大型項目:資金充足,目標明確,可以直接選擇微服務架構,避免后續拆分的麻煩。
怎么拆分:
? ? ? ? 高內聚:每個微服務的職責要盡量單一,包含的業務相互關聯度高、完整度高。
? ? ? ? 低耦合:每個微服務的功能要相對獨立,盡量減少對其他微服務的依賴。
拆分方式:
? ? ? ? 縱向拆分:按照業務模塊來拆分。
? ? ? ? 橫向拆分:抽取公共服務,提高復用性。
2、拆分服務
工程結構有兩種:獨立Project(多個項目) 和 maven聚合(一個項目多個模塊)
遠程調用
Spring給我們提供了一個RestTemplate的API,可以方便的實現Http請求的發送。使用步驟如下:
? ? ? ? ①注入Rest Template到Spring容器 (項目中寫到啟動類了)
@Configuration
public class RemoteCallConfig {@Beanpublic RestTemplate restTemplate() {return new RestTemplate();}
}
? ? ? ? ②發起遠程調用
ResponseEntity<List<ItemDTO>> response = restTemplate.exchange("http://localhost:8081/items?ids={ids}",HttpMethod.GET,null,new ParameterizedTypeReference<List<ItemDTO>>() {},Map.of("ids", CollUtil.join(itemIds, ",")));
三、服務注冊和發現
1、注冊中心原理
?
服務提供者通過心跳機制向注冊中心報告自己的健康狀況,當心跳異常時注冊中心會將異常服務剔除,并通知訂閱了該服務的消費者。
?
2、Nacos注冊中心
基于Docker來部署Nacos的注冊中心,首先我們要準備MySQL數據庫表,用來存儲Nacos的數據。由于是Docker部署,所以需要將資料中的SQL文件導入到Docker中的MySQL容器中。
然后,找到課前資料下的nacos文件夾其中的nacos/custom.env
文件中,有一個MYSQL_SERVICE_HOST也就是mysql地址,需要修改為你自己的虛擬機IP地址
然后,將課前資料中的nacos
目錄上傳至虛擬機的/root
目錄。
進入root目錄,然后執行下面的docker命令:
docker run -d \
--name nacos \
--env-file ./nacos/custom.env \
-p 8848:8848 \
-p 9848:9848 \
-p 9849:9849 \
--restart=always \
nacos/nacos-server:v2.1.0-slim
啟動完成后,訪問下面地址:http://192.168.100.128:8848/nacos/,注意將192.168.100.128
替換為你自己的虛擬機IP地址。
首次訪問會跳轉到登錄頁,賬號密碼都是nacos
3、服務注冊
①在item-service
的pom.xml
中添加依賴:
<!--nacos 服務注冊發現-->
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
?②在item-service
的application.yml
中添加nacos地址配置:
spring:application:name: cart-service #微服務名稱cloud:nacos:server-addr: 192.168.100.128:8848 # nacos地址
4、服務發現
①我們在cart-service
中的pom.xml
中添加下面的依賴:
<!--nacos 服務注冊發現-->
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
這里Nacos的依賴于服務注冊時一致,這個依賴中同時包含了服務注冊和發現的功能。因為任何一個微服務都可以調用別人,也可以被別人調用,即可以是調用者,也可以是提供者。?
?②在cart-service
的application.yml
中添加nacos地址配置:
spring:cloud:nacos:server-addr: 192.168.150.101:8848
?③服務發現
服務發現需要用到一個工具,DiscoveryClient,SpringCloud已經幫我們自動裝配,我們可以直接注入使用:
private final DiscoveryClient discoveryClient;
// 2.查詢商品//2.1 根據服務名稱獲取服務的實例列表List<ServiceInstance> instances = discoveryClient.getInstances("item-service");//獲取實例,填寫服務的名稱if(CollUtils.isEmpty(instances)){//判斷是否為空return;}//2.2 手寫負載均衡,從實例列表中挑選實例ServiceInstance instance = instances.get(RandomUtil.randomInt(instances.size()));//隨機使用實例instance.getUri();//2.3 利用restTemplate發起http請求,得到http的響應ResponseEntity<List<ItemDTO>> response = restTemplate.exchange(instance.getUri()+"/items?ids={ids}", //修改這里HttpMethod.GET,null,new ParameterizedTypeReference<List<ItemDTO>>() {},Map.of("ids", CollUtil.join(itemIds, ",")));
四、OpenFeign
1、快速入門
OpenFeign是一個聲明式的http客戶端,是SpringCloud在Eureka公司開源的Feign基礎上改造而來。其作用就是基于SpringMVC的常見注解,幫我們優雅的實現http請求的發送。
①引入依賴,包括OpenFeign和負載均衡組件SpringCloudLoadBalancer
<!--openFeign--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId></dependency><!--負載均衡器--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-loadbalancer</artifactId></dependency>
②通過@EnableFeignClients注解,啟動OpenFeign功能
????????在啟動類上添加@EnableFeignClients注解(?basePackages = "com.hmall.api.client")
③在cart-service
中,定義一個新的接口,編寫Feign客戶端:(代替前面寫的復雜的代碼)
@FeignClient("item-service") //根據服務名稱,去拉取實例列表
public interface ItemClient {@GetMapping("/items")List<ItemDTO> queryItemByIds(@RequestParam("ids") Collection<Long> ids);
}
④使用FeignClient,實現遠程調用
private final ItemClient itemClient;List<ItemDTO> items = itemClient.queryItemByIds(itemIds);
2、連接池
Feign底層發起http請求,依賴于其它的框架。其底層支持的http客戶端實現包括:
-
HttpURLConnection:默認實現,不支持連接池
-
Apache HttpClient :支持連接池
-
OKHttp:支持連接池
因此我們通常會使用帶有連接池的客戶端來代替默認的HttpURLConnection。比如,我們使用OK Http.
①在cart-service
的pom.xml
中引入依賴:
<!--OK http 的依賴 -->
<dependency><groupId>io.github.openfeign</groupId><artifactId>feign-okhttp</artifactId>
</dependency>
?在cart-service
的application.yml
配置文件中開啟Feign的連接池功能:
feign:okhttp:enabled: true # 開啟OKHttp功能
3、最佳實踐
-
思路1:抽取到微服務之外的公共module
-
思路2:每個微服務自己抽取一個module
-
方案1抽取更加簡單,工程結構也比較清晰,但缺點是整個項目耦合度偏高。
方案2抽取相對麻煩,工程結構相對更復雜,但服務之間耦合度降低。
由于item-service已經創建好,無法繼續拆分,因此這里我們采用方案1將itemClient接口抽取到hm-api模塊中。
定義的FeignClient不存在SpringBootApplication的掃描包范圍時,這些FeignClient無法使用。解決方案:
①在啟動類的注解EnablefeignClients上指定FeignClient所在包
@EnableFeignClients(basePackages = "com.hmall.api.client")
②指定FeignClient字節碼
@EnableFeignClients(clients = {ItemClient.class})
4、日志
OpenFeign只會在FeignClient所在包的日志級別為DEBUG時,才會輸出日志。而且其日志級別有4級:
-
NONE:不記錄任何日志信息,這是默認值。
-
BASIC:僅記錄請求的方法,URL以及響應狀態碼和執行時間
-
HEADERS:在BASIC的基礎上,額外記錄了請求和響應的頭信息
-
FULL:記錄所有請求和響應的明細,包括頭信息、請求體、元數據。
Feign默認的日志級別就是NONE,所以默認我們看不到請求日志。
在hm-api模塊下新建一個配置類,定義Feign的日志級別:
public class DefaultFeignConfig {@Beanpublic Logger.Level feignLogLevel(){return Logger.Level.FULL;}
}
接下來,要讓日志級別生效,還需要配置這個類。有兩種方式:
-
局部生效:在某個
FeignClient
中配置,只對當前FeignClient
生效。
@FeignClient(value = "item-service", configuration = DefaultFeignConfig.class)
-
全局生效:在
@EnableFeignClients
中配置,針對所有FeignClient
生效。
@EnableFeignClients(defaultConfiguration = DefaultFeignConfig.class)
一般去情況下不開啟日志。