Spring Cloud 快速上手之 Eureka 服務註冊

Spring Cloud 快速上手之 Eureka 服務註冊

簡介

本文主要介紹 Spring Cloud 中的 Eureka 服務註冊中心。

image.png


手機用戶請橫屏獲取最佳閱讀體驗,REFERENCES中是本文參考的鏈接,如需要鏈接和更多資源,可以掃碼加入『知識星球』(文末)獲取長期知識分享服務。

準備工作

版本

簡單的RestTemplate調用

消費端服務調用

@RestController
public class UserController {

    @Autowired
    private IUserService userService;

    @GetMapping("/user/{id}")
    public User findById(@PathVariable Long id) {
        return userService.findById(id);
    }
}

//---

@Service
public class UserServiceImpl implements IUserService {

    @Autowired
    private RestTemplate restTemplate;

    @Override
    public User findById(Long id) {
        return this.restTemplate.getForObject("http://localhost:8000/"+id,User.class);
    }

}

@Configuration
public class RpcConfig {

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

返回結果

{
  "id": 1,
  "account": "account0",
  "userName": "x_user_0",
  "age": 18
}

Spring Boot Actuator

 <!--狀態監控-->
 <dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-actuator</artifactId>
 </dependency>

.

從日誌打印的端點信息進入,查看狀態監控返回信息

//獲取健康指標
HTTP/1.1 200 
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Sun, 03 May 2020 13:53:14 GMT

{
  "status": "UP"
}

//獲取應用信息
GET http://localhost:8000/actuator/info

HTTP/1.1 200 
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Sun, 03 May 2020 13:54:41 GMT

{}

//查詢端點信息
GET http://localhost:8000/actuator

HTTP/1.1 200 
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Sun, 03 May 2020 13:55:56 GMT

{
  "_links": {
    "self": {
      "href": "http://localhost:8000/actuator",
      "templated": false
    },
    "health": {
      "href": "http://localhost:8000/actuator/health",
      "templated": false
    },
    "info": {
      "href": "http://localhost:8000/actuator/info",
      "templated": false
    }
  }
}

Response code: 200; Time: 51ms; Content length: 227 bytes

可以通過在 yml 中補充 info 節點信息:

info:
  app:
    name: @project.artifactId@
    encoding: @project.build.sourceEncoding@
    java:
      source: @java.version@
      target: @java.version@

效果如下:

GET http://localhost:8000/actuator/info

HTTP/1.1 200 
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Sun, 03 May 2020 14:01:48 GMT

{
  "app": {
    "name": "ms-provider-user-v1",
    "encoding": "UTF-8",
    "java": {
      "source": "1.8.0_181",
      "target": "1.8.0_181"
    }
  }
}

Response code: 200; Time: 182ms; Content length: 108 bytes

小結

我們通過RestTemplate直接完成服務端的接口調用,但是對於遠端應用地址的硬編碼,往往會帶來很多問題:

  • 無法解決 IP 地址或端口變更的場景。
  • 無法進行動態伸縮,不支持多實例。

服務註冊與發現

Eureka Server

編寫單點服務註冊中心

<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>

/**
 * 核心啓動類
 */
@EnableEurekaServer
@SpringBootApplication
public class MsDiscoveryEurekaApplication {

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

}

server:
  port: 8010

eureka:
  client:
    # 表示是否將自己註冊到 Eureka Server,默認爲 true
    register-with-eureka: false
    # 表示是否從 Eureka Server 獲取註冊信息,默認爲 true
    fetch-registry: false
    service-url:
      defaultZone: http://localhost:8010/eureka/

spring:
  application:
    name: ms-discovery-eureka

訪問 http://localhost:8010/

.

此處配置的是一個單點的 Eureka Server,不需要同步其他的 Eureka Server 節點的數據,因而 fetch-registry: false

Eureka Client

註冊微服務

  • 啓動類
@SpringBootApplication
public class MsProviderUserV2Application {

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

}

  • 配置
server:
  port: 8011

spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/db_yier?characterEncoding=UTF-8&rewriteBatchedStatements=true
    username: root
    password: Abc123++
    driver-class-name: com.mysql.jdbc.Driver
  jpa:
    hibernate:
      ddl-auto: update
    show-sql: true
    database-platform: org.hibernate.dialect.MySQL5Dialect

  application:
    name: ms-provider-user-v2

eureka:
  client:
    service-url:
      # 如果此處是註冊到 Eureka Server 集羣的話,建議多配幾個節點,以便適應某些極端場景
      defaultZone: http://localhost:8010/eureka/
  instance:
		# 表示將自己的 IP 註冊到 Eureka Server,若不配置,默認爲 false,表示註冊微服務所在操作系統的 hostname 到 Eureka Server
    prefer-ip-address: true

info:
  app:
    name: @project.artifactId@
    encoding: @project.build.sourceEncoding@
    java:
      source: @java.version@
      target: @java.version@

將項目ms-provider-user-v2註冊到 Eureka Server 服務中心。

.

同理,將消費者註冊到服務中心

.

Eureka Server不同,Eureka Client無需在在啓動類上加註解@EnableEurekaClient註解1

Eureka Server 的高可用

構建雙節點集羣

  • 修改 Hosts:Mac vim /etc/hosts

.

  • 修改配置
spring:
  application:
    name: ms-discovery-eureka-ha
---
spring:
  profiles: peer1
server:
  port: 8010
eureka:
  instance:
    hostname: peer1
  client:
    service-url:
      defaultZone: http://peer2:8020/eureka/

---
spring:
  profiles: peer2
server:
  port: 8020
eureka:
  instance:
    hostname: peer2
  client:
    service-url:
      defaultZone: http://peer1:8010/eureka/


  • 啓動profiles:peer1profiles:peer2

.

.

Eureka Server 集羣精簡配置

spring:
  application:
    name: ms-discovery-eureka-ha

eureka:
  client:
    service-url:
      defaultZone: http://peer2:8020/eureka/,http://peer1:8010/eureka/

---
spring:
  profiles: peer1
server:
  port: 8010
eureka:
  instance:
    hostname: peer1

---
spring:
  profiles: peer2
server:
  port: 8020
eureka:
  instance:
    hostname: peer2


用戶認證

爲註冊中心的訪問增加權限認證控制

  • 引入Spring Security
 <!--登錄認證-->
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-security</artifactId>
</dependency>
  • 配置認證信息
server:
  port: 8010

eureka:
  client:
    register-with-eureka: false
    fetch-registry: false
    service-url:
      defaultZone: http://admin:Abc123++@localhost:8010/eureka/

spring:
  application:
    name: ms-discovery-eureka-authentication
  security:
    user:
      name: admin
      password: Abc123++
  • 訪問 localhost:8010,會跳轉到登錄界面

.

服務註冊到帶有安全認證的註冊中心

  • Spring Boot 2.0 配置不兼容修改
/*
 * @ProjectName: 編程學習
 * @Copyright:   2019 HangZhou Helios Dev, Ltd. All Right Reserved.
 * @address:     微信搜索公衆號「架構探險之道」獲取更多資源。
 * @date:        2020/5/4 9:50 下午
 * @description: 本內容僅限於編程技術學習使用,轉發請註明出處.
 */
package com.yido.ms.discovery.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;

/**
 * <p>
 *
 * </p>
 *
 * @author Helios
 * @date 2020/5/4 9:50 下午
 */
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    /**
     * 高版本的丟棄了
     *
     * security:
     *   basic:
     *    enabled: true
     * 配置,應該使用以下方式開啓
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //方式1
        // Configure HttpSecurity as needed (e.g. enable http basic).
        //http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.NEVER);
        //http.csrf().disable();
        //注意:爲了可以使用 http://user:{user}:user:{password}@host:{host}:host:{port}/eureka/ 這種方式登錄,所以必須是httpBasic,
        //如果是form方式,不能使用url格式登錄
        //http.authorizeRequests().anyRequest().authenticated().and().httpBasic();

        //方式2
        //默認情況下,將其添加到classpath後,會對每個請求進行CSRF檢查。Eureka並不會生成CSRF token,
        // 所以需要關掉對/eureka/*路徑下的檢查:
        // 關閉csrf
        http.csrf().ignoringAntMatchers("/eureka/**");
        super.configure(http);
    }
}

  • YAML 配置
server:
  port: 8010

eureka:
  client:
    register-with-eureka: false
    fetch-registry: false
    service-url:
      defaultZone: http://admin:Abc123++@localhost:8010/eureka/

spring:
  application:
    name: ms-discovery-eureka-authentication
  security:
    user:
      name: admin
      password: Abc123++
  • 註冊成功

.

Eureka 元數據

元數據配置

server:
  port: 8012

spring:
  application:
    name: ms-consumer-user-v2-metadata

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8010/eureka/
  instance:
    prefer-ip-address: true
    # 定義實例元數據信息
    metadata-map:
      my-metadata: 自定義信息

查詢接口

/**
 * 查詢當前實例信息
 * @param instanceId
 * @return
 */
@GetMapping("/instances/{instanceId}")
public List<ServiceInstance> instances(@PathVariable String instanceId) {
    //爲空,返回自身實例信息
    if (StringUtils.isEmpty(instanceId)) {
        return this.discoveryClient.getInstances("ms-consumer-user-v2-metadata");
    }
    return this.discoveryClient.getInstances(instanceId);
}

演示

.

端點信息

示例

  • http://localhost:8010/eureka/apps

.

其餘參見Eureka REST operations

用途

  • 獲取微服務註冊信息
  • 通過 xml 和 json 註冊(或註銷)非 jvm 微服務

自我保護模式

.

保護模式主要用於一組客戶端和Eureka Server之間存在網絡分區場景下的保護。一旦進入保護模式,Eureka Server將會嘗試保護其服務註冊表中的信息,不再刪除服務註冊表中的數據(也就是不會註銷任何微服務)。

默認情況下,如果Eureka Server在一定時間內沒有接收到某個微服務實例的心跳,Eureka Server將會註銷該實例(默認90秒)。但是當網絡分區故障發生時,微服務與Eureka Server之間無法正常通信,以上行爲可能變得非常危險了(因爲微服務本身其實是健康的,此時本不應該註銷這個微服務)。

Eureka通過“自我保護模式”來解決這個問題:當Eureka Server節點在短時間內丟失過多客戶端時(可能發生了網絡分區故障),那麼這個節點就會進入自我保護模式。一旦進入該模式,Eureka Server就會保護服務註冊表中的信息,不再刪除服務註冊表中的數據(也就是不會註銷任何微服務)。當網絡故障恢復後,該Eureka Server節點會自動退出自我保護模式。

綜上,自我保護模式是一種應對網絡異常的安全保護措施。它的架構哲學是寧可同時保留所有微服務(健康的微服務和不健康的微服務都會保留),也不盲目註銷任何健康的微服務。使用自我保護模式,可以讓Eureka集羣更加的健壯、穩定。

自我保護的條件:

一般情況下,微服務在Eureka上註冊後,會30秒定期發送心跳,Eureka 通過心跳來判斷微服務是否健康,同時會定期刪除超過90秒沒有發送心跳的服務。

有2種情況會導致Eureka Server收不到微服務的心跳,

  1. 是微服務自身原因所致,比如故障或關閉;

  2. 是微服務與eureka之間的網絡出現故障。

通常(微服務自身的故障關閉)只會導致個別服務出現故障,一般不會出現大面積的故障,而(網絡故障)通常會導致Eureka Server在短時間內無法收到大批心跳。

考慮到這個區別,Eureka設定了一個閥值,當判斷掛掉的服務的數量超過閥值時,Eureka Server認爲很大程度上出現了網絡故障,將不再刪除心跳過期的服務。

那這個閥值是多少呢?

Eureka Server在運行期間,會統計心跳失敗的比例在15分鐘之內是否低於85%。換句話就是:默認情況下啓用自我保留,啓用自我保留的默認閾值大於當前註冊表大小的15%。

關閉自我保護模式(生產上不建議)

server:
  port: 8010

eureka:
  client:
    register-with-eureka: false
    fetch-registry: false
    service-url:
      defaultZone: http://localhost:8010/eureka/
  # 關閉自我保護模式
  server:
    enable-self-preservation: false
spring:
  application:
    name: ms-discovery-eureka

健康檢查

引入 spring-boot-starter-actuator

 <!--狀態監控-->
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

開啓健康檢查

server:
  port: 8012

spring:
  application:
    name: ms-consumer-user-v2

eureka:
  client:
    # 健康檢查
    healthcheck:
      enabled: true
    service-url:
      defaultZone: http://localhost:8010/eureka/
  instance:
    prefer-ip-address: true

查詢狀態

.

在開啓健康檢查後,應用程序可以將自己的健康狀態傳播到 Eureka Server。

REFERENCES


獲取更多

掃碼關注架構探險之道,回覆"源碼",獲取本文相關源碼

架構探險之道

掃碼加入知識星球,獲取更多珍貴筆記、視頻、電子書的等資源。

知識星球


  1. 在 Spring Cloud Edgware 以及高版本中,只需要添加相關依賴即可。 ↩︎

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章