1. 程式人生 > >Spring Cloud微服務系統架構的一些簡單介紹和使用

Spring Cloud微服務系統架構的一些簡單介紹和使用

Spring Cloud

目錄

Spring Cloud為開發人員提供了快速構建分散式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智慧路由,微代理,控制匯流排,一次性令牌,全域性鎖,領導選舉,分散式會話,叢集狀態)。分散式系統的協調導致了樣板模式, 使用Spring Cloud開發人員可以快速地支援實現這些模式的服務和應用程式。他們將在任何分散式環境中執行良好,包括開發人員自己的膝上型電腦,裸機資料中心,以及Cloud Foundry等託管平臺。

版本:Brixton.BUILD-SNAPSHOT

特徵

Spring Cloud專注於提供良好的開箱即用經驗的典型用例和可擴充套件性機制覆蓋。

  • 分散式/版本化配置

  • 服務註冊和發現

  • 路由

  • service - to - service呼叫

  • 負載均衡

  • 斷路器

  • 全域性鎖

  • Leadership選舉與叢集狀態

  • 分散式訊息傳遞

雲原生應用程式

雲原生是一種應用開發風格,鼓勵在持續交付和價值驅動開發領域輕鬆採用最佳實踐。相關的學科是建立12-factor Apps,其中開發實踐與交付和運營目標相一致,例如通過使用宣告式程式設計和管理和監控。Spring Cloud以許多具體方式促進這些開發風格,起點是分散式系統中的所有元件需要或需要時輕鬆訪問的一組功能。

許多這些功能都由Spring Boot覆蓋,我們在Spring Cloud中建立。更多的由Spring Cloud提供為兩個庫:Spring Cloud上下文和Spring Cloud Commons。Spring Cloud上下文為Spring Cloud應用程式(引導上下文,加密,重新整理範圍和環境端點)的ApplicationContext提供實用程式和特殊服務。Spring Cloud Commons是一組在不同的Spring Cloud實現中使用的抽象和常用類(例如Spring Cloud Netflix vs. Spring Cloud Consul)。

如果由於“非法金鑰大小”而導致異常,並且您正在使用Sun的JDK,則需要安裝Java加密擴充套件(JCE)無限強度管理策略檔案。有關詳細資訊,請參閱以下連結:

將檔案解壓縮到JDK / jre / lib / security資料夾(無論您使用的是哪個版本的JRE / JDK x64 / x86)。

注意 Spring Cloud在非限制性Apache 2.0許可證下發布。如果您想為文件的這一部分做出貢獻,或者發現錯誤,請在github中找到專案中的原始碼和問題跟蹤器

Spring Cloud上下文:應用程式上下文服務

Spring Boot有如何使用Spring構建應用程式的意見:例如它具有常規配置檔案的常規位置,以及用於常見管理和監視任務的端點。Spring Cloud建立在此之上,並添加了一些可能系統中所有元件將使用或偶爾需要的功能。

引導應用程式上下文

一個Spring Cloud應用程式通過建立一個“引導”上下文來執行,上下文是主應用程式的父上下文。開箱即用,負責從外部源載入配置屬性,還解密本地外部配置檔案中的屬性。這兩個上下文共享一個Environment,這是任何Spring應用程式的外部屬性的來源。Bootstrap屬性的優先順序高,因此預設情況下不能被本地配置覆蓋。

引導上下文使用與主應用程式上下文定位外部配置的不同約定,因此使用bootstrap.yml而不是application.yml(或.properties),保持引導和主上下文的外部配置非常獨立。例:

bootstrap.yml
spring:
  application:
    name: foo
  cloud:
    config:
      uri: ${SPRING_CONFIG_URI:http://localhost:8888}

如果您的應用程式需要從伺服器進行特定於應用程式的配置,那麼設定spring.application.namebootstrap.ymlapplication.yml)是個好主意。

您可以通過設定spring.cloud.bootstrap.enabled=false(例如在系統屬性中)來完全禁用引導過程。

應用程式上下文層次結構

如果您從SpringApplicationSpringApplicationBuilder構建應用程式上下文,則將Bootstrap上下文新增為該上下文的父級。這是一個Spring的功能,即子上下文從其父級繼承屬性源和配置檔案,因此與主要構建相同的上下文相比,“主”應用程式上下文將包含其他屬性源,而不使用Spring Cloud Config。額外的財產來源是:

  • “bootstrap”:如果在引導上下文中找到任何PropertySourceLocators,則可選的CompositePropertySource顯示為高優先順序,它們具有非空屬性。一個例子就是Spring Cloud Config伺服器的屬性。有關如何自定義此屬性源的內容的說明,請參閱 下文

  • “applicationConfig:[classpath:bootstrap.yml]”(和朋友,如果Spring配置檔案處於活動狀態)。如果您有一個bootstrap.yml(或屬性),那麼這些屬性用於配置引導上下文,然後在父設定時將它們新增到子上下文中。它們的優先順序低於application.yml(或屬性)以及作為建立Spring Boot應用程式程序的正常部分新增到子級的任何其他屬性源的優先順序。有關如何自定義這些屬性源的內容的說明,請參閱下文

由於屬性源的排序規則,“引導”條目優先,但請注意,這些條目不包含來自bootstrap.yml的任何資料,其優先順序非常低,但可用於設定預設值。

您可以通過簡單地設定您建立的任何ApplicationContext的父上下文來擴充套件上下文層次結構,例如使用自己的介面,或使用SpringApplicationBuilder方便方法(parent()child()sibling())。引導環境將是您建立自己的最高階祖先的父級。層次結構中的每個上下文都將有自己的“引導”屬性源(可能為空),以避免無意中將值從父級升級到其後代。層次結構中的每個上下文也可以(原則上)具有不同的spring.application.name,因此,如果存在配置伺服器,則不同的遠端屬性源。正常Spring應用程式上下文行為規則適用於屬性解析:子上下文的屬性通過名稱以及屬性源名稱覆蓋父項中的屬性(如果子級具有與父級名稱相同的屬性源,一個來自父母的孩子不包括在孩子中)。

請注意,SpringApplicationBuilder允許您在整個層次結構中共享Environment,但這不是預設的。因此,兄弟情境尤其不需要具有相同的資料或財產來源,儘管它們與父母共享共同點。

改變Bootstrap的位置Properties

可以使用spring.cloud.bootstrap.name(預設“引導”)或spring.cloud.bootstrap.location(預設為空)指定bootstrap.yml(或.properties)位置,例如系統屬性。這些屬性的行為類似於具有相同名稱的spring.config.*變體,實際上它們用於通過在其Environment中設定這些屬性來設定引導ApplicationContext。如果在正在建立的上下文中有活動的配置檔案(來自spring.profiles.active或通過Environment API),則該配置檔案中的屬性也將被載入,就像在常規的Spring Boot應用程式中,例如來自bootstrap-development.properties的“開發”簡介。

覆蓋遠端Properties的值

通過引導上下文新增到應用程式的屬性源通常是“遠端”(例如從配置伺服器),並且預設情況下,不能在本地覆蓋,除了在命令列上。如果要允許應用程式使用自己的系統屬性或配置檔案覆蓋遠端屬性,則遠端屬性源必須通過設定spring.cloud.config.allowOverride=true(無法在本地設定)授予許可權。一旦設定了該標誌,就會有一些更精細的設定來控制遠端屬性與系統屬性和應用程式本地配置的位置:spring.cloud.config.overrideNone=true覆蓋任何本地屬性源,spring.cloud.config.overrideSystemProperties=false如果只有系統屬性和env var應該覆蓋遠端設定,而不是本地配置檔案。

自定義引導配置

可以通過在org.springframework.cloud.bootstrap.BootstrapConfiguration關鍵字/META-INF/spring.factories下新增條目來訓練自舉上下文來執行任何您喜歡的操作。這是用於建立上下文的Spring @Configuration類的逗號分隔列表。您可以在此處建立要用於自動佈線的主應用程式上下文的任何bean,並且還有一個@Beans型別為ApplicationContextInitializer的特殊合同。如果要控制啟動順序(預設順序為“最後”),可以使用@Order標記類。

警告 新增自定義BootstrapConfiguration時,請注意,您新增的類不是錯誤的@ComponentScanned到您的“主”應用程式上下文中,可能不需要它們。對於您的@ComponentScan@SpringBootApplication註釋配置類尚未涵蓋的引導配置類,請使用單獨的包名稱。

引導過程通過將初始化器注入主SpringApplication例項(即正常的Spring Boot啟動順序,無論是作為獨立應用程式執行還是部署在應用程式伺服器中)結束。首先,從spring.factories中找到的類建立一個引導上下文,然後在SpringApplication型別之前將ApplicationContextInitializer型別的所有@Beans新增到開始之前。

自定義引導屬性源

引導過程新增的外部配置的預設屬性源是Config Server,但您可以通過將PropertySourceLocator型別的bean新增到引導上下文中(通過spring.factories)新增其他源。您可以使用此方法從其他伺服器或資料庫中插入其他屬性。

作為一個例子,請考慮以下微不足道的自定義定位器:

@Configuration
public class CustomPropertySourceLocator implements PropertySourceLocator {

    @Override
    public PropertySource<?> locate(Environment environment) {
        return new MapPropertySource("customProperty",
                Collections.<String, Object>singletonMap("property.from.sample.custom.source", "worked as intended"));
    }

}

傳入的Environment是要建立的ApplicationContextEnvironment,即為我們提供額外的屬性來源的。它將已經具有正常的Spring Boot提供的資源來源,因此您可以使用這些資源來定位特定於此Environment的屬性源(例如,通過在spring.application.name上鍵入,就像在預設值Config Server屬性源定位器)。

如果你在這個類中建立一個jar,然後新增一個META-INF/spring.factories包含:

org.springframework.cloud.bootstrap.BootstrapConfiguration=sample.custom.CustomPropertySourceLocator

那麼“customProperty”PropertySource將顯示在其類路徑中包含該jar的任何應用程式中。

環境變化

應用程式將收聽EnvironmentChangeEvent,並以幾種標準方式對此更改作出反應(使用者可以按常規方式新增ApplicationListeners另外的ApplicationListeners)。當觀察到EnvironmentChangeEvent時,它將有一個已經更改的鍵值列表,應用程式將使用以下內容:

  • 重新繫結上下文中的所有@ConfigurationProperties bean

  • logging.level.*中的任何屬性設定記錄器級別

請注意,配置客戶端不會通過預設輪詢檢視Environment中的更改,通常我們不建議檢測更改的方法(儘管可以使用@Scheduled註釋進行設定)。如果您有一個擴充套件的客戶端應用程式,那麼最好將EnvironmentChangeEvent廣播到所有例項,而不是讓它們輪詢更改(例如使用Spring Cloud匯流排)。

EnvironmentChangeEvent涵蓋了大量的重新整理用例,只要您實際可以更改Environment併發布事件(這些API是公開的,並且是核心Spring的一部分)。您可以通過訪問/configprops端點(普通Spring Boot Actuator功能)來驗證更改是否繫結到@ConfigurationProperties bean。例如,DataSource可以在執行時更改其maxPoolSize(由Spring Boot建立的預設DataSource是一個@ConfigurationProperties bean),並且動態增加容量。重新繫結@ConfigurationProperties不涵蓋另一大類用例,您需要更多的控制重新整理,而您需要將整個ApplicationContext變更為原子。為了解決這些擔憂,我們有@RefreshScope

重新整理範圍

當配置更改時,標記為@RefreshScope的Spring @Bean將得到特殊處理。這解決了狀態bean在初始化時只注入配置的問題。例如,如果通過Environment更改資料庫URL時DataSource有開放連線,我們可能希望這些連線的持有者能夠完成他們正在做的工作。然後下一次有人從游泳池借用一個連線,他得到一個新的URL。

重新整理範圍bean是在使用時初始化的懶惰代理(即當呼叫一個方法時),並且作用域作為初始值的快取。要強制bean重新初始化下一個方法呼叫,您只需要使其快取條目無效。

RefreshScope是上下文中的一個bean,它有一個公共方法refreshAll()來清除目標快取中的範圍內的所有bean。還有一個refresh(String)方法通過名稱重新整理單個bean。此功能在/refresh端點(通過HTTP或JMX)中公開。

注意 @RefreshScope工程(技術)上的@Configuration類,但它可能會導致令人驚訝的行為:例如,它並不 意味著所有的@Beans在類中定義本身@RefreshScope。具體來說,任何取決於這些bean的東西都不能依賴它們在重新整理啟動時被更新,除非它本身在@RefreshScope(在其中將重新重新整理並重新注入其依賴關係),那麼它們將從重新整理的@Configuration重新初始化)。

加密和解密

Spring Cloud具有用於在本地解密屬性值的Environment前處理器。它遵循與Config Server相同的規則,並通過encrypt.*具有相同的外部配置。因此,您可以使用{cipher}*格式的加密值,只要有一個有效的金鑰,那麼在主應用程式上下文獲取Environment之前,它們將被解密。要在應用程式中使用加密功能,您需要在您的類路徑中包含Spring Security RSA(Maven協調“org.springframework.security:spring-security-rsa”),並且還需要全面強大的JCE擴充套件你的JVM

如果由於“非法金鑰大小”而導致異常,並且您正在使用Sun的JDK,則需要安裝Java加密擴充套件(JCE)無限強度管理策略檔案。有關詳細資訊,請參閱以下連結:

將檔案解壓縮到JDK / jre / lib / security資料夾(無論您使用的是哪個版本的JRE / JDK x64 / x86)。

端點

對於Spring Boot Actuator應用程式,還有一些額外的管理端點:

  • POST到/env以更新Environment並重新繫結@ConfigurationProperties和日誌級別

  • /refresh重新載入引導帶上下文並重新整理@RefreshScope bean

  • /restart關閉ApplicationContext並重新啟動(預設情況下禁用)

  • /pause/resume呼叫Lifecycle方法(stop()start())上的ApplicationContext

Spring Cloud Commons:普通抽象

諸如服務發現,負載平衡和斷路器之類的模式適用於所有Spring Cloud客戶端可以獨立於實現(例如,通過Eureka或Consul發現)可以使用的普通抽象層。

@EnableDiscoveryClient

Commons提供@EnableDiscoveryClient註釋。這通過META-INF/spring.factories查詢DiscoveryClient介面的實現。Discovery Client的實現將在org.springframework.cloud.client.discovery.EnableDiscoveryClient鍵下的spring.factories中新增一個配置類。DiscoveryClient實現的例子是Spring Cloud Netflix EurekaSpring Cloud Consul發現Spring Cloud Zookeeper發現

預設情況下,DiscoveryClient的實現將使用遠端發現伺服器自動註冊本地Spring Boot伺服器。可以通過在@EnableDiscoveryClient中設定autoRegister=false來禁用此功能。

ServiceRegistry

Commons現在提供了一個ServiceRegistry介面,它提供了諸如register(Registration)deregister(Registration)之類的方法,允許您提供自定義的註冊服務。Registration是一個標記介面。

服務註冊執行器端點

Commons提供/service-registry致動器端點。此端點依賴於Spring應用程式上下文中的Registration bean。通過GET呼叫/service-registry/instance-status將返回Registration的狀態。具有String主體的同一端點的POST將將當前Registration的狀態更改為新值。請參閱您正在使用的ServiceRegistry實現的文件,以獲取更新狀態的允許值以及為狀態獲取的值。

Spring RestTemplate作為負載均衡器客戶端

RestTemplate可以自動配置為使用功能區。要建立負載平衡RestTemplate建立RestTemplate @Bean並使用@LoadBalanced限定符。

警告 通過自動配置不再建立RestTemplate bean。它必須由單個應用程式建立。
@Configuration
public class MyConfiguration {

    @LoadBalanced
    @Bean
    RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

public class MyClass {
    @Autowired
    private RestTemplate restTemplate;

    public String doOtherStuff() {
        String results = restTemplate.getForObject("http://stores/stores", String.class);
        return results;
    }
}

URI需要使用虛擬主機名(即服務名稱,而不是主機名)。Ribbon客戶端用於建立完整的實體地址。有關如何設定RestTemplate的詳細資訊,請參閱 RibbonAutoConfiguration

重試失敗的請求

負載平衡RestTemplate可以配置為重試失敗的請求。預設情況下,該邏輯被禁用,您可以通過設定spring.cloud.loadbalancer.retry.enabled=true啟用該邏輯。負載平衡RestTemplate將符合與重試失敗請求相關的某些Ribbon配置值。您可以使用的屬性是client.ribbon.MaxAutoRetriesclient.ribbon.MaxAutoRetriesNextServerclient.ribbon.OkToRetryOnAllOperations。請參閱Ribbon文件 ,瞭解屬性的具體內容。

注意 上述示例中的client應替換為您的Ribbon客戶端名稱。

多個RestTemplate物件

如果你想要一個沒有負載平衡的RestTemplate,建立一個RestTemplate bean並注入它。建立@Bean時訪問負載平衡RestTemplate usethe `@LoadBalanced限定詞。

重要 請注意下面示例中明文RestTemplate宣告的@Primary註釋,以消除不合格的@Autowired注入。
@Configuration
public class MyConfiguration {

    @LoadBalanced
    @Bean
    RestTemplate loadBalanced() {
        return new RestTemplate();
    }

    @Primary
    @Bean
    RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

public class MyClass {
    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    @LoadBalanced
    private RestTemplate loadBalanced;

    public String doOtherStuff() {
        return loadBalanced.getForObject("http://stores/stores", String.class);
    }

    public String doStuff() {
        return restTemplate.getForObject("http://example.com", String.class);
    }
}
提示 如果您發現錯誤java.lang.IllegalArgumentException: Can not set org.springframework.web.client.RestTemplate field com.my.app.Foo.restTemplate to com.sun.proxy.$Proxy89,請嘗試登出RestOperations或設定spring.aop.proxyTargetClass=true

忽略網路介面

有時,忽略某些命名網路介面是有用的,因此可以將其從服務發現註冊中排除(例如,在Docker容器中執行)。可以設定正則表示式的列表,這將導致所需的網路介面被忽略。以下配置將忽略“docker0”介面和以“veth”開頭的所有介面。

application.yml
spring:
  cloud:
    inetutils:
      ignoredInterfaces:
        - docker0
        - veth.*

您還可以強制使用正則表示式列表中指定的網路地址:

application.yml
spring:
  cloud:
    inetutils:
      pre