You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Spring Boot中使用Ribbon配置4:1权重比例的负载均衡?

How to Implement 4:1 Weighted Load Balancing with Ribbon in Spring Boot

Hey there, let's tackle your requirement to route 80% of traffic to your high-resource server and 20% to the one with limited cache. Since you're currently using Ribbon's default round-robin (which splits requests evenly), here are two reliable ways to set up fixed weighted distribution:

Method 1: Build a Custom Load Balancing Rule

Ribbon's core load balancing logic is handled by the IRule interface. We can extend the base rule class to create our own fixed-weight logic tailored to your 4:1 ratio.

Step 1: Create a Custom Weight Rule Class

Make a class that inherits AbstractLoadBalancerRule and overrides the choose method to pick servers based on your desired weight distribution.

import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractLoadBalancerRule;
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.Server;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;

public class FixedWeightDistributionRule extends AbstractLoadBalancerRule {

    // Hardcode weights here (4 for your first server, 1 for the second)
    private final int[] serverWeights = {4, 1};

    @Override
    public void initWithNiwsConfig(IClientConfig clientConfig) {
        // No extra setup needed here
    }

    @Override
    public Server choose(Object key) {
        ILoadBalancer loadBalancer = getLoadBalancer();
        if (loadBalancer == null) return null;

        List<Server> availableServers = loadBalancer.getAllServers();
        if (availableServers.isEmpty()) return null;

        // Calculate total weight to set our random range
        int totalWeight = 0;
        for (int weight : serverWeights) {
            totalWeight += weight;
        }

        // Generate a random number between 0 and totalWeight-1
        int randomWeight = ThreadLocalRandom.current().nextInt(totalWeight);

        // Match the random number to the corresponding server
        int cumulativeWeight = 0;
        for (int i = 0; i < availableServers.size(); i++) {
            cumulativeWeight += serverWeights[i];
            if (randomWeight < cumulativeWeight) {
                return availableServers.get(i);
            }
        }

        // Fallback to the first server if something goes wrong
        return availableServers.get(0);
    }
}

Step 2: Configure Ribbon to Use Your Custom Rule

Create a Ribbon client configuration to tell your target service to use this new rule.

import org.springframework.cloud.netflix.ribbon.RibbonClient;
import org.springframework.context.annotation.Configuration;

// Replace "your-target-service" with the actual name of your service
@RibbonClient(name = "your-target-service", configuration = RibbonCustomConfig.class)
@Configuration
public class GlobalRibbonConfig {
}

// Keep this config class separate to avoid making it global (unless you want that!)
@Configuration
class RibbonCustomConfig {
    @Bean
    public FixedWeightDistributionRule fixedWeightDistributionRule() {
        return new FixedWeightDistributionRule();
    }
}

Pro Tip: Don't put RibbonCustomConfig in the same package as your main application class (or any package scanned by @ComponentScan). If you do, this rule will apply to all Ribbon clients in your app instead of just the target service.

Method 2: Dynamic Weights via Eureka Metadata (If Using Service Discovery)

If your servers are registered with Eureka, you can set weights directly in each server's config and adjust your custom rule to read these values dynamically (so you don't have to hardcode weights in the rule class).

Step 1: Set Weights in Each Server's Config

For your high-resource server:

eureka:
  instance:
    metadata-map:
      weight: 4

For your low-resource server:

eureka:
  instance:
    metadata-map:
      weight: 1

Step 2: Update the Custom Rule to Read Metadata

Modify the choose method in your FixedWeightDistributionRule to pull weights from Eureka metadata instead of hardcoding:

@Override
public Server choose(Object key) {
    ILoadBalancer loadBalancer = getLoadBalancer();
    if (loadBalancer == null) return null;

    List<Server> availableServers = loadBalancer.getAllServers();
    if (availableServers.isEmpty()) return null;

    int[] serverWeights = new int[availableServers.size()];
    int totalWeight = 0;

    // Pull weights from Eureka instance metadata
    for (int i = 0; i < availableServers.size(); i++) {
        Server server = availableServers.get(i);
        String weightValue = server.getMetaInfo().getMetadata().get("weight");
        // Default to weight 1 if no value is set
        serverWeights[i] = weightValue != null ? Integer.parseInt(weightValue) : 1;
        totalWeight += serverWeights[i];
    }

    // Same random weight matching logic as before
    int randomWeight = ThreadLocalRandom.current().nextInt(totalWeight);
    int cumulativeWeight = 0;
    for (int i = 0; i < availableServers.size(); i++) {
        cumulativeWeight += serverWeights[i];
        if (randomWeight < cumulativeWeight) {
            return availableServers.get(i);
        }
    }

    return availableServers.get(0);
}

Verify the Setup

Once you deploy these changes, monitor your request logs or use a tool like Spring Boot Actuator to check traffic distribution. Over time, you should see roughly 4 requests going to your first server for every 1 to the second. Short-term fluctuations are normal (since we're using random weighting), but the long-term ratio will match your 4:1 target.


内容的提问来源于stack exchange,提问作者Piyush Raghuwanshi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 06:23:56