微服務架構的說明:
微服務的架構風格是將一個單體的應用程序開發拆解為一組"小"的服務,這里的"小"是以業務邊界 來區分的,而不是根據代碼的多少區分。每個服務都運行在一個單獨的進程
中,服務之間通過輕量級的方式進行通信,例如使用HTTP資源接口
。
單體架構與微服務架構的比較。
單體架構存在的問題:
- 由於所有的業務邏輯都寫在了一個應用service中,因此只要對該service進行修改,哪怕只是添 一行代碼,也需要編譯打包部署整個應用,需要的時間會比較久,耗時耗力。
- 假設整個應用中只有
一個接口到達了瓶頸
,我們想要水平擴展該接口,這個時候只能通過水平擴展整個應用
來達到目的。 - 隨着應用程序規模的增加,即使我們使用Maven進行模塊化開發,也很難保證對於一個模塊的修改不會影響其他模塊。
為此,我們可以將整個應用切分為多個小的服務,將它們獨立運行在自己的進程,當我們修改了一個服務的代碼,那么只需要單獨部署該服務即可,如果要擴展一個服務的接口,那么只擴展該服務就可以了。
微服務架構的缺點:
- 由於整體應用的拆解,不可避免不同服務之間存在冗余的代碼。例如,service1和service2中都編寫了JedisCluster的工具類。
- 維護一個應用程序簡單,但是維護幾十甚至幾百個服務就很麻煩了,需要配備功底深厚的運維人員,也需要搭建完善的運維系統,例如,完善的計數監控系統,完善的日志系統及完善的鏈路跟蹤系統等。
- 服務眾多,服務之間的調用也由原來的單體架構中的進程內調用變為了進程之間調用,這就需要考慮很多問題,例如使用什么通信方式,如何處理網絡延遲及服務容錯等問題。這是分布式系統都會存在的問題,但是在微服務架構中這些問題尤其嚴重,因為“分布”得非常厲害。
- 如果從零開始搭建一套微服務系統,那么需要掌握的組件技術會比較多,從而開發的難度較大,開發周期會比較長。
- 采用微服務架構就會涉及怎樣將一個整體應用拆分成多個微服務,我們說了拆分的原則是根據業務拆分,但是這個業務邊界有時候是比較難划分的。
微服務中的組件和技術選型
- 服務注冊與發現
服務注冊可以理解為將服務的ip和port注冊到注冊中心,這里可以簡單的將注冊中心理解為一個Map,其中的key是服務的唯一標識(可以是serviceId也可以是serviceName),而value是一個包含ipAndPort的結構體的集合,例如是一個List集合,該集合存放了指定service所在的所有服務器。
服務發現就是根據服務的唯一標識key,從注冊中心獲取指定服務所在的服務器列表,根據上述Map中的key來獲取value。
使用服務注冊和服務發現的好處很多,其中最主要的就是實現了服務之間的解稿。如果不使用服務注冊中心,那么我們需要將被調用服務的服務器列表直接寫在調用服務的配置文件中,這造成了兩個服務的直接稿合。
- 健康檢查
健康檢查是檢查兩個東西是否處於正常狀態:一個是服務所在服務器的運行狀態;一個是服務本身的運行狀態。健康檢查的目的其實就是為了在服務發現和服務路由的時候,可以將服務的調用請求發送到處於健康狀態的機器上。
常用的健康檢查技術有Consul、Spring Boot的Actuator。
- 配置管理
配置管理主要做三件事。
- 在一個地方將服務集中管理,例如在Consul-KV中集中配置,保護配置信息的安全。
- 實現服務的配置與代碼分離,這樣修改配置信息后不需要再編譯、打包、部署整個服務。
- 實現
熱配置
,當修改配置信息之后,不需要重啟服務就可以自動獲取修改后的配置信息。
- 服務通信
服務通信是指服務之間的相互調用。服務之間的調用協議可以使用TCP協議,也可以使用HTTP協議。通常用來實現服務通信的技術有Netty、Mina、Retrofit、OkHttp和AsyncHttpClient等。
- 服務路由
服務路由的過程是這樣的:當一個請求過來時,通過服務發現和健康檢查選出健康的服務器列表,之后采用一定的負載均衡策略(路由策略)從這些服務器中選出一台,最后將請求發送到這台服務器上去。
- 服務容錯
服務容錯指的是當服務集群中的一台機器岩機了,也不會導致整個服務不可用,甚至
不會因為級聯失敗導致多個服務不可用,形成雪崩。
參考技術: Hystrix。
- 日志系統
日志系統主要用於收集散落在各台機器上的日志,並提供高效的存儲和查詢方式,通過清晰易懂的界面進行結果展示。當然,也會提供方便的分析功能等。
參考技術: Logback、ELK、Redis、Flume、Hadoop、Kafka等。
-
全鏈路追蹤系統
-
計數監控系統
-
文檔輸出
-
持續集成與持續部署系統
-
服務網關
-
服務編排
微服務基礎架構
- 從Spring Boot開始
Application類中包含了一個main方法,作為入口。
注解@SpringBootApplication是一個復合注解,其包含了比較重要的注解有下面三個。
@SpringBootConfiguration
該注解也是一個復合注解,其中最重要的注解是@Configuration
,指明該類由Spring容器管理。@EnableAutoConfiguration
:該注解用於啟動服務的自動配置功能。@ComponentScan
:該拄解用於掃描類,其作用類似於 Spring 中自<context: componentscan>
標簽。
再來看一個簡單的controller。
該類非常簡單,只提供了一個接口,並返回了一個String。該類使用了@RestController
注解,該注解是一個復合注解,包含了@Controller
和@ResponseBody
,指定controller返回的對象自動轉化為json格式並返回,(基本類型及包裝類、String除外)。
微服務文檔輸出
- Swagger概述
Swagger是一款可以用於設計、構建、文檔化並且執行API的框架,使用該框架,可以輕松創建一個API文檔。
- 如何使用Swagger
@SpringBootApplication
@EnableSwagger2 // 注解啟動Swagger
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
@ApiModel("用戶模型") // 指定一個POJO類作為注釋
public class Blog {
@ApiModelProperty("ID") // 用來為POJO類中的屬性做注解
private int id ;
@ApiModelProperty("TITLE")
private String title ;
@ApiModelProperty("內容")
private String disc ;
@ApiModelProperty("作者")
private String author ;
// set,get等省略
}
@Api("user相關的api") // 為一個controller類做注釋,說明該controller的職能
@RestController
public class BlogController {
@ApiOperation("根據ID獲取用戶信息") // 對該接口的注釋,說明該controller的職能
@ApiImplicitParams({ // 通常用來包含接口的一組參數注解,可以將其簡單地理解為參數注解的集合。
@ApiImplicitParam(paramType = "query" ,name = "id",dataType = "int",
required = true,value = "用戶名的id",defaultValue = "1")
/*
paramType參數所放置的地方,包含query/header/path/body/form,最常用的是前4個。
需要注意的是query域中的值需要使用@RequestParam取,
header域中的值需要使用@RequestHeader獲取,
path域中的值需要使用@PathVariable獲取,
body域中的值需要使用@RequestBody獲取,否則可能出錯。
name,參數名。
dataType,參數類型。
required,參數是否必須傳。
value,參數的值。
defaultValue,參數的默認值。
*/
})
@ApiResponses({ // 通常用來包含接口的一組響應注解,可以將其簡單地理解為響應注解的集合。
@ApiResponse(code = 400,message = "請求參數沒填好"),
@ApiResponse(code = 404,message = "請求路徑沒有或頁面跳轉路徑不對")
// 用在@ApiResponses 中,一般用於表達一個錯誤的響應信息。
/*
code,即httpCode字,例如400。
message信息,例如"請求參數沒填好"。
*/
})
@RequestMapping("/user")
public Blog blog(@RequestParam("id") int id){
if (id ==1) {
return new Blog(1,"a","b","c");
}
return new Blog(2,"d","e","f");
}
}
啟動項目,打開http://localhost:8080/swagger-ui.html
路徑。
微服務數據庫
2019-07-31-09:38