Eureka
1. Eureka簡介
Eureka是Netflix開發的服務發現框架,是一個基於REST的服務
主要包含兩個組件: Eureka Server和Eureka Client
主要有:
- Eureka Server(服務註冊中心)
- 服務提供方
- 服務消費方
可以看這張圖瞭解大概
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-C0z9laYE-1570769790806)(BDB475AE408B4089B5B993F0A6FC85F3)]
2. Eureka Server搭建
2.1 依賴配置
<dependencies>
<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>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<!-- 在寫版本的時候,不能像官網那樣寫 Greenwich SR2, -->
<version>Greenwich.SR2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
2.2 application.yml配置文件
server:
port: 7961
eureka:
instance:
hostname: localhosh #eureka的服務機器名
client:
fetch-registry: false
register-with-eureka: false
service-url:
defaultZone: http://localhost:${server.port}/eureka/
2.3 啓動類代碼
@SpringBootApplication
@EnableEurekaServer
public class SpringcloudMsEureka7961Application {
public static void main(String[] args) {
SpringApplication.run(SpringcloudMsEureka7961Application.class, args);
}
}
2.4 測試
訪問訪問http://localhost:7961/
3. 服務提供方搭建
3.1 依賴配置
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<!-- 在寫版本的時候,不能像官網那樣寫 Greenwich SR2, -->
<version>Greenwich.SR2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
3.2 application.yml配置(阿里Durid 和 數據庫讀寫分離)
server:
port: 6001
eureka:
client:
fetch-registry: false
register-with-eureka: true
service-url:
defaultZone: http://localhost:7961/eureka/
instance:
prefer-ip-address: true
logging:
level:
com.vip.weborder.mapper: debug
mybatis-plus:
mapper-locations: classpath:mappers/**/*.xml
spring:
datasource:
druid:
stat-view-servlet:
loginUsername: root
loginPassword: root
dynamic:
datasource:
master:
username: root
password: root
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://120.24.94.104:3316/aaaa?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
druid:
initial-size: 3
max-active: 8
min-idle: 2
max-wait: -1
min-evictable-idle-time-millis: 30000
max-evictable-idle-time-millis: 30000
time-between-eviction-runs-millis: 0
validation-query: select 1
validation-query-timeout: -1
test-on-borrow: false
test-on-return: false
test-while-idle: true
pool-prepared-statements: true
max-open-prepared-statements: 100
filters: stat,wall
share-prepared-statements: true
slave_1:
username: root
password: root
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://120.24.94.104:3317/aaaa?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
druid:
initial-size: 3
max-active: 8
min-idle: 2
max-wait: -1
min-evictable-idle-time-millis: 30000
max-evictable-idle-time-millis: 30000
time-between-eviction-runs-millis: 0
validation-query: select 1
validation-query-timeout: -1
test-on-borrow: false
test-on-return: false
test-while-idle: true
pool-prepared-statements: true
max-open-prepared-statements: 100
filters: stat,wall
share-prepared-statements: true
<!--注意最好是給名字方便消費層調用-->
application:
name: ms-provider
3.3 啓動類代碼
@SpringBootApplication
@EnableEurekaClient //啓動Eureka客戶端
public class ShopProviderApplication {
public static void main( String[] args){
SpringApplication.run(ShopProviderApplication.class, args);
}
}
4. 服務消費方搭建
4.1 導入依賴
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.qf</groupId>
<artifactId>spring-cloud</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<groupId>com.example</groupId>
<artifactId>springcloud-ms-consumer-8080</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springcloud-ms-consumer-8080</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
<dependency>
<groupId>com.qf</groupId>
<artifactId>spring-cloud</artifactId>
<version>0.0.1-SNAPSHOT</version>
<exclusions>
<exclusion>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
</exclusion>
<exclusion>
<groupId>tk.mybatis</groupId>
<artifactId>mapper-spring-boot-starter</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<!-- 在寫版本的時候,不能像官網那樣寫 Greenwich SR2, -->
<version>Greenwich.SR2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
4.2 application.yml配置
spring:
application:
name: shop-consumer
server:
port: 8080
eureka:
client:
fetch-registry: true
register-with-eureka: false
service-url:
defaultZone: http://localhost:7961/eureka/
4.3 啓動類代碼
@SpringBootApplication
@EnableEurekaClient
public class SpringcloudMsConsumer8080Application {
public static void main(String[] args) {
SpringApplication.run(SpringcloudMsConsumer8080Application.class, args);
}
}
5 啓動 Ribbon 負載均衡(單純啓動默認)
5.1 配置依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
5.2 實現負載均衡
Ribbon只是一個客戶端的負載均衡器工具,實現起來非常的簡單,我們只需要在注入RestTemplate的bean上加上@LoadBalanced就可以了。如下:
@Configuration
public class BeanConfig {
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
5.3 啓動類配置
@SpringBootApplication
@EnableEurekaClient
public class ShopConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ShopConsumerApplication.class, args);
}
}
5.4 服務的調用
在服務的消費方,不再採用主機名+端口的形式進行調用,而是直接採用服務名的方式進行調用。
@RestController
@RequestMapping(value="/user")
public class UserController {
@Resource
private RestTemplate restTemplate;
@RequestMapping(value = "/ticket/{id}", method = RequestMethod.GET)
public Object getTicket(@PathVariable(value = "id") Integer id) {
Person person = new Person();
person.setId(23);
person.setName("張三三");
// shop-provider 是服務名,不需要使用ip:端口的形式進行調用
List<Ticket> ticketList = restTemplate.getForObject("http://shop-provier/ticket", List.class, person);
return ticketList;
}
}
5.5 負載均衡策略
Ribbon提供了一個很重要的接口叫做IRule,其中定義了很多的負載均衡策略,默認的是輪詢的方式,以下是Ribbon的負載均衡策略:
類名 | 描述 |
---|---|
RoundRobbinRule | 輪詢 |
RandomRule | 隨機挑選 |
RetryRule | 按照輪詢的方式去調用服務,如果其中某個服務不可用,但是還是會嘗試幾次,如果嘗試過幾次都沒有成功,那麼就不在調用該服務,會輪詢調用其他的可用服務。 |
AvailabilityFilteringRule | 會先過濾掉因爲多次訪問不可達和併發超過閾值的服務,然後輪詢調用其他的服務 |
WeightedResponseTimeRule | 根據平均響應時間計算權重,響應越快權重越大,越容易被選中。服務剛重啓的時候,還未統計出權重會按照輪詢的方式;當統計信息足夠的時候,就會按照權重信息訪問 |
ZoneAvoidanceRule | 判斷server所在的區域性能和可用性選擇服務器 |
BestAvailableRule | 會過濾掉多次訪問都不可達的服務,然後選擇併發量最小的服務進行調用,默認方式 |
改變Ribbon的負責均衡策略:
@Bean
public IRule getRule() {
return new RandomRule();
}
5.6 自定義負載均衡策略
我們自定義的負載均衡策略需要繼承AbstractLoadBalancerRule這個類,然後重寫choose方法,然後將其注入到容器中,如下所示:
public class Customize_Rule extends AbstractLoadBalancerRule {
private static Logger logger = LoggerFactory.getLogger(Customize_Rule.class);
private int currentIndex = 0; //當前調用的索引
private int num = 1; //次數
private int limit = 5;
/**
* 初始化工作
* @param iClientConfig
*/
@Override
public void initWithNiwsConfig(IClientConfig iClientConfig) {
}
@Override
public Server choose(Object key) {
ILoadBalancer balancer = getLoadBalancer();
return choose(balancer, key);
}
private Server choose(ILoadBalancer balancer, Object key) {
Server server = null;
while(null == server) {
//獲取所有可用的服務
List<Server> reachableServers = balancer.getReachableServers();
if (0 == reachableServers.size()) {
logger.error("沒有可用的服務");
return null; //退出while循環
}
int total = reachableServers.size(); //可用服務的數量
synchronized (this) {
/**
* 有種極端情況,當我們在使用最後一個服務的時候,其他的服務都不可用,可能導致索引越界異常
*/
if (currentIndex + 1 > total) {
currentIndex = 0;
server = reachableServers.get(currentIndex); //獲取第一個服務
num = 0;
num++;
} else {
if(limit == num) {
currentIndex++;
num = 0;
if(currentIndex == total) {
currentIndex=0;
server = reachableServers.get(currentIndex); //獲取第一個服務
num++;
}else{
server = reachableServers.get(currentIndex);
num++;
}
}else {
server = reachableServers.get(currentIndex);
num++;
}
}
}
}
return server;
}
}
將其注入到容器中,如下所示:
@Bean
public IRule getRule() {
return new Customize_Rule();
}
這種對Controller層的入侵太強而且,不方便觀看,所以我們可以用下一個Feign 實現負載均衡
6. Feign 負載均衡
eign是基於Ribbon的另外一個負載均衡的客戶端框架,只需要在接口上定義要調用的服務名即可,使用起來非常的簡單。
6.1 添加依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
6.2 啓動類配置
需要在啓動類上加上@EnableFeignClients註解即可開啓feign,如下所示:
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
public class ShopConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ShopConsumerApplication.class, args);
}
}
6.3 service層 直接用註解調用其他模塊
@Service
@FeignClient(name = "shop-provier")
public interface TicketService {
@RequestMapping(value = "ticket", method = RequestMethod.GET)
public List<Ticket> getAllTicket(Person person);
}
這樣我們用起來在Controllor層就和平時用的寫的一樣,只是Service層有所不同,看上去也更加舒服
6.4 yml 配置
注意,有時候會遇到超時問題,可以配置一下設置時間
client:
config:
default:
connectTimeout: 160000000
readTimeout: 160000000