通過微服務進行分布式應用開發
微服務架構設計模式相對于整體設計模式,具有很多優點。 它不去創建一個大型的單個應用程序,而是想著要把單個的應用程序細分成一堆互相連接起來的子應用程序。每一個微服務都有類似于整體應用程序的分層架構。
通過使用微服務架構搭配一些設計模式,有幾個優勢可以很容易的得到實現。
可擴展性。應用程序通常會有三種類型的擴展。X維度上的擴展就是對應用程序進行平面的克隆, Y維度上的擴展就是將不同的應用程序功能進行分割, 而Z維度上的擴展就是對數據進行分區和分片。當Y維度上的擴展被應用到整體應用程序時,應用程序就會被分成許多更小的單元,各自被分配到具有微服務架構風格的業務功能。
模式: 每一個微服務都擁有自己的被隔離的實體和容器。多個實體中的相同服務可以實現服務層面的負載均衡。
可利用性:微服務被部署在不同的實例,比如相同的微服務運行在多實例中,保證整個系統的高可用。
模式:分級服務的負載平衡通過優化實現高可用,電路破壞者模式可以通過優化實現容錯,而服務配置與探測可以使新服務建立通信。
可持續部署性。每個微服務之間相互獨立。這就保證任何 相互獨立 服務的部署速度更快,實現可持續部署。
循環處理性。微服務提供不同方式來獲取循環處理。每個微服務在分級服務有自己的結構層次,在數據庫作為一個持續層來運行于自我隔離的環境。
技術多樣性。考慮到微服務具有一個隔離特征,一個混合多樣技術在整個應用程序中,可以使用來安裝不同微服務。
低成本。服務實例可以基于應用程序使用習慣進行優化。低利用率的實例可以用于最少使用的服務,而高利用率的實例可用于商業級別的服務。
性能。考慮到微服務的技術上多個優勢,將會直接影響到性能。比如說,高阻塞調用服務運行在單線程的技術棧中,而高CPU使用率的服務運行于多線程的技術棧中。
相比龐大結構,微服務也擁有一些缺陷。第一,部署和管理分布式應用相比一個獨立程序時非常困難的。微服務需要一個進程間通信(IPC)機制來與不同微服務之間進行通信,這樣會影響到性能(取決于網絡帶寬)。
高效的微服務需要實現如下特性:
-
要實現IPC,則微服務間需要通過 rest請求或者RPC 相互 調用 。
-
一個微服務可能會調用另一個或多個微服務。一個服務由于負載過高或者其他服務異常可能會不可用,或者沒有及時響應。所以需要有響應的 局部故障或者回退機制 。
-
基于微服務的應用相對與單一結構應用,其部署的復雜度會更高,因為其包含了不同的服務,而這些服務又可能是運行在不同的容器或者實例中。需要有響應的 服務注冊和發現機制 將新服務注冊進去同時能發現需要交互的服務。
-
一個微服務客戶端在一個功能中可能會調用多個遠程微服務。這可能會導致大量的基于網絡的rest或者RPC請求。應該有一個 服務網關 用于接受微服務的一個請求然后 生成多個本地請求(服務網關的本地),最后將這些請求結果聚合起來返回到客戶端微服務。
-
當同一個微服務被部署為同一個實例的不同容器時,需要有服務層的 負載均衡 用于分發負載和實現故障恢復機制。
-
分布式應用同時也需要某種 集中日志 框架用于將所有數據集中處理以生成日志數據。
從頭完全實現上述特性將會是十分復雜并且耗時的,而且開發人員也需要消耗大量時間開發和測試基礎框架。但是,如果這些都是用現成的,就可以只關注于業務邏輯了。
Spring Cloud 框架提供了工具來快速構建那些在分布式服務中的通用模式,比如配置管理、服務發現、容錯、分布式緩存、服務網關、rest客戶端以及服務級負載均衡器。Spring Cloud 工程的初始化可以通過向工程中添加幾個 Maven 依賴來實現。這個也可以利用 spring initialize 網站來實現。
許多對微服務的部署至關重要的 Spring Cloud 組件都來自于 Netflix 開放源代碼軟件 (Netflix OSS) 中心。
Spring Cloud 是在 Spring Boot 之上構建的, 而 Spring Boot 里面則包含了使用了最少量配置代碼的嵌入式 tomcat 服務器。
下面是在 AWS 云上面使用微服務的分布式應用程序的架構圖。
在上圖中有三個不同的為服務,主服務使用一個REST客戶端同服務A和服務B進行通信。服務A會在兩個容器中被啟動,而服務B也會在相同實體中的兩個容器中被啟動。被暴露給一個客戶端的主服務將會通過服務客戶端同服務A和服務B的實體進行交互,而服務客戶端就是一個負載均衡器。這樣就使得負載均衡不僅能在實體層面進行,也能在相同實體的服務層面進行。這被稱作服務級別的負載均衡。當有服務請求發起時,客戶端服務會通過向 Eureka 服務注解表和發現機制進行查詢來獲取到服務實體的地址。
Spring Cloud 已經支持了 Eureka 的服務注冊功能, 而 Eureka 的服務注冊功能則可以通過添加 @EnableEurekaServer 注解來啟用。
@SpringBootApplication
@EnableEurekaServer
public class EurekaServer {
public static void main(String[] args) {
System.setProperty("spring.config.name", "registration-server");
SpringApplication.run(EurekaServer.class, args);
}
}
還有用于注冊服務的 application.yml:
eureka:
instance:
hostname: localhost
client: # Not a client, don't register with yourself
registerWithEureka: false
fetchRegistry: false
serviceUrl:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
server:
port: 1111 # HTTP (Tomcat) port
微服務可以通過添加 @ EnableDiscoverClient 注解來將它自己注冊到 Eureka 服務器上 , Eureka 服務會將地址,以及端口添加注冊到 application.yml 或者 application.properties 文件里去。
eureka:
client:
serviceUrl:
defaultZone: http://localhost:1111/eureka/
fetchRegistry: true
Spring Cloud 提供了多種進程間通信的方式,包括Feign客戶端還有rest模板。 Feign 客戶端非常靈巧、干凈,并且易于實現 。通過添加 @ EnableFeignClients 注解可以啟用 Feign 客戶端。
客戶端應用程序要創建一個接口,里面要有一個帶有 @RequestMapping 的方法,并且接口要帶上 @FeignClient 注解,注解要帶上服務 ID。
@FeignClient(value = "serviceA")
public interface ServiceClientA {
@RequestMapping(value = "/user/{userId}", method = RequestMethod.GET, produces = { MediaType.APPLICATION_JSON_VALUE })
public UserProfile getUserProfile(
@PathVariable("userId") Integer userId);
}
我們通過創建一個新的類 , ServiceClientBean.java,來調用這些接口方法。
@Component
public class ServiceClientBean {
@Autowired
private ServiceClientA serviceClientA;
@HystrixCommand(fallbackMethod = "defaultMethod")
public UserProfile getUserProfile(Integer userId) {
UserProfile user=serviceClientA.getUSerProfile(userId);
return user;
}
public UserProfile defaultMethod() {
return new UserProfile();
}
}
通過在 @EnableFeignClients 中加入 basePackageClasses 屬性值,所有的 @FeignClient 類都被注冊為 Spring bean。
@EnableFeignClients(basePackageClasses = ServiceClientA.class)
開發者可以在客戶端和服務端之間共享相同的接口定義, 不過這樣做會增加客戶端和服務端之間輕微的耦合。
Feign 客戶端會使用Ribbon自動對服務均衡進行支持。Ribbon 是一個客戶端服務均衡器,它能對 HTTP 和 TCP 請求進行許多的控制。我們可以使用外部屬性 client.ribbon.* 來對 ribbon客戶端進行配置。
在 ServiceClientBean.java 中, 我們添加了一個 @HystrixCommand 注解來處理局部失敗。這個命令會告訴 Spring,這個方法容易發生失敗。Spring Cloud 庫封裝了這些方法,通過啟用斷路器來處理容錯和延遲容忍。Hystrix 命令一般都會帶有一個回退方法。為了應對發生錯誤的情況,Hystrix 會自動啟用前述回退方法,并將流量轉移到回退方法。
如果服務A不能及時響應或者可能關閉,那么 hystrix 就會調用回退方法來返回默認的響應消息。
通過添加 hystrix 儀表盤應用程序,我們可以查看到 hystrix 個各項運行指標并對其進行監控。
還有一個組件,交過 Zuul 代理,它是一個服務網關。這個在上面的架構圖中沒有提到。服務網關會在內部調用到多個微服務,對來自這些微服務的調用結果進行整合后發送給客戶端服務。
Zuul 代理內部使用了 Eureka 服務進行服務發現,使用 Ribbon 進行服務實體間的負載均衡。
分布式應用程序需要某種類型的中央日志框架,而這個可以很容易的通過 ELK 技術棧來實現。
來自:https://www.oschina.net/translate/distributed-application-development