006 SpringCloud-Ribbon机制实现负载均衡

        负载均衡对于一个系统架构来说非常重要,是必须要有的一个基础设施,它能够有效的缓解网络压力和流量扩容。我们知道的负载均衡可能分为两种,一种是硬件的负载均衡,比如F5服务器或者SLB负载设施;另外一种是软件负载均衡设施,比如我们耳熟能详的Nginx反向代理负载均衡、Lvs(基于IP级别)负载均衡、Haproxy(TCP通讯层面)负载均衡等等。但是只要是负载均衡服务都是能以类似的架构方式来构建。

Spring Cloud Ribbon是一个基于HTTPTCP的客户端复杂均衡工具。他基于Netflix Ribbon实现。通过Spring Cloud的封装,可以让我们轻松的将面向服务的Rest模板请求自动转换成客户端负载均衡的服务调用。在服务架构中,以后我们学习的API网关以及Feign代理都是通过Ribbon为基础进行调用服务的。  

      对于Spring Cloud Ribbon 的负载均衡我们基于RestTemplate去使用,只需要在配置BEAN中加入注解@LoadBalanced即可, Ribbon负载均衡器: 

注意问题:我们的RestTemplate加上@LoadBalanced注解后会走这个类(轮训策略类)RibbonLoadBalancerClientserverid必须是我们访问的服务名称 ,当我们直接输入ip的时候获取的servernull,就会抛出异常;

模拟实现:

1. 创建spring-cloud-02-eureka引入依赖:

<parent>
    <groupId>com.cc</groupId>
    <artifactId>spring-cloud-matser</artifactId>
    <version>0.0.1-SNAPSHOT</version>
  </parent>
  <artifactId>spring-cloud-02-eureka-server</artifactId>

<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
    </dependency>

</dependencies>
<!-- 版本配置项 -->
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Edgware.SR4</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
<build>
    <finalName>spring-cloud-02-eureka-server</finalName>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
                <mainClass>com.cc.springcloud.Application</mainClass>
            </configuration>
        </plugin>
    </plugins>
</build>

配置application.properties:

spring.application.name=eureka

server.port=8001
##主机名称,在hosts文件中配置后可以直接使用配置的名字
eureka.instance.hostname=eureka1

##关闭自我保护机制,如不关闭,eureka容易出现在一定时间内无法使用,就不能保证AP高可用
eureka.server.enable-self-preservation=false
##定时清理不可用的服务列表信息,配置定时时间周期,默认60秒(服务下线)
eureka.server.eviction-interval-timer-in-ms=10000

##客户端向服务器端(注册中心)发送的心跳间隔时间
eureka.instance.lease-renewal-interval-in-seconds=10
##服务器注册租期到期的时间:Eureka服务在收到最后一次心跳的时候算起,如果后续30秒内没有收到任何的心跳,Eureka主动标示该服务会被剔除,然后由定时任务清理服务列表
eureka.instance.lease-expiration-duration-in-seconds=30

##注册中心的访问地址
eureka.client.service-url.defaultZone=http://eureka1:8001/eureka
#高可用:将eureka1的注册地址配置为eureka2,即互相配置对方
#eureka.client.service-url.defaultZone=http://eureka2:8002/eureka

创建Application.java:

package com.cc.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

@EnableEurekaServer   //启用服务发现,注册中心
@SpringBootApplication   //springboot 核心配置
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}
 

2. 创建spring-cloud-02-provider-1和spring-cloud-02-provider-2用于模拟两个生产者,除名字和端口外其他内容一致:

配置pom:

<parent>
    <groupId>com.cc</groupId>
    <artifactId>spring-cloud-matser</artifactId>
    <version>0.0.1-SNAPSHOT</version>
  </parent>
  <artifactId>spring-cloud-02-provider-1</artifactId>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!-- 标示这个工程是一个服务,需要引入此jar -->
      <dependency>
          <groupId>org.springframework.cloud</groupId>
          <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
      </dependency>
      <!-- 动态刷新的一个模块jar -->
      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-actuator</artifactId>
      </dependency>
</dependencies>
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Edgware.SR4</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
<build>
    <finalName>spring-cloud-02-provider-1</finalName>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
                <mainClass>com.cc.springcloud.Application</mainClass>
            </configuration>
        </plugin>
    </plugins>
</build>

配置application.properties:

#两个结点做负载均衡,service那么必须相同
spring.application.name=provider-service
##微服务方式尽量不要加server.context-path,只用名字加方法实现
#server.context-path=/provider
server.port=7001

##需要引入eureka注册中心的地址
##下面两条配置代表注册到注册中心后显示自己的IP地址,实际工作中尽量加上
eureka.instance.prefer-ip-address=true
eureka.instance.instance-id=${spring.application.name}:${spring.cloud.client.ipAddress}:${server.port}

##租期到期时间间隔
#eureka.instance.lease-expiration-duration-in-seconds=30
##租期更新时间间隔
#eureka.instance.lease-renewal-interval-in-seconds=10

##开启健康检查,必须要引入spring-boot-starter-actuator动态刷新jar
eureka.client.healthcheck.enabled=true

eureka.client.service-url.defaultZone=http://eureka1:8001/eureka

package com.cc.springcloud.entity;

import java.io.Serializable;

public class User implements Serializable{
    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    private String id;
    private String name;
    
    public User(String id, String name) {
        super();
        this.id = id;
        this.name = name;
    }
    public User() {
        
    }
    
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }


}
----------------------------------------------------------------------------------------------------------------------------------------

package com.cc.springcloud.api;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.cc.springcloud.entity.User;

@RestController
public class UserController {

    @RequestMapping(value="/getUser",method= {RequestMethod.GET})
    public User getUser(@RequestParam("id")String id) throws InterruptedException {
        System.out.println("provider-1---->1"+id);
        Thread.sleep(1000);
        return new User(id,"张三");
    }
    
    @RequestMapping(value="/postUser",method= {RequestMethod.POST})
    public User postUser(@RequestParam("id")String id) throws InterruptedException {
        System.out.println("provider-1---->1"+id);
        Thread.sleep(1000);
        return new User(id,"李四");
    }
    
}
--------------------------------------------------------------------------------------------------------------------------

package com.cc.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@EnableDiscoveryClient   //标示是一个具体的服务,需要向注册中心注册
@SpringBootApplication   //springboot 核心配置
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}


3.创建spring-cloud-02-consumer来模拟消费者:

配置pom:

<parent>
    <groupId>com.cc</groupId>
    <artifactId>spring-cloud-matser</artifactId>
    <version>0.0.1-SNAPSHOT</version>
  </parent>
  <artifactId>spring-cloud-02-consumer</artifactId>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!-- 标示这个工程是一个服务,需要引入此jar -->
      <dependency>
          <groupId>org.springframework.cloud</groupId>
          <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
      </dependency>
      <!-- 动态刷新的一个模块jar -->
      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-actuator</artifactId>
      </dependency>
      <!-- 引入ribbon组件 -->
      <dependency>
          <groupId>org.springframework.cloud</groupId>
          <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
      </dependency>
</dependencies>
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Edgware.SR4</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
<build>
    <finalName>spring-cloud-02-consumer</finalName>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
                <mainClass>com.cc.springcloud.Application</mainClass>
            </configuration>
        </plugin>
    </plugins>
</build>

配置application.properties:

spring.application.name=consumer-service
##微服务方式尽量不要加server.context-path,只用名字加方法实现
#server.context-path=/provider
server.port=7003

##需要引入eureka注册中心的地址
##下面两条配置代表注册到注册中心后显示自己的IP地址,实际工作中尽量加上
eureka.instance.prefer-ip-address=true
eureka.instance.instance-id=${spring.application.name}:${spring.cloud.client.ipAddress}:${server.port}

##租期到期时间间隔
#eureka.instance.lease-expiration-duration-in-seconds=30
##租期更新时间间隔
#eureka.instance.lease-renewal-interval-in-seconds=10

##开启健康检查,必须要引入spring-boot-starter-actuator动态刷新jar
eureka.client.healthcheck.enabled=true

eureka.client.service-url.defaultZone=http://eureka1:8001/eureka

User类一致;

创建ConsumerController:

package com.cc.springcloud.api;

import java.util.HashMap;
import java.util.Map;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import com.cc.springcloud.entity.User;

@RestController
public class ConsumerController {
    
    @Autowired
    private RestTemplate restTemplate;
    
    @RequestMapping(value="/get")
    public String get() {
        ResponseEntity<User> responseEntity = restTemplate.getForEntity("http://provider-service/getUser?id=001", User.class);
        User user = responseEntity.getBody();
        System.out.println("username"+user.getName());
        return "get success";
    }
    @RequestMapping(value="/post")
    public String post() {
        //模拟表单提交此处使用Map报错
        //Map<String,String> params = new HashMap<String,String>();
        //使用org.springframework.util.MultiValueMap类表单提交对象
        MultiValueMap<String,String> params = new LinkedMultiValueMap<>();
        params.set("id", "002");
        ResponseEntity<User> responseEntity = restTemplate.postForEntity("http://provider-service/postUser", params,User.class);
        User user = responseEntity.getBody();
        System.out.println("username"+user.getName());
        return  "post success";
    }

}
创建Application:

package com.cc.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

@EnableDiscoveryClient   //标示是一个具体的服务,需要向注册中心注册
@SpringBootApplication   //springboot 核心配置
public class Application {

    @Bean
    @LoadBalanced  //用于实现内部的服务负载均衡机制:service-id或service-name
    public RestTemplate restTemplate() {
        //通过工厂模式创建返回RestTemplate
        HttpComponentsClientHttpRequestFactory httpComponentsClientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory();
        //设置超时时间
        httpComponentsClientHttpRequestFactory.setConnectTimeout(10000);
        httpComponentsClientHttpRequestFactory.setConnectionRequestTimeout(1000);
        httpComponentsClientHttpRequestFactory.setReadTimeout(20000);
        return new RestTemplate(httpComponentsClientHttpRequestFactory);
    }
    
    
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}
 

4.整体启动模拟访问:

 

模拟实现了Ribbon负载均衡;

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值