Netflix Ribbon 简单实例

本章节将通过一个简单实例介绍怎样使用 Netflix Ribbon 实现负载均衡调用目标服务。

假如我们创建一个用户服务,该服务将分别运行在本机的 7001、7002 和 7003 三个端口。然后使用 Netflix Ribbon 实现简单的负载均衡调用。注意:这里没有将服务注册到 Eureka 服务端,也不用 Spring Cloud 相关的技术,仅仅是一个简单的 Java 项目。如下图:

上图中,我们将 user 服务分别运行在 7001、7002 和 7003 端口,然后客户端使用 Netflix Ribbon 进行负载均衡调用 user 服务。下面将介绍怎样实现上面实例:

提供 User 服务

使用 Spring Boot 创建一个简单的 WEB 项目,并且提供一个 REST 接口,获取当前日期信息。代码如下:

package com.hxstrive.springcloud.ribbon_service_users;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Date;

@RestController
@SpringBootApplication
@EnableEurekaClient
public class RibbonServiceUsersApplication {

    @Value("${appName:server}")
    private String appName;

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

    @GetMapping("/info")
    public String getInfo() {
        return "From " + appName + " - " + new Date();
    }

}

上面代码中,getInfo() 方法将返回当前日期,前面的 appName 是从我们执行“java -jar”命令时提供的,用于区分启动多个User服务时,说明返回数据来自哪个服务。项目编译成功后,通过 maven package 进行打包,然后执行如下命令:

# 服务1
java -jar ribbon_service_user-0.0.1-SNAPSHOT.jar --appName=user1 --server.port=7001 --eureka.instance.instance-id=user1

# 服务2
java -jar ribbon_service_user-0.0.1-SNAPSHOT.jar --appName=user2 --server.port=7002 --eureka.instance.instance-id=user2

# 服务3
java -jar ribbon_service_user-0.0.1-SNAPSHOT.jar --appName=user3 --server.port=7003 --eureka.instance.instance-id=user3

上面命令将启动三个服务。我们可以使用 http://localhost:7001/info  、http://localhost:7002/info  和  http://localhost:7003/info 三个地址分别调用接口。

实现客户端

使用 IDEA 创建一个简单的 Maven Java 项目。

(1)向项目中添加如下 Maven 依赖:

<dependency>
    <groupId>com.netflix.ribbon</groupId>
    <artifactId>ribbon</artifactId>
    <version>2.2.5</version>
</dependency>
<dependency>
    <groupId>com.netflix.ribbon</groupId>
    <artifactId>ribbon-core</artifactId>
    <version>2.2.5</version>
</dependency>
<dependency>
    <groupId>com.netflix.ribbon</groupId>
    <artifactId>ribbon-httpclient</artifactId>
    <version>2.2.5</version>
</dependency>
<dependency>
    <groupId>com.netflix.ribbon</groupId>
    <artifactId>ribbon-loadbalancer</artifactId>
    <version>2.2.5</version>
</dependency>
<dependency>
    <groupId>com.netflix.archaius</groupId>
    <artifactId>archaius-core</artifactId>
    <version>0.7.4</version>
</dependency>
<dependency>
    <groupId>commons-configuration</groupId>
    <artifactId>commons-configuration</artifactId>
    <version>1.8</version>
</dependency>
<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>16.0.1</version>
</dependency>

(2)添加 application.properties 配置文件,内容如下:

# Max number of retries
user.ribbon.MaxAutoRetries=1

# Max number of next servers to retry (excluding the first server)
user.ribbon.MaxAutoRetriesNextServer=1

# Whether all operations can be retried for this client
user.ribbon.OkToRetryOnAllOperations=true

# Interval to refresh the server list from the source
user.ribbon.ServerListRefreshInterval=2000

# Connect timeout used by Apache HttpClient
user.ribbon.ConnectTimeout=3000

# Read timeout used by Apache HttpClient
user.ribbon.ReadTimeout=3000

# Initial list of servers, can be changed via Archaius dynamic property at runtime
user.ribbon.listOfServers=localhost:7001,localhost:7002,localhost:7003
user.ribbon.EnablePrimeConnections=true

注意:上面配置中 user.ribbon.listOfServers 配置我们刚刚上面启动的服务地址,分别为 7001、7002 和 7003 端口。而在每个配置项前面拥有前缀“user”,该前缀为客户端名称,后续在 ClientFactory.getNamedClient("user") 代码中使用,用来获取 RestClient 对象。

(3)新增 Demo1.java 文件,代码如下:

package com.hxstrive.springcloud.ribbon_demo1;

import com.netflix.client.ClientFactory;
import com.netflix.client.http.HttpRequest;
import com.netflix.client.http.HttpResponse;
import com.netflix.config.ConfigurationManager;
import com.netflix.niws.client.http.RestClient;

public class Demo1 {

    public static void main(String[] args) throws Exception{
        // 1.加载配置信息
        ConfigurationManager.loadPropertiesFromResources("application.properties");
        System.out.println(ConfigurationManager.getConfigInstance().getProperty("user.ribbon.listOfServers"));

        // 2.返回名称为 user 的 RestClient 客户端
        // 注意:这里的名称是在 application.properties 文件中配置 ribbon 时的前缀
        //       user.ribbon.listOfServers=localhost:7001,localhost:7002,localhost:7003
        //       上面配置中的 user 就是客户端名称
        RestClient client = (RestClient) ClientFactory.getNamedClient("user");

        // 3.构建指定 URL 的 HTTP 请求
        HttpRequest request = HttpRequest.newBuilder().uri("/info").build();
        for (int i = 0; i < 10; i++)  {
            // 4.使用负载均衡算法发起 HTTP 请求
            HttpResponse response = client.executeWithLoadBalancer(request);
            // 打印调用状态和结果
            System.out.println("Status code for " + response.getRequestedURI() + "  status:"
                    + response.getStatus() + " entity: " + response.getEntity(String.class));
        }
    }

}

运行上面代码,输出结果如下:

SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
[localhost:7001, localhost:7002, localhost:7003]
Status code for http://localhost:7002/info  status:200 entity: From user2 - Fri Mar 26 18:00:09 CST 2021
Status code for http://localhost:7003/info  status:200 entity: From user3 - Fri Mar 26 18:00:09 CST 2021
Status code for http://localhost:7001/info  status:200 entity: From user1 - Fri Mar 26 18:00:09 CST 2021
Status code for http://localhost:7002/info  status:200 entity: From user2 - Fri Mar 26 18:00:09 CST 2021
Status code for http://localhost:7003/info  status:200 entity: From user3 - Fri Mar 26 18:00:09 CST 2021
Status code for http://localhost:7001/info  status:200 entity: From user1 - Fri Mar 26 18:00:09 CST 2021
Status code for http://localhost:7002/info  status:200 entity: From user2 - Fri Mar 26 18:00:09 CST 2021
Status code for http://localhost:7003/info  status:200 entity: From user3 - Fri Mar 26 18:00:09 CST 2021
Status code for http://localhost:7001/info  status:200 entity: From user1 - Fri Mar 26 18:00:09 CST 2021
Status code for http://localhost:7002/info  status:200 entity: From user2 - Fri Mar 26 18:00:09 CST 2021

仔细观察可知,客户端使用了轮询的方式调用服务列表。即调用 7002、7003 和 7001,然后再次调用 7002、7003……

说说我的看法
全部评论(
没有评论
关于
本网站属于个人的非赢利性网站,转载的文章遵循原作者的版权声明,如果原文没有版权声明,请来信告知:hxstrive@outlook.com
公众号