SpringCloud微服務部署
編輯推薦: |
本文來自於csdn,本文詳細介紹了SpringCloud的部署,主要從元件配置搭建,希望對您的學習有幫助。 |
微服務的其中一個特點就是有許許多的粒度小(功能單一,比如使用者管理,簡訊傳送管理,郵件傳送管理,檔案管理等)、能獨立部署、擴充套件、執行的小應用,可以稱為api,也就是服務提供者。api之間可以相互呼叫,但更多的是供app呼叫,比如學生管理系統,它是面向使用者的,是許許多多功能的集合體,它需要呼叫許多api完成業務功能,所以這學生管理系統可以稱為app。
eureka的作用
傳統的單體應用開發,就是將api和app的程式碼全部整合在一起,在同一個程序中執行,對應java web通俗的說就是全部打包在一個war中部署在一個tomcat中執行。而微服務的每個api,app都擁有自己的程序,也就是都有自己的tomcat,某個api掛了,不影響其他api和app執行。
api是採取restfull風格暴漏出去的,所以app(api)呼叫api時,採取http://ip:埠這形式進行通訊。那麼問題來了,如果有很多app都呼叫了某個api,如果api的ip或埠發生了更改,如果app中對api的ip和埠等資訊是寫在配置檔案的,難道要通知每個app,說這個api的地址和埠變了,app要進行修改重新編譯部署(這是舉例子而已,實際情況有些企業對常量的配置可能寫配置檔案,也可能寫資料庫)。這太麻煩了,如果api的地址和埠有發生變化,app能及時獲知自行變更,那就好了。還有個弊端,就是api是否掛了,也沒法直觀觀察到。
所以,如果在app和api之間增加個服務管理中心,api像服務管理中心註冊資訊,app從服務管理中心獲取api的資訊,api有個唯一標識,api有變更的時候通知服務管理中心,服務管理中心通知相關的app或者app定時從服務管理中心獲取最新的api資訊,同時服務管理中心具有很高的穩定性、可靠性。
eureka就是為了這樣的一個服務管理中心,下面是我根據自己的理解畫的一張圖。
下面這張是官方的架構圖
1.Application Service 相當於服務提供者/api
2.Application Client 相當於服務消費者/app
3.Make Remote Call,其實就是實現服務的使用/比如httpClient,restTemplate
4.us-east-1 Eureka 叢集服務
5.us-east-1c、us-east-1d、us-east-1e 就是具體的某個eureka
Eureka:
1. 是純正的 servlet 應用,需構建成war包部署
2. 使用了 Jersey 框架實現自身的 RESTful HTTP介面
3. peer之間的同步與服務的註冊全部通過 HTTP 協議實現
4. 定時任務(傳送心跳、定時清理過期服務、節點同步等)通過 JDK 自帶的 Timer 實現
5. 記憶體快取使用Google的guava包實現
eureka叢集搭建
和eureka類似功能的有zookeeper,etcd等。spring boot已經集成了eureka,所以我們可以像spring boot那樣搭建環境,部署執行。
我是在window10下使用eclipse學習的。
準備工作。
在修改hosts檔案,在最後面加上(位置:C:\Windows\System32\drivers\etc)
127.0.0.1 01.eureka.server
127.0.0.1 02.eureka.server
127.0.0.1 03.eureka.server
eclipse下建立個普通的maven專案eureka-server。
pom.xml
<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>
<groupId>com.fei.springcloud</groupId>
<artifactId>springcloud-eureka-server</artifactId>
<version>0.0.1-SNAPSHOT</version>
<description>eureka服務端</description>
<!-- 依賴倉庫 設定從aliyun倉庫下載 -->
<repositories>
<repository>
<id>alimaven</id>
<url>http://maven.aliyun.com/nexus/content/repositories/central/</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
<releases>
<enabled>true</enabled>
</releases>
</repository>
</repositories>
<!-- 外掛依賴倉庫 -->
<pluginRepositories>
<pluginRepository>
<id>alimaven</id>
<url>http://maven.aliyun.com/nexus/content/repositories/central/</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
<releases>
<enabled>true</enabled>
</releases>
</pluginRepository>
</pluginRepositories>
<properties>
<!-- 檔案拷貝時的編碼 -->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<!-- 編譯時的編碼 -->
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
<java.version>1.8</java.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.2.RELEASE</version>
<relativePath />
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Dalston.RELEASE</version>
<type>pom</type>
<scope>import</scope><!-- 這個不能丟 -->
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
啟動類Application.java
package com.fei.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@EnableEurekaServer
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
注意註解:@EnableEurekaServer,表明這是server服務
配置檔案application.properties
logging.config=classpath:logback.xml
logging.path=d:/logs
##tomcat set###
# eureka的預設埠是8761
server.port=8081
server.session-timeout=60
###########
spring.application.name=eureka-server-01
####下面2個一定要false,因為這程式是要作為服務端
但是jar中存在eureka-client.jar,所以要false,否則啟動會報錯的
#是否註冊到eureka
eureka.client.register-with-eureka=false
#是否獲取註冊資訊
eureka.client.fetch-registry=false
#為了便於測試,取消eureka的保護模式,如果啟動的話,
比如api提供者關閉了,但是eureka仍然保留資訊
eureka.server.enable-self-preservation=false
#服務名稱
eureka.instance.hostname=01.server.eureka
#eureka的服務地址,/eureka是固定的
eureka.client.serviceUrl.defaultZone=http://02.
server.eureka:8082/eureka/,http://03.server.eureka:8083/eureka/
注意:eureka.client.serviceUrl.defaultZone的配置,如果是01,則填寫02、03的地址和埠;如果是02,則填寫01、03的地址和埠,也就是說讓01,02,03這3個eureka服務能相互間同步資料,如果是01->02->03->01,則api提供者註冊資訊到01時,01會同步資料到02,但02不會同步到03,01也不會同步到03,也就是說03缺資料了。看原始碼,服務的註冊資訊不會被二次傳播,看PeerAwareInstanceRegistryImpl.java
啟動01 eureka,然後修改application.properties,變為02 eureka的配置
logging.config=classpath:logback.xml
logging.path=d:/logs
##tomcat set###
# eureka的預設埠是8761
server.port=8082
server.session-timeout=60
###########
spring.application.name=eureka-server-02
####下面2個一定要false,因為這程式是要作為服務端,
但是jar中存在eureka-client.jar,所以要false,否則啟動會報錯的
#是否註冊到eureka
eureka.client.register-with-eureka=false
#是否獲取註冊資訊
eureka.client.fetch-registry=false
#為了便於測試,取消eureka的保護模式,如果啟動的話,
比如api提供者關閉了,但是eureka仍然保留資訊
eureka.server.enable-self-preservation=false
#服務名稱
eureka.instance.hostname=02.server.eureka
#eureka的服務地址,/eureka是固定的
eureka.client.serviceUrl.defaultZone=http://01.server.
eureka:8081/eureka/,http://03.server.eureka:8083/eureka/
然後執行啟動類,03也是一樣的操作。
瀏覽器訪問http://01.server.eureka:8081/(或者http://02.server.eureka:8082/,或者http://03.server.eureka:8083/)看到
api提供者
建立個普通的maven專案eureka-api,該api是個使用者服務提供者。採取spring boot開發模式
pom.xml
<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>
<groupId>com.fei.springcloud</groupId>
<artifactId>springcloud-eureka-server</artifactId>
<version>0.0.1-SNAPSHOT</version>
<description>eureka服務端</description>
<!-- 依賴倉庫 設定從aliyun倉庫下載 -->
<repositories>
<repository>
<id>alimaven</id>
<url>http://maven.aliyun.com/nexus/content/repositories/central/</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
<releases>
<enabled>true</enabled>
</releases>
</repository>
</repositories>
<!-- 外掛依賴倉庫 -->
<pluginRepositories>
<pluginRepository>
<id>alimaven</id>
<url>http://maven.aliyun.com/nexus/content/repositories/central/</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
<releases>
<enabled>true</enabled>
</releases>
</pluginRepository>
</pluginRepositories>
<properties>
<!-- 檔案拷貝時的編碼 -->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<!-- 編譯時的編碼 -->
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
<java.version>1.8</java.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.2.RELEASE</version>
<relativePath />
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Dalston.RELEASE</version>
<type>pom</type>
<scope>import</scope><!-- 這個不能丟 -->
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
它和eureka 服務端,有個依賴是不一樣的。
application.properties
logging.config=classpath:logback.xml
logging.path=d:/logs
##tomcat set###
# eureka的預設埠是8761
server.port=9081
server.session-timeout=60
###########
spring.application.name=api-user-server
#像eureka服務註冊資訊時,使用ip地址,預設使用hostname
eureka.instance.preferIpAddress=true
#服務的instance-id預設預設值是${spring.cloud.client.hostname
:${spring.aplication.name}
:${spring.application.instance_id:${server.port}} ,
#也就是機器主機名:應用名稱:應用埠
eureka.instance.instance-id=${spring.cloud.client.ipAddress}:${server.port}
#eureka的服務地址
eureka.client.serviceUrl.defaultZone=http://01.server.eureka:8081/eureka/
Application.java
package com.fei.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@EnableEurekaClient
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
@EnableEurekaClient,不管是消費者還是提供者,對應eureka server來說都是客戶端client
寫個普通的controller,UserProvider.java.提供個根據id獲取使用者資訊的介面
package com.fei.springcloud.provider;
import javax.servlet.http.HttpServletRequest;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/user")
public class UserProvider {
@GetMapping(value="/find/{id}")
public String find(@PathVariable("id") String id,HttpServletRequest request){
//實際專案中,這裡可以使用JSONObject,返回json字串
//為了便於測試消費者app的負載均衡,返回服務端埠
String s = "張三"+" 服務端埠:"+request.getLocalPort();
return s;
}
}
執行Application.java,將application.properties的埠修改為9082,再次執行
瀏覽器訪問http://01.server.eureka:8081/
Application就是檔案中定義的spring.application.name=api-user-server,它會自動轉為大寫
app消費者
在Spring Cloud Netflix中,使用Ribbon實現客戶端負載均衡,使用Feign實現宣告式HTTP客戶端呼叫——即寫得像本地函式呼叫一樣.
ribbo負載均衡的app消費者
建立個普通的maven專案eureka-app-ribbo.
pom.xml
<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>
<groupId>com.fei.springcloud</groupId>
<artifactId>springcloud-eureka-app-ribbo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<description>eureka消費者ribbo</description>
<!-- 依賴倉庫 設定從aliyun倉庫下載 -->
<repositories>
<repository>
<id>alimaven</id>
<url>http://maven.aliyun.com/nexus/content/repositories/central/</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
<releases>
<enabled>true</enabled>
</releases>
</repository>
</repositories>
<!-- 外掛依賴倉庫 -->
<pluginRepositories>
<pluginRepository>
<id>alimaven</id>
<url>http://maven.aliyun.com/nexus/content/repositories/central/</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
<releases>
<enabled>true</enabled>
</releases>
</pluginRepository>
</pluginRepositories>
<properties>
<!-- 檔案拷貝時的編碼 -->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<!-- 編譯時的編碼 -->
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
<java.version>1.8</java.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.2.RELEASE</version>
<relativePath />
</parent>
<dependencies>
<!-- 客戶端負載均衡 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifactId>
</dependency>
<!-- eureka客戶端 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<!-- spring boot實現Java Web服務 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Dalston.RELEASE</version>
<type>pom</type>
<scope>import</scope><!-- 這個不能丟 -->
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
application.properties
logging.config=classpath:logback.xml
logging.path=d:/logs
##tomcat set###
# eureka的預設埠是8761
server.port=7081
server.session-timeout=60
###########
spring.application.name=app-user
#像eureka服務註冊資訊時,使用ip地址,預設使用hostname
eureka.instance.preferIpAddress=true
#服務的instance-id預設預設值是${spring.cloud.client.hostname}${spring.application.name}
:${spring.application.instance_id:${server.port}} ,
#也就是機器主機名:應用名稱:應用埠
eureka.instance.instance-id=${spring.cloud.client.ipAddress}:${server.port}
#eureka的服務地址
eureka.client.serviceUrl.defaultZone=http://01.server.eureka:
8081/eureka/,http://02.server.eureka:8082/eureka/,
http://03.server.eureka:8083/eureka/
UserController.java
logging.config=classpath:logback.xml
logging.path=d:/logs
##tomcat set###
# eureka的預設埠是8761
server.port=7081
server.session-timeout=60
###########
spring.application.name=app-user
#像eureka服務註冊資訊時,使用ip地址,預設使用hostname
eureka.instance.preferIpAddress=true
#服務的instance-id預設預設值是${spring.cloud.client.hostname}
:${spring.application.name}:${spring.application.instance_id:${server.port}} ,
#也就是機器主機名:應用名稱:應用埠
eureka.instance.instance-id=${spring.cloud.client.ipAddress}:${server.port}
#eureka的服務地址
eureka.client.serviceUrl.defaultZone=http://01.server.eureka:8081/eureka/
,http://02.server.eureka:8082/eureka/,http://03.server.eureka:8083/eureka/
使用restTemplate需要自己拼接url
啟動類Application.java
package com.fei.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@EnableEurekaClient
@SpringBootApplication
public class Application {
@Bean //定義REST客戶端,RestTemplate例項
@LoadBalanced //開啟負債均衡的能力
RestTemplate restTemplate() {
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
eureka服務
瀏覽器訪問http://127.0.0.1:7081/user/find
看到資訊“張三 服務端埠:9081”,重新整理瀏覽器看到“張三 服務端埠:9082”,說明的確是有負載均衡。
但是訪問外網的時候,http://127.0.0.1:7081/user/test,也就是域名不在eureka註冊過的,就不行了。
以後再研究下如何解決。
feign的app消費者
feign可以寫個介面,加上相關的註解,呼叫的時候,會自動拼接url,呼叫者就像呼叫本地介面一樣的操作。
Feign也用到ribbon,當你使用@ FeignClient,ribbon自動被應用。
像ribbo建立個專案,或者直接在ribbo專案修改都OK。
pom.xml 把ribbo的依賴修改為feign
<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>
<groupId>com.fei.springcloud</groupId>
<artifactId>springcloud-eureka-app-feign</artifactId>
<version>0.0.1-SNAPSHOT</version>
<description>eureka消費者feign</description>
<!-- 依賴倉庫 設定從aliyun倉庫下載 -->
<repositories>
<repository>
<id>alimaven</id>
<url>http://maven.aliyun.com/nexus/content
/repositories/central/</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
<releases>
<enabled>true</enabled>
</releases>
</repository>
</repositories>
<!-- 外掛依賴倉庫 -->
<pluginRepositories>
<pluginRepository>
<id>alimaven</id>
<url>http://maven.aliyun.com/nexus/content/repositories/central/</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
<releases>
<enabled>true</enabled>
</releases>
</pluginRepository>
</pluginRepositories>
<properties>
<!-- 檔案拷貝時的編碼 -->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<!-- 編譯時的編碼 -->
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
<java.version>1.8</java.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.2.RELEASE</version>
<relativePath />
</parent>
<dependencies>
<!-- Feign實現宣告式HTTP客戶端 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
<!-- eureka客戶端 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<!-- spring boot實現Java Web服務 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Dalston.RELEASE</version>
<type>pom</type>
<scope>import</scope><!-- 這個不能丟 -->
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
application.properties和上面一樣
logging.config=classpath:logback.xml
logging.path=d:/logs
##tomcat set###
# eureka的預設埠是8761
server.port=7081
server.session-timeout=60
###########
spring.application.name=app-user
#像eureka服務註冊資訊時,使用ip地址,預設使用hostname
eureka.instance.preferIpAddress=true
#服務的instance-id預設預設值是${spring.cloud.client.hostname}
:${spring.application.name}:${spring.application.instance_id:${server.port}} ,
#也就是機器主機名:應用名稱:應用埠
eureka.instance.instance-id=${spring.cloud.client.ipAddress}:${server.port}
#eureka的服務地址
eureka.client.serviceUrl.defaultZone=http://01.server.eureka
8081/eureka/,http://02.server.eureka:8082/eureka/,
http://03.server.eureka:8083/eureka/
增加個UserService.java介面類
package com.fei.springcloud.service;
import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@FeignClient("API-USER-SERVER")
public interface UserService {
@GetMapping(value="/user/find/{id}")
String find(@PathVariable("id") String id);
}
UserController.java
package com.fei.springcloud.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.fei.springcloud.service.UserService;
@Controller
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
@GetMapping(value = "/find")
@ResponseBody
public String find() {
//url中對應api提供者的名稱,全大寫
String s = userService.find("123");
return s;
}
}
瀏覽器訪問http://127.0.0.1:7081/user/find,得到資訊“張三 服務端埠:9081”,重新整理,得到“張三 服務端埠:9082”,Feign也用到ribbon,當你使用@ FeignClient,ribbon自動被應用。所以也會負載均衡
ribbo負載均衡策略選擇
AvailabilityFilteringRule:過濾掉那些因為一直連線失敗的被標記為circuit tripped的後端server,並過濾掉那些高併發的的後端server(active connections 超過配置的閾值) | 使用一個AvailabilityPredicate來包含過濾server的邏輯,其實就就是檢查status裡記錄的各個server的執行狀態
RandomRule:隨機選擇一個server
BestAvailabl:選擇一個最小的併發請求的server,逐個考察Server,如果Server被tripped了,則忽略
RoundRobinRule:roundRobin方式輪詢選擇, 輪詢index,選擇index對應位置的server
WeightedResponseTimeRule:根據響應時間分配一個weight(權重),響應時間越長,weight越小,被選中的可能性越低
RetryRule:對選定的負載均衡策略機上重試機制,在一個配置時間段內當選擇server不成功,則一直嘗試使用subRule的方式選擇一個可用的server
ZoneAvoidanceRule:複合判斷server所在區域的效能和server的可用性選擇server
ResponseTimeWeightedRule:作用同WeightedResponseTimeRule,二者作用是一樣的,ResponseTimeWeightedRule後來改名為WeightedResponseTimeRule
在app消費者的application.properties配置檔案中加入
#ribbo負載均衡策略配置,預設是依次輪詢
API-USER-SERVER.ribbon.NFLoadBalancerRuleClassName=com.
netflix.loadbalancer.RandomRule
其中API-USER-SERVER是api服務提供者的服務名稱,也就是說,可以給每個不同的api服務提供者配置不同的複製均衡策略,驗證就不貼圖了
完整的程式碼
負載均衡策略在消費端配置的缺點
在上面的例子中,ribbon的負載均衡是在消費端完成的。流程是這樣的:提供者服務A叢集,啟動2個程序A1,A2,都註冊到eureka,app消費端根據api服務者名稱獲取到A1,A2的具體連線地址,ribbon就對A1,A2進行負載均衡。
缺點:
1) 如果所有的app消費端的配置策略不好,導致絕大部分的請求都到A1,那A1的壓力就大了。也就是說負載策略不是有api提供者所控制的了(這裡就不說A1,A2所在的伺服器哪個效能更好了,因為如果app/api都是在Docker中執行,k8s負責資源調配的話,可以認為每個服務的程序所在的docker配置是一樣的,比如A服務對應的A1,A2系統環境是一致的,B服務對應的B1,B2,B3系統環境是一致的,只是所對應的宿主機伺服器估計不一樣而已)。
2)如果api提供者需要開放給第三方公司的時候,總不能把A1,A2告訴第三方吧,說我們這A服務叢集了,有A1,A2,你隨意吧。
我們實際專案中的做法,都是每個提供者服務都有自己的nginx管理自己的叢集,然後把nginx的域名提供給app消費者即可。之所以每個服務提供者都有自己的nginx,是因為docker被k8s管控的時候,ip都是變化的,需要更新到nginx中。如果A,B都共用一個nginx,那A重構建部署的時候,A1,A2的ip變化了,需要更新到nginx中去,那如果導致nginx出現問題了,豈不是影響到B的使用了,所以A,B都有自己的nginx。那spring cloud沒有解決方案了嗎?有。spring cloud集成了zuul,zuul服務閘道器,不但提供了和nginx一樣的反向代理功能,還提供了負載均衡、監控、過濾等功能,在後面學習zuul的時候,我們再學習。
docker+k8s實現的devOps平臺(paas平臺),構建好映象後,部署的時候,k8s負責調控資源,將docker分配到不同的節點伺服器,同時將docker的ip相關資訊更新到nginx。這是自動化的,不需要開發人員手動操作docker,nginx配置。