1. 程式人生 > >筆記76 微服務筆記3

筆記76 微服務筆記3

static line enabled exc temp 角色 interrupt com 更新數據

SpringCloud基礎概念(一)

一、SpringCloud的幾大組件

  • Eureka:註冊中心
  • Zuul:網關服務
  • Ribbon:負載均衡
  • Feign:服務調用
  • Hystix:熔斷器

技術分享圖片

二、微服務場景模擬

1.服務提供者(user-service-demo)

<1>依賴

<2>application.yml

<3>實體類pojo

<4>mapper

<5>service

<6>controller

2.服務調用者(consumer-demo)

<1>依賴,剔除mybatis相關數據庫依賴。

<2>首先在啟動器中註冊RestTemplate用來發送http請求。

1   @Bean
2     public RestTemplate restTemplate() {
3         // 這次我們使用了OkHttp客戶端,只需要註入工廠即可
4         return new RestTemplate(new OkHttp3ClientHttpRequestFactory());
5     }

<3>編寫DAO,註意,這裏不調用mapper查詢數據庫了,直接通過RestTemplate遠程查詢user-service-demo中的接口。

<4>編寫service,使用DAO請求數據。

<5>編寫controller。

3.存在的問題

    • 在consumer中,我們把url地址硬編碼到了代碼中,不方便後期維護

    • consumer需要記憶user-service的地址,如果出現變更,可能得不到通知,地址將失效

    • consumer不清楚user-service的狀態,服務宕機也不知道

    • user-service只有1臺服務,不具備高可用性

    • 即便user-service形成集群,consumer還需自己實現負載均衡

三、Eureka註冊中心

1.原理圖

技術分享圖片

    • Eureka:就是服務註冊中心(可以是一個集群),對外暴露自己的地址

    • 提供者:啟動後向Eureka註冊自己信息(地址,提供什麽服務)

    • 消費者:向Eureka訂閱服務,Eureka會將對應服務的所有提供者地址列表發送給消費者,並且定期更新

    • 心跳(續約):提供者定期通過http方式向Eureka刷新自己的狀態

2.基礎架構

Eureka架構中的三個核心角色:

    • 服務註冊中心

      Eureka的服務端應用,提供服務註冊和發現功能,就是剛剛我們建立的eureka-demo

    • 服務提供者

      提供服務的應用,可以是SpringBoot應用,也可以是其它任意技術實現,只要對外提供的是Rest風格服務即可。本例中就是我們實現的user-service-demo

    • 服務消費者

      消費應用從註冊中心獲取服務列表,從而得知每個服務方的信息,知道去哪裏調用服務方。本例中就是我們實現的consumer-demo

3.編寫EurekaServer

<1>編寫啟動類

1 @SpringBootApplication
2 @EnableEurekaServer // 聲明這個應用是一個EurekaServer
3 public class EurekaDemoApplication {
4 
5     public static void main(String[] args) {
6         SpringApplication.run(EurekaDemoApplication.class, args);
7     }
8 }

<2>編寫配置

 1 server:
 2   port: 10086 # 端口
 3 spring:
 4   application:
 5     name: eureka-server # 應用名稱,會在Eureka中顯示
 6 eureka:
 7   client:
 8     register-with-eureka: false # 是否註冊自己的信息到EurekaServer,默認是true
 9     fetch-registry: false # 是否拉取其它服務的信息,默認是true
10     service-url: # EurekaServer的地址,現在是自己的地址,如果是集群,需要加上其它Server的地址。
11       defaultZone: http://127.0.0.1:${server.port}/eureka
12   server:
13     eviction-interval-timer-in-ms: 5000 #每隔5秒剔除一次失效的服務
14     enable-self-preservation: false #關閉自我保護

4.將user-service註冊到Eureka

<1>添加SpringCloud依賴

<2>然後再添加Eureak客戶端依賴

<3>通過添加@EnableDiscoveryClient來開啟Eureka客戶端功能

<4>配置信息

 1 server:
 2   port: 8086
 3 mybatis:
 4   type-aliases-package: com.liyuanjun.demo.userservicedemo.pojo
 5 spring:
 6   datasource:
 7     url: jdbc:mysql://127.0.0.1:3306/sh?characterEncoding=UTF-8&useSSL=false
 8     username: root
 9     password: 123456
10     hikari:
11       maximum-pool-size: 20
12       minimum-idle: 10
13   application:
14     name: user-service  #服務名字
15 
16 eureka:
17   client:
18     service-url:
19       defaultZone: http://127.0.0.1:10086/eureka,http://127.0.0.1:10086/eureka
20   instance:
21     lease-expiration-duration-in-seconds: 10 # 10秒即過期
22     lease-renewal-interval-in-seconds: 5 # 5秒一次心跳
23     instance-id: ${spring.application.name}:${server.port}

4.消費者從Eureka獲取服務

<1>添加SpringCloud依賴

<2>添加Eureka客戶端

<3>在啟動類中開啟Eureka客戶端

<4>修改配置

 1 server:
 2   port: 8080
 3 spring:
 4   application:
 5     name: consumer # 應用名稱
 6 eureka:
 7   client:
 8     service-url: # EurekaServer地址
 9       defaultZone: http://127.0.0.1:10086/eureka
10   instance:
11     prefer-ip-address: true # 當其它服務獲取地址時提供ip而不是hostname
12     ip-address: 127.0.0.1 # 指定自己的ip信息,不指定的話會自己尋找

<5>修改DAO,用DiscoveryClient類的方法,根據服務名稱,獲取服務實例:

 1  @Autowired
 2     private RestTemplate restTemplate;
 3 
 4     @Autowired
 5     private DiscoveryClient discoveryClient;// Eureka客戶端,可以獲取到服務實例信息
 6 
 7     public List<User> queryUserByIds(List<Long> ids) {
 8         List<User> users = new ArrayList<>();
 9         // String baseUrl = "http://localhost:8081/user/";
10         // 根據服務名稱,獲取服務實例
11         List<ServiceInstance> instances = discoveryClient.getInstances("user-service");
12         // 因為只有一個UserService,因此我們直接get(0)獲取
13         ServiceInstance instance = instances.get(0);
14         // 獲取ip和端口信息
15         String baseUrl = "http://"+instance.getHost() + ":" + instance.getPort()+"/user/";
16         ids.forEach(id -> {
17             // 我們測試多次查詢,
18             users.add(this.restTemplate.getForObject(baseUrl + id, User.class));
19             // 每次間隔500毫秒
20             try {
21                 Thread.sleep(500);
22             } catch (InterruptedException e) {
23                 e.printStackTrace();
24             }
25         });
26         return users;
27     }

5.高可用的Eureka Server——集群

  多個Eureka Server之間也會互相註冊為服務,當服務提供者註冊到Eureka Server集群中的某個節點時,該節點會把服務的信息同步給集群中的每個節點,從而實現數據同步。因此,無論客戶端訪問到Eureka Server集群中的任意一個節點,都可以獲取到完整的服務列表信息。

6.服務提供者

  服務提供者要向EurekaServer註冊服務,並且完成服務續約等工作。

<1>服務註冊

  服務提供者在啟動時,會檢測配置屬性中的:eureka.client.register-with-erueka=true參數是否正確,事實上默認就是true。如果值確實為true,則會向EurekaServer發起一個Rest請求,並攜帶自己的元數據信息,Eureka Server會把這些信息保存到一個雙層Map結構中。第一層Map的Key就是服務名稱,第二層Map的key是服務的實例id。

<2>服務續約

  在註冊服務完成以後,服務提供者會維持一個心跳(定時向EurekaServer發起Rest請求),告訴EurekaServer:“我還活著”。這個我們稱為服務的續約(renew)。

有兩個重要參數可以修改服務續約的行為:

1 eureka:
2   instance:
3     lease-expiration-duration-in-seconds: 90
4     lease-renewal-interval-in-seconds: 30
      • lease-renewal-interval-in-seconds:服務續約(renew)的間隔,默認為30秒

      • lease-expiration-duration-in-seconds:服務失效時間,默認值90秒

  也就是說,默認情況下每個30秒服務會向註冊中心發送一次心跳,證明自己還活著。如果超過90秒沒有發送心跳,EurekaServer就會認為該服務宕機,會從服務列表中移除,可以根據實際情況進行調整。

7.服務消費者

<1>獲取服務列表

當服務消費者啟動是,會檢測eureka.client.fetch-registry=true參數的值,如果為true,則會從Eureka Server服務的列表只讀備份,然後緩存在本地。並且每隔30秒會重新獲取並更新數據。我們可以通過下面的參數來修改:

1 eureka:
2   client:
3     registry-fetch-interval-seconds: 5

8.失效剔除和自我保護

<1>失效剔除

  有些時候,我們的服務提供方並不一定會正常下線,可能因為內存溢出、網絡故障等原因導致服務無法正常工作。Eureka Server需要將這樣的服務剔除出服務列表。因此它會開啟一個定時任務,每隔60秒對所有失效的服務(超過90秒未響應)進行剔除。可以通過eureka.server.eviction-interval-timer-in-ms參數對其進行修改,單位是毫秒。

<2>自我保護

  關停一個服務,就會在Eureka面板看到一條警告:

  技術分享圖片

  這是觸發了Eureka的自我保護機制。當一個服務未按時進行心跳續約時,Eureka會統計最近15分鐘心跳失敗的服務實例的比例是否超過了85%。在生產環境下,因為網絡延遲等原因,心跳失敗實例的比例很有可能超標,但是此時就把服務剔除列表並不妥當,因為服務可能沒有宕機。Eureka就會把當前實例的註冊信息保護起來,不予剔除。生產環境下這很有效,保證了大多數服務依然可用。

  但是這給我們的開發帶來了麻煩, 因此開發階段我們都會關閉自我保護模式:

1 eureka:
2   server:
3     enable-self-preservation: false # 關閉自我保護模式(缺省為打開)
4     eviction-interval-timer-in-ms: 1000 # 掃描失效服務的間隔時間(缺省為60*1000ms)

筆記76 微服務筆記3