zoukankan      html  css  js  c++  java
  • 分布式环境中的负载均衡策略

    分布式环境中的负载均衡策略

    在分布式系统中相同的服务常常会部署很多台,每一台被称为一个服务节点(实例)。通过一些负载均衡策略将服务请求均匀地分布到各个节点,以实现整个系统支撑海量请求的需求。本文描述一些简单的负载均衡策略。

    Round-robin

    简单地轮询。记录一个选择位置,每次请求来时调整该位置到下一个节点:

    curId = ++curId % nodeCnt
    

    随机选择

    随机地在所有节点中选择:

    id = random(nodeCnt);
    

    本机优先

    访问后台服务的访问者可能本身是一个整合服务,或者是一个proxy,如果后台服务节点恰好有节点部署在本机的,则可以优先使用。在未找到本机节点时则可以继续走Round-robin策略:

    if (node->ip() == local_ip) {
        return node;
    } else {
        return roundRobin();
    }
    

    一旦遍历到本机节点,则后面的请求会一直落到本机节点。所以这里可以加上一些权重机制,仅是保证本机节点会被优先选择,但不会被一直选择。例如:

    // initial
    cur_weight = 100;
    ...
    // select node
    cur_weight -= 5;
    if (cur_weight <= 0)
        cur_weight = 100;
    if (cur_weight > 50 && node->ip() == local_ip) {
        return node;
    } else {
        return roundRobin();
    }
    

    本机房优先

    服务节点可能会被部署到多个机房,有时候确实是需要考虑跨机房服务。同本机优先策略类似,本机房优先则是优先考虑位于相同机房内的服务节点。该请求是从哪个机房中的前端服务发送过来的,则需要前端在请求参数中携带上机房ID。

    在服务节点对应的数据结构中,也最好按照机房来组织。

    本机房优先策略实际上会作为节点选择的第一道工序,它可以把非本机房的节点先过滤掉,然后再传入后面的各种节点选择策略。这里还可以考虑节点数参数,如果本机房的节点过少,则可以不使用该策略,避免流量严重不均。

    Weighted Round-Robin

    加权轮询。相对于普通轮询而言,该策略中每一个节点都有自己的权重,优先选择权重更大的节点。权重可以根据机器性能预先配置。摘抄一下网上的算法:

    假设有一组服务器S = {S0, S1, …, Sn-1},W(Si)表示服务器Si的权值,一个
    指示变量i表示上一次选择的服务器,指示变量cw表示当前调度的权值,max(S)
    表示集合S中所有服务器的最大权值,gcd(S)表示集合S中所有服务器权值的最大
    公约数。变量i初始化为-1,cw初始化为零。
    
    while (true) {
      i = (i + 1) mod n;
      if (i == 0) {
         cw = cw - gcd(S); 
         if (cw <= 0) {
           cw = max(S);
           if (cw == 0)
             return NULL;
         }
      } 
      if (W(Si) >= cw) 
        return Si;
    }
    

    遍历完所有节点后权重衰减,衰减到0后重新开始。这样可以让权重更大的节点被选择得更多。

    Consistent Hash

    一致性哈希。一致性哈希用于在分布式环境中,分布在各个节点上的请求,不会因为新增节点(扩容)或减少节点(节点宕机)而变化。如果每个服务节点上都有自己的缓存,其保存了该节点响应请求时的回应。正常情况下,这些缓存都可以很好地被运用,也即cache命中率较高。

    如果某个节点不可用了,我们的选择策略又是基于所有节点的公平选择,那么原来一直分配在节点A上请求就很可能被分配到节点B上,从而导致节点A上的缓存较难被命中。这个时候就可以运用一致性哈希来解决。

    其基本思想是,在节点选择区间内,在找节点时以顺时针方向找到不小于该请求对应的哈希值的节点。在这个区间里增加很多虚拟节点,每一个虚拟节点相当于一个物理节点的引用,这样相当于把物理节点变成了一个哈希值区间。这个哈希值区间不会因为增加节点和减少节点而变化,那么对某个请求而言,它就会始终落到这个区间里,也就会始终被分配到原来的节点。

    至于这个不可用的节点,其上的请求也会被均匀地分配到其他节点中。

    摘抄网上的一段代码:

    // 添加一个物理节点时,会随之增加很多虚拟节点
    template <class Node, class Data, class Hash>
    size_t HashRing<Node, Data, Hash>::AddNode(const Node& node)
    {
        size_t hash;
        std::string nodestr = Stringify(node);
        for (unsigned int r = 0; r < replicas_; r++) {
            hash = hash_((nodestr + Stringify(r)).c_str());
            ring_[hash] = node;  // 物理节点和虚拟节点都保存在一个std::map中
        }
        return hash;
    }
    
    // 选择data对应的节点,data可以是请求
    template <class Node, class Data, class Hash>
    const Node& HashRing<Node, Data, Hash>::GetNode(const Data& data) const
    {
        if (ring_.empty()) {
            throw EmptyRingException();
        }
        size_t hash = hash_(Stringify(data).c_str()); // 对请求进行哈希
        typename NodeMap::const_iterator it;
        // Look for the first node >= hash
        it = ring_.lower_bound(hash); // 找到第一个不小于请求哈希的节点
        if (it == ring_.end()) {
            // Wrapped around; get the first node
            it = ring_.begin();
        }
        return it->second;
    }
    

    参考一致性 hash 算法(consistent hashing)Consistent Hash Ring

  • 相关阅读:
    地理学考 要结合地图记忆的知识点
    物理选修3-1学习笔记
    UOJ#506. 【JOISC2020】遗迹 动态规划
    UOJ#39. 【清华集训2014】简单回路 动态规划 插头DP
    UOJ#339. 【清华集训2017】小 Y 和二叉树 贪心
    Codeforces 1239E. Turtle 折半
    概率论学习笔记
    UOJ#469. 【ZJOI2019】开关 生成函数
    被鄙视
    UOJ#468. 【ZJOI2019】Minimax搜索 动态DP
  • 原文地址:https://www.cnblogs.com/yangchunchun/p/7372304.html
Copyright © 2011-2022 走看看