负载均衡对于一个系统架构来说非常重要,是必须要有的一个基础设施,它能够有效的缓解网络压力和流量扩容。我们知道的负载均衡可能分为两种,一种是硬件的负载均衡,比如F5服务器或者SLB负载设施;另外一种是软件负载均衡设施,比如我们耳熟能详的Nginx反向代理负载均衡、Lvs负载均衡、Haproxy负载均衡等等。但是只要是负载均衡服务都是能以类似的架构方式来构建。
1.硬件方面负载均衡:F5服务器或者SLB负载设施
2.软件级别负载均衡:Nginx反向代理负载均衡、Lvs负载均衡、Haproxy负载均衡等等。但是只要是负载均衡服务都是能以类似的架构方式来构建。
3.软件方面负载均衡实现:Spring Cloud Ribbon
Spring Cloud Ribbon是一个基于HTTP和TCP的客户端复杂均衡工具。他基于Netflix Ribbon实现。通过Spring Cloud的封装,可以让我们轻松的将面向服务的Rest模板请求自动转换成客户端负载均衡的服务调用。在服务架构中,以后我们学习的API网关以及Feign代理都是通过Ribbon为基础进行调用服务的。
@Bean
@LoadBalanced // 如果加了这个注解 , 那么就说明 具有了服务发现的特性
//负载均和的机制:意味着可以通过服务名请求数据
public RestTemplate restTemplate(){
return new RestTemplate();
}
注意问题:我们的RestTemplate加上@LoadBalanced注解后会走这个类
(轮训策略类)RibbonLoadBalancerClient,serverid必须是我们访问
的服务名称 ,当我们直接输入ip的时候获取的server是null,就会抛出异常
一。注册中心:高可用后,即两个eureka相互注册
二。将两个provider:customer-service,customer-service-other注册到注册中心
customer-service与customer-service-other中有相同代码接口,两个服务提供者只有端口不同
如下:
package com.zx.dt2b.controller;
import com.zx.dt2b.entity.User;
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;
/**
* Author:码图科技
* Date:2018至今
* Description:版权所有,违者必究
*/
@RestController
public class UserController {
private int counter = 0;
@RequestMapping(value="/getUser", method = {RequestMethod.GET})
public User getUser(@RequestParam("id")String id) throws InterruptedException {
System.err.println("provider-1 ----> id: " + id);
Thread.sleep(2500);
counter++;//1 + 1
System.err.println(counter);
return new User(id, "张三");
}
@RequestMapping(value="/postUser", method = {RequestMethod.POST})
public User postUser(@RequestParam("id")String id) throws InterruptedException {
System.err.println("provider-1 ----> id: " + id);
Thread.sleep(1000);
return new User(id, "李四");
}
}
三。消费者引入ribbon组件:项目erp
<!-- 引入ribbon组件 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>com.zx.dt2b.erp</artifactId>
<groupId>com.zx.dt2b.erp</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>erp</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>
<!--eureka版本-->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<!-- <version>Dalston.SR5</version> -->
<version>Edgware.SR4</version>
<!-- <version>Finchley.SR1</version> -->
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<finalName>erp</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>com.zx.dt2b.ErpApplication</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
主入口:
其中
@Bean
@LoadBalanced //用于实现内部的服务负载均衡机制: service-id service-name// 如果加了这个注解 , 那么就说明 具有了服务发现的特性 负载均和的机制:意味着可以通过服务名请求数据
public RestTemplate restTemplate(){
HttpComponentsClientHttpRequestFactory httpComponentsClientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory();
httpComponentsClientHttpRequestFactory.setConnectTimeout(10000);
httpComponentsClientHttpRequestFactory.setConnectionRequestTimeout(10000);
httpComponentsClientHttpRequestFactory.setReadTimeout(20000);
return new RestTemplate(httpComponentsClientHttpRequestFactory);
}
package com.zx.dt2b;
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;
/**
* Author:码图科技
* Date:2018至今
* 作为服务消费者存在
* Description:版权所有,违者必究
*/
@EnableDiscoveryClient //标识具体的一个服务,需要向注册中心注册
@SpringBootApplication //SpringBoot 核心配置
public class ErpApplication {
@Bean
@LoadBalanced //用于实现内部的服务负载均衡机制: service-id service-name// 如果加了这个注解 , 那么就说明 具有了服务发现的特性 负载均和的机制:意味着可以通过服务名请求数据
public RestTemplate restTemplate(){
HttpComponentsClientHttpRequestFactory httpComponentsClientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory();
httpComponentsClientHttpRequestFactory.setConnectTimeout(10000);
httpComponentsClientHttpRequestFactory.setConnectionRequestTimeout(10000);
httpComponentsClientHttpRequestFactory.setReadTimeout(20000);
return new RestTemplate(httpComponentsClientHttpRequestFactory);
}
public static void main(String[] args) {
SpringApplication.run(ErpApplication.class, args);
}
}
接口调用:
package com.zx.dt2b.controller;
import com.zx.dt2b.entity.User;
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;
/**
* Author:码图科技
* Date:2018至今
* Description:版权所有,违者必究
*/
@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.err.println("username: " + user.getName());
return "get success!";
}
@RequestMapping(value="/post")
public String post(){
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.err.println("username: " + user.getName());
return "post success!";
}
//---------负载均衡------------
//------------一阶段:分布式架构介绍------------------
@RequestMapping(value="/getByUrl")//请求http://localhost:7002/erpservice/getByUrl
public String getByUrl(){
RestTemplate rt1 = new RestTemplate();//不用注入的restTemplate,是restTemplate已经被微服务配置
ResponseEntity<String> responseEntity = rt1.getForEntity("http://localhost:7001/customerservice/index", String.class);
String ret = responseEntity.getBody();
System.err.println("返回provider服务调用结果: " + ret);
return "----------get by url----------";
}
@RequestMapping(value="/getByServiceName")//请求http://localhost:7002/erpservice/getByServiceName
public String getByServiceName(){
ResponseEntity<String> responseEntity = restTemplate.getForEntity("http://customer-service/customerservice/index", String.class);
String ret = responseEntity.getBody();
System.err.println("返回provider服务调用结果: " + ret);
return "----------get by service name----------";
}
//------------一阶段------------------
}