1. 背景
在分布式系统中,由于存在多台机器,在下发任务时往往需要优先选择一台压力最小的机器。
接下来介绍一种针对CPU密集型任务的机器负载均衡策略。
2. 设计目标
- 优先选择空闲的机器,避免单台mixserver机器压力过大。
- 保证服务的高可用性。
3. 总体设计
- 机器通过心跳向中控程序上报机器信息,包括机器网络信息(idc、局域网ip),机器物理信息(CPU核数、处理器主频等),机器压力信息(内存使用率、CPU负载)
- 中控程序根据心跳,存储和更新存活机器信息,并计算机器空闲能力,选择空闲能力最大的机器。
4. 详细设计
4.1 概念
CPU空闲率(idle) = 1- CPU使用率
空闲处理能力(capacity):由CPU核数和CPU空闲率计算的得来,表示机器的处理能力。
4.2 CPU空闲处理能力计算
(1)为综合考虑CPU空闲率和CPU核数,初始设定
capacity = idle * coreNumber
这种策略可以避免处理能力弱的机器过早被打满机器。
(2)在(1)的基础上,计算得到空闲能力相同的情况,还需要考虑选择小核优先还是大核优先。
对于大核优先,相同处理能力时,其实大核机器的CPU占用率已经很高了,这时候仍然选择大核机器会使得,的和机器和小核机器之间的CPU占用率进一步扩大。而使用小核优先,一定程度上可以使得高负载时大核和小核机器的CPU使用率较为接近。所以在(1)基础上,还要考虑机器核数。
capacity = (idle * coreNumber)* coreMax + (coreMax - coreNumber)
计算示例:
private double calCpuIdle(int load, int coreNum) {
return ((100 - load) * coreNum) << 10 | (1024 - coreNum);
}
4.3 负载数据更新策略
是不是选择了空闲能力最大的机器就没有问题了呢?假如我们选择了机器A作为任务机器,而机器上报的间隔是10s,那么10s内机器A的CPU负载率还是旧的数据,这时候又接连到来100个任务请求,均选择了机器A,相信机器A CPU很快就会被打满。
所以,需要在每个请求下发后及时更新机器的负载信息。
具体做法可以参考:
- 需要事先测试一个任务,大概需要占用多少CPU。可以在一台机器上测试可以跑多少个任务。如果x个核上可以跑n个任务,那么说明一个任务大概可以跑满CPU数目:x/n,那么一个任务占用的CPU百分比为:(x/n)/coreNum。也可以观察一个任务对机器整体CPU占用率又多大影响
- 在收到机器心跳时计算机器空闲能力,并缓存;
- 下发任务时需要更新CPU空闲能力:capacity = capacity_old – (x/coreNumber * 100 * corenum) * coreMax;
- 需要注意对机器信息和负载信息的缓存要设置过期时间,防止机器服务宕机、停止等异常情况。
4.4 Top K机器随机选择
是否在下发任务后及时更新机器空闲能力就不会出现多个任务打满同一台机器的现象呢?
从获取机器空闲能力、到下发任务、再到更新机器空闲能力这短暂的时间内,如果同时有成百上千个请求到来的话,那仍然是会使得所有任务下发到同一台机器上。
对于这种高并发的场景,可以考虑两种做法:
- 如果各台机器配置相差无几,那么可以考虑轮询策略,公平分配任务;
- 也可以采用本文的策略,但是在选择机器时不是选择空闲能力最大的机器,而是从空闲能力Top K的机器中随机选取,这样可以在很大程度上避免大量请求同时打到同一台机器的情况。
5. 总结
在进行负载均衡时,不仅仅要考虑到各个机器的负载情况,更重要的是保证服务的高可用性。本文主要针对CPU密集型任务设计了一种负载均衡策略,但思路一样适合IO密集型任务,相应的需要调整下空闲能力算法。