2023-07-25
AWS Global Accelerator 是 AWS 的一项全球加速服务,通过提供的静态 IP 将玩家的流量路由到 AWS 在全球部署的边缘节点,流量通过监控良好、无拥塞的、冗余的 AWS 全球网络传输到终端节点。通过最大限度地利用 AWS 全球骨干网络,AWS Global Accelerator 可确保流量始终通过最佳网络路径进行路由。
AWS Global Accelerator 有 2 种类型,标准(Standard)加速器和自定义路由(Custom Routing)加速器,两者各有不同应用场景。
在自定义路由加速器出现之前,游戏业务中标准加速器广泛应用于一些无状态服务的加速,例如游戏玩家的信息、游戏公会信息获取以及修改、副本数据更新、战斗结果保存等业务处理,但是在占比更多的其他游戏业务场景中,标准加速器就显得力不从心,例如:
1)标准加速器客户端关联性配置(Client affinity)为空的时候,标准加速器通过五元组属性(源 IP、源端口、目标 IP、目标端口、目标端口和协议)来选择哈希值,当源端口变化时不能保证断线重连时重新连接到同一台服务器,导致同一游戏房间中的玩家异常掉线,对玩家体验和游戏公平性均会造成较大影响。
2)客户端关联性配置为源 IP 时,使用二元组属性(源 IP 和目标 IP)来选择哈希值,然而当玩家的网络状态变差时,玩家可能会选择切换接入网络,玩家从新的运营商接入点获得更新的 IP,这时候玩家就没有办法再回到原来的服务器,导致存储在特定对战服务器内存中的游戏数据丢失。
在游戏中会经常出现多人一同打 BOSS、刷装备,以及人与人之间相互对战/组队对战,例如 MOBA(Multiplayer Online Battle Arena)类游戏,这时候需要把所有参与组队的玩家连接到同一台服务器,由于标准加速器只能根据五元组或者二元组来选择哈希值,玩家只能被随机分配到后面的 EC2 服务器上,不能实现组队游戏玩法。
当需要组队游戏时,通常的做法是:
1)中心服务器为组队的多个玩家分配一台 EC2 服务器,玩家通过公网直接连接到对战服务器 EC2,这种方式把游戏服务器暴露在公网是非常不安全的。
2)为每一台游戏服务器添加一个标准加速器,这对于流量不大的游戏可能是一种办法,当需要成千上万台游戏对战服务器时,需要的标准加速器以及 Anycast IP 的数量就远远不够,同时这种用法也存在极大的资源浪费。
自定义路由加速器发布后,以上的问题可以得到很好的解决,通过自定义路由可以将来自玩家的请求路由到内网的单台 EC2 服务器的特定的端口,这种机制为对战游戏匹配玩家、共同连接同一台游戏战斗服提供了可能。在此也列出了标准加速器和自定义路由加速器在用法上的一些区别,供大家对比参考。
标准加速器 | 自定义路由加速器 | |
路由 | 加速器自动选择最近健康的终端节点,可以使用 Traffic dials,endpoint 的权重以及 affinity 来管理流量 | 可以通过选择静态 IP+端口来路由到特定的 EC2 实例端口 |
终端节点 | ALB/NLB/EC2/EIP | VPC subnets(流量路由到子网中的 EC2 实例) |
协议选择 | 在 Listener 可以选择 TCP 或者 UDP | Endpoint Group 可以选择 TCP 和/或 UDP |
简而言之,如果要将用户路由到特定的 EC2 游戏服务器上,你需要自定义路由加速器,本文介绍了如何通过自定义路由建立战斗服加速服务的一种实现方式。
本场景模拟玩家在游戏中发起一场对战的情况,整体的处理过程如下:
在开始之前,请先确保您具有登录 AWS 控制台的账号,并具备 AWS Global Accelerator 的操作权限权限,您可以先登录控制台,选择合适的区域,本文的重点在于使用 AWS Global Accelerator 的自定义路由,其他服务器创建可以参考链接自行完成。
1. 通过以下命令可以查找到指定 EC2 内网 IP 的对外端口
aws globalaccelerator list-custom-routing-port-mappings-by-destination —destination-address 10.0.0.57 —endpoint-id subnet-xxxxxxxxxxxxxxxxxx —region us-west-2
可以看到 AWS Global Accelerator 的 Listener 对外端口 10010 指向子网中 IP 为 10.0.0.57 的 EC2 的 8080 端口。
2. 我们在 EC2 服务器上通过以下命令启动测试服务器,用来模拟一个游戏进程(MOBA 中对战房间):
注:此验证过程无需搭建本文中所述的完整游戏架构,只需构建 AWS Global Accelerator 和后端 EC2 部分即可。
cat << EoF > battleserver_demo.py
import socket
import time
import threading
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('0.0.0.0', 8080))
s.listen(5)
print('Server is running...')
connections = []
def TCP(sock):
while True:
data = sock.recv(1024)
time.sleep(1)
if not data or data.decode('utf-8').replace('
', '').replace('
', '') == 'quit':
Clean()
break
Battle(data)
def Clean():
global connections
for connection in connections:
connection.close()
connections = []
def Battle(data):
for connection in connections:
connection.send(data.decode('utf-8').upper().encode())
if __name__=='__main__':
while True:
sock, addr = s.accept()
if len(connections) < 2:
connections.append(sock)
thread = threading.Thread(target=TCP, args=(sock,))
thread.start()
EoF
nohup python3 battleserver_demo.py&
3. 通过 Telnet 命令,分别在两台游戏客户端上通过 AWS Global Accelerator 暴露的对外端口连接到后端 EC2 游戏服务器。
telnet xxxxxxxx.awsglobalaccelerator.com 10010
4. 连接上 TCP 服务器后,模拟两台客户端上互发消息。
我们在测试机 1 发出“ping“消息,在测试机 1 和测试机 2 上都收到了 PING(测试服务器默认把所有消息大写)消息,可以验证测试机 1 和测试机 2 都成功连接到了内网 EC 的 8080 端口并能够进行消息交互。
通常每个游戏服上会运行多个游戏进程(在 MOBA 游戏中即为多个对战房间),本示例中从 AWS Global Accelerator 10010 映射到 EC2 的 8080 即为其中一个游戏进程,10011 映射到 8081 即为第二个游戏进程。如需要,您可以在更多的游戏服务器上运行上述 Python 程序进行进一步会话交互验证。
在使用 AWS Global Accelerator 自定义路由的时候,请注意以下事项:
本文从建立对战请求,到后端游戏会话管理,完整地介绍了如何利用 AWS Global Accelerator 的自定义路由功能来加速游戏会话,同时也对游戏重连逻辑进行了说明。 标准加速器适用于 4 层的无状态,或对会话粘性要求不高的业务场景进行加速;自定义路由加速器则可以根据您的业务特征,通过端口映射的方式来实现精准匹配和重连。针对不同的业务场景,可以选择不同的加速器来满足您的业务需求。