SpringBoot實戰電商項目mall(20k+star)地址: https://github.com/macrozheng/mall
Spring Cloud Ribbon 是Spring Cloud Netflix 子項目的核心組件之一,主要給服務間調用及API網關轉發提供負載均衡的功能,本文將對其用法進行詳細介紹。java
在微服務架構中,不少服務都會部署多個,其餘服務去調用該服務的時候,如何保證負載均衡是個不得不去考慮的問題。負載均衡能夠增長系統的可用性和擴展性,當咱們使用RestTemplate來調用其餘服務時,Ribbon能夠很方便的實現負載均衡功能。git
RestTemplate是一個HTTP客戶端,使用它咱們能夠方便的調用HTTP接口,支持GET、POST、PUT、DELETE等方法。
<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);
返回對象爲響應體中數據轉化成的對象,舉例以下:github
@GetMapping("/{id}") public CommonResult getUser(@PathVariable Long id) { return restTemplate.getForObject(userServiceUrl + "/user/{1}", CommonResult.class, id); }
返回對象爲ResponseEntity對象,包含了響應中的一些重要信息,好比響應頭、響應狀態碼、響應體等,舉例以下:web
@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接口。
/** * 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服務調用測試服務
https://github.com/macrozheng/springcloud-learning算法
mall項目全套學習教程連載中,關注公衆號第一時間獲取。spring