Spring Cloud Ribbon:负载均衡的服务调用

关注“蛋皮皮”,公众号回复“666”获取独家整理的学习视频资料!

Ribbon简介

? ? ? ?简单的说,Ribbon 是 Netflix 发布的开源项目,主要功能是提供客户端的软件负载均衡算法,将 Netflix 的中间层服务连接在一起。Ribbon 客户端组件提供一系列完善的配置项如连接超时,重试等。简单的说,就是在配置文件中列出Load Balancer(简称LB)后面所有的机器,Ribbon 会自动的帮助你基于某种规则(如简单轮询,随机连接等)去连接这些机器。我们也很容易使用 Ribbon 实现自定义的负载均衡算法。

RestTemplate的使用

RestTemplate是一个HTTP客户端,使用它我们可以方便的调用HTTP接口,支持GET、POST、PUT、DELETE等方法。

GET请求方法

T getForObject(String url, Class responseType, Object... uriVariables);

T getForObject(String url, Class responseType, Map uriVariables);

T getForObject(URI url, Class responseType);

ResponseEntitygetForEntity(String url, Class responseType, Object... uriVariables);

ResponseEntitygetForEntity(String url, Class responseType, Map uriVariables);

ResponseEntitygetForEntity(URI var1, Class responseType);

getForObject方法

@GetMapping("/{id}")

public CommonResultgetUser(@PathVariable Long id) {

return restTemplate.getForObject(userServiceUrl +"/user/{1}", CommonResult.class, id);

}

getForEntity方法

//返回对象为ResponseEntity对象,包含了响应中的一些重要信息,比如响应头、响应状态码、响应体等

@GetMapping("/getEntityByUsername")

public CommonResultgetEntityByUsername(@RequestParam String username) {

ResponseEntity entity = restTemplate.getForEntity(userServiceUrl +"/user/getByUsername?username={1}", CommonResult.class, username);

? ? if (entity.getStatusCode().is2xxSuccessful()) {

return entity.getBody();

? ? }else {

return new CommonResult("操作失败", 500);

? ? }

}

POST请求方法

T postForObject(String url, @Nullable Object request, Class responseType, Object... uriVariables);

T postForObject(String url, @Nullable Object request, Class responseType, Map uriVariables);

T postForObject(URI url, @Nullable Object request, Class responseType);

ResponseEntitypostForEntity(String url, @Nullable Object request, Class responseType, Object... uriVariables);

ResponseEntitypostForEntity(String url, @Nullable Object request, Class responseType, Map uriVariables);

ResponseEntitypostForEntity(URI url, @Nullable Object request, Class responseType);

postForObject示例

@PostMapping("/create")

public CommonResultcreate(@RequestBody User user) {

return restTemplate.postForObject(userServiceUrl +"/user/create", user, CommonResult.class);

}

postForEntity示例

@PostMapping("/create")

public CommonResultcreate(@RequestBody User user) {

return restTemplate.postForEntity(userServiceUrl +"/user/create", user, CommonResult.class).getBody();

}

PUT请求方法

void put(String url, @Nullable Object request, Object... uriVariables);

void put(String url, @Nullable Object request, Map uriVariables);

void put(URI url, @Nullable Object request);

PUT请求示例

@PutMapping("/update")

public CommonResultupdate(@RequestBody User user) {

restTemplate.put(userServiceUrl +"/user/update", user);

? ? return new CommonResult("操作成功",200);

}

DELETE请求方法

void delete(String url, Object... uriVariables);

void delete(String url, Map uriVariables);

void delete(URI url);

DELETE请求示例

@DeleteMapping("/delete/{id}")

public CommonResultdelete(@PathVariable Long id) {

restTemplate.delete(userServiceUrl +"/user/delete/{1}", null, id);

? ? return new CommonResult("操作成功",200);

}

创建user-service???/p>

用来给ribbon提供服务,添加依赖

? <groupId>org.springframework.cloud

? <artifactId>spring-cloud-starter-netflix-eureka-client

? <groupId>org.springframework.boot

? <artifactId>spring-boot-starter-web

</dependency>

添加配置文件

server:

port:8201

spring:

application:

name: user-service

eureka:

client:

register-with-eureka: true

fetch-registry: true

service-url:

defaultZone: http://localhost:8001/eureka/

添加userController常用接口

package com.macro.cloud.controller;

import com.macro.cloud.domain.CommonResult;

import com.macro.cloud.domain.User;

import com.macro.cloud.service.UserService;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.web.bind.annotation.*;

import java.util.List;

/**

* Created by danpipi.

*/

@RestController

@RequestMapping("/user")

public class UserController {

private LoggerLOGGER = LoggerFactory.getLogger(this.getClass());

? ? @Autowired

? ? private UserServiceuserService;

? ? @PostMapping("/create")

public CommonResultcreate(@RequestBody User user) {

userService.create(user);

? ? ? ? return new CommonResult("操作成功", 200);

? ? }

@GetMapping("/{id}")

public CommonResultgetUser(@PathVariable Long id) {

User user =userService.getUser(id);

? ? ? ? LOGGER.info("根据id获取用户信息,用户名称为:{}",user.getUsername());

? ? ? ? return new CommonResult<>(user);

? ? }

@GetMapping("/getUserByIds")

public CommonResult>getUserByIds(@RequestParam List ids) {

List userList=userService.getUserByIds(ids);

? ? ? ? LOGGER.info("根据ids获取用户信息,用户列表为:{}",userList);

? ? ? ? return new CommonResult<>(userList);

? ? }

@GetMapping("/getByUsername")

public CommonResultgetByUsername(@RequestParam String username) {

User user =userService.getByUsername(username);

? ? ? ? return new CommonResult<>(user);

? ? }

@PostMapping("/update")

public CommonResultupdate(@RequestBody User user) {

userService.update(user);

? ? ? ? return new CommonResult("操作成功", 200);

? ? }

@PostMapping("/delete/{id}")

public CommonResultdelete(@PathVariable Long id) {

userService.delete(id);

? ? ? ? return new CommonResult("操作成功", 200);

? ? }

}

创建ribbon-service???,调用user-service??槭迪指涸鼐猓砑右览?/p>

? <groupId>org.springframework.boot

? <artifactId>spring-boot-starter-web

? <groupId>org.springframework.cloud

? <artifactId>spring-cloud-starter-netflix-eureka-client

? <groupId>org.springframework.cloud

? <artifactId>spring-cloud-starter-netflix-ribbon

</dependency>

配置文件

server:

port:8301

spring:

application:

name: ribbon-serviceeureka:

client:

register-with-eureka:true

? ? fetch-registry:true

? ? service-url:

defaultZone: http://localhost:8001/eureka/

service-url:

user-service: http://user-service

@LoadBalanced注解可以提供RestTemplate负载均衡

package com.macro.cloud.config;

import org.springframework.cloud.client.loadbalancer.LoadBalanced;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

import org.springframework.web.client.RestTemplate;

/**

* Created by 蛋皮皮 on 2020/8/29.

*/

@Configuration

public class RibbonConfig {

@Bean

@LoadBalanced

? ? public RestTemplaterestTemplate(){

return new RestTemplate();

? ? }

}

UserRibbonController

package com.macro.cloud.controller;

import com.macro.cloud.domain.CommonResult;

import com.macro.cloud.domain.User;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.beans.factory.annotation.Value;

import org.springframework.http.ResponseEntity;

import org.springframework.web.bind.annotation.*;

import org.springframework.web.client.RestTemplate;

/**

* Created by 蛋皮皮 on 2020/8/29.

*/

@RestController

@RequestMapping("/user")

public class UserRibbonController {

@Autowired

? ? private RestTemplaterestTemplate;

? ? @Value("${service-url.user-service}")

private StringuserServiceUrl;

? ? @GetMapping("/{id}")

public CommonResultgetUser(@PathVariable Long id) {

return restTemplate.getForObject(userServiceUrl +"/user/{1}", CommonResult.class, id);

? ? }

@GetMapping("/getByUsername")

public CommonResultgetByUsername(@RequestParam String username) {

return restTemplate.getForObject(userServiceUrl +"/user/getByUsername?username={1}", CommonResult.class, username);

? ? }

@GetMapping("/getEntityByUsername")

public CommonResultgetEntityByUsername(@RequestParam String username) {

ResponseEntity entity =restTemplate.getForEntity(userServiceUrl +"/user/getByUsername?username={1}", CommonResult.class, username);

? ? ? ? if (entity.getStatusCode().is2xxSuccessful()) {

return entity.getBody();

? ? ? ? }else {

return new CommonResult("操作失败", 500);

? ? ? ? }

}

@PostMapping("/create")

public CommonResultcreate(@RequestBody User user) {

return restTemplate.postForObject(userServiceUrl +"/user/create", user, CommonResult.class);

? ? }

@PostMapping("/update")

public CommonResultupdate(@RequestBody User user) {

return restTemplate.postForObject(userServiceUrl +"/user/update", user, CommonResult.class);

? ? }

@PostMapping("/delete/{id}")

public CommonResultdelete(@PathVariable Long id) {

return restTemplate.postForObject(userServiceUrl +"/user/delete/{1}", null, CommonResult.class, id);

? ? }

}

启动后调用接口测试http://localhost:8301/user/1

Ribbon的常用配置

#全局配置

ribbon:

ConnectTimeout: 1000 #服务请求连接超时时间(毫秒)

ReadTimeout: 3000 #服务请求处理超时时间(毫秒)

OkToRetryOnAllOperations: true #对超时请求启用重试机制

MaxAutoRetriesNextServer: 1 #切换重试实例的最大个数

MaxAutoRetries: 1 #切换实例后重试最大次数

NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule #修改负载均衡算法

指定服务配置

user-service:

ribbon:

ConnectTimeout: 1000 #服务请求连接超时时间(毫秒)

? ReadTimeout: 3000 #服务请求处理超时时间(毫秒)

? OkToRetryOnAllOperations: true #对超时请求启用重试机制

? MaxAutoRetriesNextServer: 1 #切换重试实例的最大个数

? MaxAutoRetries: 1 #切换实例后重试最大次数

? NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule #修改负载均衡算法

使用到的???/p>

springcloud-learning

├── eureka-server -- eureka注册中心

├── user-service --提供User对象CRUD接口的服务

└── ribbon-service -- ribbon服务调用测试服务

?著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,029评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,238评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事?!?“怎么了?”我有些...
    开封第一讲书人阅读 159,576评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,214评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,324评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,392评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,416评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,196评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,631评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,919评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,090评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,767评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,410评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,090评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,328评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,952评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,979评论 2 351

推荐阅读更多精彩内容