Spring Cloud 之 Eureka.

来源:https://www.cnblogs.com/jmcui/archive/2019/06/27/11093602.html
-Advertisement-
Play Games

一、微服務概述 1. 什麼是微服務  簡單地說, 微服務是系統架構上的一種設計風格, 它的主旨是將一個原本獨立的系統拆分成多個小型服務,這些小型服務都在各自獨立的進程中運行,服務之間基於 RPC 進行通信協作。 被拆分成的每一個小型服務都圍繞著系統中的某一項或一些耦合度較高的業務功能進行構 ...


一、微服務概述

1. 什麼是微服務

 簡單地說, 微服務是系統架構上的一種設計風格, 它的主旨是將一個原本獨立的系統拆分成多個小型服務,這些小型服務都在各自獨立的進程中運行,服務之間基於 RPC 進行通信協作。 被拆分成的每一個小型服務都圍繞著系統中的某一項或一些耦合度較高的業務功能進行構建, 並且每個服務都維護著自身的數據存儲(劃重點,每個微服務都有自己的資料庫實例)、 業務開發、自動化測試案例以及獨立部署機制。

2. 微服務的特性

  • 服務組件化:一個獨立的系統拆成多個小型服務。
  • 以業務劃分服務:微服務應該以業務來劃分,而不是按能力或其他因素來劃分(比如之前做的一個項目直接將緩存能力建成了一個微服務組件)。
  • 智能端點和啞管道:服務之間通過 RPC 的方式調用,通常會使用以下兩種服務調用方式:
    第一種:使用 HTTP 的 RESTfl API 或輕量級的消息發送協議, 實現信息傳遞與服務調用的觸發。
    第二種:通過在輕量級消息匯流排上傳遞消息, 類似 RabbitMQ 等 一些提供可靠非同步交換的中間件。
  • 去中心化處理:不同的微服務組件可以選擇不同的技術方案,甚至可以選擇不同的語言。只有實現了對技術平臺的透明, 才能更好地發揮不同語言對不同業務處理能力的優勢, 從而打造更為強大的大型系統。
  • 去中心化管理數據:採用分散式資料庫,不同的微服務組件有著自己單獨的資料庫實例。雖然數據管理的去中心化可以讓數據管理更加細緻化,通過採用更合適的技術可讓數據存儲和性能達到最優。但是,由於數據存儲於不同的資料庫實例中後,數據一致性也成為微服務架構中亟待解決的問題之一。
  • 基礎設施自動化:自動化測試(每次部署前的強心劑, 儘可能地獲得對正在運行的軟體的信心)、自動化部署(解放煩瑣枯燥的重覆操作以及對多環境的配置管理)等。
  • 容錯設計:在微服務架構中,快速檢測出故障源並儘可能自動恢復服務是必須被設計和考慮的。
  • 演進式設計:沒有必要一開始就把服務拆分的又細又多,可以隨著業務系統的發展,把壓力大的服務或者穩定不變化的模塊做拆分合併動作。

2. 微服務的缺陷

  1. 運維的成本提高。這個是不可避免的,原來只需要運維一個單一獨立的系統,現在要管理幾個或者幾十個微服務。
  2. 介面的一致性問題。A 微服務修改了介面,需要調用方B、C 服務同時做出修改。除非開發過程中嚴格遵守開閉原則(在這個敏捷流式開發的背景下,幾乎很難做到)。
  3. 分散式的複雜性。網路延遲、分散式事務、非同步消息等。

tips:分散式事務本身的實現難度就非常大,所以在微服務架構中,我們更強調在各服務之間進行 “ 無事務 ” 的調用,而對於數據一致性,只要求數據在最後的處理狀態是一致的即可;若在過程中發現錯誤,通過補償機制來進行處理,使得錯誤數據能夠達到最終的一致性。

二、Spring Cloud 簡介

 Spring Cloud 是一個基於Spring Boot實現的微服務架構開發工具。它為微服務架構中涉及的配置管理、服務治理、斷路器、智能路由、微代理、控制匯流排、全局鎖、決策競選、分散式會話和集群狀態管理等操作提供了一種簡單的開發方式。

 Spring Cloud 的出現,可以說是對微服務架構的巨大支持和強有力的技術後盾。它是一個解決微服務架構實施的綜合性解決框架,它整合了諸多被廣泛實踐和證明過的框架作為實施的基礎部件,又在該體系基礎上創建了一些非常優秀的邊緣組件。舉個 Dubbo 和 Spring Cloud 差異性的例子:在使用 Dubbo 開發過程中,分散式配置中心(百度的 Disconf、Netflix的Archaius、360的QConf、淘寶的 Diamond 等)、鏈接跟蹤(京東的 Hydra、Twitter的 Zipkin 等)...一系列需要的組件,我都要去找第三方進行集成,還要考慮版本相容的問題。而 Spring Cloud 就是一個微服務解決方案的“全家桶”,幾乎我需要的全部微服務組件,我都能在其中找到“原裝組件”:分散式配置中心(Config)、鏈接跟蹤(Sleuth)、批量任務(Task),而且可以完美相容。

三、Eureka 簡介

 服務治理體系可以說是微服務架構中最為核心和基礎的模塊, 它主要用來實現各個微服務實例的自動化註冊與發現。服務治理體系中的三個核心角色: 服務註冊中心、 服務提供者以及服務消費者。而 Eureka Server 就承擔了 Spring Cloud 的服務註冊中心。接下來捋一捋 Eureka Server 進行服務治理的過程:

  1. 服務註冊:”服務提供者”在啟動的時候會通過發送 REST 請求的方式將自己註冊到 Eureka Server 上,同時帶上了自身服務的一些元數據信息(hostName 之類的)。Eureka Server 接收到這個 REST 請求之後,將元數據信息存儲在一個雙層結構Map中,其中第一層的key是服務名,第二層的key是具體服務的實例名。
  2. 服務同步:由於服務註冊中心之間互相註冊為服務(Eureka Server 高可用場景),當服務提供者發送註冊請求到一個服務註冊中心時,它會將該請求轉發給集群中相連的其他註冊中心, 從而實現註冊中心之間的服務同步。通過服務同步,兩個服務提供者的服務信息就可以通過這兩台服務註冊中心中的任意一臺獲取到。
  3. 服務續約:在註冊完服務之後,“服務提供者”會維護一個心跳用來持續告訴 Eureka Sever "我還活著 ”, 以防止Eureka Server 的 “ 剔除任務 ” 將該服務實例從服務列表中排除出去。
  4. 服務消費:當我們啟動“服務消費者”的時候,它會發送一個 REST 請求給服務註冊中心,來獲取上面註冊的服務清單 。為了性能考慮, Eureka Serer會維護一份只讀的服務清單來返回給客戶端,同時該緩存清單會每隔30秒更新一次。
  5. 服務調用:“服務消費者”在 獲取服務清單後,通過服務名可以獲得具體提供服務的實例名和該實例的元數據信息。因為有這些服務實例的詳細信息,所以客戶端可以根據自己的需要決定具體調用哪個實例,在 Ribbon 中會預設採用輪詢的方式進行調用,從而實現客戶端的負載均衡。
  6. 服務下線:服務實例進行正常的關閉操作時,它會觸發一個服務下線的 REST 請求給 Eureka Server,告訴服務註冊中心:“我要下線了 ”。服務端在接收到請求之後,將該服務狀態置為下線(DOWN), 並把該下線事件傳播出去。
  7. 失效剔除:有些時候,我們的服務實例並不一定會正常下線,可能由於記憶體溢出、網路故障等原因使得服務不能正常工作,而服務註冊中心並未收到 “服務下線 ” 的請求。為了從服務列表中將這些無法提供服務的實例剔除,Eureka Server 在啟動的時候會創建一個定時任務,預設每隔 一段時間(預設為60秒) 將當前清單中超時(預設為90秒)沒有續約的服務剔除出去。
  8. 自我保護:Eureka Server在運行期間,會統計心跳失敗的比例在15分鐘之內是否低於85%, 如果出現低於的情況(在單機調試的時候很容易滿足, 實際在生產環境上通常是由於網路不穩定導致),Eureka Server 會將當前的實例註冊信息保護起來, 讓這些實例不會過期, 儘可能保護這些註冊信息。

tips:Spring Cloud Eureka實現的服務治理機制強調了CAP原理中的AP, 即可用性與分區容錯性,它與Zoo Keeper這類強調CP( 一致性、分區容錯性)的服務治理框架最大的區別就是,Eureka為了實現更高的服務可用性,犧牲了一定的一致性,在極端情況下它寧願接受故障實例也不要丟掉“健康”實例,比如,當服務註冊中心的網路發生故障斷開時,由於所有的服務實例無法維持續約心跳,在強調 AP的服務治理中將會把所有服務實例都剔除掉,而 Eureka 則會因為超過 85% 的實例丟失心跳而會觸發保護機制,註冊中心將會保留此時的所有節點,以實現服務間依然可以進行互相調用的場景,即使其中有部分故障節點,但這樣做可以繼續保障大多數的服務正常消費。

四、Eureka 實戰

SpringBoot 版本號:2.1.6.RELEASE
SpringCloud 版本號:Greenwich.RELEASE

1. 服務註冊中心

  • pom.xml
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
            <version>2.1.0.RELEASE</version>
        </dependency>
  • application.yml
server:
  port: 1111

eureka:
  instance:
    hostname: localhost
    prefer-ip-address: true
  client:
    # 表示不向註冊中心註冊自己
    register-with-eureka: false
    # 註冊中心的職責是維護實例,不需要去檢索服務
    fetch-registry: false
    service-url:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
   server:
     # 是否要打開自我保護機制
     enable-self-preservation: true

eureka 的配置項主要有三項:instance、client、server。“instance”維護該服務的實例信息,包括 hostname、port 這類描述實例特征的元數據信息;“client”主要是服務註冊數據的配置,比如超時時間、服務緩存時間等;“server”是服務註冊中心特有的配置,配置 Eureka Server 的相關配置項,比如上面的是否打開自我保護。

  • Application.java
//啟動一個服務註冊中心
@EnableEurekaServer
@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

至此,我們一個Eureka Server — 服務註冊中心就搭建好了。

2. 服務提供者

  • pom.xml
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
  • application.yml
server:
  port: 2222

spring:
  application:
    name: cloud-eureka-client

eureka:
  # 服務註冊相關的配置信息
  client:
    service-url:
      defaultZone: http://localhost:1111/eureka/
  instance:
    # 是否優先使用IP地址作為主機名的標識
    prefer-ip-address: true

就這樣,我們的一個 Eureka Client 算是註冊到 Eureka Server 上了。接下來,讓我們試試用 DiscoveryClient 發現我們的服務信息:

// 自動化配置, 創建 DiscoveryClient 介面針對 Eureka 客戶端的 EurekaDiscoveryClient 實例
@EnableDiscoveryClient
@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application .class, args);
    }
}
@RestController
public class HelloController {

    private final Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    private DiscoveryClient discoveryClient;
    @Value("${spring.application.name}")
    private String serviceId;

    @RequestMapping(value = "/hello", method = RequestMethod.GET)
    public String index() {
        List<ServiceInstance> instances = discoveryClient.getInstances(serviceId);
        ServiceInstance instance = instances.get(0);
        logger.info("/hello, host:" + instance.getHost() + ", serviceId:" + instance.getServiceId());
        return "Hello World";
    }
}

3. 服務消費者

 有了服務註冊中心和服務提供者,我們還差一個服務消費者,服務消費者需要依賴 Spring Cloud Ribbon。
 Spring Cloud Ribbon 是一個基於 HTTP 和 TCP 的客戶端負載均衡工具,它基於 Netflix Ribbon 實現。通過 Spring Cloud 的封裝,可以讓我們輕鬆地將面向服務的 REST 模板請求自動轉換成客戶端負載均衡的服務調用。Spring Cloud Ribbon 雖然只是一個工具類框架,它不像服務註冊中心、配置中心、API 網關那樣需要獨立部署,但是它幾乎存在於每一個 Spring Cloud 構建的微服務和基礎設施中。因為微服務間的調用,API 網關的請求轉發等內容實際上都是通過 Ribbon 來實現的。

  • pom.xml
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
        </dependency>
  • Application.java
@EnableDiscoveryClient
@SpringBootApplication
public class ConsumerApplication {

    public static void main(String[] args) {
        SpringApplication.run(ConsumerApplication.class, args);
    }


    @LoadBalanced
    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}
  • ConsumerController.java
@RestController
public class ConsumerController {

    @Autowired
    private RestTemplate restTemplate;

    @RequestMapping("/ribbon-consumer")
    public String helloConsumer() {
        // 這裡訪問的是服務名,而不是一個具體的地址(為了實現負載均衡策略),在服務治理框架中,這是一個非常重要的特性。
        ResponseEntity<String> result = restTemplate.getForEntity("http://cloud-eureka-client/hello", String.class);
        return result.getBody();
    }
}

接下來我們來捋一捋 Spring Cloud Ribbon 實現客戶端負載均衡的步驟:

  1. 首先被 @loadBalanced 註解的 RestTemplate 發起的服務請求會被 LoadBalancerInterceptor 攔截下來。
  2. LoadBalancerInterceptor 把請求重新組織後,帶上 serviceName(服務名) 交由 LoadBalancerClient 去處理(在 Eureka 和 Ribbon 的集成中,處理由 RibbonLoadBalancerClient 進行)。
  3. RibbonLoadBalancerClient 根據 serviceName 得到負載均衡策略 ILoadBalancer(預設的是 ZoneAwareLoadBalancer 區域親和策略)。
  4. ILoadBalancer 根據負載均衡規則選取一臺伺服器 Server。
  5. 有了 Server 信息以後,正式發起一次請求,具體的請求動作在 AsyncLoadBalancerInterceptor 進行。它先將 restTemplate 中的 serviceName 轉換成 host:port 的形式(這個在 ServiceRequestWrapper 中實現),然後發起一個非同步請求。

五、附加

  • 預設情況下,Eureka 使用 Jersey 和 XStream 配合 JSON 作為 Server 與 Client 之間的通信協議。
  • YAML 的意思其實是: Yet Another Markup Language — 仍是一種標記語言(這個看著有點想笑)。
  • 在 SpringBoot 的屬性配置文件中,可以通過使用 ${random} 配置來產生隨機的 int 值、long 值或者 string 字元串。
  • 在 Spring Boot 中,多環境配置的文件名需要滿足 application-{profile}.properties的格式, 其中{profile}對應你的環境標識。通過啟動參數 --spring.profiles.active=test 來指定激活的環境變數。
  • 負載均衡:

演示源代碼 :https://github.com/JMCuixy/spring-cloud-demo

內容參考《Spring Cloud 微服務實戰》


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 求兩個數的二進位位不同的位置,最先想到的就是 異或操作 , 異或:按位運算,相同為0,不同為1。 比如: a = 6 對應的二進位表示為: 0 0 1 1 1 ​ b = 9 對應的二進位表示為: 0 1 0 0 1 則 a ^ b = 14 對應的二進位表示為: 0 1 1 1 0 所以,只要算出 ...
  • 今天我們來看看java中數據類型的相關信息,其中java中數據類型分為java基本數據類型和引用類型,其中: 基本數據類型分為: 整型 浮點型 字元型 boolean型 整型包括byte(位元組型)、short(短整型)、int(整型)、long(長整型)在對變數賦值時,如果值超出變數所屬類型表示範圍 ...
  • 參考:https://www.t9vg.com/archives/304 ...
  • 2.1.函數的定義和使用 函數基本使用 實例一:寫一個守護進程,nginx如果關閉自動開啟 vim nginx_daemon.sh 把這個腳本放到後臺運行 關閉後查看 2.2.向函數傳遞參數 shell中傳參 函數調用 舉例 2.3.函數的返回值 返回值的方式 使用return返回值 使用retur ...
  • 1.1原理: Cookie是保存在客戶端的信息包(一個文件) 1.客戶端向伺服器發送請求 2.伺服器將值放到響應頭中發送到客戶端 3.瀏覽器自動的將信息放到請求投資帶到伺服器 1.2設置Cookie 客戶端有cookei信息後,每次請求伺服器,cookie的信息都會自動的放到請求頭中帶到伺服器。 1 ...
  • 前面我們介紹了簡單工廠模式,今天我們來看一下工廠模式。 工廠模式的定義為:定義一個用於創建對象的介面,讓子類決定實例化哪一個類。工廠方法使一個類的實例化延遲到子類。 我們看以下例子。首先是產品類,用來定義共產所生產的部分產品,這部分代碼和簡單工廠模式的代碼相同。 接下來是和簡單工廠不同的地方,首先我 ...
  • JAVA-基礎(Class對象及反射) 1.(1)什麼是class對象? 首先,java有兩種對象,第一種是實例對象,第二種是Class對象,每一個類運行的類型信息就是用Class對象表示的,每一個對象都有一個到java.lang.Class(用於描述對象的結構)的實例的引用。Class類沒有公共的 ...
  • 小白程式猿,練練手,做做題目,分享下經驗, 有不對的,還請大家能夠指出,多多包涵!謝謝!! 先簡單,後複雜,循序漸進,希望能夠堅持下來, 大家一起進步~~ ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...