SpringBoot實戰電商項目mall(20k+star)地址:github.com/macrozheng/…java
Spring Cloud Ribbon 是Spring Cloud Netflix 子項目的核心組件之一,主要給服務間調用及API網關轉發提供負載均衡的功能,本文將對其用法進行詳細介紹。git
在微服務架構中,不少服務都會部署多個,其餘服務去調用該服務的時候,如何保證負載均衡是個不得不去考慮的問題。負載均衡能夠增長系統的可用性和擴展性,當咱們使用RestTemplate來調用其餘服務時,Ribbon能夠很方便的實現負載均衡功能。github
RestTemplate是一個HTTP客戶端,使用它咱們能夠方便的調用HTTP接口,支持GET、POST、PUT、DELETE等方法。web
<T> T getForObject(String url, Class<T> responseType, Object... uriVariables);
<T> T getForObject(String url, Class<T> responseType, Map<String, ?> uriVariables);
<T> T getForObject(URI url, Class<T> responseType);
<T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Object... uriVariables);
<T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Map<String, ?> uriVariables);
<T> ResponseEntity<T> getForEntity(URI var1, Class<T> responseType);
複製代碼
返回對象爲響應體中數據轉化成的對象,舉例以下:算法
@GetMapping("/{id}")
public CommonResult getUser(@PathVariable Long id) {
return restTemplate.getForObject(userServiceUrl + "/user/{1}", CommonResult.class, id);
}
複製代碼
返回對象爲ResponseEntity對象,包含了響應中的一些重要信息,好比響應頭、響應狀態碼、響應體等,舉例以下:spring
@GetMapping("/getEntityByUsername")
public CommonResult getEntityByUsername(@RequestParam String username) {
ResponseEntity<CommonResult> entity = restTemplate.getForEntity(userServiceUrl + "/user/getByUsername?username={1}", CommonResult.class, username);
if (entity.getStatusCode().is2xxSuccessful()) {
return entity.getBody();
} else {
return new CommonResult("操做失敗", 500);
}
}
複製代碼
<T> T postForObject(String url, @Nullable Object request, Class<T> responseType, Object... uriVariables);
<T> T postForObject(String url, @Nullable Object request, Class<T> responseType, Map<String, ?> uriVariables);
<T> T postForObject(URI url, @Nullable Object request, Class<T> responseType);
<T> ResponseEntity<T> postForEntity(String url, @Nullable Object request, Class<T> responseType, Object... uriVariables);
<T> ResponseEntity<T> postForEntity(String url, @Nullable Object request, Class<T> responseType, Map<String, ?> uriVariables);
<T> ResponseEntity<T> postForEntity(URI url, @Nullable Object request, Class<T> responseType);
複製代碼
@PostMapping("/create")
public CommonResult create(@RequestBody User user) {
return restTemplate.postForObject(userServiceUrl + "/user/create", user, CommonResult.class);
}
複製代碼
@PostMapping("/create")
public CommonResult create(@RequestBody User user) {
return restTemplate.postForEntity(userServiceUrl + "/user/create", user, CommonResult.class).getBody();
}
複製代碼
void put(String url, @Nullable Object request, Object... uriVariables);
void put(String url, @Nullable Object request, Map<String, ?> uriVariables);
void put(URI url, @Nullable Object request);
複製代碼
@PutMapping("/update")
public CommonResult update(@RequestBody User user) {
restTemplate.put(userServiceUrl + "/user/update", user);
return new CommonResult("操做成功",200);
}
複製代碼
void delete(String url, Object... uriVariables);
void delete(String url, Map<String, ?> uriVariables);
void delete(URI url);
複製代碼
@DeleteMapping("/delete/{id}")
public CommonResult delete(@PathVariable Long id) {
restTemplate.delete(userServiceUrl + "/user/delete/{1}", null, id);
return new CommonResult("操做成功",200);
}
複製代碼
首先咱們建立一個user-service,用於給Ribbon提供服務調用。架構
<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-web</artifactId>
</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類定義了對User對象常見的CRUD接口。app
/** * Created by macro on 2019/8/29. */
@RestController
@RequestMapping("/user")
public class UserController {
private Logger LOGGER = LoggerFactory.getLogger(this.getClass());
@Autowired
private UserService userService;
@PostMapping("/create")
public CommonResult create(@RequestBody User user) {
userService.create(user);
return new CommonResult("操做成功", 200);
}
@GetMapping("/{id}")
public CommonResult<User> getUser(@PathVariable Long id) {
User user = userService.getUser(id);
LOGGER.info("根據id獲取用戶信息,用戶名稱爲:{}",user.getUsername());
return new CommonResult<>(user);
}
@GetMapping("/getUserByIds")
public CommonResult<List<User>> getUserByIds(@RequestParam List<Long> ids) {
List<User> userList= userService.getUserByIds(ids);
LOGGER.info("根據ids獲取用戶信息,用戶列表爲:{}",userList);
return new CommonResult<>(userList);
}
@GetMapping("/getByUsername")
public CommonResult<User> getByUsername(@RequestParam String username) {
User user = userService.getByUsername(username);
return new CommonResult<>(user);
}
@PostMapping("/update")
public CommonResult update(@RequestBody User user) {
userService.update(user);
return new CommonResult("操做成功", 200);
}
@PostMapping("/delete/{id}")
public CommonResult delete(@PathVariable Long id) {
userService.delete(id);
return new CommonResult("操做成功", 200);
}
}
複製代碼
這裏咱們建立一個ribbon-service模塊來調用user-service模塊演示負載均衡的服務調用。負載均衡
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
複製代碼
主要是配置了端口、註冊中心地址及user-service的調用路徑。
server:
port: 8301
spring:
application:
name: ribbon-service
eureka:
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://localhost:8001/eureka/
service-url:
user-service: http://user-service
複製代碼
能夠看出使用Ribbon的負載均衡功能很是簡單,和直接使用RestTemplate沒什麼兩樣,只需給RestTemplate添加一個@LoadBalanced便可。
/** * Created by macro on 2019/8/29. */
@Configuration
public class RibbonConfig {
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
複製代碼
注入RestTemplate,使用其調用user-service中提供的相關接口,這裏對GET和POST調用進行了演示,其餘方法調用都可參考。
/** * Created by macro on 2019/8/29. */
@RestController
@RequestMapping("/user")
public class UserRibbonController {
@Autowired
private RestTemplate restTemplate;
@Value("${service-url.user-service}")
private String userServiceUrl;
@GetMapping("/{id}")
public CommonResult getUser(@PathVariable Long id) {
return restTemplate.getForObject(userServiceUrl + "/user/{1}", CommonResult.class, id);
}
@GetMapping("/getByUsername")
public CommonResult getByUsername(@RequestParam String username) {
return restTemplate.getForObject(userServiceUrl + "/user/getByUsername?username={1}", CommonResult.class, username);
}
@GetMapping("/getEntityByUsername")
public CommonResult getEntityByUsername(@RequestParam String username) {
ResponseEntity<CommonResult> 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 CommonResult create(@RequestBody User user) {
return restTemplate.postForObject(userServiceUrl + "/user/create", user, CommonResult.class);
}
@PostMapping("/update")
public CommonResult update(@RequestBody User user) {
return restTemplate.postForObject(userServiceUrl + "/user/update", user, CommonResult.class);
}
@PostMapping("/delete/{id}")
public CommonResult delete(@PathVariable Long id) {
return restTemplate.postForObject(userServiceUrl + "/user/delete/{1}", null, CommonResult.class, id);
}
}
複製代碼
ribbon:
ConnectTimeout: 1000 #服務請求鏈接超時時間(毫秒)
ReadTimeout: 3000 #服務請求處理超時時間(毫秒)
OkToRetryOnAllOperations: true #對超時請求啓用重試機制
MaxAutoRetriesNextServer: 1 #切換重試實例的最大個數
MaxAutoRetries: 1 # 切換實例後重試最大次數
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule #修改負載均衡算法
複製代碼
與全局配置的區別就是ribbon節點掛在服務名稱下面,以下是對ribbon-service調用user-service時的單獨配置。
user-service:
ribbon:
ConnectTimeout: 1000 #服務請求鏈接超時時間(毫秒)
ReadTimeout: 3000 #服務請求處理超時時間(毫秒)
OkToRetryOnAllOperations: true #對超時請求啓用重試機制
MaxAutoRetriesNextServer: 1 #切換重試實例的最大個數
MaxAutoRetries: 1 # 切換實例後重試最大次數
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule #修改負載均衡算法
複製代碼
所謂的負載均衡策略,就是當A服務調用B服務時,此時B服務有多個實例,這時A服務以何種方式來選擇調用的B實例,ribbon能夠選擇如下幾種負載均衡策略。
springcloud-learning
├── eureka-server -- eureka註冊中心
├── user-service -- 提供User對象CRUD接口的服務
└── ribbon-service -- ribbon服務調用測試服務
複製代碼
mall項目全套學習教程連載中,關注公衆號第一時間獲取。