spring-cloud-eureka 与 Ribbon负载均衡(二)

梦里梦外; 2022-01-06 07:47 302阅读 0赞

Ribbon简单介绍

1、 Ribbon主要提供客户端的软件负载均衡算法(说白了就是排队的时候哪个队伍人少就排哪)。

2、Ribbon客户端组件提供一系列完善的配置项如何连接超时、重试等。

3、负载均衡的算法可以自定义。

搭建环境

我这里搭建的是eureka的集群,可以使用单机版的配置就可以了,这里就讲一下如何搭建和配置单机版的Eureka,不会搭集群或是想要搭的铁汁儿点这里:https://blog.csdn.net/qq_41647999/article/details/93382252

Eureka的环境搭建与配置

新建一个maven的模块,如下:

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQxNjQ3OTk5_size_16_color_FFFFFF_t_70

POM.xml

这里注意:引入的eureka记得加上版本,可以再项目的主POM里面加了引入一下,还有就是需要引入熔断器,可能是eureka的高版本要求的。

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5. <parent>
  6. <artifactId>microservice</artifactId>
  7. <groupId>com.djun.demo</groupId>
  8. <version>1.0-SNAPSHOT</version>
  9. </parent>
  10. <modelVersion>4.0.0</modelVersion>
  11. <packaging>jar</packaging>
  12. <artifactId>demo-eureka-7001</artifactId>
  13. <version>${project.version}</version>
  14. <dependencies>
  15. <!-- Eureka -->
  16. <dependency>
  17. <groupId>org.springframework.cloud</groupId>
  18. <artifactId>spring-cloud-netflix-eureka-server</artifactId>
  19. <!--<version>2.2.0.BUILD-SNAPSHOT</version>-->
  20. </dependency>
  21. <dependency>
  22. <groupId>org.springframework.cloud</groupId>
  23. <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
  24. </dependency>
  25. </dependencies>
  26. </project>

EurekaServer7001_App.java

  1. import org.springframework.boot.SpringApplication;
  2. import org.springframework.boot.autoconfigure.SpringBootApplication;
  3. import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
  4. @SpringBootApplication
  5. // 标注这是EurekaServer服务启动类,接收其它微服务注册进来
  6. @EnableEurekaServer
  7. public class EurekaServer7001_App {
  8. public static void main(String[] args) {
  9. SpringApplication.run(EurekaServer7001_App.class,args);
  10. }
  11. }

application.yml

  1. server:
  2. port: 7001
  3. eureka:
  4. instance:
  5. # eureka服务端的实例名称
  6. hostname: localhost
  7. client:
  8. #false表示不向注册中心注册自己。
  9. register-with-eureka: false
  10. #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务
  11. fetch-registry: false
  12. service-url:
  13. #设置与Eureka Server交互的地址查询服务和注册服务都需要依赖这个地址(单机版)。
  14. defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

微服务提供模块的搭建

这个模块主要是用来提供api,我这里主要是在搭架子,数据库只有一张表:

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQxNjQ3OTk5_size_16_color_FFFFFF_t_70 1

接口也就是对这张表的增删改查,这里的代码不是重点就不写出来了,关键是一些配置信息问题请看下方。

值得强调的是,这个是一个微服务需要作为Eureka的客户端向Eureka服务端注册:

启动类:DemoProvider8001_App.java

  1. import org.springframework.boot.SpringApplication;
  2. import org.springframework.boot.autoconfigure.SpringBootApplication;
  3. import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
  4. import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
  5. /**
  6. * created by DJun on 2019/6/20
  7. */
  8. @SpringBootApplication
  9. // 服务启动之后自动注册进入Eureka
  10. @EnableEurekaClient
  11. // 服务发现
  12. @EnableDiscoveryClient
  13. public class DemoProvider8001_App {
  14. // 启动嵌入式的 Tomcat 并初始化 Spring 环境及其各 Spring 组件
  15. public static void main(String[] args) {
  16. SpringApplication.run(DemoProvider8001_App.class,args);
  17. }
  18. }

application.yml

微服务注册进入Eureka的配置如下

  1. eureka:
  2. client:
  3. #客户端注册进eureka服务列表内
  4. service-url:
  5. # 1、单机版配置
  6. defaultZone: http://localhost:7001/eureka/
  7. # 2、集群版配置
  8. # defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
  9. instance:
  10. # 服务名称修改
  11. instance-id: demo-provider-8001
  12. # 设置访问信息有IP 信息提示
  13. prefer-ip-address: true
  14. # info是当前微服务的信息
  15. info:
  16. app.name: microservice-demo
  17. company.name: com.djun.demo
  18. build.artifactId: $project.artifactId$
  19. build.version: $project.version$

ribbon客户端的搭建

其实,ribbon的使用很简单,但是原理不容易学。这里再配置文件里面加上一个 @LoadBalanced 即可开启ribbon的负载均衡,ribbon也提供了很多种负载均衡的算法,在他们的GitHub上可以找到算法的源码,也可以自定义算法,下面我将举一个demo如何自定义负载均衡的算法(建议配置成集群版的eureka)。

客户端也需要注册进入Eureka,新建一个maven模块如下:

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQxNjQ3OTk5_size_16_color_FFFFFF_t_70 2

ConfigBean.java

  1. import com.netflix.loadbalancer.*;
  2. import org.springframework.cloud.client.loadbalancer.LoadBalanced;
  3. import org.springframework.context.annotation.Bean;
  4. import org.springframework.context.annotation.Configuration;
  5. import org.springframework.web.client.RestTemplate;
  6. @Configuration
  7. public class ConfigBean {
  8. @Bean
  9. //开启负载均衡
  10. @LoadBalanced
  11. public RestTemplate restTemplate(){
  12. return new RestTemplate();
  13. }
  14. @Bean
  15. public IRule myRule(){
  16. // 根据平均响应的时间计算所有服务的权重,响应时间越快服务权重越大被选中的概率越高
  17. // return new WeightedResponseTimeRule();
  18. // 自定义的算法类
  19. return new CustomizedRule();
  20. }
  21. }

CustomizedRule.java

  1. import com.netflix.client.config.IClientConfig;
  2. import com.netflix.loadbalancer.AbstractLoadBalancerRule;
  3. import com.netflix.loadbalancer.ILoadBalancer;
  4. import com.netflix.loadbalancer.Server;
  5. import java.util.List;
  6. /**
  7. * created by DJun on 2019/6/27
  8. * 每个微服务访问5次 再轮询
  9. */
  10. public class CustomizedRule extends AbstractLoadBalancerRule {
  11. private int callTotal = 0; // 总共被调用的次数,目前要求每台被调用5次
  12. private int currentIndex = 0; // 当前提供服务的机器号
  13. public Server choose(ILoadBalancer lb, Object key) {
  14. if (lb == null) {
  15. return null;
  16. }
  17. Server server = null;
  18. while (server == null) {
  19. if (Thread.interrupted()) {
  20. return null;
  21. }
  22. // 获取正常工作的微服务
  23. List<Server> upList = lb.getReachableServers();
  24. // 获取全部的微服务
  25. List<Server> allList = lb.getAllServers();
  26. // 微服务总数
  27. int serverCount = allList.size();
  28. if (serverCount == 0) {
  29. return null;
  30. }
  31. // 当前微服务使用未满5次
  32. if (callTotal < 5) {
  33. server = upList.get(currentIndex);
  34. callTotal++;
  35. } else { // 已满5次,换下一台微服务
  36. callTotal = 0;
  37. currentIndex++;
  38. // 如果微服务的机器超过了最后一台,再轮询
  39. if (currentIndex >= upList.size()) {
  40. currentIndex = 0;
  41. }
  42. }
  43. if (server == null) {
  44. // 服务为空(比如某台服务挂掉了)则让其它的现成先进行
  45. Thread.yield();
  46. continue;
  47. }
  48. if (server.isAlive()) {
  49. return (server);
  50. }
  51. server = null;
  52. Thread.yield();
  53. }
  54. return server;
  55. }
  56. @Override
  57. public Server choose(Object key) {
  58. return choose(getLoadBalancer(), key);
  59. }
  60. @Override
  61. public void initWithNiwsConfig(IClientConfig clientConfig) {
  62. }
  63. }

DeptController_Consumer.java

这里用了一个 RestTemplate 将Controller的api在进一次封装隐藏,解释见注释:

  1. import com.djun.demo.model.Dept;
  2. import org.springframework.web.bind.annotation.GetMapping;
  3. import org.springframework.web.bind.annotation.PathVariable;
  4. import org.springframework.web.bind.annotation.RequestMapping;
  5. import org.springframework.web.bind.annotation.RestController;
  6. import org.springframework.web.client.RestTemplate;
  7. import javax.annotation.Resource;
  8. import java.util.List;
  9. /**
  10. * created by DJun on 2019/6/22
  11. */
  12. @RestController
  13. public class DeptController_Consumer {
  14. /**
  15. * 1、RestTemplate 类似于 JDBCTemplate
  16. * 2、Controller 通过RestTemplate来对Rest的调用和发出
  17. * 3、参数: (url, requestMap, ResponseBean.class)
  18. * url: REST 请求地址
  19. * requestMap:请求参数
  20. * ResponseBean.class: HTTP响应转换被转换成的对象类型
  21. *
  22. */
  23. @Resource
  24. private RestTemplate restTemplate;
  25. // 访问微服务提供者的端口地址
  26. // private static final String REST_URL_PREFIX = "http://localhost:8001";
  27. // 微服务提供者的名称
  28. private static final String REST_URL_PREFIX = "http://MICROSERVICE-DEMO";
  29. @RequestMapping("/consumer/dept/add")
  30. public boolean add(Dept dept){
  31. return restTemplate.postForObject(REST_URL_PREFIX+"/dept/add",dept,Boolean.class);
  32. }
  33. @SuppressWarnings("unchecked")
  34. @RequestMapping("/consumer/dept/findById/{id}")
  35. public List<Dept> findById(@PathVariable("id") Long id){
  36. return restTemplate.getForObject(REST_URL_PREFIX+"/dept/findById/"+id,List.class);
  37. }
  38. @SuppressWarnings("unchecked")
  39. @RequestMapping("/consumer/dept/list")
  40. public List<Dept> findAll(){
  41. return restTemplate.getForObject(REST_URL_PREFIX+"/dept/list",List.class);
  42. }
  43. @GetMapping("/consumer/discovery")
  44. public Object discovery(){
  45. return restTemplate.getForObject(REST_URL_PREFIX+"/discovery",Object.class);
  46. }
  47. }

启动类

  1. import com.djun.demo.cfgbeans.ConfigBean;
  2. import org.springframework.boot.SpringApplication;
  3. import org.springframework.boot.autoconfigure.SpringBootApplication;
  4. import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
  5. import org.springframework.cloud.netflix.ribbon.RibbonClient;
  6. @SpringBootApplication
  7. @EnableEurekaClient
  8. //@EnableDiscoveryClient
  9. // 加载自定的Ribbon配置类
  10. @RibbonClient(name = "MICROSERVICE-DEMO",configuration = ConfigBean.class)
  11. public class DeptConsumer80_App {
  12. public static void main(String[] args) {
  13. SpringApplication.run(DeptConsumer80_App.class,args);
  14. }
  15. }

再次访问接口的时候就要使用消费者模块的80端口。

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQxNjQ3OTk5_size_16_color_FFFFFF_t_70 3

发表评论

表情:
评论列表 (有 0 条评论,302人围观)

还没有评论,来说两句吧...

相关阅读

    相关 负载均衡Ribbon

    1. Feign 默认集成了 Ribbon Feign 是一个声明式的伪 Http 客户端,它使得写 Http 客户端变得更简单。使用 Feign,只需要创建一个接口并注

    相关 负载均衡---ribbon

    Ribbon:提供云端负载均衡,有多种负载均衡策略可供选择,可配合服务发现和断路器使用。 上一篇简单讲解了eureka的使用,这一篇文章基于上一篇的基础上,讲一下spring

    相关 eurekaribbon负载均衡

    接着上一篇博文,看下ribbon的负载均衡 重点,ribbon的负载均衡功能 改造上一篇博文的内容,服务注册中心的端口号修改为5550 服务提供者,修改端口号为5551,

    相关 Ribbon负载均衡

    1. 集中式负载均衡 > 在客户端和服务端之间使用独立的负载均衡设施(可以是硬件,如F5, 也可以是软件,如nginx、LVS等), 由该设施负责把访问请求通过某种策略转发