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