3.消费者(REST+Ribbon实现负载均衡)

来源:互联网 发布:钢琴曲鉴赏 知乎 编辑:程序博客网 时间:2024/05/17 07:59

1.将上一个博文Eureka注册中心打成jar包,将服务提供者打成jar包(port=8763),再将服务提供者打成jar包(port=8764)

首先将服务提供者配置文件的端口改为8763这样就有两个相同的服务(端口不同),注意配置文件中name相同(这样才能保证是同一个服务)

eureka:  client:    serviceUrl:      defaultZone: http://localhost:8761/eureka/server:  port: 8763spring:  application:    name: eureks-serverProvider-test
注意name不要用下划线,这样在使用服务名称访问时会报找不到有效hostname错误
将三个jar包(一个Eureka注册中心,两个服务)分别命名为Registry-Center/ServerProvider_1/ServerProvider_2,放到D盘依次在cmd下启动


D:\>java -jar Registry-Center.jarD:\>java -jar ServerProvider_1.jarD:\>java -jar ServerProvider_2.jar

在web窗口下访问Eureka注册中心(localhost:8761)


可以看到同一个服务在两个端口下同时提供服务,这时候消费者在调用服务时调用谁就涉及到一个选择问题(请求路由/负载均衡)


2.创建一个消费者工程

(1.)pom.xml

<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">  <modelVersion>4.0.0</modelVersion>  <groupId>com.tyf</groupId>  <artifactId>ribbon_test</artifactId>  <version>0.0.1-SNAPSHOT</version>  <packaging>jar</packaging>  <name>ribbon_test</name>  <url>http://maven.apache.org</url>  <!-- springboot -->  <parent>        <groupId>org.springframework.boot</groupId>        <artifactId>spring-boot-starter-parent</artifactId>        <version>1.5.2.RELEASE</version>        <relativePath/>   </parent>  <!-- 编码 -->  <properties>    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>  </properties>  <dependencies>  <!-- springcloud -->  <dependency>            <groupId>org.springframework.cloud</groupId>            <artifactId>spring-cloud-starter-eureka</artifactId>        </dependency>        <!-- ribbon -->        <dependency>            <groupId>org.springframework.cloud</groupId>            <artifactId>spring-cloud-starter-ribbon</artifactId>        </dependency>        <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-web</artifactId>        </dependency><!-- test -->        <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-test</artifactId>            <scope>test</scope>        </dependency>  </dependencies>    <dependencyManagement>        <dependencies>            <dependency>                <groupId>org.springframework.cloud</groupId>                <artifactId>spring-cloud-dependencies</artifactId>                <version>Dalston.RC1</version>                <type>pom</type>                <scope>import</scope>            </dependency>        </dependencies>    </dependencyManagement>    <!-- maven插件 -->    <build>        <plugins>            <plugin>                <groupId>org.springframework.boot</groupId>                <artifactId>spring-boot-maven-plugin</artifactId>            </plugin>        </plugins>    </build>            <repositories>        <repository>            <id>spring-milestones</id>            <name>Spring Milestones</name>            <url>https://repo.spring.io/milestone</url>            <snapshots>                <enabled>false</enabled>            </snapshots>        </repository>    </repositories>  </project>

(2)建立resources/application.yml文件

eureka:  client:    serviceUrl:      defaultZone: http://localhost:8761/eureka/server:  port: 8765spring:  application:    name: RIBBON_SERVERCONSUMER_TEST
指明服务注册中心/消费者程序端口/消费者程序名称

(3)启动类

package com.tyf.ribbon_test;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.web.client.RestTemplate;/* *1.@SpringBootApplication: *2.@EnableDiscoveryClient:向服务中心注册 *3.@Bean:向程序ioc中注入一个bean(方法返回值就是这个bean) *4.@LoadBalanced:方法开启负载均衡功能 *5.restTemplate(): * * */@SpringBootApplication@EnableDiscoveryClientpublic class App {public static void main(String[] args) {        SpringApplication.run(App.class, args);    }    @Bean    @LoadBalanced    RestTemplate restTemplate() {        return new RestTemplate();    }}
可以看到,启动类通过bean注解向程序ioc注入一个restTemplate对象,这个对象可以用来调用其他服务(见下面的service),通过@LocalBalanced开启负载均衡

(4)Service

package com.tyf.ribbon_test;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import org.springframework.web.client.RestTemplate;/* * 1.@Service: * 2.@Autowired:向ioc获取一个bean * 3.RestTemplate restTemplate: * 这个bean是启动类中注入ioc的一个bean * 通过其getForObject发送请求调用服务方法 * (同一个服务的多个实例提供了负载均衡的功能) * 4.http://eureks-serverProvider-test/helloWorld/test: * 使用服务的名称来调用服务,后面是服务的@RequestMapping地址 *  *  */@Servicepublic class modelService {@Autowired    RestTemplate restTemplate;    public void testConsumer() {    //使用服务名称访问服务        restTemplate.getForObject("http://eureks-serverProvider-test/helloWorld/test",String.class);    }}
可以看到,通过启动类中注入的restTemplate实例来调用其他服务,同时启用负载均衡,这里使用eureks-serverProvider-test(服务名称)访问服务,helloworld/test是服务内的地址映射

(5)Controller

package com.tyf.ribbon_test;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import org.springframework.web.bind.annotation.RestController;/* *  * 访问地址:http://localhost:8765/modelController/test *  */@RestController@RequestMapping("/modelController")public class modelController {@AutowiredmodelService model_service;    @RequestMapping(value="/test",method = RequestMethod.GET)    public void test(){    model_service.testConsumer();    }}

用户使用/modelController/test访问消费者,消费者在通过service调用其他服务

3.将注册中心/两个服务/一个消费者工程全部启动

浏览器访问消费者控制器:http://localhost:8765/modelController/test
观察服务提供者的控制台(或者cmd)查看输出信息如下

访问了三次,消费者调用同一个服务三次,分别在两个服务提供者中做了负载均衡,简单实现了集群下的请求路由以及负载均衡


4.总结

(1)负载均衡的实现

其实从头到尾就是向消费者注入了一个restTemplate实例,通过这个实例实现负载均衡,在底层使用的是Ribbon实现的负载均衡,消费者将服务id先传给Ribbon,Ribbon使用负载均衡器(RestTemplate/FeignClient)获取服务实例并调用服务

(2)远程调用的返回值问题

RPC提供的是“将远程的方法像在本地一样调用”,既然如此远程方法被调用之后的方法返回值是在哪里呢?,例如上面的服务提供者和消费者中,消费者调用了服务,而服务方法返回的数据会返回到消费者手中有一个前提:服务提供者的controller和service中都是有返回值的,服务提供者的controller再将数据返回给消费者的service中,消费者service将数据返回给消费者controller。

原创粉丝点击