基准 #

在本次评估中,我们对Nakama的部分工作负载进行了基准测试,测试对象为几个核心API,这些API通常用于构建大型多人游戏。

这些工作负载已经在一组不同的硬件配置上运行,以展示Nakama的对现代硬件友好且高可扩展的架构带来的性能优势。

结果表明:Nakama的性能随着硬件规模的增长而增长。向上和向外扩展都提供了许多优势:从集群管理的简化,到获得总体上更好的硬件和规模经济,均包括在内。

方法 #

基准测试用强大的分布式负载测试工具Tsung执行。

Tsung工作负载在单节点部署(Nakama OSS)和集群模式(NakamaEnterprise)中使用单个数据库实例,在几种不同的配置中对Nakama进行基准测试。

数据库实例硬件在所有配置和工作负载中保持不变,以确保没有I/O瓶颈。尽管我们还测试了一些数据库绑定的API,但这些基准测试将关注Nakama的功能。

Tsung服务器在Google Compute Engine (GCE)上运行。Nakama OSS和Enterprise均在我们的Heroic Cloud架构上运行。

在实际工作负载之前,并没有预热运行。

设置 #

Tsung / 数据库 #

Tsung拓扑结构由一个主节点和20个从节点组成。此设置在所有基准测试运行中都保持不变,硬件规格为:

Tsung MainTsung Redundant数据库
实例类型n1-standard-32n1-standard-32dedicated-core vCPU
vCPU / Mem6 / 8GB3 / 2GB8 / 30GB
IOPS (read/write)--3000

数据库在Google CloudSQL上设定。

Nakama #

我们针对三种配置运行了基准工作负载:

Nakama OSS

  • 1 节点 - 1 CPU / 3GB RAM

Nakama Enterprise

  • 2 节点 - 1 CPU / 3GB RAM(每节点)
  • 2 节点 - 2 CPU / 6GB RAM(每节点)

所有容器都在GCP实例类型“n1-standard-32”上运行,并在Heroic Cloud平台上创建。Nakama节点位于GCP L7负载平衡器后。

工作负载 #

建议的工作负载旨在显示针对轻松投产规模的Nakama的吞吐量和产能。

我们将展示以下工作负载的基准测试结果:

  1. 并存套接字连接数(CCU数)。
  2. 新用户注册吞吐量。
  3. 用户身份验证吞吐量。
  4. Lua运行时中自定义RPC吞吐量。
  5. Go运行时中自定义RPC吞吐量。
  6. 使用自定义比赛处理程序的权威实时比赛数。

以下小节分别针对上述每个工作负载,其中对每个工作负载都将进行更详细的介绍;然后是Tsung收集的每个考查的硬件和拓扑配置的基准结果。

结果 #

工作负载1 — 并发套接字连接数(CCU数)量 #

此工作负载包括验证用户、打开与Nakama的套接字连接,并保持其打开约200秒。

1 节点 - 1 CPU / 3GB RAM

连接的用户数

基准寄存器
基准寄存器

2 节点 - 1 CPU / 3GB RAM(每节点)

连接的用户数

基准寄存器
基准寄存器

2 节点 - 2 CPU / 6GB RAM(每节点)

连接的用户数

基准寄存器
基准寄存器

Time to connect
HardwareMax Connectedhighest 10sec meanlowest 10sec meanHighest RateMean RateMean
1 Node - 1 CPU / 3GB RAM1954242.40 msec26.54 msec1340 / sec196.12 / sec34.21 msec
2 Nodes - 1 CPU / 3GB RAM (each)2755816.93 msec15.92 msec930 / sec161.52 / sec16.60 msec
2 Nodes - 2 CPU / 6GB RAM (each)3209220.17 msec18.18 msec1097.7 / sec187.82 / sec19.15 msec

如上所示,具有单个CPU内核的单个Nakama实例可以有多达19500个连接用户。最多可扩展到2个节点,每个节点有2个CPU核,此值可达32000 CCU。

工作负载2 - 注册新用户 #

此工作负载模拟通过游戏服务器的设备身份验证API注册新用户,该API将新帐户存储到数据库中。

1 节点 - 1 CPU / 3GB RAM

吞吐量(请求/秒)

基准寄存器
基准寄存器

2 节点 - 1 CPU / 3GB RAM(每节点)

吞吐量(请求/秒)

基准寄存器
基准寄存器

2 节点 - 2 CPU / 6GB RAM(每节点)

吞吐量(请求/秒)

基准寄存器
基准寄存器

Request statistics
Hardwarehighest 10sec meanlowest 10sec meanHighest RateMean RateMean
1 Node - 1 CPU / 3GB RAM29.07 msec20.10 msec849.6 / sec519.46 / sec24.60 msec
2 Nodes - 1 CPU / 3GB RAM (each)31.65 msec20.01 msec1014.3 / sec672.18 / sec25.95 msec
2 Nodes - 2 CPU / 6GB RAM (each)0.14 sec20.01 msec1160.8 / sec750.76 / sec28.46 msec

如上所示,一台Nakama服务器可以处理平均约500个请求/秒的负载,在为新用户执行数据库写入操作时,请求以24.60毫秒(平均值)送达。按照这个速度,一个游戏每小时可以创建186万个新玩家。当扩展到2个节点时,该值将达到每小时270万个玩家账户。

工作负载3 — 对用户进行身份验证 #

此工作负载包括使用游戏服务器的设备身份验证API对现有用户进行身份验证。

1 节点 - 1 CPU / 3GB RAM

吞吐量(请求/秒)

基准寄存器
基准寄存器

2 节点 - 1 CPU / 3GB RAM(每节点)

吞吐量(请求/秒)

基准寄存器
基准寄存器

2 节点 - 2 CPU / 6GB RAM(每节点)

吞吐量(请求/秒)

基准寄存器
基准寄存器

Request statistics
Hardwarehighest 10sec meanlowest 10sec meanHighest RateMean RateMean
1 Node - 1 CPU / 3GB RAM33.40 msec17.27 msec802.2 / sec499.63 / sec24.61 msec
2 Nodes - 1 CPU / 3GB RAM (each)27.87 msec16.81 msec1035.5 / sec673.42 / sec22.19 msec
2 Nodes - 2 CPU / 6GB RAM (each)76.85 msec16.95 msec1162 / sec776.77 / sec25.03 msec

工作负载4 - 自定义Lua RPC调用 #

此工作负载执行通过Lua运行时公开的简单RPC函数。该函数接收JSON字符串形式的有效负载,对其进行解码,并将其回传给发送方。

1 节点 - 1 CPU / 3GB RAM

吞吐量(请求/秒)

基准寄存器
基准寄存器

2 节点 - 1 CPU / 3GB RAM(每节点)

吞吐量(请求/秒)

基准寄存器
基准寄存器

2 节点 - 2 CPU / 6GB RAM(每节点)

吞吐量(请求/秒)

基准寄存器
基准寄存器

Request statistics
Hardwarehighest 10sec meanlowest 10sec meanHighest RateMean RateMean
1 Node - 1 CPU / 3GB RAM26.18 msec15.01 msec976.5 / sec633.42 / sec20.22 msec
2 Nodes - 1 CPU / 3GB RAM (each)19.25 msec15.68 msec1192 / sec706.71 / sec17.48 msec
2 Nodes - 2 CPU / 6GB RAM (each)20.27 msec16.11 msec1383.4 / sec823.55 / sec18.16 msec

工作负载5 - 自定义Go RPC调用 #

此工作负载执行通过Go运行时公开的简单RPC函数。该函数接收JSON字符串形式的有效负载,对其进行解码并将其回传给发送方。

1 节点 - 1 CPU / 3GB RAM

吞吐量(请求/秒)

基准寄存器
基准寄存器

2 节点 - 1 CPU / 3GB RAM(每节点)

吞吐量(请求/秒)

基准寄存器
基准寄存器

2 节点 - 2 CPU / 6GB RAM(每节点)

吞吐量(请求/秒)

基准寄存器
基准寄存器

Request statistics
Hardwarehighest 10sec meanlowest 10sec meanHighest RateMean RateMean
1 Node - 1 CPU / 3GB RAM26.12 msec14.42 msec975.9 / sec635.36 / sec19.97 msec
2 Nodes - 1 CPU / 3GB RAM (each)20.87 msec14.91 msec1205.7 / sec707.12 / sec17.29 msec
2 Nodes - 2 CPU / 6GB RAM (each)20.19 msec15.59 msec1386.4 / sec820.41 / sec18.00 msec

如上所示,一台Nakama服务器平均可以在19.97毫秒(平均)内处理约600个请求/秒。当与工作负载5的结果进行比较时,我们发现Lua和Go运行时之间的结果非常相似。这是因为被基准测试的工作负载不会引起大量的CPU计算;使得尽管Lua虚拟机存在差异,结果仍然相似。对于CPU密集型代码,性能结果将有所不同,Lua运行时的RAM使用情况也会不同。

工作负载6 - 自定义权威比赛逻辑 #

此工作负载模拟在Nakama的服务器权威多人游戏引擎上运行的实时多人游戏。尽管客户端和自定义逻辑不是实际的多人游戏;从服务器和连接的游戏客户端之间交换的消息的角度,该代码创建了近似的真实用例场景。我们将简单介绍此工作负载中的服务器和客户端逻辑。

服务器端逻辑 #

服务器以每秒10次节拍率运行多人比赛。每场比赛最多可有10个玩家。

服务器实现了一个RPC调用,客户端可以查询该调用以获得正在进行的比赛(少于10名玩家)的ID。当调用此API时,服务器将使用列出比赛功能查找未满的比赛并返回第一个结果。如未找到比赛,则开始一个新的比赛。

比赛循环逻辑很简单;服务器期望从客户端接收两个操作码中的一个,并执行以下任一操作:

  1. 将收到的消息回显给客户端。
  2. 将消息广播给所有的比赛参与者。

客户端逻辑 #

客户端逻辑也很简单;每个游戏客户端按顺序执行以下步骤:

  1. 对现有用户进行Nakama身份验证以接收令牌。
  2. 执行服务器RPC函数以接收正在进行的比赛(未满)的ID。
  3. 建立与实时API的网络套接字连接。
  4. 使用步骤2中收到的ID加入比赛。
  5. 客户端将循环180秒,每半秒将交替发送一条操作码为1或2的消息。

客户端发送的消息包含固定大小的有效负载,操作码1和2分别为44和35个字符。

1 节点 - 1 CPU / 3GB RAM

连接的用户数

基准寄存器
基准寄存器

2 节点 - 1 CPU / 3GB RAM(每节点)

连接的用户数

基准寄存器
基准寄存器

2 节点 - 2 CPU / 6GB RAM(每节点)

连接的用户数

基准寄存器
基准寄存器

这些结果是客户端发出的每个请求的平均值,因为此工作负载涉及:

  1. 身份验证
  2. RPC调用
  3. 连接到网络套接字和
  4. 通过网络套接字连接发送消息;

结果考虑了在每个客户端会话中执行的整个请求逻辑集。

Request statistics
Hardwarehighest 10sec meanlowest 10sec meanHighest RateMean RateMean
1 Node - 1 CPU / 3GB RAM42.21 msec1.07 msec126.5 / sec36.72 / sec15.06 msec
2 Nodes - 1 CPU / 3GB RAM (each)0.10 sec1.14 msec213.8 / sec54.68 / sec28.21 msec
2 Nodes - 2 CPU / 6GB RAM (each)41.82 msec1.07 msec350 / sec85.82 / sec15.93 msec

下表包括游戏服务器利用比赛中交换的数据消息处理的网络吞吐量。可见,客户端接收的字节数远高于发送的字节数;如上所述,客户端发送的50%的消息由服务器广播给所有比赛参与者。

Network Throughput
HardwareSent/ReceivedHighest RateTotal
1 Node - 1 CPU / 3GB RAMSent4.65 Mbits/sec157.92 MB
Received24.88 Mbits/sec809.65 MB
2 Node - 1 CPU / 3GB RAM (each)Sent5.90 Mbits/sec201.35 MB
Received31.96 Mbits/sec1020.68 MB
2 Node - 2 CPU / 6GB RAM (each)Sent7.64 Mbits/sec261.61 MB
Received40.54 Mbits/sec1.30 GB