zoukankan      html  css  js  c++  java
  • 实现负载均衡的两种方式

    Load Balancing,即负载均衡, 是一种计算机技术,用来在多个计算机(计算机集群)、网络连接、CPU、磁盘驱动器或其他资源中分配负载,以达到最优化资源使用、最大化吞吐率、最小化响应时间、同时避免过载的目的。

    实现负载均衡的两大方式:

    一、服务端负载均衡:Nginx实现负载均衡

    负载均衡是Nginx常用的一个功能,是在服务端通过的负载均衡算法实现的,Nginx也要具有很多不同的负载均衡策略。负载均衡的意思是将请求分摊到不同的服务器上执行,例如:web服务器、企业内部服务器等等,这样可以提高系统的吞吐量和请求的响应速度。

    常见的负载均衡算法有三策略(这里只挑选三种来说明):

    1. 轮询(默认)
    #每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器down掉,能自动剔除
    
    upstream test {
            server localhost:8080;
            server localhost:8081;
    }
    
    server {
      listen       8081;                                                         
      server_name  localhost;                                               
      client_max_body_size 1024M;
    
      location / {
        proxy_pass http://test;
        proxy_set_header Host $host:$server_port;
      }
    }

    这里模拟了两台tomcat服务器,采用不同的端口8080、8081,当两台服务器之间有一个服务器处于不能访问的状态(服务器挂了),请求就不会打到该服务器,所有避免了一台服务器挂了而直接影响到整个系统业务不能正常使用的情况,由于Nginx默认是采用RR策略,所有不需要替他更多的配置。

    2. 权重

    #指定轮询几率,weight和访问比率成正比,用于后端服务器性能不均的情况upstream test {
            server localhost:8080 weight=8;
            server localhost:8081 weight=2;
    }
    1. ip_hash
    upstream test {
        ip_hash;
        server localhost:8080;
        server localhost:8081;
    }

    二、客户端负载均衡:手写负载均衡算法实现负载均衡

    假设现在有用户中心服务 user-center 和内容中心 content-center 服务,内容中心需要调用用户中心的端口服务,由于在并发较高的环境下,这是要在内容中心(客户端)实现一个负载均衡算法来实现调用user-center(服务端)服务,如何手写一个负载均衡算法来实现呢?

    ShareController

    @RestController
    @RequestMapping("/shares")
    public class ShareController {
    
        @Autowired
        private ShareService shareService;
    
        @GetMapping("/{id}")
        public ShareDTO findById(@PathVariable Integer id) {
            return this.shareService.findById(id);
        }
    }

    ShareServiceImpl

    
    @Slf4j
    @Service
    public class ShareServiceImpl implements ShareService {
    
        @Autowired
        private ShareMapper shareMapper;
    
        @Autowired
        private RestTemplate restTemplate;
    
        @Autowired
        private DiscoveryClient discoveryClient;
    
    
        @Override
        public ShareDTO findById(Integer id) {
            //1.获取分享详情
            Share share = shareMapper.selectByPrimaryKey(id);
            //2.发布人的id
            Integer userId = share.getUserId();
            //拿到用户中心所有实例的信息
            List<ServiceInstance> instances = discoveryClient.getInstances("user-center");
            //获取所有用户中心实例请求地址
            List<String> targetUrls = instances.stream()
                    .map(instance -> instance.getUri().toString() + "/users/1")
                    .collect(Collectors.toList());
            //设计随机算法,随机生成i
            int i = ThreadLocalRandom.current().nextInt(targetUrls.size());
    
            String targetUrl = targetUrls.get(i);
            log.info("请求目标地址:{}", targetUrl);
    
            //调用用户微服务的/users/{userId}?使用RestTemplate,RestTemplate会帮我们自动转换成UserDTO
            UserDTO userDTO = this.restTemplate.getForObject(
                    "http://user-center/users/1",
                    UserDTO.class);
            //3.消息的装配
            ShareDTO shareDTO = new ShareDTO();
            BeanUtils.copyProperties(share, shareDTO);
            shareDTO.setWxNickname(userDTO.getWxNickname());
    
            return shareDTO;
        }
    
    }
    

    我们通过log打印出请求目标地址如下,我们可以清楚的看到分别打到8080、8081端口,实现了客户端的负载均衡:

    三、使用Spring Cloud Ribbon实现负载均衡

    Ribbon组成

    Ribbon是比较灵活的,它对所有的组件值都提供了接口,如果你对这些值不满意,你可以基于Ribbon的接口自定义来实现。

    接口    作用 默认值
    IClientConfig 服务配置 DefaultClientConfigImpl
    IRule 负载均衡规则,选择实例 ZoneAvoidanceRule
    IPing 筛选掉ping不通的实例 DumyPing(该类什么不干,认为每个实例都可用,都能ping通)
    ServerList 交给Ribbon的实例列表 Ribbon:ConfigurationBasedServerList
    Spring Cloud Alibaba:NacosServerList
    ServerListFilter 过滤掉不符合条件的实例 ZonePreferenceServerListFilter                                     
    ILoadBalancer Ribbon负载均衡的入口 ZoneAwareLoadBalancer
    ServerListUpdater 更新交给Ribbon的List的策略 PollingServerListUpdater

    Ribbon八大负载均衡规则介绍

    规则名称特点
    AvailabilityFilteringRule 过滤掉一直连接失败的被标记为circuit tripped(电路跳闸)的后端Service,并过滤掉那些高并发的后端Server或者使用一个AvailabilityPredicate来包含过滤Server的逻辑,其实就是检查status的记录的各个Server的运行状态
    BestAvailableRule 选择一个最小的并发请求的Server,逐个考察Server,如果Server被tripped了,则跳过
    RandomRule 随机选择一个Server
    ResponseTimeWeightedRule 已废弃,作用同WeightedResponseTimeRule
    RetryRule 对选定的负责均衡策略机上充值机制,在一个配置时间段内当选择Server不成功,则一直尝试使用subRule的方式选择一个可用的Server
    RoundRobinRule 轮询选择,轮询index,选择index对应位置Server
    WeightedResponseTimeRule 根据相应时间加权,相应时间越长,权重越小,被选中的可能性越低
    ZoneAvoidanceRule (默认是这个)负责判断Server所Zone的性能和Server的可用性选择Server,在没有Zone的环境下,类似于轮询(RoundRobinRule

    引入Ribbon


    配置在RestTemplate添加@LoadBalanced负载均衡注解,这时候会为RestTemplate整合Ribbon:

    @Bean
    @LoadBalanced
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }

    使用Ribbon我们不需要关注负载均衡算法的实现,因为Ribbon已经涵盖了丰富的负载均衡策略,我们只需要给Ribbon注册一个实例列表,Ribbon会自动帮我们选择具体的某个实例,引进Ribbon代码演进如下:

     @Override
        public ShareDTO findById(Integer id) {
            //1.获取分享详情
            Share share = shareMapper.selectByPrimaryKey(id);
            //2.发布人的id
            Integer userId = share.getUserId();
            //调用用户微服务的/users/{userId}?使用RestTemplate,RestTemplate会帮我们自动转换成UserDTO
            UserDTO userDTO = this.restTemplate.getForObject(
                    "http://user-center/users/1",
                    UserDTO.class);
            //3.消息的装配
            ShareDTO shareDTO = new ShareDTO();
            BeanUtils.copyProperties(share, shareDTO);
            shareDTO.setWxNickname(userDTO.getWxNickname());
    
            return shareDTO;
        }
    

    引入Ribbon之后我们的代码简化了很多,这是后访问 http://localhost:8888/shares/1 也能得到结果,表示我们使用Ribbon实现实现了负载均衡:

  • 相关阅读:
    鳥哥的 Linux 私房菜——第十三章、学习 Shell Scripts(转发)(未完待续)
    鳥哥的 Linux 私房菜——第十六章、例行性工作排程 (crontab) (转发)(未完待续)
    RT-Thread ------ event 事件
    sscanf() ------ 获取字符串中的参数
    燃气热水器的调节
    Adobe Illustrator CC ------ AI脚本插件合集
    你真的理解CSS的linear-gradient?
    IDEA中Grep Console插件的安装及使用
    Windows下删除以.结尾文件夹的方法
    lwip库的发送和接收函数
  • 原文地址:https://www.cnblogs.com/lhboke/p/15292135.html
Copyright © 2011-2022 走看看