springCloud 一 .集成eureka分佈式服務發現框架

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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章