服務註冊與發現---Eureka


Eureka是美國Netflix公司出品的服務註冊與發現組件,Spring Cloud集成了該組件,然而時代發展,技術革新,Eureka已經停止更新了,但部分老的Spring Cloud的服務註冊與發現組件還是用的Eureka。
學學瞭解瞭解,也有裨益,畢竟思想沒有變化。

Eureka停更說明

1. Eureka系統架構

在這裏插入圖片描述
Eureka採用了CS的設計架構,Eureka Server 作爲服務的註冊功能的服務器,它是服務註冊中心。而系統的其他服務,使用Eureka的客戶端連接到Eureka Server 並維持心跳鏈接。這樣系統的維護人員可以通過Eureka Server來監控系統中各個微服務是否正常運行。
服務註冊與發現中,有一個註冊中心(Eureka Server)。當服務器啓動的時候,會把當前自己的服務器的信息,例如服務IP地址端口等以別名的方式註冊到註冊中心上(Eureka Server)。另一方服務以別名的方式去註冊中心上獲取到的實際通信地址(IP+Port),然後在實現本地的遠程調用,調用方式可以是Restful風格的接口(例如Spring boot 的 Controller)或者 RPC(例如Alibaba 的 Dubbo)。
核心設計思想是使用服務中心管理每個服務之間的依賴關係(服務治理概念),這樣可以在部署時方便的擴容或遷移服務,而不用去維護服務之間的依賴關係,說的直白一點就是,服務部署的IP和端口發生變化,註冊中心的數據同時發生變化(服務啓動的時候會向中心自動註冊),服務的消費者,可以從註冊中心通過約定的別名(一般是服務名)獲取變更後服務的IP和端口,然後去調用這個服務。

Eureka包含兩個組件:
Eureka Server提供服務來註冊服務
各個微服務節點通過配置啓動後,會在Eureka Server中進行註冊,這樣EurekaServer中的服務註冊表中將會存儲所有的可用節點的信息,服務節點的信息可以在界面中直觀看到。

Eureka Client通過註冊中心進行訪問
是一個java客戶端,用於簡化Eureka Server的交互,客戶端同時也具備一個內置的、使用輪詢(round-robin)負載算法的負載均衡器。在應用啓動後,將會向Eureka Server發送心跳(默認週期30秒)。如果Eureka Server在多個心跳週期沒有接收到某個節點的心跳,Eureka Server將會從服務註冊表中把這個服務節點移除(默認90秒)

2. Eureka編碼舉例

2.1 先創建Eureka Server

創建一個Spring boot應用,導入一下依賴

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

application.yml:

server:
  port: 7001

# eureka 配置
eureka:
  instance:
    # eureka 的服務器實例名稱
    hostname: localhost
  client:
    # false 表示不向註冊中心註冊自己
    register-with-eureka: false
    # false 表示本服務就是註冊中心,本服務的職責就是維護服務實例,並不需要去檢索服務
    fetch-registry: false
    service-url:
      # 設置於Eureka  Server交互的地址,註冊服務和查詢服務都需要依賴這個地址
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

在主類上加@EnableEurekaServer

@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaServerApplication.class, args);
    }
}

啓動服務,訪問localhost:7001
在這裏插入圖片描述

2.2 編寫一個Provider

pom中添加如下依賴:

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

配置application.yml

server:
  port: 8001

spring:
  application:
    name: cloud-payment-service
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: org.gjt.mm.mysql.Driver
    url: jdbc:mysql://localhost:3306/db2020?useUnicode=true&characterEncoding=utf-8&useSSL=false
    username: root
    password: 123
  http:
    encoding:
      charset: UTF-8
      force: true

# eureka client配置
eureka:
  client:
    # 表示是否將自己註冊進 EurekaServer, 默認true
    register-with-eureka: true
    # 是否從Eureka Server抓取自己的註冊信息,默認true。單節點無所謂,集羣必須設置爲true才能配合ribbon使用負載均衡
    fetch-registry: true
    service-url:
      # 註冊中心地址
      defaultZone: http://localhost:7001/eureka

mybatis:
  mapper-locations: classpath:mapper/*.xml
  # 所有Entity別名類所在包
  type-aliases-package: com.yp.entity

在主類上添加@EnableEurekaClient

@SpringBootApplication
@EnableEurekaClient
public class PaymentApplication {
    public static void main(String[] args) {
        SpringApplication.run(PaymentApplication.class, args);
    }
}

啓動服務,訪問localhost:7001
在這裏插入圖片描述
會發現有一個服務cloud-payment-service(大寫)已經註冊上來了

2.2 編寫一個Consumer

pom中添加如下依賴:

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

配置application.yml

server:
  port: 80

spring:
  application:
    name: cloud-order-service
  http:
    encoding:
      charset: UTF-8
      force: true

eureka:
  client:
    # 表示是否將自己註冊進 EurekaServer, 默認true
    register-with-eureka: true
    # 是否從Eureka Server抓取自己的註冊信息,默認true。單節點無所謂,集羣必須設置爲true才能配合ribbon使用負載均衡
    fetch-registry: true
    service-url:
      # 註冊中心地址
      defaultZone: http://localhost:7001/eureka

在主類上添加@EnableEurekaClient

@SpringBootApplication
@EnableEurekaClient
public class OrderApplication {
    public static void main(String[] args) {
        SpringApplication.run(OrderApplication.class, args);
    }
}

啓動服務,訪問localhost:7001
在這裏插入圖片描述

2.3 測試Consumer訪問Provider

2.31 Consumer編寫

在Consumer中寫一個RestTemplete配置,主要是實現負載均衡,和Restful接口訪問

@Configuration
public class ApplicationContextConfig {
    @Bean
    @LoadBalanced
    public RestTemplate getRestTemplate() {
        return new RestTemplate();
    }
}

Consumer寫Controller

@RestController
@Slf4j
public class OrderController {
    // 直接訪問地址
    private static final String PAYMENT_URL = "http://localhost:8001";

    // eureka上註冊的微服務
    private static final String SERVICE_NAME = "http://CLOUD-PAYMENT-SERVICE";

    @Autowired
    private RestTemplate restTemplate;

    @GetMapping("consumer/payment/get/{id}")
    public CommonResult<Payment> getPayment(@PathVariable("id") Long id) {
        return restTemplate.getForObject(SERVICE_NAME + "/payment/" + id, CommonResult.class);
    }
}

2.3.2 編寫Provider

在Provider中寫一個Controller,爲了簡化,後續service、dao不再列出

@RestController
@Slf4j
public class PaymentController {
	// 僅僅是爲了驗證負載均衡,因爲本地驗證只能由端口區分
    @Value("${server.port}")
    private int servicePort;

    @Autowired
    private PaymentService paymentService;

    @GetMapping("/payment/{id}")
    public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id) {
        Payment payment = paymentService.getPaymentById(id);

        if (payment != null) {
            return new CommonResult<>(200, "獲取數據成功! servicePort: " + servicePort, payment);
        } else {
            return new CommonResult<>(500, "獲取數據失敗! servicePort: " + servicePort, null);
        }
    }
}

2.3.3 運行測試

在這裏插入圖片描述

3. Eureka集羣

目的是提高容錯,原理就是互相註冊

3.1 配置hosts

因爲本地實驗,要區分多個Eureka Server,同一IP映射多個域名

127.0.0.1	eureka7001.com
127.0.0.1	eureka7002.com

3.2 創建Eureka Server的application.yml

創建application7001.yml

server:
  port: 7001

# eureka 配置
eureka:
  instance:
    # eureka 的服務器實例名稱
    hostname: eureka7001.com
  client:
    # false 表示不向註冊中心註冊自己
    register-with-eureka: false
    # false 表示本服務就是註冊中心,本服務的職責就是維護服務實例,並不需要去檢索服務
    fetch-registry: false
    service-url:
      # 設置於Eureka  Server交互的地址,註冊服務和查詢服務都需要依賴這個地址
      defaultZone: http://eureka7002.com:7002/eureka

創建application7002.yml

server:
  port: 7002

# eureka 配置
eureka:
  instance:
    # eureka 的服務器實例名稱
    hostname: eureka7002.com
  client:
    # false 表示不向註冊中心註冊自己
    register-with-eureka: false
    # false 表示本服務就是註冊中心,本服務的職責就是維護服務實例,並不需要去檢索服務
    fetch-registry: false
    service-url:
      # 設置於Eureka  Server交互的地址,註冊服務和查詢服務都需要依賴這個地址
      defaultZone: http://eureka7001.com:7001/eureka

3.3 打Eureka Server的jar包

在pom中加入plugin

	<build>
        <finalName>eureka-server</finalName>
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <filtering>true</filtering>
                <includes>
                    <include>**/*.xml</include>
                </includes>
            </resource>
            <resource>
                <directory>src/main/resources</directory>
                <includes>
                    <include>**.*</include>
                    <include>**/*.*</include><!-- i18n能讀取到 -->
                    <include>**/*/*.*</include>
                </includes>
            </resource>
        </resources>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>

                <configuration>
                    <fork>true</fork> <!-- 如果沒有該配置,devtools不會生效 -->
                    <!-- 指定該Main Class爲全局的唯一入口 -->
                    <mainClass>com.yp.EurekaServerApplication</mainClass>
                    <layout>ZIP</layout>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal><!--可以把依賴的包都打包到生成的Jar包中-->
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

3.4 運行 eureka-server.jar

在兩個cmd窗口獨立運行

java -jar eureka-server.jar --spring.config.location=D:\spring-cloud-demo\application7001.yml
java -jar eureka-server.jar --spring.config.location=D:\spring-cloud-demo\application7002.yml

在這裏插入圖片描述

3.5 修改Provider和Consumer的配置

ProviderConsumer的application.yml defaultZone作同樣的修改
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka

eureka:
  client:
    # 表示是否將自己註冊進 EurekaServer, 默認true
    register-with-eureka: true
    # 是否從Eureka Server抓取自己的註冊信息,默認true。單節點無所謂,集羣必須設置爲true才能配合ribbon使用負載均衡
    fetch-registry: true
    service-url:
      # 註冊中心地址
      defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka

3.5 測試結果:

在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

4. Provider集羣驗證

啓動兩個cloud-payment-service進程,一個端口8001,另一個8002,打包與Eureka Server一樣

java -jar payment-server.jar --spring.config.location=.\application8001.yml
java -jar payment-server.jar --spring.config.location=.\application8002.yml

在這裏插入圖片描述
在這裏插入圖片描述
端口輪詢:
在這裏插入圖片描述
在這裏插入圖片描述

5. Eureka Server註冊信息優化

instance:
# 主機名
instance-id: payment_8001
# 訪問路徑顯示IP
prefer-ip-address: true

eureka:
  client:
    # 表示是否將自己註冊進 EurekaServer, 默認true
    register-with-eureka: true
    # 是否從Eureka Server抓取自己的註冊信息,默認true。單節點無所謂,集羣必須設置爲true才能配合ribbon使用負載均衡
    fetch-registry: true
    service-url:
      # 註冊中心地址
      defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
  instance:
    # 主機名
    instance-id: payment_8001
    # 訪問路徑顯示IP
    prefer-ip-address: true

在這裏插入圖片描述

6. Eureka Server註冊表微服務信息

寫一個Controller用於相應註冊中心註冊表服務實例

@RestController
@RequestMapping("/consumer")
@Slf4j
public class ServiceInstancesController {
    @Autowired
    private DiscoveryClient discoveryClient;
    
    @GetMapping("/payment/serviceInstances")
    public List<ServiceVo> discovery() {
        List<ServiceVo> serviceVoList = new ArrayList<>();
        List<String> services = discoveryClient.getServices();
        for (String serviceName : services) {
            ServiceVo serviceVo = new ServiceVo();
            List<ServiceInstanceVo> instanceVoList = new ArrayList<>();
            serviceVo.setServiceName(serviceName);

            List<ServiceInstance> instances = discoveryClient.getInstances(serviceName);
            for (ServiceInstance serviceInstance : instances) {
                ServiceInstanceVo instanceVo = new ServiceInstanceVo();
                instanceVo.setServiceId(serviceInstance.getServiceId());
                instanceVo.setHost(serviceInstance.getHost());
                instanceVo.setPort(serviceInstance.getPort());
                instanceVo.setUri(serviceInstance.getUri().toString());
                instanceVoList.add(instanceVo);
            }
            serviceVo.setInstances(instanceVoList);
            serviceVoList.add(serviceVo);
        }

        return serviceVoList;
    }
}

在主類上加 @EnableDiscoveryClient

請求:
http://localhost/consumer/payment/serviceInstances
在這裏插入圖片描述
格式化:

[
    {
        "serviceName":"cloud-payment-service",
        "instances":[
            {
                "host":"192.168.110.1",
                "port":8001,
                "uri":"http://192.168.110.1:8001",
                "serviceId":"CLOUD-PAYMENT-SERVICE"
            },
            {
                "host":"192.168.110.1",
                "port":8002,
                "uri":"http://192.168.110.1:8002",
                "serviceId":"CLOUD-PAYMENT-SERVICE"
            }
        ]
    },
    {
        "serviceName":"cloud-order-service",
        "instances":[
            {
                "host":"192.168.110.1",
                "port":80,
                "uri":"http://192.168.110.1:80",
                "serviceId":"CLOUD-ORDER-SERVICE"
            }
        ]
    }
]

7. Eureka的自我保護

某時刻某一服務不可用了,Eureka不會立刻清理,依舊會對該微服務的信息進行保存,提高系統可用性,這主要是考慮網絡阻塞,擁堵對健康檢查的影響。
在這裏插入圖片描述
Eureka Service配置
server:
# 關閉自我保護
enable-self-preservation: false
# 時間間隔,單位毫秒
eviction-interval-timer-in-ms: 3000

server:
  port: 7001

# eureka 配置
eureka:
  instance:
    # eureka 的服務器實例名稱
    hostname: eureka7001.com
  client:
    # false 表示不向註冊中心註冊自己
    register-with-eureka: false
    # false 表示本服務就是註冊中心,本服務的職責就是維護服務實例,並不需要去檢索服務
    fetch-registry: false
    service-url:
      # 設置於Eureka  Server交互的地址,註冊服務和查詢服務都需要依賴這個地址
      defaultZone: http://eureka7002.com:7002/eureka
  server:
    # 關閉自我保護
    enable-self-preservation: false
    # 時間間隔,單位毫秒
    eviction-interval-timer-in-ms: 3000

註冊的服務配置
lease-renewal-interval-in-seconds: 2
# Eureka服務端在接收最後一次心跳等待時間上限,單位秒(默認90秒),超時將剔除服務
lease-expiration-duration-in-seconds: 3

eureka:
  client:
    # 表示是否將自己註冊進 EurekaServer, 默認true
    register-with-eureka: true
    # 是否從Eureka Server抓取自己的註冊信息,默認true。單節點無所謂,集羣必須設置爲true才能配合ribbon使用負載均衡
    fetch-registry: true
    service-url:
      # 註冊中心地址
      defaultZone: http://eureka7001.com:7001/eureka
  instance:
    # 主機名
    instance-id: payment_8001
    # 訪問路徑顯示IP
    prefer-ip-address: true
    # Eureka客戶端向服務端發送心跳的時間間隔,單位秒(默認30秒)
    lease-renewal-interval-in-seconds: 2
    # Eureka服務端在接收最後一次心跳等待時間上限,單位秒(默認90秒),超時將剔除服務
    lease-expiration-duration-in-seconds: 3

測試:
在這裏插入圖片描述

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