Java實(shí)現(xiàn)Consul/Nacos根據(jù)GPU型號(hào)、顯存余量執(zhí)行負(fù)載均衡的步驟詳解
Java實(shí)現(xiàn)Consul/Nacos根據(jù)GPU型號(hào)、顯存余量執(zhí)行負(fù)載均衡
步驟一:服務(wù)端獲取GPU元數(shù)據(jù)
1. 添加依賴
在pom.xml
中引入Apache Commons Exec用于執(zhí)行命令:
<dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-exec</artifactId> <version>1.3</version> </dependency> <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>2.8.9</version> </dependency>
2. 實(shí)現(xiàn)GPU信息采集
import org.apache.commons.exec.CommandLine; import org.apache.commons.exec.DefaultExecutor; import org.apache.commons.exec.PumpStreamHandler; import java.io.ByteArrayOutputStream; import java.io.IOException; import com.google.gson.Gson; public class GpuInfoUtil { public static List<GpuMeta> getGpuMetadata() throws IOException { CommandLine cmd = CommandLine.parse("nvidia-smi --query-gpu=name,memory.total,memory.free --format=csv,noheader,nounits"); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); PumpStreamHandler streamHandler = new PumpStreamHandler(outputStream); DefaultExecutor executor = new DefaultExecutor(); executor.setStreamHandler(streamHandler); executor.execute(cmd); String output = outputStream.toString(); return parseOutput(output); } private static List<GpuMeta> parseOutput(String output) { List<GpuMeta> gpus = new ArrayList<>(); for (String line : output.split("\\r?\\n")) { String[] parts = line.split(","); if (parts.length >= 3) { String name = parts[0].trim(); long total = Long.parseLong(parts[1].trim()) * 1024 * 1024; // MB -> bytes long free = Long.parseLong(parts[2].trim()) * 1024 * 1024; gpus.add(new GpuMeta(name, total, free)); } } return gpus; } public static class GpuMeta { private String name; private long totalMem; private long freeMem; // 構(gòu)造方法、getters、setters省略 } }
步驟二:服務(wù)注冊(cè)到Consul/Nacos
1. Consul注冊(cè)實(shí)現(xiàn)
import com.ecwid.consul.v1.ConsulClient; import com.ecwid.consul.v1.agent.model.NewService; public class ConsulRegistrar { public void register(String serviceName, String ip, int port) throws Exception { ConsulClient consul = new ConsulClient("localhost", 8500); List<GpuMeta> gpus = GpuInfoUtil.getGpuMetadata(); NewService service = new NewService(); service.setId(serviceName + "-" + ip + ":" + port); service.setName(serviceName); service.setAddress(ip); service.setPort(port); // 序列化GPU元數(shù)據(jù) Gson gson = new Gson(); service.getMeta().put("gpus", gson.toJson(gpus)); consul.agentServiceRegister(service); } }
2. Nacos注冊(cè)實(shí)現(xiàn)
import com.alibaba.nacos.api.naming.NamingFactory; import com.alibaba.nacos.api.naming.NamingService; import com.alibaba.nacos.api.naming.pojo.Instance; public class NacosRegistrar { public void register(String serviceName, String ip, int port) throws Exception { NamingService naming = NamingFactory.createNamingService("localhost:8848"); List<GpuMeta> gpus = GpuInfoUtil.getGpuMetadata(); Instance instance = new Instance(); instance.setIp(ip); instance.setPort(port); instance.setServiceName(serviceName); instance.getMetadata().put("gpus", new Gson().toJson(gpus)); naming.registerInstance(serviceName, instance); } }
步驟三:動(dòng)態(tài)更新元數(shù)據(jù)
import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; public class MetadataUpdater { private ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(); private ConsulClient consulClient; private String serviceId; public void startUpdating() { scheduler.scheduleAtFixedRate(() -> { try { List<GpuMeta> gpus = GpuInfoUtil.getGpuMetadata(); String gpuJson = new Gson().toJson(gpus); // 重新注冊(cè)以更新元數(shù)據(jù) NewService service = new NewService(); service.setId(serviceId); service.setMeta(Collections.singletonMap("gpus", gpuJson)); consulClient.agentServiceRegister(service); } catch (Exception e) { e.printStackTrace(); } }, 0, 10, TimeUnit.SECONDS); } }
步驟四:客戶端負(fù)載均衡(Spring Cloud示例)
1. 自定義負(fù)載均衡器
import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier; import reactor.core.publisher.Flux; public class GpuAwareServiceSupplier implements ServiceInstanceListSupplier { private final ServiceInstanceListSupplier delegate; private final Gson gson = new Gson(); public GpuAwareServiceSupplier(ServiceInstanceListSupplier delegate) { this.delegate = delegate; } @Override public Flux<List<ServiceInstance>> get() { return delegate.get().map(instances -> instances.stream() .filter(instance -> { String gpuJson = instance.getMetadata().get("gpus"); List<GpuMeta> gpus = gson.fromJson(gpuJson, new TypeToken<List<GpuMeta>>(){}.getType()); return gpus.stream().anyMatch(g -> g.getFreeMem() > 2 * 1024 * 1024 * 1024L); // 2GB }) .collect(Collectors.toList()) ); } }
2. 配置負(fù)載均衡策略
@Configuration public class LoadBalancerConfig { @Bean public ServiceInstanceListSupplier discoveryClientSupplier( ConfigurableApplicationContext context) { return ServiceInstanceListSupplier.builder() .withDiscoveryClient() .withCaching() .withHealthChecks() .withBlockingDiscoveryClient() .build(context); } }
最終驗(yàn)證
檢查注冊(cè)中心元數(shù)據(jù)
curl http://localhost:8500/v1/catalog/service/my-service | jq .
輸出應(yīng)包含類似:
{ "ServiceMeta": { "gpus": "[{\"name\":\"Tesla T4\",\"totalMem\":17179869184,\"freeMem\":8589934592}]" } }
客戶端調(diào)用驗(yàn)證
客戶端會(huì)自動(dòng)選擇顯存充足的節(jié)點(diǎn),日志輸出示例:
INFO Selected instance 192.168.1.101:8080 with 8GB free GPU memory
通過以上步驟,即可在Java中實(shí)現(xiàn)基于GPU元數(shù)據(jù)的服務(wù)注冊(cè)與負(fù)載均衡。
到此這篇關(guān)于Java實(shí)現(xiàn)Consul/Nacos根據(jù)GPU型號(hào)、顯存余量執(zhí)行負(fù)載均衡的文章就介紹到這了,更多相關(guān)Java負(fù)載均衡內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Mybatis-Plus最優(yōu)化持久層開發(fā)過程
Mybatis-plus(簡(jiǎn)稱MP)是一個(gè)Mybatis的增強(qiáng)工具,在mybatis的基礎(chǔ)上只做增強(qiáng)不做改變,提高效率,自動(dòng)生成單表的CRUD功能,這篇文章主要介紹了Mybatis-Plus最優(yōu)化持久層開發(fā),需要的朋友可以參考下2024-07-07idea一招搞定同步所有配置(導(dǎo)入或?qū)С鏊信渲?
使用intellij idea很長(zhǎng)一段時(shí)間,軟件相關(guān)的配置也都按照自己習(xí)慣的設(shè)置好,如果需要重裝軟件,還得需要重新設(shè)置,本文就詳細(xì)的介紹了idea 同步所有配置,感興趣的可以了解一下2021-07-07MyBatis 多個(gè)條件使用Map傳遞參數(shù)進(jìn)行批量刪除方式
這篇文章主要介紹了MyBatis 多個(gè)條件使用Map傳遞參數(shù)進(jìn)行批量刪除方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12java基于TCP協(xié)議實(shí)現(xiàn)聊天程序
這篇文章主要為大家詳細(xì)介紹了java基于TCP協(xié)議實(shí)現(xiàn)聊天程序,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-07-07Java使用過濾器防止SQL注入XSS腳本注入的實(shí)現(xiàn)
這篇文章主要介紹了Java使用過濾器防止SQL注入XSS腳本注入,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-01-01SpringBoot實(shí)現(xiàn)發(fā)送QQ郵件的示例代碼
這篇文章主要介紹了SpringBoot如何實(shí)現(xiàn)發(fā)送QQ郵件功能,本文通過實(shí)例圖文相結(jié)合給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-09-09spring boot整合redis實(shí)現(xiàn)RedisTemplate三分鐘快速入門
這篇文章主要介紹了spring boot整合redis實(shí)現(xiàn)RedisTemplate三分鐘快速入門,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-12-12