策略设计模式的应用

1:背景介绍

有没有想过在多个服务调用之间,例如Netflix的Ribbon(spring cloud Ribbon)是如何做的负载均衡?就比如A服务调用B服务,但是此时B服务是多台机器部署,你要选择那一台进行调用?是随机选一台?还是轮询选一台?还是按照权重选一台?本次不介绍Ribbon,咱们就借助Ribbon这个场景来实现下策略设计模式;

2:类图设计

在这里插入图片描述
在这里插入图片描述

设计思想:首先定义一个负载均衡接口(LoadBalanceStrategy),然后使用不同的子类去实现此接口,在程序启动的时候分别实例化负载均衡类,将负载均衡类注入到LoadBalanceContent策略上下文中,类型是HashMap<String, LoadBalanceStrateg>,key主要是负载均衡的名字,值就是它本身,程序启动根据配置负载均衡策略的名字,来使用不同的负载均衡器;AbstractLoadBalanceStrategy中维护目标主机的列表,只能子类使用;

3:代码

public interface LoadBalanceStrategy {
    String getHost();
}

public abstract class AbstractLoadBalanceStrategy implements LoadBalanceStrategy {
    /**
     * 维护的主机ip地址列表
     */
    protected List<String> hosts;

    public AbstractLoadBalanceStrategy(List<String> hosts) {
        this.hosts = hosts;
    }
}

轮询负载均衡器

public class PollLoadBalance extends AbstractLoadBalanceStrategy {
    final AtomicInteger atomicInteger = new AtomicInteger(0);

    public PollLoadBalance(List<String> hosts) {
        super(hosts);
    }

    @Override
    public String getHost() {
    	// 轮询选机器
        synchronized (atomicInteger){
            atomicInteger.compareAndSet(hosts.size() - 1, 0);
            int index = atomicInteger.getAndIncrement();
            return hosts.get(index);
        }
    }
}

随机负载均衡器

public class RandomLoadBalance extends AbstractLoadBalanceStrategy {

    public RandomLoadBalance(List<String> hosts) {
        super(hosts);
    }

    @Override
    public String getHost() {
        // 随机选择目标主机
        int random = (int)(Math.random() * 10000);
        return hosts.get(random % hosts.size());
    }
}

权重负载均衡器

public class WeightLoadBalance extends AbstractLoadBalanceStrategy {
    /**
     * ip 权重
     * 例: ["192.168.0.1", "192.168.0.1", "192.168.0.1", "192.168.0.2"]
     * 192.168.0.1 权重是3, 192.168.0.2 权重是1
     */
    private List<String> hostWeight;

    public WeightLoadBalance(List<String> hosts) {
        super(hosts);
        // 将每个主机ip,随机生成权重
        hostWeight = hosts.stream()
                .map(ip -> {
                    String[] ips = new String[(int) (Math.random() * 10)];
                    Arrays.fill(ips, ip);
                    return ips;
                })
                .flatMap(Stream::of)
                .collect(Collectors.toList());
    }
    @Override
    public String getHost() {
   		// 权重选机器
        Random random = new Random();
        int index = random.nextInt(hostWeight.size());
        return hostWeight.get(index);
    }
}

策略上下文

@Component
public class LoadBalanceContent {

    @Value("${loadBalanceName}")
    private String LoadBalanceName;

    private HashMap<String, LoadBalanceStrategy> loadBalanceMap;

    public LoadBalanceContent() {
        // 假如初始化 3台机器
        ArrayList<String> hosts = new ArrayList<>();
        hosts.add("192.168.0.1");
        hosts.add("192.168.0.2");
        hosts.add("192.168.0.3");
        // 初始化负载均衡器
        loadBalanceMap = new HashMap<>();
        loadBalanceMap.put("POLL", new PollLoadBalance(hosts));
        loadBalanceMap.put("WEIGHT", new WeightLoadBalance(hosts));
        loadBalanceMap.put("RANDOM", new RandomLoadBalance(hosts));
    }

    /**
     * 获取下一台主机
     * @return
     */
    public String nextHost() {
        return loadBalanceMap.get(LoadBalanceName).getHost();
    }
}

application.yml配置文件

loadBalanceName: POLL  # 轮询负载均衡策略

Controller

@RestController
@RequestMapping("/fuzhu/simple")
public class SimpleController {

    @Autowired
    private SimpleService simpleService;


    @GetMapping("/testLoadbalance")
    public ResultInfo testLoadbalance(){
        return simpleService.testLoadbalance();
    }
}

Service

@Service
@Slf4j
public class SimpleServiceImpl implements SimpleService {

    @Autowired
    private LoadBalanceContent loadBalanceContent;
    
    @Override
    public ResultInfo testLoadbalance() {
        // 获取目标机器
        String host = loadBalanceContent.nextHost();
        log.info("目标主机是: {}", host);
        return ResultInfo.buildSuccess("success");
    }
}

4:测试

轮询负载均衡策略
在这里插入图片描述
随机负载均衡策略
在这里插入图片描述
权重负载均衡策略
在这里插入图片描述

5:策略设计模式的优点

每个算法单独封装,减少了算法和算法调用者的耦合。
不过每多一个策略,就需要一个策略类

代码中难免会有不正确的地方,还望多多指正

6:代码库地址

设计模式

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值