基于微服務的分布式應用開發

分類:技術 時間:2017-01-13

微服務架構設計模式對于單塊設計模式而言有很多優點。核心思想就是將單個巨大的應用劃分成互聯的不同應用。與單塊應用類似,每個微服務都有其自己的層級架構。

使用下列的模式,微服務可以輕易取得如下優點:

可擴展性一款典型的應用會使用3個方向的擴展。X軸擴展是指橫向擴展應用,Y軸擴展是指劃分不同的應用功能,Z軸擴展是指對于數據的分區(partioning)和分片(sharding)。當Y軸擴展應用到單塊應用時,該應用就會被打散,按照符合微服務特性的業務功能,形成許多更小的單元。

模式:每個微服務有其隔離的實例或容器。服務級別的負載均衡可以通過將相同服務托管于多個實例實現。

可用性如同相同的微服務會托管于多個實例中一樣,微服務會部署于不同的實例中,這使整個系統高度可用。

模式:服務級別的負載均衡可被用以實現高可用性,斷路器模式可被用以實現容錯,服務配置和服務發現可使發現新服務以通訊成為可能。

持續部署每個微服務均是獨立的。這就導致任何服務均可獨立于其它服務完成部署,從而達到更加快速且可持續性的部署目標。

松耦合微服務提供不同的方式實現松耦合。每個微服務都應在服務級別有其自身的層級架構,并且在使用數據庫作為持久層時,它運行于自己的獨立環境中。

技術多樣性將微服務視為隔離的特性,多種技術的混合可以用于實現服務于整體應用的多種微服務。

高效成本服務實例可以基于應用使用率進行優化。低價實例可以用以最低優先的服務,而高價實例則可以用到關鍵業務服務。

性能考慮到微服務技術多樣化的優點,這會對性能有直接影響。例如,高阻塞率的服務調用在進線程技術棧中實現,CPU密集型服務在多線程技術棧中實現。

和單塊架構相比,微服務也有一些缺點。

諸如,和單塊應用相比,開發和管理分布式應用很困難。微服務需要進程間通訊(IPC)機制以使不同微服務之間得以通訊,當然這可能會對性能有點影響(取決于網絡帶寬)。

以下是為了實現高效微服務需要實現的功能:

  • 對于IPC,每個微服務都應該使用 Rest調用或RPC 來調用其它微服務。
  • 一個微服務可能會與單個或多個微服務通訊。一個服務可能會是不可用的,或者因為高負載或某種服務錯誤,而無法在限定時間內響應。為了應對這種場景,應該有 部分故障或回滾機制
  • 部署一款基于微服務的應用相比單塊應用而言會更加復雜,因為基于微服務的應用有不同的服務,并且每個服務可能會運行在不同的容器或實例上。因此需要一種 服務注冊和發現機制 ,來完成想要通訊的新服務的注冊和發現。
  • 一個客戶端微服務可能會因為單個功能來調用多個遠程的微服務。這可能會導致跨網絡rest或RPC的高負載調用。因此需要一個 服務網關 ,它會接受來自微服務的一個調用,然后內部分發這個調用給多個本地服務調用(對于服務網關而言是本地的),將這些服務的結構匯總,并返回給客戶端微服務。
  • 當同一個微服務托管于同一主機的不同容器中時,這里就需要一個 服務級的負載均衡 來分發負載,并實現災備機制。
  • 分布式應用也需要某種 中心化日志 框架,因此所有的數據可以被集中并生成日志數據。

自行實現上述的所有特性是很復雜的,會占用大量時間,并且會使開發者消耗大量時間來開發和測試基礎框架配置。然而,如果你已經具備了上述的一切,那么你就只需要聚焦于業務邏輯了。

Spring Cloud 框架提供了相關工具在分布式服務中快速構建一些基礎模式,例如配置管理,服務發現,斷路保護,分布式session,服務網關,rest客戶端和服務級負載均衡器等。Spring Cloud項目通過在項目中添加一些Maven依賴來完成初始化。這些也可以由使用 spring initialize 的項目創建。

Spring Cloud的許多組件來自Netflix開源軟件中心(Netflix OSS),它們對于微服務部署而言是至關重要的。

Spring Cloud基于Spring Boot構建,其中Spring Boot包含了使用最小配置的內嵌tomcat服務器。

如下是在AWS云上使用微服務的分布式應用的架構圖。

上述圖例中,我們有3個不同的微服務,其中主微服務使用REST客戶端與微服務A和微服務B通信。微服務A運行于2個容器中,微服務B運行于同一實例的2個容器中。主微服務暴露給客戶端,會通過服務客戶端與任何微服務A或微服務B的實例互動,這個客戶端是一款負載均衡器。這將會使得負載均衡不僅存在于實例級別,更存在于同一實例的服務級別。這就是所謂的服務級負載均衡。當向一個服務發送請求時,客戶端服務會通過查詢Eureka服務注冊和服務發現取得服務實例的地址。

Spring Cloud已經支持使用Eureka作為服務注冊,并且Eureka服務注冊可以通過添加 @EnableEurekaServer 標注開啟。

@SpringBootApplication

@EnableEurekaServer

public class EurekaServer {

    public static void main(String[] args) {

        System.setProperty(quot;spring.config.namequot;, quot;registration-serverquot;);

        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服務注冊的地址以及端口放置于application.yml或application.properties文件,以將自己注冊到Eureka服務器。

eureka:

  client:

    serviceUrl:

      defaultZone: http://localhost:1111/eureka/

    fetchRegistry: true

Spring Cloud提供多種進程間通訊方式,其中包括外部客戶端和Rest模板。外部客戶端是十分靈巧、干凈以及易于實現的。可以通過添加 @EnableFeignClient 標注來開啟外部客戶端。

客戶端應用必須創建一個接口,該接口使用 @FeignClient 標注,需配合服務ID,內部的方法使用 @RequestMapping 標注。

@FeignClient(value = http://www.tuicool.com/articles/quot;serviceAquot;)

public interface ServiceClientA {

    @RequestMapping(value = quot;/user/{userId}quot;, method = RequestMethod.GET, produces = { MediaType.APPLICATION_JSON_VALUE })

    public UserProfile getUserProfile(

        @PathVariable(quot;userIdquot;) Integer userId);

}

我們可以通過創建一個新的類來調用這些接口方法,ServiceClientBean.java。

@Component

public class ServiceClientBean {

    @Autowired

    private ServiceClientA serviceClientA;

    @HystrixCommand(fallbackMethod = quot;defaultMethodquot;)

    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)

開發者可以在客戶端和服務器之間共享相同的接口定義,但這會增加客戶端和服務器之間的耦合度。

外部客戶端自動支持使用Ribbon的負載均衡。Ribbon是客戶端的負載均衡器,其對HTTP和TCP請求提供了大量控制支持。我們可以使用外部屬性 client.ribbon.* 來配置Ribbon客戶端。

在ServiceClientBean.java中,我們添加了一個 @HystrixCommand 標注來處理部分失敗。此命令會告訴Spring,該方法容易出錯。Spring Cloud庫包裝了這些方法以通過斷路器來實施容錯和延遲容忍。典型的Hystrix命令后面跟著回滾方法。至于故障,Hystrix會自動啟用回滾方法提醒,并且將流量引導至回滾方法。

如果微服務A無法在限定時間內發送響應或者是干脆直接宕掉,那么Hystrix將會調用回滾方法來獲取默認的響應。

我們可以通過添加Hystrix儀表盤應用來查看Hystrix統計和監控。

這里還有一個稱為Zuul代理的組件,能夠充當服務網關。上文的架構圖例中并沒有提及。服務網關內部調用多個微服務,并將來自這些微服務的結果聚合,并返回給客戶端服務。

Zuul代理內部使用Eureka服務器作為服務發現,使用Ribbon作為服務實例間的負載均衡。

分布式應用需要某種中心化日志框架,這可以通過ELK工具棧來簡單實現。


Tags: 微服務

文章來源:http://dockone.io/article/2009


ads
ads

相關文章
ads

相關文章

ad