全球 OSS 低延迟解决方案

全球 OSS 低延迟解决方案

需求

海外游戏的用户遍布全球,对于一个 OSS,全球各地连接的速度都不一样。为了尽量让玩家能够以更低的延迟进行游戏,减少网络等待的时间,因此需要一个低延迟的 OSS 解决方案。

思路

  • 增加位于全球各地的 OSS 服务器。
  • 通过统一的接口获取所有 OSS 服务器地址列表,然后同时连接测速,选出耗时最少的服务器。

使用的工具与产品

  • OSS
  • 云函数

具体步骤

准备工作

1. 创建 OSS 与云函数

创建位于全球各地的 OSS 服务器,并且配套创建云函数服务器。

注意设置 OSS 的跨域、读写权限、子账号等(根据具体项目实行)。

2. 创建测速云函数

在每个云函数服务器上创建 speedTest 函数,该函数只要返回一个客户端能够识别的值即可。

// Http 触发器,nodejs6 环境,GET
'use strict';

module.exports.handler = function(request, response, context) {
  console.log('success');
  response.send('success');
}
3. 创建云函数地址列表

收集每个云函数服务器的地址,编入一个文件,放在一个可以让全球范围访问的 OSS 上(我们称之为 云函数地址列表)。

{
	"USA": "https://xxx.us-west-1.fc.aliyuncs.com/2016-08-15/proxy/wechatgame/",
	"India": "https://xxx.ap-south-1.fc.aliyuncs.com/2016-08-15/proxy/wechatgame/",
	"Singapore": "https://xxx.ap-southeast-1.fc.aliyuncs.com/2016-08-15/proxy/wechatgame/",
	"China": "https://xxx.cn-hangzhou.fc.aliyuncs.com/2016-08-15/proxy/wechatgame/"
}
4. 编写读和写 OSS 的云函数

云函数能够直接对同服务器的 OSS 进行读写,详情参考供应商文档。

游戏客户端

  1. 玩家进入游戏后检测是否已有云函数服务器地址。
  2. 如果没有云函数地址,则请求获取云函数地址列表,并且请求列表中云函数服务器上的 speedTest 接口,记录每个接口请求的耗时(这里建议同时请求,队列请求的话整个过程耗时会很大)。
  3. 获取耗时最少的云服务器地址,缓存(下次登录游戏就不需要重新获取)。游戏中需要进行 OSS 存储的数据,就可以通过该地址,存储在对应的 OSS 上。
this.url = null; // 最后选定出来的云函数
this.costTime = {}; // 记录测速时间
this.stopFlag = false; // 停止测速的 flag
this.cloudList = null; // 云函数地址列表

// 查看缓存中是否已经有云函数地址
checkCacheUrl() {
    const url = localStorage.getItem('url');
    if (!url) {
        this.getUrlList();
    } else {
        // TODO: 通过 url 获取玩家信息等
        cc.loader.load(url, (error, data) => {
            if (error) {
                // TODO: 重连,超过一定次数后重新调用 this.getUrlList(); 获取能够连接上的服务器
                return;
            }
            
            // TODO: 游戏内其他逻辑
        });
    }
},

// 获取云函数列表
getUrlList() {
    const listUrl = 'https://xxx.cn-hangzhou.fc.aliyuncs.com/2016-08-15/proxy/pub-read/cloud-list.json';
    
    // 也可以用其他网络请求方式
    cc.loader.load(listUrl, (error, data) => {
        if (!error) {
            this.cloudList = data;
            this.length = this.cloudList.length;
            
            this.testListSpeed();
        }
    });
},

// 对获取的云函数列表的地址进行测速
testListSpeed() {
    for (const key in this.cloudList) {
        if (this.cloudList.hasOwnProperty(key)) {
            const url = this.cloudList(key);
            this.speedTest(key, url);
        }
    }
    
    // 间隔为 1s 的计时器。只要开始检测收到结果就可以停止
    // 如果确定网络请求不会因为顺序阻塞,可以处理成收到回复就完成测速
    this.intervalId = setInterval(() => {
        const keys = Object.keys(this.costTime);
        if (keys.length > 0) {
            clearInterval(this.intervalId);
            this.stopFlag = true;
            this.getFastestUrl();
        }
    }, 1000);
},

// 测速
speedTest(key, url) {
    const start = Date.now();
    // url: https://xxx.com/projectName/
    cc.loader.load(`${url}speedTest`, (error, data) => {
        if (data === 'success' && this.stopFlag) {
            const end = Date.now();
            const delta = end - start;
            
            this.costTime[key] = delta;
        }
    });
},

// 对比各个地址连接耗时
getFastestUrl() {
    let min = Number.MAX_SAFE_INTEGER;
    for (const key in this.costTime) {
        if (this.costTime.hasOwnProperty(key)) {
            const cost = this.costTime[key];
            if (cost < min) {
                min = cost;
                this.url = this.cloudList[key];
            }
        }
    }
    
    // 缓存
    if (this.url) {
        localStorage.setItem('url', this.url);
    }
},

缺陷

  1. 目前每个 OSS 之间数据不互通。服务器地址缓存在本地,一旦玩家更换设备,或者因为连不上原本的服务器而被连接到新的云函数服务器上,之前的游戏数据无法获取。
  2. 没有用户系统时更换设备无法获取原本玩家的数据。

改进方案(待实现与验证)

  • 使用 IP 进行范围定位,而不是通过请求耗时。
  • 研究 OSS 之间数据同步的可行性。
  • 网络异常时,再执行一次测速,将玩家数据更新到新筛选出的云函数地址,并更新缓存的地址(或者在玩家每次登录都执行此操作)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值