SpringCloud-Netflix(Usage of Ribbon)
SpringCloud有两个流派【Netflix;Alibaba】,因为现在使用多的还是Netflix这一套,所以我准备先从Netflix开始聊。当然现在很多公司也开始使用Alibaba这套,所以阿里的这套我会放在后面聊。我们知道SpringCloud就是提供了一些常用的解决方案也就是一些组件。本篇我想先从Ribbon开始聊。并且使用的还是【Hoxton.SR12】(因为在2020版本去除了很多组件,比如Hystrix、Ribbon、Zuul等。),它对应的SpringBoot版本是【2.3.12.RELEASE】。
Outline of Ribbon
因为微服务之间的调用是基于Http这种方式调用,我们是可以使用RestTemplate通过微服务之间的地址进行调用。但是,我们都清楚,微服务的出现,使得一个服务可以部署多个,那如果只是使用RestTemplate通过URL这种调用方式,无疑是特别繁琐的,如果我们自己实现对微服务的调用,我们需要考虑的东西很多,
比如:【各个微服务URL灵活的配置、负载均衡的配置、失败重试、参数可配置化、微服务的下线/扩容】那Ribbon就能为我们解决我们考虑的问题。从而完成客户端的负载均衡
Usage of Ribbon
添加Ribbon依赖
View Code<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-ribbon</artifactId> <version>2.2.9.RELEASE</version> </dependency>注入Resttemplate并且使用ribbon注解的方式(对要访问的微服务地址进行拦截和解析)
View Code@Configuration public class RestTemplateConfiguration { @LoadBalanced @Bean public RestTemplate restTemplate(){ return new RestTemplate(); } }在application中维护服务地址,以及使用的负载均衡算法类(这里使用随机的负载算法)。
View Code#微服务地址,因为一个微服务可能被部署多个,所以这个是多个地址 goods-service.ribbon.listOfServers=\ http://localhost:9090,http://localhost:9093 #负载均衡使用的类,我们这里使用随机策略 goods-service.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RandomRule注:Ribbon为我们提供了7种负载均衡的策略,以下。
- BestAvailableRule:再选择其中并发链接最低的微服务。
- ZoneAvoidanceRule:综合判微服务所在区域的性能,和微服务的可用性。
- AvailabilityFilteringRule:过滤掉一直失败并被标记为circuit tripped的微服务。
- RoundRobinRule:轮询选择微服务
- ResponseTimeWeightedRule:根据微服务的响应时间分配权重,响应时间越长,权重越低
- RandomRule:随机选择微服务
- RetryRule:重试,在配置的时间段中。
在代码中想要调用某个微服务的时候只用写在配置文件中配置的微服务名称,在Resttemplate调用之前,Ribbon会拦截请求,并且根据我们为它指定的负载均衡算法路由到我们的实际的微服务中,从而达成客户端的负载均衡。
View Code@GetMapping public String order(){ log.info("begin do order"); // 调用商品服务 String goodsInfo=restTemplate.getForObject("http://goods-service/goods",String.class); // 调用市场服务 String promotionInfo=restTemplate.getForObject("http://marking-service/promotion",String.class); MultiValueMap<String,Object> param=new LinkedMultiValueMap<>(); param.add("goodsInfo",goodsInfo); param.add("pomotionInfo",promotionInfo); HttpEntity<MultiValueMap<String,Object>> httpEntity=new HttpEntity<>(param,new HttpHeaders()); // 调用订单服务 ResponseEntity<String> response=restTemplate.postForEntity("http://order-service/order",httpEntity,String.class); return response.getBody(); }测试:我们从前端去调用我们统一的api,然后由统一的api调用我们的goods服务,发现,ribbon已经采用了随机的负载均衡机制对商品的微服务进行负载的调用。
但是,这里有个问题,当我们手动停止一个服务,模拟服务器宕机后,前端是无法感知到这个状况的,如果ribbon的请求落到了这个宕机的节点后,就发现请求失败,对于这个我们可以这样实现Ribbon中的一个【iping】接口,实现后ribbon会根据我们配置的间隔时间,对我们的微服务进行ping,从而达到了宕机转移的效果。
实现iping接口
View Codepublic class HealthChecker implements IPing { @Override public boolean isAlive(Server server) { String url="http://"+server.getId()+"/healthCheck"; boolean isAlive=true; HttpClient httpClient=new DefaultHttpClient(); HttpUriRequest request=new HttpGet(url); try { HttpResponse response = httpClient.execute(request); isAlive = response.getStatusLine().getStatusCode() == 200; }catch (Exception e){ isAlive=false; }finally { request.abort(); } return isAlive; } }在相关的微服务中提供ping的响应接口
View Code@Slf4j @RestController public class HealthController { @GetMapping("/healthCheck") public String health(){ log.info("healthCheck......"); return "SUCCESS"; } }在application中进行类的装配
View Code#实现了iping接口的类 goods-service.ribbon.NFLoadBalancerPingClassName=com.glenmall.mall.glenmallportal.HealthChecker #check的间隔时间 goods-service.ribbon.NFLoadBalancerPingInterval=3这样看起来解决了某个节点宕机的问题,但是还有一些问题比如:
- 我们现在的微服务地址都是配置在application中的,这样如果地址多的话,会造成一定的维护困难
- 如果发生了配置变化,我们依然要重启服务
也就是说,我们现在加入ribbon后有两个痛点,
- 微服务目标地址的维护
- 监测微服务的健康状态
上面Ribbon引出的问题,我们实际上通过Eureka和ribbon的配合就可以解决。所以下篇我准备聊聊Eureka。