在微服務中,使用什么協議來構建服務體系,一直是個熱門話題。 爭論的焦點集中在兩個候選技術: RPC or Restful
Restful架構是基於Http應用層協議的產物,RPC架構是基於TCP傳輸層協議的產物。
網絡七層模型
在說RPC和HTTP的區別之前,了解一下七層網絡結構模型(雖然實際應用中基本上都是五層),它可以分為以下幾層: (從上到下)
- 第一層:應用層。定義了用於在網絡中進行通信和傳輸數據的接口;
- 第二層:表示層。定義不同的系統中數據的傳輸格式,編碼和解碼規范等;
- 第三層:會話層。管理用戶的會話,控制用戶間邏輯連接的建立和中斷;
- 第四層:傳輸層。管理着網絡中的端到端的數據傳輸;
- 第五層:網絡層。定義網絡設備間如何傳輸數據;
- 第六層:鏈路層。將上面的網絡層的數據包封裝成數據幀,便於物理層傳輸;
- 第七層:物理層。這一層主要就是傳輸這些二進制數據。
實際應用過程中,五層協議結構里面是沒有表示層和會話層的。應該說它們和應用層合並了。我們應該將重點放在應用層和傳輸層這兩個層面。因為HTTP是應用層協議,而TCP是傳輸層協議。
RPC
RPC 即遠程過程調用(Remote Procedure Call Protocol,簡稱RPC),像調用本地服務(方法)一樣調用服務器的服務(方法)。通常的實現有 XML-RPC , JSON-RPC , 通信方式基本相同, 所不同的只是傳輸數據的格式.
RPC框架的主要目標就是讓遠程服務調用更簡單、透明。RPC框架負責屏蔽底層的傳輸方式(TCP或者UDP)、序列化方式(XML/JSON/二進制)和通信細節。開發人員在使用的時候只需要了解誰在什么位置提供了什么樣的遠程服務接口即可,並不需要關心底層通信細節和調用過程。

Restful
REST即表述性狀態傳遞(Representational State Transfer,簡稱REST),是一種軟件架構風格。REST通過HTTP協議定義的通用動詞方法(GET、PUT、DELETE、POST) ,以URI對網絡資源進行唯一標識,響應端根據請求端的不同需求,通過無狀態通信,對其請求的資源進行表述。滿足REST約束條件和原則的架構,就被稱為是RESTful架構.
區別
使用RPC遠程服務調用方式與傳統http接口直接調用方式的差別在於:
1. 從使用方面看,Http接口只關注服務提供方(服務端),對於客戶端怎么調用,調用方式怎樣並不關心,通常情況下,客戶端使用Http方式進行調用時,只要將內容進行傳輸即可,這樣客戶端在使用時,需要更關注網絡方面的傳輸,比較不適用與業務方面的開發;而RPC服務則需要客戶端接口與服務端保持一致,服務端提供一個方法,客戶端通過接口直接發起調用,業務開發人員僅需要關注業務方法的調用即可,不再關注網絡傳輸的細節,在開發上更為高效。
2. 從性能角度看,使用Http時,Http本身提供了豐富的狀態功能與擴展功能,但也正由於Http提供的功能過多,導致在網絡傳輸時,需要攜帶的信息更多,從性能角度上講,較為低效。而RPC服務網絡傳輸上僅傳輸與業務內容相關的數據,傳輸數據更小,性能更高。
3. 從運維角度看,使用Http接口時,常常使用一個前端代理,來進行Http轉發代理請求的操作,需要進行擴容時,則需要去修改代理服務器的配置,較為繁瑣,也容易出錯。而使用RPC方式的微服務,則只要增加一個服務節點即可,注冊中心可自動感知到節點的變化,通知調用客戶端進行負載的動態控制,更為智能,省去運維的操作。
Feign
Feign 是一個聲明web服務客戶端,這便得編寫web服務客戶端更容易,使用Feign 創建一個接口並對它進行注解,它具有可插拔的注解支持包括Feign注解與JAX-RS注解,Feign還支持可插拔的編碼器與解碼器,Spring Cloud 增加了對 Spring MVC的注解,Spring Web 默認使用了HttpMessageConverters, Spring Cloud 集成 Ribbon 和 Eureka 提供的負載均衡的HTTP客戶端 Feign.
maven 多模塊下的Feign使用
目前我的項目中有2個模塊device和equip,每個模塊由於業務的需要拆分成4部分(parent、client、common、server)

parent為父項目,基本沒什么代碼,會定義一些依賴作統一管理,其pom.xml如下
<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>com.skyworth.tvmanage</groupId> <artifactId>management-equip</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>pom</packaging> <name>equip</name> <description>equip servers</description> <modules> <module>management-equip-client</module> <module>management-equip-common</module> <module>management-equip-server</module> </modules> <!-- 必須要引入 springboot parent ,幫我們實現了很多jar包的依賴管理 --> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.2.RELEASE</version> <relativePath /> <!-- lookup parent from repository --> </parent> <!-- 版本集中配置 --> <properties> <spring.cloud.version>Finchley.RELEASE</spring.cloud.version> <management-common.version>0.0.1-SNAPSHOT</management-common.version> </properties> <!-- cloud --> <dependencyManagement> <dependencies> <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-dependencies --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring.cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>com.skyworth.tvmanage</groupId> <artifactId>management-equip-common</artifactId> <version>${management-common.version}</version> </dependency> </dependencies> </dependencyManagement> </project>
server部分為業務模塊,common為一些公共調用的類,client部分定義向外暴露的接口,client部分pom.xml如下
<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> <parent> <groupId>com.skyworth.tvmanage</groupId> <artifactId>management-equip</artifactId> <version>0.0.1-SNAPSHOT</version> </parent> <!-- 向外暴露的接口 client --> <artifactId>management-equip-client</artifactId> <name>equip-client</name> <description>equip servers</description> <!-- 版本集中配置 --> <properties> </properties> <dependencies> <dependency> <groupId>com.skyworth.tvmanage</groupId> <artifactId>management-equip-common</artifactId> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> </dependencies> </project>
然后,再來看client接口的定義 ManagementEquipClient.class, @FeignClient里的名稱為Eureka里注冊的需要調用的服務名稱
@FeignClient("MANAGEMENT-EQUIP") public interface ManagementEquipClient { @PostMapping("/tvmanage/equip/addEquip") public void addEquip(@RequestBody Equip equip); @RequestMapping(value="/tvmanage/equip/checkEquipExists", method=RequestMethod.GET) Integer checkEquipExists(@RequestParam String core,@RequestParam String type,@RequestParam String country); @RequestMapping(value="/tvmanage/equip/getDefaultScheme", method=RequestMethod.GET) Integer getDefaultScheme(@RequestParam String core,@RequestParam String type,@RequestParam String country); }
由於我這里,feign是device調用equip,基本equip部分配置就差不多了,再來看看devcie部分,在device應用主類中通過@EnableFeignClients注解開啟Feign功能。
這里需要注意的是@EnableFeignClients的掃包問題,就是***的地址要正確
@SpringBootApplication @EnableDiscoveryClient @EnableFeignClients(basePackages="****") public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
然后在device部分的controller中,聲明equip服務,就可以正常調用了

