Part1前言
peer-stream是inveta团队开源的基于UE的像素流插件。和官方臃肿不堪的像素流SDK相比,我们在官方的基础上做了大量的优化和精简,开发出了轻量、零依赖、开箱即用的软件套装,前端的peer-stream.js基于WebComponentsAPI,后端signal.js基于NodeJS和npm/ws。
本次我们更新了四个主要功能:
1、更精准的负载均衡,解决之前问题(https://github.com/inveta/peer-stream/issues/56)
2、支持跨机器的负载均衡方案
3、优化了预加载机制,可以动态加载空闲的实例
4、增加了当gpu资源不足时,可以进行用户排队,并定期通知排队进展
Part2精准负载均衡
之前存在的问题是在配置的资源池里面process.env.UE5_GPU_0里面的资源,当其断开之后,无法感知其是否已经断开。为了解决这个问题,我们引入了一个新技术,通过动态修改UE连接websocket的url地址,使得每个地址唯一,从而可以精准定位到那个UE示例是否启动,是否已经被释放。这里的配置参数和之前的兼容,这里不需要修改。
G_StartUe5Pool = []
function InitUe5Pool() {
execUe5Pool = Object.entries(process.env)
.filter(([key]) => key.startsWith('UE5_'))
.map(([key, value]) => {
return [key, value]
})
for (const item of execUe5Pool) {
const [key, value] = item
// 将命令行字符串转换为数组
const args = value.split(' ')
// 使用正则表达式提取 -PixelStreamingURL 参数的值
const match = value.match(/-PixelStreamingURL=([^ ]+)/)
// 如果匹配成功,则输出 PixelStreamingURL 的值
if (!match) {
console.error(`PixelStreamingURL not found. ${value}`)
continue
}
const url = require('url')
const pixelStreamingURL = match[1]
const paseUrl = url.parse(pixelStreamingURL)
paseUrl.pathname = key
const newPixelStreamingURL = url.format(paseUrl)
// 使用正则表达式或字符串替换修改 PixelStreamingURL 值
const modifiedArgs = args.map((arg) =>
arg.replace(
/-PixelStreamingURL=.*/,
`-PixelStreamingURL=${newPixelStreamingURL}`
)
)
let localCmd = true
let startCmd
const ipAddress = args[0]
const isIpAddress = /^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/.test(args[0])
if (isIpAddress) {
localCmd = false
modifiedArgs.shift()
startCmd = modifiedArgs.join(' ')
G_StartUe5Pool.push([localCmd, ipAddress, key, startCmd])
continue
}
startCmd = modifiedArgs.join(' ')
G_StartUe5Pool.push([localCmd, '', key, startCmd])
}
}
Part3跨机器负载
跨机器负载我们尝试过很多方案,参考https://github.com/inveta/peer-stream/issues/56 。最后选择了自己写一个websocket客户端的方案,这样可以更好的进行控制。这里引入了一个新的文件 https://github.com/inveta/peer-stream/blob/main/exec-ue.js
这个文件和之前所有的文件没有关系,只需要部署在需要负载的机器上即可。需要修改两个配置参数:
signalIp = '127.0.0.1'
signalPort = 88
这里修改为signal.js的端口和IP地址即可。启动命令
node exec-ue.js
Part4预加载
为了提高用户体验,我们还提供了预加载机制,可以先把实例开起来,通过在.signal.js配置文件中的 process.env.preload = 1;来设置,可以设置预加载的个人。
Part5用户排队
当GPU资源池的实例都被使用之后,我们可以进行用户排队,并实时通知。在前端注册排队事件
ps.addEventListener("playerqueue", e => {
});
排队消息为
{"type":"playerqueue","seq":1}
seq为当前排队的序列,1表示当前排队有1个人。
Part6总结
本文主要介绍了peer-stream库的更新,主要解决了更精准的负载均衡、支持跨机器的负载均衡方案、优化了预加载机制以及用户排队
Part7Inveta团队
Inveta团队由研发、美术设计、建模等组成。
团队开源项目:
https://github.com/inveta