背景说明
将微服务注册到nacos管理后可以通过load balance做负载均衡,负载均衡是微服务架构的核心。Spring Cloud Alibaba组件提供了几种常用的复杂均衡策略:轮循策略、随机策略、以及基于集群和权重的NacosLoadBalancer策略。它们的实现逻辑可以看下面三个类的代码。
之所以还要探索修改元数据和权重的方法,是为了方便做更加个性化的自定义负载均衡算法。例如:可以根据服务器的 CPU占用率调整负载,可以根据服务器的内存占用率调整负载等等。
方案简述
微服务通过定时器周期性地向nacos服务器发送消息,修改服务器的指标数据。
实现步骤
1. 获取CPU利用率和内存利用率
import java.lang.management.ManagementFactory;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Enumeration;
import com.sun.management.OperatingSystemMXBean;
/**
* 获取服务指标的工具类
*
* @author neo
* @since 2025/4/21
* @version 1.0
*/
public class ServerMetricUtil {
private static OperatingSystemMXBean operatingSystemMXBean = (OperatingSystemMXBean)ManagementFactory
.getOperatingSystemMXBean();
/**
* 获取服务器CPU占用率
*
* @return CPU占用率
* @author neo
* @since 2025/4/21
*/
public static int getCPUUsage() {
double cpuUsage = operatingSystemMXBean.getSystemCpuLoad();
return (int)(cpuUsage * 100);
}
/**
* 获取服务器内存使用率
*
* @return 内存使用率
* @author neo
* @since 2025/4/21
*/
public static int getMemoryUsage(){
long totalMemory = operatingSystemMXBean.getTotalPhysicalMemorySize();
long freeMemory = operatingSystemMXBean.getFreePhysicalMemorySize();
double memoryUsage = ((totalMemory - freeMemory) * 1.0) / totalMemory;
return (int)(memoryUsage * 100);
}
/**
* 获取服务器IP地址
*
* @return 服务器IP
* @author neo
* @since 2025/4/21
*/
public static String getHostIp() throws SocketException {
// 遍历所有接口
Enumeration<NetworkInterface> ifs = NetworkInterface.getNetworkInterfaces();
for (; ifs.hasMoreElements(); ) {
NetworkInterface networkInterface = ifs.nextElement();
// 遍历每次接口的IP地址
Enumeration<InetAddress> addresses = networkInterface.getInetAddresses();
for (; addresses.hasMoreElements();) {
InetAddress address = addresses.nextElement();
if (address.isLoopbackAddress()) {
continue;
}
if (address.isSiteLocalAddress()) {
return address.getHostAddress();
}
}
}
return "";
}
}
2. 通过定时器周期采集数据上报
/**
* 搜集服务器指标数据。每10秒采集一次,刷新nacos服务器的数据
*
* @author neo
* @since 2025/4/21
*/
@Scheduled(cron = "0/10 * * * * ? ")
public void collectMetrics(){
LOGGER.info("Collect metrics begin.");
try {
Properties properties = nacosDiscoveryProperties.getNacosProperties();
NamingService namingService = nacosServiceManager.getNamingService(properties);
// 获取服务的所有实例
List<Instance> instancesList = namingService.getAllInstances(serverName);
// 获取当前实例
String hostIp = ServerMetricUtil.getHostIp();
Instance curInstance = null;
for (Instance instance : instancesList) {
if (instance.getIp().equals(hostIp) && instance.getPort() == port) {
curInstance = instance;
break;
}
}
// 更新自定义指标
curInstance.addMetadata("cpu.usage", String.valueOf(ServerMetricUtil.getCPUUsage()));
curInstance.addMetadata("memory.usage", String.valueOf(ServerMetricUtil.getMemoryUsage()));
// 也可以更新权重(这里随便指定一个值,看修改的效果。实现应用根据自身项目的业务规则处理)
curInstance.setWeight(98);
// 更新实例
NamingMaintainService namingMaintainService = nacosServiceManager.getNamingMaintainService(properties);
namingMaintainService.updateInstance(curInstance.getServiceName(), curInstance);
} catch (Exception e) {
LOGGER.error("Collect metrics fail.", e);
}
LOGGER.info("Collect metrics end.");
}
上述代码通过比较IP和端口,筛选出当前需要更新元数据和权重的服务实例。
查看修改结果
可以看到。服务实例的权重值已修改,同时新的元数据也加上了。后面我们就可以基于每个服务上报的指标数据实现个性化的负载均衡策略。
更多技术文章请关注微信公众号:Neo Yong