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