1.新建Module-註冊中心
作為註冊中心
1.1配置 pom.xml
<!-- 引入 eureka-server -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
1.2配置application.yml
server:
port: 9001
eureka:
instance:
hostname: localhost # Eureka 服務端的主機名
client:
register-with-eureka: false # 是否將自己註冊到 Eureka 服務端,表明自己是一個 Eureka 註冊中心,職責是維護服務例項,並不需要註冊自己
fetch-registry: false # 是否從 Eureka 服務端獲取註冊資訊
service-url:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ #設定與 eureka server 互動的模組,查詢服務和註冊服務都需要依賴這個地址
1.3新建啟動類
@SpringBootApplication
@EnableEurekaServer //開啟Eureka服務
public class EurekaApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaApplication.class, args);
}
}
1.4測試
瀏覽器訪問 http://localhost:9001/
2.服務提供者
配置服務提供者的Module資訊
2.1 服務提供者引入eureka-client依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
2.2 配置application.yml
eureka:
client:
register-with-eureka: true # 將自己註冊到 Eureka 服務端
fetch-registry: true # 是否從 Eureka 服務端獲取註冊資訊,預設為true,叢集必須為true,才能配合負載均衡
service-url:
defaultZone: http://localhost:9001/eureka/ #設定與 eureka server 互動的模組,查詢服務和註冊服務都需要依賴這個地址
2.3 設定啟動類
@SpringBootApplication
@EnableEurekaClient //開啟Eureka客戶端
public class MemberApplication {
public static void main(String[] args) {
SpringApplication.run(MemberApplication.class, args);
}
}
2.4 測試
啟動客戶端的啟動類後,訪問 localhost:9001
,會看到新註冊的例項
例項的名稱是怎麼確定的呢,這是在我們的application.yml自定義的
spring:
application:
name: member-service-provider #配置應用的名稱
3.服務消費者
配置服務消費者的Module資訊
3.1 引入依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
3.2 配置 application.yml
eureka:
client:
register-with-eureka: true # 將自己註冊到 Eureka 服務端
fetch-registry: true # 是否從 Eureka 服務端獲取註冊資訊,預設為true,叢集必須為true,才能配合負載均衡
service-url:
defaultZone: http://localhost:9001/eureka/ #表示關聯的eureka服務端地址,註冊/拉取服務資訊
3.3 配置啟動類
@SpringBootApplication
@EnableEurekaClient
public class MemberConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(MemberConsumerApplication.class, args);
}
}
3.4 測試
啟動,測試
4.Eureka自我保護模式
在以上測試中,我們會發現eureka頁面中有以下紅色提示:
- 預設情況下EurekaClient定時向EurekaServer端傳送心跳包
- 如果Eureka在server端在一定時間內(預設90秒)沒有收到EurekaClient傳送心跳包便會直接從服務註冊列表中剔除該服務
- 如果Eureka 開啟了自我保護模式/機制, 那麼在短時間(90秒中)內丟失了大量的服務例項心跳,這時候EurekaServer會開啟自我保護機制,不會剔除該服務(該現象可能出現在如果網路不通或者阻塞) 因為客戶端還能正常傳送心跳,只是網路延遲問題,而保護機制是為了解決此問題而產生的
- 可以在eureka-server端禁用自我保護模式,設定application.yml
server:
enable-self-preservation: false # 關閉自我保護機制
eviction-interval-timer-in-ms: 6000 # 設定心跳檢測的時間間隔,預設是60秒
- 設定eureka-client端 application.yml
eureka:
instance:
lease-expiration-duration-in-seconds: 5 # Eureka服務端在收到最後一次心跳後等待時間上限,單位為秒,預設90秒,超過這個時間服務端會將例項從註冊列表中剔除
lease-renewal-interval-in-seconds: 2 # eureka客戶端向服務端傳送心跳的時間間隔,單位為秒,預設30秒
5.搭建EurekaServer叢集
微服務RPC遠端服務呼叫最核心的是實現高可用,如果註冊中心只有1個,那麼一旦出現故障,導致整個服務環境都不可用,解決方案就是搭建Eureka註冊中心叢集,並且實現負載均衡和故障容錯。
5.1 新建Module-第二個註冊中心
配置過程如第一個註冊中心,區別是appication.yml的配置:
server:
port: 9002
eureka:
instance:
hostname: eureka9002.com # 區別於9001的註冊中心
client:
register-with-eureka: false
fetch-registry: false
service-url:
defaultZone: http://eureka9001:9001/eureka/ # 相互註冊
因為是相互註冊,所以把第一個註冊中心的hostname改成了eureka9001.com
:
server:
port: 9001
eureka:
instance:
hostname: eureka9001.com # Eureka 服務端的主機名
client:
register-with-eureka: false
fetch-registry: false
service-url:
defaultZone: http://eureka9002.com:9002/eureka/
5.2 設定系統hosts
C:\Windows\System32\drivers\etc\hosts
加入
#eureka 主機名和 ip 對映
127.0.0.1 eureka9001.com
127.0.0.1 eureka9002.com
5.3 測試
瀏覽器開啟對應的地址,會發現互相指向,按理說配置好hosts檔案後,我應該訪問eureka9001.com/9001
和 eureka9002.com/9002
,但是沒能成功,先用localhost:9001
和localhost:9002
進行測試
5.4 服務提供者註冊到Eureka叢集
註冊到多個eureka即可
啟動後,進行測試,也就是到localhost:9001
和localhost:9002
檢視註冊成功
5.5 服務消費者註冊到Eureaka叢集
註冊到多個eureka
6.搭建服務提供方叢集
Eureka已經搭建好叢集,實際中服務提供方也是會有多個形成一個叢集
6.1 新建一個新的服務提供方
複製貼上第一個服務提供方的程式碼,唯一要必須修改的地方是埠號,我們設定成10003,其中spring.application.name 必須統一,因為要作為一個叢集提供服務
進行測試:
7.服務消費者使用服務叢集
7.1 修改Controller
原先的Controller如下,具體來說,MEMBER_SERVICE_PROVIDER_URL被固定了:
@RestController
@Slf4j
public class MemberConsumerController {
public static final String MEMBER_SERVICE_PROVIDER_URL = "http://localhost:10002";
@Resource
private RestTemplate restTemplate;
@PostMapping("/member/consumer/save")
public Result<Member> save(Member member) {
return restTemplate.postForObject(MEMBER_SERVICE_PROVIDER_URL + "/member/save", member, Result.class);
}
@GetMapping("/member/consumer/get/{id}")
public Result<Member> get(@PathVariable("id") Long id) {
return restTemplate.getForObject(MEMBER_SERVICE_PROVIDER_URL + "/member/get/" + id, Result.class);
}
}
我們修改成服務提供者[叢集]的註冊別名:
修改後:
public static final String MEMBER_SERVICE_PROVIDER_URL = "http://MEMBER-SERVICE-PROVIDER";
因為我們現在的服務提供者是叢集,所以需要使用負載均衡,加上註解@LoadBalanced賦予RestTemplate負載均衡的能力, [即選擇 MEMBER-SERVICE-PROVIDER 某一個服務訪問]
@Configuration
public class CustomizationBean {
// 注入 RestTemplate
@Bean
@LoadBalanced
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
}
7.2 測試
啟動服務消費者,進行測試
再傳送一次
會發現當前負載均衡的策略是輪詢演算法
8.獲取Eureka Server服務註冊資訊
以服務消費者為例獲取eureka的服務註冊資訊
8.1 修改Controller
我們在cotroller加入程式碼
@Resource
private DiscoveryClient discoveryClient;
@GetMapping("/member/consumer/discovery")
public Object discovery() {
List<String> services = discoveryClient.getServices();
for (String element : services) {
System.out.println("======== 服 務 名 " + element +
"=======================");
List<ServiceInstance> instances = discoveryClient.getInstances(element);
for (ServiceInstance instance : instances) {
System.out.println(instance.getServiceId() + "\t" + instance.getHost() + "\t" + instance.getPort() + "\t" + instance.getUri());
}
}
return this.discoveryClient;
}
其中,DiscoverClient引入下面包的:
8.2 修改啟動類
新增@EnableDiscoveryClient註解
@SpringBootApplication
@EnableEurekaClient
@EnableDiscoveryClient
public class MemberConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(MemberConsumerApplication.class, args);
}
}
8.3 測試
啟動後,瀏覽器訪問http://localhost/member/consumer/discovery
瀏覽器返回:
{
"services": [
"member-service-consumer",
"member-service-provider"
],
"order": 0
}
後臺返回: