跳到主要内容

Virtual Server

1. Overview

Virtual Server is an Extension service offered by PGOS, allowing developers to expand the functionality and implement customized features through code writing and deploy third-party software to run. The essence of a Virtual Server is that developers create web servers, which are then deployed and run on the container runtime platform provided by PGOS. To orchestrate and manage the virtual servers written by developers, PGOS uses the Knative framework and ensures isolation between Virtual Servers under different TitleRegions.

image-20240914114144870

Virtual Server offers the following fundamental features:

  • Language transparency: Developers can use any programming language to build their virtual server.
  • Backend HTTP API: Developers can call PGOS backend APIs within their code. Sample code is provided for assembling the correct requests using Golang, Node.js, and Python.
  • Autoscaling: CPU and memory usage can be set for each virtual server instance, which can hold multiple instances based on actual load and needs.
  • Triggers: Virtual servers can be triggered from game clients and dedicated servers and can also be bound with PGOS events for seamless integration.
  • CI/CD: Developers can upload source code, allowing PGOS to build Docker images. Alternatively, developers can upload zip files containing exported Docker images or provide a public Docker repository address for PGOS to pull images and create a Virtual Server accordingly.
  • Data visualization: PGOS can generate graphs depicting CPU, memory, and instance count trends, as well as overall request Round-Trip Time (RTT) and Queries Per Second (QPS) statistics. Moreover, it can display the distribution of RTT API response times in histograms.
  • Log collection: PGOS can store, index, and analyze logs printed on the console shell by Virtual Servers, organized by revision. This enables efficient log management and tracking for developers. Especially, the access log is supported in Nginx default log format.
  • VS Storage: Access databases and cloud disk in your Virtual Server.
  • Intranet Communication: The Virtual Server can communicate with each other internally by the intranet
  • Access in browser: You can visit your Virtual Server in Browser directly. Note that you can do it only through the PGOS Portal.

2. Create and Manage Virtual Server

To create a Virtual Server, a docker image needs to be prepared. This can be done in three ways:

  1. Export your docker image to a zip file and upload on web portal by using docker save command.
  2. Upload your source code that contains Dockerfile and PGOS will do the CI job for you.
  3. Submit a public docker registry path so PGOS is able to pull the image.

Then navigate to Virtual Server page, and click the "+ Add Virtual Server" button.

image-20240902144527115

These fields are required:

  • Server Name: a name that can only contain uppercase and lowercase letters, numbers, and hyphens (-).

  • Resource Type & Pull Method: select how you want to build your docker image.

    • Source Code with Dockerfile: let PGOS build it for you, and you must upload the source code with Dockerfile in the root folder.

    • Docker Image from local file: upload your docker image already built, which can be exported using the docker save command.

    • Docker Image pull from the registry: let PGOS fetch the image from a public registry.

  • Specification per Instance & Max Instances:

    • The smallest running unit of a Virtual Server is referred to as a Pod, where each Pod can have its CPU and memory usage configured. Virtual Server supports automatic scaling, allowing you to customize the maximum number of instances running concurrently.

    • You can allocate the required CPU and memory size based on your program's needs, considering whether it is computation-intensive or space-intensive. This flexibility allows for optimal resource management tailored to your application's requirements.

  • Listen Port: since Virtual Server is essentially a Web Server, a port is needed to listen to HTTP requests. It's worth noted it is only the internal listen port inside the pod. If you access the virtual server outside such as in the browser or Http API, the port will be 443.

  • Persistent Volume: The disk that is mounted to the virtual server. You should create one in the Virtual Server Storage page.

  • Environment Variables: Your program can access environment variables, enabling it to adapt and respond to different configurations and runtime conditions effectively.

  • Launch Args: The arguments for the Virtual Server launching.

  • Visibility: Virtual Server can be accessed from both the game client, backend http API and dedicated server. For safety issues, you can choose to block requests from the client side.

After a Virtual Server is created, you can inspect the deployment status:

image-20240419142551128

Under normal circumstances, the Building Status will first attempt to build the Docker image, and the Running Status will initially display 'Deploying.' Once the image is built successfully, the Running Status transitions to 'Running.' However, if a fatal error occurs during the image startup or if it fails to launch properly, the status will be 'Exception.'

提示

Common reasons for Virtual Server failing to start may include:

  • Listening port number in program is inconsistent with the one in the configuration.
  • The IP address the server listens to should be 0.0.0.0 instead of 127.0.0.1
  • A program crash.
  • The provided image address is unreachable for retrieval, among other issues.
  • Insufficient memory to launch space-intensive programs.
提示

When a Virtual Server remains in a low-load state for an extended period, the minimum number of instances will be reduced to 1, continuing to consume CPU and memory resources. If you wish to minimize resource usage during the development phase, you can click the 'Stop' button on the page to halt Virtual Server instances and fully reclaim all resources. When you need to run the Virtual Server again, simply clicking the 'Start' button will quickly create it back.

3. Virtual Server Environment Variables

The environment variables of Virtual Server are set when creating the Virtual Server, which can be accessed during the Virtual Server runtime to access different configurations and runtime environments. We can also modify them later. The environment variables of the current PGOS Virtual Server come from two sources:

  1. User-defined environment variables.
  2. System preset environment variables.

3.1 User-defined environment variables

When creating or updating a Virtual Server, you can set environment variables, which can be accessed during the Virtual Server runtime to access different configurations and runtime environments. The setting of environment variables is as follows:

image-20240419143318958

3.2 System preset environment variables

System preset environment variables are set by the system for the current Title Region, which can be accessed during the Virtual Server runtime to access different configurations and runtime environments. The preset environment variables are as follows:

Environment VariablesDescriptionExample
PGOS_Title_IDThe ID of the current Title5tcsa
PGOS_Title_NameThe name of the current TitlePGOS Test Game
PGOS_Title_LogoThe logo of the current Titlehttps://pgos-1303878176.cos.eu-frankfurt.myqcloud.com/logo/1629706971800-sh.png
PGOS_Title_Region_IDThe ID of the current Title Regioneuff_5tcsa_812179_dev
PGOS_Title_Region_NameThe name of the current Title RegionPGOS Dev Title Region
PGOS_Title_Region_TypeThe type of the current Title Regiondev, test, release
PGOS_Title_Region_Cloud_ProviderThe cloud provider of the current Title Regiontcloud, aws
PGOS_Title_Region_Backend_API_DomainThe domain of the backend API of the current Title Regioneuff.server.pgos.intlgame.com
PGOS_Title_Region_CLI_API_DomainThe domain of the CLI API of the current Title Regioneuff.pgos.intlgame.com
PGOS_VS_NameThe name of the current Virtual ServerPGOS-Test-Virtual-Server-001
PGOS_VS_Listen_PortThe listen port of the current Virtual Server8080
PGOS_VS_Storage_<Storage Name>The configuration of the Virtual Server StoragePGOS provides Redis and MongoDB storage, each with different configuration information, as follows.

3.2.1 Redis Environment Variable

If we have a Redis storage named "RedisA", we can access the configuration information of this storage through the environment variable PGOS_VS_Storage_RedisA. The configuration information of the Redis storage is as follows:

PGOS_VS_Storage_RedisA = '{"type":"Redis","version":"5.2.0","name":"RedisA","memory":1,"network":[{"port":6379,"inner_ip":"172.21.0.81"}],"password":"TVCND0FHGk4jE8x7","instanceId":"crs-9vnjdg8g","clusterType":"Standard","shardNumber":0,"masterSlaveNumber":1}',

Environment variable value is a JSON string, which contains the configuration information of the Redis storage, as follows:

{
"type": "Redis",
"version": "5.2.0",
"name": "RedisA",
"memory": 1,
"network": [
{
"port": 6379,
"inner_ip": "172.21.0.0"
}
],
"password": "xxxxx",
"instanceId": "crs-9vnjdg8g",
"clusterType": "Standard",
"shardNumber": 0,
"masterSlaveNumber": 1
}
  • type: Storage type, which is Redis
  • version: Redis version
  • name: Redis name
  • memory: Redis memory size
  • network: Redis network configuration, including port and inner IP
  • password: Redis password
  • instanceId: Redis instance ID
  • clusterType: Redis cluster type
  • shardNumber: Redis shard number
  • masterSlaveNumber: Redis master-slave number

3.2.2 MongoDB Environment Variable

If we have a MongoDB storage named "MongoDBA", we can access the configuration information of this storage through the environment variable PGOS_VS_Storage_MongoDBA. The configuration information of the MongoDB storage is as follows:

PGOS_VS_Storage_MongoDBA = '{"type":"MongoDB","version":"5.0.0","cpu":2,"disk":100,"name":"MongoDBA","memory":4,"account":"mongouser","network":[{"port":27017,"role":"Primary","inner_ip":"172.21.0.42"},{"port":27017,"role":"Secondary","inner_ip":"172.21.0.116"},{"port":27017,"role":"Secondary","inner_ip":"172.21.0.145"}],"password":"2bnUyqZ3fbgUxM4T","mongosCpu":0,"instanceId":"cmgo-rgde6vl5","replicaSet":"cmgo-rgde6vl5_0","clusterType":"Standard","shardNumber":0,"mongosMemory":0,"mongosNodeNum":0,"masterSlaveNumber":3}'

Environment variable value is a JSON string, which contains the configuration information of the MongoDB storage, as follows:

{
"type": "MongoDB",
"version": "5.0.0",
"cpu": 2,
"disk": 100,
"name": "MongoDBA",
"memory": 4,
"account": "mongouser",
"network": [
{
"port": 27017,
"role": "Primary",
"inner_ip": "172.21.0.1"
},
{
"port": 27017,
"role": "Secondary",
"inner_ip": "172.21.0.2"
},
{
"port": 27017,
"role": "Secondary",
"inner_ip": "172.21.0.3"
}
],
"password": "xxxx",
"mongosCpu": 0,
"instanceId": "cmgo-rgde6vl5",
"replicaSet": "cmgo-rgde6vl5_0",
"clusterType": "Standard",
"shardNumber": 0,
"mongosMemory": 0,
"mongosNodeNum": 0,
"masterSlaveNumber": 3
}
  • type: Storage type, which is MongoDB
  • version: MongoDB version
  • cpu: MongoDB CPU cores
  • disk: MongoDB disk size
  • name: MongoDB name
  • memory: MongoDB memory size
  • account: MongoDB account
  • network: MongoDB network configuration, including port, role, and inner IP
  • password: MongoDB password
  • mongosCpu: MongoDB mongos CPU cores
  • instanceId: MongoDB instance ID
  • replicaSet: MongoDB replica set
  • clusterType: MongoDB cluster type
  • shardNumber: MongoDB shard number
  • mongosMemory: MongoDB mongos memory size
  • mongosNodeNum: MongoDB mongos node number
  • masterSlaveNumber: MongoDB master-slave number

3.3 Access Environment Variables

When the Virtual Server is running, you can access the environment variables through the code. Different programming languages and frameworks have different ways to access them. Here is an example using NodeJS/Golang/Python to access the environment variables:

  package main

import (
"fmt"
"os"
)

func main() {
// 1. Print all environment variables
for _, e := range os.Environ() {
fmt.Println(e)
}

// 2. Print specified environment variables
titleID := os.Getenv("PGOS_Title_ID")
titleName := os.Getenv("PGOS_Title_Name")
titleLogo := os.Getenv("PGOS_Title_Logo")
titleRegionID := os.Getenv("PGOS_Title_Region_ID")
titleRegionName := os.Getenv("PGOS_Title_Region_Name")
titleRegionType := os.Getenv("PGOS_Title_Region_Type")
titleRegionCloudProvider := os.Getenv("PGOS_Title_Region_Cloud_Provider")
titleRegionBackendAPIDomain := os.Getenv("PGOS_Title_Region_Backend_API_Domain")
titleRegionCLIAPIDomain := os.Getenv("PGOS_Title_Region_CLI_API_Domain")

vsName := os.Getenv("PGOS_VS_Name")
vsListenPort := os.Getenv("PGOS_VS_Listen_Port")

vsStorageRedis := os.Getenv("PGOS_VS_Storage_Redis")
vsStorageMongoDB := os.Getenv("PGOS_VS_Storage_MongoDB")
}

4. Trigger Virtual Server

Virtual Server can interact with other services on PGOS, such as subscribing to Events, implementing scheduled Tasks, and integrating with the economic system's events. Developers can also access Virtual Server from the client-side or Dedicated Server (DS) using HTTP API, just like interacting with other PGOS services.

4.1 Triggered by PGOS Event

PGOS generates numerous Events, including player login/logout, room creation, room disbanding, player entry, and game session start/stop. You can write Virtual Servers to subscribe to these events and execute custom actions when the events are triggered.

For instructions on handling Events, please click here.

For structure definitions of all PGOS Events, please click here.

4.2 Triggered by Backend HTTP API

PGOS allows game backends access PGOS services by using HTTP API, which includes Virtual Server. You can fire a request to the Virtual Server directly by backend HTTP API, for example:

curl
-H "content-type: application/json" \
-H "TitleId: your_title_id" \
-H "TitleRegionId: your_titleregion_id" \
-H "SecretId: your_secret_id" \
-H "ServerTicket: your_server_ticket" \
-X POST -d "I am request body" -v http://your_titleregion_domain/virtualserver/invoke/vs-sample-python/backend_hello

NOTE: the SecretId is the first part of your Server Key, the ServerTicket is a ticket which is calculated by PGOS backend Http ticketing algorithm. You can also do it in your source code for sure, so that you can access the Virtual Server in your own program. For more instructions, please click here.

4.3 Triggered by PGOS Task

PGOS supports scheduling tasks to run at specified intervals. For information on configuring scheduled tasks to trigger Virtual Server, please click here.

4.4 Triggered by PGOS Economy Service

PGOS's economic system allows players to trigger in-game logic through a Virtual Server when using consumable items. For usage instructions, please click here.

4.5 Triggered by PGOS Matchmaking Service

PGOS's matchmaking system allows developers to change matchmaking result through a Virtual Server, which can modify team assignments, split one battle into more, or drop some tickets out of a battle. For usage instructions, please click here.

4.6 Triggered by IDIP Adapter

Bind Virtual Server in IDIP addon.

4.7 Triggered by Game Client

PGOS allows game to trigger virtual server through the following PgosSDK APIs on the game client:

/**
* Invoke the specified virtual server.
*
* @param Req The request info of the call.
*/
void InvokeVirtualServer(
const FVirtualServerReq& Req,
TFunction<void(const FPgosResult& Ret, const FVirtualServerResp* Data)> Callback) const;

struct FVirtualServerReq
{
/** The name of the virtual server. */
FString server_name;
/** [Optional] The requested url if there is any. For example: "/battle/settlement". */
FString url;
/**
* Extra header fields required by the game.
* It is advisable to add a "Content-Type" field to avoid being rejected by the server, based on the request body format.
* for example: extra_headers["Content-Type"] = "text/plain"
* Here are the fields reserved for PGOS that cannot be used by the game:
* "SDKVersion", "ProtoVersion", "TitleId", "TitleRegionId", "SessionId", "PlayerId", "PlayerTicket",
* "RoutingKey", "UicAccountInfo", "SecretID", "Pid", "ServerTicket", "DstAddr", "DstCode", "AccTicket".
*/
TMap<FString, FString> extra_headers;
/** [Optional] The request binary data. */
TArray<uint8> body;
};

struct FVirtualServerResp
{
/** The HTTP status code of the response. */
int32 status = 200;
/** The HTTP header of the response. */
TMap<FString, FString> resp_headers;
/** The HTTP body of the response. */
FString resp_body;
};

Example Code:

#include "PgosSDKCpp.h"

void SomeUObjectClass::SomeFunction()
{
auto Extension = IPgosSDKCpp::Get().GetClientExtensionAPI();
if (Extension)
{
FVirtualServerReq Req;
Req.server_name = TEXT("sample_vs"); // Virtual Server name
Req.url = TEXT("/battle/settlement"); // Virtual Server respond to /battle/settlement
Req.extra_headers.Add("Content-Type", "text/plain"); // Based on the request body format
FString BodyString = TEXT("This is a test string from the game client.");
int32 Utf8Length = FTCHARToUTF8_Convert::ConvertedLength(*BodyString, BodyString.Len());
Req.body.SetNumUninitialized(Utf8Length);
FTCHARToUTF8_Convert::Convert((ANSICHAR*)req.body.GetData(), req.body.Num(), *BodyString, BodyString.Len());
Extension->InvokeVirtualServer(Req, [](const FPgosResult& Ret, const FVirtualServerResp* Data) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("InvokeVirtualServer Success"));
}
else
{
UE_LOG(LogTemp, Log, TEXT("InvokeVirtualServer Failed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}

4.8 Triggered by Game Server

PGOS allows game to trigger virtual server through the following PgosSDK APIs on the game server:

/**
* Invoke the specified virtual server.
*
* @param Req The request info of the call.
*/
void InvokeVirtualServer(
const FVirtualServerReq& Req,
TFunction<void(const FPgosResult& Ret, const FVirtualServerResp* Data)> Callback) const;

struct FVirtualServerReq
{
/** The name of the virtual server. */
FString server_name;
/** [Optional] The requested url if there is any. For example: "/battle/settlement". */
FString url;
/**
* Extra header fields required by the game.
* It is advisable to add a "Content-Type" field to avoid being rejected by the server, based on the request body format.
* for example: extra_headers["Content-Type"] = "text/plain"
* Here are the fields reserved for PGOS that cannot be used by the game:
* "SDKVersion", "ProtoVersion", "TitleId", "TitleRegionId", "SessionId", "PlayerId", "PlayerTicket",
* "RoutingKey", "UicAccountInfo", "SecretID", "Pid", "ServerTicket", "DstAddr", "DstCode", "AccTicket".
*/
TMap<FString, FString> extra_headers;
/** [Optional] The request binary data. */
TArray<uint8> body;
};

struct FVirtualServerResp
{
/** The HTTP status code of the response. */
int32 status = 200;
/** The HTTP header of the response. */
TMap<FString, FString> resp_headers;
/** The HTTP body of the response. */
FString resp_body;
};

Example Code:

#include "PgosSDKCpp.h"

void SomeUObjectClass::SomeFunction()
{
auto Extension = IPgosSDKCpp::Get().GetServerExtensionAPI();
if (Extension)
{
FVirtualServerReq Req;
Req.server_name = TEXT("sample_vs"); // Virtual Server name
Req.url = TEXT("/battle/settlement"); // Virtual Server respond to /battle/settlement
Req.extra_headers.Add("Content-Type", "text/plain"); // Based on the request body format
FString BodyString = TEXT("This is a test string from the game server.");
int32 Utf8Length = FTCHARToUTF8_Convert::ConvertedLength(*BodyString, BodyString.Len());
Req.body.SetNumUninitialized(Utf8Length);
FTCHARToUTF8_Convert::Convert((ANSICHAR*)req.body.GetData(), req.body.Num(), *BodyString, BodyString.Len());
Extension->InvokeVirtualServer(Req, [](const FPgosResult& Ret, const FVirtualServerResp* Data) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("InvokeVirtualServer Success"));
}
else
{
UE_LOG(LogTemp, Log, TEXT("InvokeVirtualServer Failed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}

5. Handle the Request in Virtual Server

5.1 URI Specification

Virtual Server is a web server essentially. So, every request will be handled based on URI. There are two types of URI: reserved URI and customized URI. The reserved URIs are predefined by the PGOS backend and used in specific scenarios. The customized URIs are defined by yourself and used to request a virtual server for the game client or backend. The following table lists all the cases:

URITriggersHTTP MethodDefinerIs PGOS ReservedDescRelated Data Schema
/pgos_eventPGOS EventPOSTPGOSYesTriggered by Event HandlerEvent Data Schema
/pgos_taskPGOS TaskPOSTPGOSYesTriggered by TaskTask Data Schema
/pgos_economyPGOS Economy ServicesPOSTPGOSYesTriggered by EconomyEconomy Data Schema
/pgos_matchmakingPGOS Matchmaking ServicesPOSTPGOSYesTriggered by MatchmakingMatchmaking Post Processing Schema
/pgos_idipTencent IDIP ProtocolDefined by IDIPPGOSYesOnly for Tencent GameDefined by IDIP
URI only for game backendGame BackendPOSTGame DeveloperNoThe invoker is the game server
Backend API: InvokeVirtualServer
Defined by Game Developer
URI only for game clientGame ClientPOSTGame DeveloperNoThe invoker is the game client
Client API: InvokeVirtualServer
Defined by Game Developer
提示

The requester will receive an error message if the game client or backend requests the reserved URI(like /pgos_event) directly. Because the reserved URIs are only accessible for specific services and are triggered by PGOS automatically.

5.2 Request Headers and Security Handling

Several predefined and reserved request headers may be helpful for the game. You can also use any other headers as long as they are not the reserved headers that will be mentioned.

Header KeyValue SpecScopeIs PGOS Reserved
TitleidThe ID of your titleAllYes
TitleregionidThe ID of your title regionAllYes
PlayeridThe Player ID of the game clientOnly Game Client RequestYes
SessionidThe Player Session ID of the game clientOnly Game Client RequestYes
Invokerevent / task / economy / idip / backend / client / intranetAll
(intranet only from virtual server)
Yes
X-Forwarded-ForIPs of the request. The first IP is from the request clientGame Backend/Client RequestNo
(Defined in RFC 2616)
提示

NOTE: The header Invoker is set by the PGOS backend automatically. PGOS can guarantee it is set or overwritten with proper value even though the requester set it. This header is noteworthy for game developers and can help the virtual server to validate if the request is valid. For safety considering, you should validate this header at the beginning of every request handling. For example, you implement the URI /backend_func. It is only visible for the backend. So, any request from the client to the /backend_func will fail, because you do the validation by checking the header Invoker if it equals backend. The sample Node.js code is as below:

var invoker = ctx.request.headers['Invoker'];
if (invoker != 'backend') {
ctx.status = 401; // return http code 401 to the requester
return;
}

Here is specification of the Invoker.

URIInvoker Header ValueDesc
/pgos_eventeventTriggered by Event Handler
/pgos_tasktaskTriggered by Task
/pgos_economyeconomyTriggered by Economy
/pgos_matchmakingmatchmakingTriggered by Matchmaking
/pgos_idipidipOnly for Tencent Game IDIP System
URI only for game backendbackendThe invoker is the game server
Backend HTTP API: InvokeVirtualServer
URI only for game clientclientThe invoker is the game client
Client API: InvokeVirtualServer
提示

If you don't want to expose the server to the game client totally, a simpler way is to set the Block Game Client Request in the Configuration page of the virtual server. Please refer to the 2. Create and Manage Virtual Server

5.3 The Request and Response Protocol

For the customized URI, you decide the status code, headers and body schema of the request and response. So, you can implement your backend services with virtual server. But, for the reserved URI, you should follow the protocol specification defined by PGOS. Here are the details:

5.3.1 The Protocol of /pgos_event

/pgos_event is used to handle the PGOS Event when you bind the Event handler with the virtual server on the portal.

  • Content-Type: application/json

  • The Request body schema:

// e.g. event_player_login_pgos
{
"trigger_id": "24ea65b9-a6fb-4de7-9622-410e33c73339",
"event_name": "event_player_login_pgos",
"event_time": "1683603150102",
"event_data": {
"custom_data": "123",
"ip_addr": "183.14.133.2",
"is_new_player": false,
"location": "-",
"platform": "WINDOWS",
"player_id": "123",
"session_id": "1655777737338073088",
"start_time": 1683603150
},
"args": {
"arg1": 1
}
}

Here is the detailed Extension Data Schema for every event.

  • The Response body schema

PGOS will store the response body into the access logs for event. So, you can leave it with empty string, or fill with the any string. You can view the access log on the page Extensions/Events/Trigger Logs of portal.

  • HTTP Status Code

HTTP 200 should be returned if you handle the event successfully, and other abnormal code can be returned if any error occurs on your side. It will also be stored into the access logs.

5.3.2 The Protocol of /pgos_task

/pgos_task is used to handle the PGOS Task when you bind the Task with the virtual server on the portal.

  • Content-Type: application/json

  • The Request body schema:

// e.g. event_player_login_pgos
{
"trigger_id": "24ea65b9-a6fb-4de7-9622-410e33c73339",
"task_name": "event_player_login_pgos",
"task_time": "1683603150102",
"args": {
"arg1": 1
}
}

Here is the detailed Extension Data Schema for task.

  • The Response body schema

PGOS will store the response body in the access logs for the event. So, you can leave it with an empty string, or fill it with any string. You can view the access log on the page Extensions/Events/Trigger Logs of the portal.

  • HTTP Status Code

HTTP 200 should be returned if you handle the event successfully, and other abnormal codes can be returned if any error occurs on your side. It will also be stored in the access logs.

5.3.3 The Protocol of /pgos_economy

/pgos_economy is used to handle the PGOS Economy when you bind the virtual server for Economy service on the portal.

  • Content-Type: application/json

  • The Request body schema:

 // e.g. item_consume
{
"trigger_id": "24ea65b9-a6fb-4de7-9622-410e33c73339",
"operation": "item_consume",
"trigger_time": "1683603150102",
"data": {
...
}
}

Here is the detailed Extension Data Schema for every economy handling.

  • The Response body schema

PGOS will store the response body in the logs for the economy. So, you can leave it with an empty string, or fill it with any string. You can view the logs of the specific player on the page Players/Query/Economy/Logs of the portal

  • HTTP Status Code

HTTP 200 should be returned if you handle the event successfully, and other abnormal codes can be returned if any error occurs on your side. It will also be stored in the access logs.

5.3.4 The Protocol of /pgos_matchmaking

/pgos_matchmaking is used to handle the matchmaking task when you have a match config associated with a virtual server.

  • Content-Type: application/json

  • The Request body schema:

 // e.g. matchmaking_post_processing
{
"trigger_id": "24ea65b9-a6fb-4de7-9622-410e33c73339",
"operation": "matchmaking_post_processing",
"trigger_time": "1683603150102",
"data": {
"battle": { ... } ,
"battle_properties": [ ... ]
}
}

Here is the detailed Extension Data Schema for every matchmaking request handling.

  • The Response body schema:
 // e.g. matchmaking_post_processing
{
"battles": [ ... ],
"requeued_tickets": [ ... ]
}

Here is the detailed Extension Data Schema for every matchmaking response handling.

  • Precautions

When implementing a virtual server, please follow the best practices recommended in the PGOS documentation.

  • HTTP Status Code

HTTP 200 should be returned if you handle the event successfully, and other abnormal codes can be returned if any error occurs on your side. It will also be stored in the access logs.

5.3.5 The Protocol of /pgos_idip

/pgos_idip is used to handle the message of the IDIP system(a Tencent in-house system and only for Tencent games) if you configure the virtual server on the IDIP add-on.

  • Content-Type: defined by the IDIP system
  • The Request body format: defined by the IDIP system
  • The Response body format: defined by the IDIP system
  • HTTP Status Code: HTTP 200. The error code and message are in the response body.

5.4 Access Virtual Storage in Virtual Server

PGOS provides Virtual Storage for the game to store the data in the DB or Cache. Since the virtual server can be built with any language and tech stack. Once you get the instance of virtual storage, you can access the storage by using any suitable driver. Here is an example: language is Golang, virtual storage is a redis, and the driver github.com/gomodule/redigo may be a good choice.

As for how to create a virtual storage, please visit virtual storage manual.

5.5 Access PGOS Backend with HTTP API in Virtual Server

Maybe you need to access PGOS Backend in a virtual server, such as getting the player's info, modifying player data, etc. You can also use the HTTP API in any language to access the PGOS backend in a virtual server, just like doing it in-game servers. There is no difference between the two ways. Please visit Backend HTTP API to learn how to do it.

提示

For performance and cost consideration, the requests will be automatically routed to the intranet of PGOS if your virtual server accesses the endpoints of PGOS Backend HTTP API in the same region.

5.6 Timeout Limitation

Every request has timeout limitation. If the RTT from the virtual server is over the limitation, the PGOS backend would break the request and return an HTTP 504 error to the requester. So, you should keep the maximum timeout in the virtual server.

URITimeout Limitation
/pgos_event3 seconds
/pgos_task
/pgos_economy
/pgos_idip
/pgos_matchmaking
10 seconds
URI only for game client10 seconds
URI only for game backend10 seconds
提示

Why we set event timeout limitation to only 3 seconds? Because events are dispatched by a queue system(kafka) underlayer to gaurantee the order of the events that triggered by backend. If every event handler takes too long, it can cause a lot of blocking , eventually the throughput of the whole system will drop dramatically. So, for performance considering, every event handler needs to be set a shorter timeout limitation.

6. Local Virtual Server

You can run your virtual server locally for debugging or testing before deploying it online. As a web server, you can access the local virtual server directly through any HTTP tools (cURL, Postman, etc.). However, in this chapter, we will explain how to enable a game client or local DS (game server) to access a local virtual server.

6.1 Run Local Virtual Server

After finishing coding your virtual server, you can run it locally via the IDE or start it directly. The following screenshot is an example of launching via VS Code.

image-20230627162915025

In this example, we will configure the following information on the portal console so that the game client and DS invocation code can work properly with this virtual server, whether it is running locally or online:

  • Server Name: vs-smoke
  • Listen Port: 8082

6.2 Add Codes to Invoke Virtual Server

Whether the virtual server is running locally or online, you can invoke it from the game client or the game server. Click the links to learn how to invoke the virtual server from game client and from game server.

6.3 Config Local Virtual Server

Configure local virtual servers for your game client or game server to access. Find and open the configuration file: pgos_config.ini (for game client) or pgos_server_config.ini (for game server)

The location of these configuration files:

  • If launching the client/server via the UE project, look in the directory: {GameProjectPath}\Saved\PgosRes\
  • If launching the client/server from a packaged program, look in the directory: {PackedGamePath}\{GameName}\Binaries\pgos_res

Add the local_vs_config configuration item in the configuration file:

image-20230627170606877

[Local VS Environment]
local_vs_config = {"vs_addrs":{"vs-smoke":"127.0.0.1:8082"}}

The value of the local_vs_config configuration item is a JSON string, and you can add any virtual server you want to access locally in vs_addrs:

  • JSON key: the server name of the virtual server
  • JSON value: the address of virtual server (including port), for example: 127.0.0.1:8082

6.4 Access Local Virtual Server

After completing the above operations, run your game client or game server. When the relevant code is executed, it will trigger access to the local virtual server.

7. Access Virtual Server via Browser

After PGOS v0.27.0, you can access your virtual server in browser, which is an useful feature for the following scenarios:

  • Deploying the open source software in virtual server, such as Prometheus, Grafana, etc.
  • Install open source database console to manage your database or disk
  • Write your own admin system and deploy it to manage the data stored in the virtual server storage(Redis/MongoDB/Disk). For example, A player management system you implement.

7.1 How to Access Virtual Server via Browser

The entry of browsing virtual server is disabled by default. You can find the entry in the Summary page of a virtual server. You should enable it before browsing like the screenshot showed. Once enabled, you can click the Open Home Page link to open your virtual server on the new tab of the browser.

image-20240912110852226

7.2 Security of Virtual Server Browsing

PGOS has the security validation for virtual server browsing. Every time you open the virtual server in browser, PGOS would validate the authentication of Portal, only the legitimate requests will be granted access. It is only accessed by your title managers(the users have virtual server updating permission of your title region). It will fail if anyone types the portal domain of the virtual server directly in the browser to open the virtual server. So, it is safety.

7.3 Known Issue

提示

Currently, Virtual Server doesn't support the web socket connection. So, it may doesn't work if your app deployed in VS using web socket.

8. Intranet Communication for Virtual Servers

The virtual server can communiate with other virtual servers currently. You can find the Domain for Intranet field in the Summary page of a virtual server, shown as below.

image-20240912110658485

提示

Note that the domain for intranet is only used for communicating internally for same title. Currently the domain suffix is virtualserver.int, the protocol is HTTP and the port is 80. Such as http://prometheus.xxx.xxx.virtualserver.int

9. Log Collection

Currently there are two type of logs that are supported: Server log and Access log.

  • Server log

    PGOS would collect your server log automatically as long as your server print the logs into stdout. You can query them in the Logs page of the virtual server.

  • Access log

    PGOS will collect the access log in Nginx default format for every virtual server once you open the option in the Summary page shown as below. You can query them in the Logs page as well.

    image-20240912110552244

10. Best Practice of Writing a Virtual Server

10.1 Suggested Steps

Since the virtual server is a web server essentially. You should choose a suitable languages and framework to implement a web server. Here are the suggested steps:

Step 1. Choose a suitable language based on your scenario

To implement a server, the choice of language is the top big thing at the beginning. You always need to consider many factors, such as:

  • The requirements and scenario of the server
  • The language habits of the development team
  • The performance expectation
  • The perfection of the language ecosystem
  • The development efficiency

Here are some mainstream languages that can be used to implement a server: Golang, NodeJS, Python, etc.

Step 2. Choose a suitable web server framework

The choice of server framework is the next big thing once the language is determined. A good framework should be reliable and high-performance. Here are some mainstream frameworks for your reference:

  • Golang: Fiber, Beego
  • NodeJS: Koa, Express
  • Python: Flask, Bottle

Step 3. Write your server

You should confirm the functionality that the virtual server needs to implement. Such as:

  • If it handles the PGOS Event, Task, Economy, etc. You should handle the specific URL.
  • If it handles the request from the game client, you should make the protocol for communicating between the game client and the virtual server.
  • If it handles the request from the game server, you should make the protocol for communicating between the game server and the virtual server, and then write the code to handle the request from the game server. Since a server can serve the server and client at the same time, So, don't forget the Invoker validation.
  • If it needs to access virtual storage, you need to create the virtual storage instance in advance, and then choose a suitable driver to write the code to access it.

Step 4. Debug or test it locally

Since the virtual server is a standalone web server, you can debug and test it locally. But, if you want to do the local debug for the code of accessing virtual storage directly, you will fail to access the virtual storage since the virtual storage is deployed in the intranet of PGOS backend. Maybe you need a debug agent to access the virtual storage locally ( only for Dev Title Region).

Step 5. Upload the image and test it

You can upload the build to the virtual server on the portal or CLI once you complete all development and debug works. Then, you may need to test it on the game client or DS directly. Please make sure all functionality works well before you release your game client.

Step 6. Utilize resource efficiently

To deliver a seamless and robust experience while maintaining cost-effectiveness, it is a key aspect to utilize resource efficiently. By conducting stress tests on your service and observing the CPU and memory usage graphs on the Dashboard, you can assess whether your service is more sensitive to computation or space requirements. This information allows for a more scientific approach to adjusting the specifications of the CPU and memory, ensuring optimal performance and resource allocation. When a single instance cannot handle user requests due to performance limitations, you can improve the performance level of stateless services proportionally by adjusting the value of Max Instances. This scaling mechanism ensures that the platform adapts to increased demands while maintaining seamless user experience and operational efficiency.

10.2 Sample Code

We wrote several samples to demonstrate how to write the virtual server with different languages and write suitable Dockerfile. You can even copy it and modify the code to implement your version:) If you want to use it to deploy your virtual server, note that you should upload it as the source type Source Code with Dockerfile. Please enjoy them.

11. Best Practice of Deploying Third-party Software

PGOS enhanced the virtual server to support database, disk and accessing via browser. Our goal is to make it easier to run the software directly. Currently, you can almost run most of software on the market like Docker Hub, github, etc. We are building virtual server to become a game backend eco-system. There are a few typical scenarios:

  • Deploy monitor software to monitor your game backend, you may need use databases or disk that are created in Virtrual Server Storages
  • Write your own server and access the data stored in the databases or disk to implement your custom services for your players
  • Write your own admin system to manage your game backend, which can be accessed via browser directly in PGOS portal

If the softwares you deployed need to communicate with each other internally. You can also use the Domain for intranet to do it. For example, you can configure the intranet domain of MongoDB Exporter you deployed as the scrape target of the Prometheus you deployed.

We released the market for virtual server, in which there will be the mainstream software images and installation guidances. We believe it would dramatically increase your productivity. Click the Virtual Server Market to see the details.