在微服务架构中,业务都会被拆分成一个独立的服务,服务与服务的通讯是基于http restful的。Spring Cloud有两种服务调用方式,一种是Ribbon+RestTemplate,另一种是Feign。在这里首先讲解下基于Ribbon+Rest。
一、Ribbon简介
Ribbon是Netflix发布的负载均衡器,它有助于控制HTTP和TCP客户端的行为。为Ribbon配置服务提供者地址列表后,Ribbon就可基于某种负载均衡算法,自动地帮助服务消费者去请求。Ribbon默认为我们提供了很多的负载均衡算法,例如轮询、随机等。当然,我们也可为Ribbon实现自定义的负载均衡算法。
Ribbon 已经默认实现了这些配置bean:
-
IClientConfig ribbonClientConfig: DefaultClientConfigImpl
-
IRule ribbonRule: ZoneAvoidanceRule
-
IPing ribbonPing: NoOpPing
-
ServerList ribbonServerList: ConfigurationBasedServerList
-
ServerListFilter ribbonServerListFilter: ZonePreferenceServerListFilter
-
ILoadBalancer ribbonLoadBalancer: ZoneAwareLoadBalancer
二、准备工作
本篇文章基于上一篇的工程,启动了eureka server(服务注册中心)和service hi(服务提供者)两个工程。
编写service hi
工程服务,这里我们简单写一下,输出传入的参数和端口号就可以,新建一个HiController,代码如下:
@RestController
@RequestMapping("/hi")
public class HiController {
@Value("${server.port}")
private String port;
@RequestMapping("{name}")
public String hi(@PathVariable String name){
return "hi "+name+" i am from port:"+port;
}
}
现在我们需要启动两个service hi
工程,一个端口为9091,另一个为9092,首先点击右上角的 Edit Configurations
可以看到这里有 eureka server
和 service hi
两个启动类,我们复制一个 service hi
启动类,在原来的启动类名称加上 9091,新复制的一个加上 9092,便于区分,最后在9092启动类加上参数 -Dport=9092
修改service-hi
工程的application.yml文件:
server:
port: ${port:9091}
spring:
application:
name: service-hi
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:10086/eureka
port: ${port:9091}
表示port参数有值则使用,没有则使用9091。
我们在9092启动类定义了port参数,这样启动9091启动类时就是9091端口,启动9092启动类就是9092端口
我们分别启动9091和9092
查看Eureka Server监控页面,这时会发现service-hi
注册了两个实例,这样准备工作完成。
三、建一个服务消费者
新建一个springBoot工程,取名为 service-consumer,在pom.xml文件分别引入依赖,spring-cloud-starter-netflix-eureka-client
、spring-boot-starter-web
、spring-boot-starter-test
。
因为Eureka已经集成了Ribbon,所以我们无需引入Ribbon依赖。
<?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>springCloudTest</artifactId>
<groupId>com.test</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>service-consumer</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Eureka客户端 -->
<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-test</artifactId>
</dependency>
</dependencies>
</project>
编写application.yml配置文件,指定服务注册中心地址http://127.0.0.1:10086/eureka,服务名称为 service-consumer,端口号为8760。文件如下:
server:
port: 8760
spring:
application:
name: service-consumer
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:10086/eureka
在工程的启动类中,通过@EnableDiscoveryClient
向服务中心注册;并且向程序的ioc注入一个bean: restTemplate
,并通过@LoadBalanced
注解表明这个restTemplate
开启负载均衡的功能。
@SpringBootApplication
@EnableDiscoveryClient //开启eureka客户端发现功能
public class ConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class, args);
}
@Bean
@LoadBalanced //表明这个restRemplate开启负载均衡的功能
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
写一个测试类HelloController,通过之前注入ioc容器的restTemplate来消费service-hi
服务的“/hi”
接口。
开启Ribbon负载均衡后,我们直接用服务名称替代了具体的url地址,在Ribbon中它会根据服务名来选择具体的服务实例,根据服务实例在请求的时候会用具体的url替换掉服务名。
代码如下:
@RestController
@RequestMapping("/hello")
public class HelloController {
@Autowired
private RestTemplate restTemplate;
@GetMapping("{name}")
public String hello(@PathVariable String name){
String url = "http://service-hi/hi/"+name;
return restTemplate.getForObject(url,String.class);
}
}
四、启动测试
分别启动eureka-server、两个service-hi工程(9091、9092),最后启动服务消费者service-consumer,查看Eureka监控页面:
在浏览器上多次访问:http://127.0.0.1:8760/hello/wangYouXiaoFeng 交替显示:
hi wangYouXiaoFeng i am from port:9091
hi wangYouXiaoFeng i am from port:9092
这说明当我们通过调用restTemplate.getForObject(url,String.class);
方法时,已经做了负载均衡,访问了不同的端口的服务实例。
五、负载均衡策略
Ribbon默认的负载均衡策略是简单的轮询
在刚刚的测试中,我们不断访问 http://127.0.0.1:8760/hello/wangYouXiaoFeng 发现 9091和9092 端口是交替显示的,说明确实是轮询方式。
SpringBoot也帮我们提供了修改负载均衡规则的配置入口,现在我们修改负载均衡策略为随机:
server:
port: 8760
spring:
application:
name: service-consumer
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:10086/eureka
service-hi: #修改Ribbon负载均衡规则,更改为随机算法
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
格式:{服务名称}.ribbon.NFLoadBalancerRuleClassName
,值就是IRule的实现类。
再次测试 http://127.0.0.1:8760/hello/wangYouXiaoFeng :发现9091和9092是随机显示的了。