注:本部分學習資料為某馬的SpringCloud文檔,雖然小商城隻是練手的項目,但是個人覺得學習到的東西遠遠勝過在很多小公司實習2-3個月所能學習到的也幫助自己拿到了不少offer,感謝!
1 系統架構演變
随着網際網路的發展,網站應用的規模不斷擴大。需求的激增,帶來的是技術上的壓力。系統架構也是以也不斷的演進、更新、疊代。從單一應用,到垂直拆分,到分布式服務,到SOA,以及現在火熱的微服務架構,還有在Google帶領下來勢洶湧的Service Mesh。我們到底是該乘坐微服務的船隻駛向遠方,還是偏安一隅得過且過?
1.1. 集中式架構
當網站流量很小時,隻需一個應用,将所有功能都部署在一起,以減少部署節點和成本。此時,用于簡化增删改查工作量的資料通路架構(ORM)是影響項目開發的關鍵。
存在的問題:
- 代碼耦合,開發維護困難
- 無法針對不同子產品進行針對性優化
- 無法水準擴充
- 單點容錯率低,并發能力差
1.2.垂直拆分
當通路量逐漸增大,單一應用無法滿足需求,此時為了應對更高的并發和業務需求,我們根據業務功能對系統進行拆分:
優點:
- 系統拆分實作了流量分擔,解決了并發問題
- 可以針對不同子產品進行優化
- 友善水準擴充,負載均衡,容錯率提高
缺點:
- 系統間互相獨立,會有很多重複開發工作,影響開發效率
1.3.分布式服務
當垂直應用越來越多,應用之間互動不可避免,将核心業務抽取出來,作為獨立的服務,逐漸形成穩定的服務中心,使前端應用能更快速的響應多變的市場需求。此時,用于提高業務複用及整合的分布式調用是關鍵。
優點:
- 将基礎服務進行了抽取,系統間互相調用,提高了代碼複用和開發效率
缺點:
- 系統間耦合度變高,調用關系錯綜複雜,難以維護
1.4.服務治理(SOA)
當服務越來越多,容量的評估,小服務資源的浪費等問題逐漸顯現,此時需增加一個排程中心基于通路壓力實時管理叢集容量,提高叢集使用率。此時,用于提高機器使用率的資源排程和治理中心(SOA)是關鍵
以前出現了什麼問題?
- 服務越來越多,需要管理每個服務的位址
- 調用關系錯綜複雜,難以理清依賴關系
- 服務過多,服務狀态難以管理,無法根據服務情況動态管理
服務治理要做什麼?
- 服務注冊中心,實作服務自動注冊和發現,無需人為記錄服務位址
- 服務自動訂閱,服務清單自動推送,服務調用透明化,無需關心依賴關系
- 動态監控服務狀态監控報告,人為控制服務狀态
缺點:
- 服務間會有依賴關系,一旦某個環節出錯會影響較大
- 服務關系複雜,運維、測試部署困難,不符合DevOps思想
1.5.微服務
前面說的SOA,英文翻譯過來是面向服務。微服務,似乎也是服務,都是對系統進行拆分。是以兩者非常容易混淆,但其實缺有一些差别:
微服務的特點:
- 單一職責:微服務中每一個服務都對應唯一的業務能力,做到單一職責
- 微:微服務的服務拆分粒度很小,例如一個使用者管理就可以作為一個服務。每個服務雖小,但“五髒俱全”。
- 面向服務:面向服務是說每個服務都要對外暴露服務接口API。并不關心服務的技術實作,做到與平台和語言無關,也不限定用什麼技術實作,隻要提供Rest的接口即可。
- 自治:自治是說服務間互相獨立,互不幹擾
- 團隊獨立:每個服務都是一個獨立的開發團隊,人數不能過多。
- 技術獨立:因為是面向服務,提供Rest接口,使用什麼技術沒有别人幹涉
- 前後端分離:采用前後端分離開發,提供統一Rest接口,後端不用再為PC、移動段開發不同接口
- 資料庫分離:每個服務都使用自己的資料源
- 部署獨立,服務間雖然有調用,但要做到服務重新開機不影響其它服務。有利于持續內建和持續傳遞。每個服務都是獨立的元件,可複用,可替換,降低耦合,易維護
2.遠端調用方式
無論是微服務還是SOA,都面臨着服務間的遠端調用。那麼服務間的遠端調用方式有哪些呢?
常見的遠端調用方式有以下幾種:
- RPC:Remote Produce Call遠端過程調用,類似的還有RMI。自定義資料格式,基于原生TCP通信,速度快,效率高。早期的webservice,現在熱門的dubbo,都是RPC的典型
-
Http:http其實是一種網絡傳輸協定,基于TCP,規定了資料傳輸的格式。現在用戶端浏覽器與服務端通信基本都是采用Http協定。也可以用來進行遠端服務調用。缺點是消息封裝臃腫。
現在熱門的Rest風格,就可以通過http協定來實作。
既然兩種方式都可以實作遠端調用,我們該如何選擇呢?
- 速度來看,RPC要比http更快,雖然底層都是TCP,但是http協定的資訊往往比較臃腫,不過可以采用gzip壓縮。
- 難度來看,RPC實作較為複雜,http相對比較簡單
- 靈活性來看,http更勝一籌,因為它不關心實作細節,跨平台、跨語言。
是以,兩者都有不同的使用場景:
- 如果對效率要求更高,并且開發過程使用統一的技術棧,那麼用RPC還是不錯的。
- 如果需要更加靈活,跨語言、跨平台,顯然http更合适
那麼我們該怎麼選擇呢?
微服務,更加強調的是獨立、自治、靈活。而RPC方式的限制較多,是以微服務架構中,一般都會采用基于Http的Rest風格服務。
3.Http用戶端工具與RestTemplate的使用
既然微服務選擇了Http,那麼我們就需要考慮自己來實作對請求和響應的處理。不過開源世界已經有很多的http用戶端工具,能夠幫助我們做這些事情,例如:
- HttpClient
- OKHttp
- URLConnection
接下來我們會使用SpringCloud,Spring最擅長的就是內建,把世界上最好的架構拿過來,內建到自己的項目中,自然也整合了這些用戶端工具。
Spring提供了一個RestTemplate模闆工具類,對基于Http的用戶端進行了封裝,并且實作了對象與json的序列化和反序列化,非常友善。RestTemplate并沒有限定Http的用戶端類型,而是進行了抽象,目前常用的3種都有支援:
- HttpClient
- OkHttp
- JDK原生的URLConnection(預設的)
3.1 RestTemplate的使用
寫兩個工程,一個工程springboot2提供服務,一個工程http-demo調用服務。浏覽器通路http-demo,http-demo調用springboot2提供的服務,得到結果後響應浏覽器。
建立maven工程springboot2:
- 導包
- 編寫啟動類
- 編寫pojo和controller
導包
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.6.RELEASE</version>
</parent>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
編寫啟動類
@SpringBootApplication
public class WebApplicationStarter {
public static void main(String[] args) {
SpringApplication.run(WebApplicationStarter.class, args);
}
}
編寫User類
@Data
public class User {
private Long id;
private String username;
private String password;
private String phone;
private String email;
private Date created;
private Date updated;
private String note;
public User(Long id, String username, String password, String phone, String email, Date created, Date updated,
String note) {
super();
this.id = id;
this.username = username;
this.password = password;
this.phone = phone;
this.email = email;
this.created = created;
this.updated = updated;
this.note = note;
}
}
編寫UserController類
@RestController
@RequestMapping("user")
public class UserController {
@GetMapping("{id}")
public User findUser(@PathVariable("id") long id){
User user = new User(id, "tom"+id, "123456", "13456788754", "[email protected]", new Date(),
new Date(), "hello world!");
return user;
}
}
寫完了服務提供方再寫調用方工程http-demo,步驟同上
1、導包同上
2、編寫配置檔案application.yml,主要修改端口為8081
server:
port: 8081
3、編寫啟動類WebApplicationStarter
@SpringBootApplication
public class WebApplicationStarter {
@Bean //注入RestTemplate到容器中
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(WebApplicationStarter.class, args);
}
}
4、編寫User類
@Data
public class User {
private Long id;
private String username;
private String password;
private String phone;
private String email;
private Date created;
private Date updated;
private String note;
//需要空參構造,json序列化需要
}
5、編寫UserController
@RestController
public class UserController {
@Autowired
private RestTemplate restTemplate;
@GetMapping("hello")
public User hello(){
String url = "http://localhost:8080/user/1";
User user = restTemplate.getForObject(url, User.class);//傳入請求的服務位址和反序列化需要得到的類
return user;
}
}
文檔結構圖如下
啟動兩個項目,浏覽器(這裡使用了postman)通路