注冊中心
由於微服務多為集群部署,在這種情況下,微服務之間要調用彼此的接口,如果使用url或者ip地址的形式調用會帶來很多麻煩,例如無法確定要連的主機是否可用。在這種情形下,便需要一個系統對所有的微服務進行統一的管理,實時的確定各個微服務所部署的主機的可用狀態,這個系統就是注冊中心。
注冊中心主要的作用就是統一管理各個微服務,微服務向注冊中心注冊自己的信息,然后定時的和注冊中心通信,以便注冊中心區分可用和不可用的主機;而要調用服務的程序則向注冊中心申請相應服務,注冊中心返回給程序請求服務可用的主機ip以及端口號,這樣實現服務的調用,常用的注冊中心有eureka,zookeeper等,這里介紹了eureka的使用。
eureka是springcloud下的一個注冊中心,通過它可以實現微服務的統一管理;
eureka的部署:
首先父工程的pom文件:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <!--springboot依賴,微服務工程使用springboot構建--> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.1.RELEASE</version> </parent> <groupId>cn.ly</groupId> <artifactId>ly_cloud_test</artifactId> <packaging>pom</packaging> <version>1.0-SNAPSHOT</version> <modules> <module>ly_eureka</module> <module>ly_feignribbon_test_server01</module> <module>ly_fergnribbon_test_server02</module> </modules> <properties> <okhttp.version>3.9.1</okhttp.version> <feign-okhttp.version>8.18.0</feign-okhttp.version> </properties> <!--依賴管理,對子工程進行相應的依賴版本管理--> <dependencyManagement> <dependencies> <!--springcloud依賴--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Finchley.SR1</version> <type>pom</type> <scope>import</scope> </dependency> <!--遠程調用--> <dependency> <groupId>com.squareup.okhttp3</groupId> <artifactId>okhttp</artifactId> <version>${okhttp.version}</version> </dependency> <dependency> <groupId>com.squareup.okhttp3</groupId> <artifactId>okhttp</artifactId> <version>${okhttp.version}</version> </dependency> <dependency> <groupId>com.netflix.feign</groupId> <artifactId>feign-okhttp</artifactId> <version>${feign-okhttp.version}</version> </dependency> </dependencies> </dependencyManagement> </project>
然后建立eureka子工程ly_eureka,
引入依賴:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency>
配置文件application.yml:
server:
port: ${PORT:50101} #端口號
spring:
application:
name: ly-govern-center #服務名
eureka:
client:
register-with-eureka: false #是否向注冊中心注冊服務
fetch-registry: false #是否向注冊中心發現服務
serviceUrl:
defaultZone: http://localhost:50101/eureka/ #注冊中心地址,配置多服務器注冊中心時需要將多個ip用‘,’分隔
server:
enable-self-preservation: false #自我保護設置,當微服務不再報告狀態時,也不會立即將其刪除,在開發階段建議設置false
eviction-interval-timer-in-ms: 60000 #服務注冊表清理間隔
instance:
hostname: ${EUREKA_DOMAIN:eureka01}
springboot的主函數:
package cn.ly; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; @SpringBootApplication @EnableEurekaServer // 聲明這是一個eureka的服務器 public class GovernCenterApplication { public static void main(String[] args) { SpringApplication.run(GovernCenterApplication.class, args); } }
直接啟動即可完成eureka注冊中心的部署,啟動后,在瀏覽器中輸入:localhost:50101看到eureka頁面即表明部署成功;
作為一個服務,其本身也是可以集群部署的,只要在配置文件defaultzone中將所有的要部署的ip寫上去就行了,中間用逗號隔開;
向eureka中注冊服務
服務使用springboot來搭建,創建子工程server01,引入依賴:
<!--向eureka注冊服務依賴--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency>
在主函數上添加注解:
@EnableDiscoveryClient //表明該工程是eureka的客戶端,會向eureka注冊服務並從中發現服務
提供一個簡單的controller:
package cn.ly.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; @Controller public class HelloController { int i = 0; @ResponseBody @RequestMapping("/hello") public String hello() { i++; System.out.println("被調用..."+i); return "hello"; } }
配置文件application.yml
server:
port: ${PORT:31001}
spring:
application:
name: ly-server01 #服務名,在下面的配置中作為實例名注冊到eureka中,其他程序調用服務時需要向eureka提供要調用的實例名,即這個名稱
eureka:
client:
fetch-registry: true #發現服務
register-with-eureka: true #注冊服務
service-url:
defaultZone: ${EUREKA_server:http://localhost:50101/eureka/} #eureka的地址
instance:
prefer-ip-address: true #將自己的IP注冊到eureka
ip-address: ${IP_ADDRESS:127.0.0.1} #注冊的ip地址
instance-id: ${spring.application.name}:${server.port} #注冊的實例名稱
啟動該服務,再次訪問localhost:50101,即可看到:
如此,服務便注冊成功了。
通過ribbon調用服務
ribbon是一個通過客戶端實現負載均衡的系統,它通過服務名向eureka請求可用的服務url,然后通過負載均衡的算法選擇一個可用的服務主機進行訪問,獲得結果;
建立另一個微服務子工程server02,和上述服務一樣,需要做成eureka客戶端,除此之外,還需要引入額外的依賴:
<dependency> <groupId>com.squareup.okhttp3</groupId> <artifactId>okhttp</artifactId>
</dependency>
另外,需要配置bean:
@Bean @LoadBalanced // 這個注解是實現負載均衡的,如果不寫的話,就只能直接通過url訪問其他服務 public RestTemplate restTemplate() { return new RestTemplate(new OkHttp3ClientHttpRequestFactory()); }
配置文件同上面的一致;
另外將上server01工程開上兩份,開啟時通過設置jvm的參數-DPORT 來設置不同的端口,否則端口會沖突;
通過restTemplate調用hello接口:
@Autowired RestTemplate restTemplate; @Test public void run() { for (int i = 0; i < 10; i++) {
// 直接通過服務名調用接口 ResponseEntity<String> forEntity = restTemplate.getForEntity("http://ly-server01/hello", String.class); String body = forEntity.getBody(); System.out.println(body); } }
上面調用了hello接口10次,對應於服務端,兩個注冊服務的服務分別被調用5次,這是因為默認的負載均衡的方式是輪詢,也就是依次調用可用的主機;
通過feign調用
feign客戶端調用遠程http接口,可以實現向調用本地接口方法那樣調用遠程服務,依舊是server02工程調用server01工程的服務;
在server02中添加依賴:
<!--feign調用--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> <dependency> <groupId>com.netflix.feign</groupId> <artifactId>feign-okhttp</artifactId> </dependency>
在主函數上添加注解:@EnableFeignClients
在該工程下創建一個feign接口如下:
package cn.ly.client; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.RequestMapping; @FeignClient("ly-server01") // feign客戶端注解,value是要調用的服務名,就是server01工程的服務名 public interface HelloClient {
// 注意一點,如果方法返回的是一個復雜對象類型,那么這個對象類型必須有無參構造器,否則會報錯 @RequestMapping("/hello") public String hello();// 這個方法和要調用的服務的接口方法書寫要一致,上面的url注意要書寫正確且完整,如果被調用的接口的controller類上也有url,那么在這里需要將其補全 }
然后在測試方法中將這個接口注入進去后,即可直接使用方法:
@Autowired HelloClient helloClient; @Test public void run2() { for (int i = 0; i < 10; i++) { String hello = helloClient.hello(); System.out.println(hello); } }
上面依舊是調用了10次,分別在兩個開啟的server01工程中執行5次,輪詢的負載均衡;