Social networking is a basic need of game players, which should be implemented in a mature and stable game chat system. This document shows the successful use of Tencent Cloud SCF by RiverGame and describes how to upgrade the chat system in a game with SCF.
RiverGame used its proprietary chat system in its two games: "Top War: Battle Game" and "Farm Town". However, as the number of online players increased, the system stability and costs were facing more challenges, which called for an upgrade in its technology stack so as to reduce the labor and resource costs while ensuring high performance. In this regard, it chose SCF as its solution for the following reasons:
Accordingly, it is only needed to focus on how to migrate the existing system seamlessly, i.e., how to use SCF to meet all the specific needs.
With Swoole used as the bottom-layer extension, some legacy APIs were deployed in CVM and used CLB to receive external requests, Composer to manage packages at the code layer, and the open-source framework EasySwoole as the HTTP business framework.
With the SCF scheme in place, API Gateway and SCF would be used to provide services at the non-code layer, while Composer would still be used to manage packages at the code layer. The legacy Swoole-based HTTP framework could no longer be used, and the framework was the focus of code modification as shown below:
The following is the modification principle:
url
:https://url/controller/action?query
The controller
and action
can be obtained simply by parsing the path
provided by the SCF function. After the fields are determined, the method of the corresponding class will be called to return relevant content. Based on such an entry, the legacy logic processing classes can be called.querystring
content, parsingbody
, or returning values in a unified format, needs to be implemented.date_default_timezone_set('Asia/Shanghai');
require_once__DIR__ . "/vendor/autoload.php";
function run($event, $context)
{
$path = $event->path;
// Parse `path`
list($controller, $action) = parsePath($path);
$controllerClassName = "\\App\\HttpController\\" . ucwords($controller);
if(!class_exists($controllerClassName)){
return return404();
}
$controllerClass = new $controllerClassName($event, $context);
// Do not call classes that should not be called externally in the `HttpController` directory
if(!controllerClassName instanceof \App\BaseController){
return return404();
}
if(!method_exists($controllerClass, $action)){
return return404();
}
try{
return $controllerClass->$action();
}catch(Throwable $e){
return return500();
}
}
The quick release capability is indispensable. During the migration, various tests were conducted repeatedly. As the local testing feature of SCF did not support PHP during the migration back then, the release process when API Gateway and SCF were used together was as follows:
$LATEST
version of the function$LATEST
versionThe release process was relatively complicated. When the migration started, API call as described in step 3 was not supported yet; therefore, automated deployment could not be implemented, which is currently supported though. The scheme where API Gateway was used to directly point to the $LATEST
version of the function and then the function was deployed can still be used, but it is quite simple and only applicable to testing instead of release in the production environment.
We combined the two methods, i.e., using the release process of stable version for stable features and creating an API path pointing to the $LATEST
version for new features. In this way, new versions could be released at any time without affecting the features in the production environment.
When API Gateway was published, the resources might exceed the limit, which was found to be caused by the limit on the number of concurrent SCF instances. When a new API version was published, access to a new instance would be requested while the legacy instance had not been released yet. If the total numbers of new and legacy instances exceeded the limit, it would be needed to apply to Tencent Cloud for quota increase.
The migration was at the system level, but some contents in the legacy system still needed to be used in the future. Therefore, SCF needed to interconnect with the legacy CVM instances over the private network. As SCF supports deployment in the existing private network, it is easy to implement private network interconnection.
As the API service needed to send requests to the public network, but private network SCF could not directly access the public network during the system migration, NAT Gateway was used to enable SCF to access the public network. For more information, please see Configuring NAT Gateway in VPC.
Note:
When NAT Gateway is used, it is recommended to assign a separate subnet to SCF, as the egress IP will change if NAT Gateway is bound to an existing subnet. If the server IP of the subnet is in some whitelists, it will result in certain impact.
Originally, logs were directly stored in the disk and compressed and dumped periodically. After the system was migrated to SCF, the SCF log mechanism needed to be used. SCF can directly deliver logs to CLS, and any output information can be directly delivered as logs. It is required to plan the log contents as needed.
The original information, URL paths, client IPs, parameters after parsing, and business logs of the function entry can be output for quick problem locating and query. In addition, there is no need to output the returned values separately, as SCF can print them automatically.
Note:
After log delivery is enabled, logs can be viewed only after index is enabled. If log content includes index separators, the corresponding keywords need to be deleted from the separators when the index is configured; otherwise, the content will be split.
During the system migration, the SCF log feature had certain shortcomings, such as separate SCF and API Gateway logs. As the original HTTP entry was API Gateway, which might cause some problems hard to be traced. Currently, the RequestId
fields in SCF and API Gateway have been aligned, which makes it easier to query the logs of the same request through the same ID.
The legacy scheme used task
of Swoole to process time-consuming tasks. As the PHP environment of SCF supports Swoole, the modification scheme in the following figure was used as an initial attempt:
$p = "1";
$process = new \swoole_process(function (\swoole_process $worker) use ($p){
echo $p;
sleep(3);
echo $p;
});
$pid = $process->start();
However, the process implemented through this scheme could not be completely controllable. As discovered from testing, the printed logs belonged to other requests, and the process time and lifecycle could not be determined. Therefore, a more assured "message queue" scheme was used.
CKafka, Tencent Cloud's proprietary message queue service, was used. After a message body with a general structure is encapsulated and sent to CKafka, it will trigger another SCF function (which runs time-consuming task code). If a general structure is used, the CKafka topic can be ignored. If there is any task requiring async operations, it only needs to be written into the SCF function to be triggered by CKafka, and the name and parameters of the function will be sent to CKafka as shown below:
Only one partition is created for one CKafka topic by default. If the consumption speed is not satisfactory, it can be increased by adding new partitions. After a new partition is added, the trigger needs to be deleted and added again in the SCF function.
Configuration files in the system were large and required frequent updates, such as the list of banned words used in the chat service.
In the legacy scheme, a configuration file had its own Git library, and Jenkins was started after the planner submitted the file, which then uploaded the file to CVM and reloaded it.
After the system was migrated to SCF, configuration files could not be uploaded separately but could only be placed in the code. The scheme was updated as follows: the planner submits a file to Git, Jenkins gets it from Git and uploads it to COS, and SCF pulls it from COS as shown below:
There was a performance problem where it took some time for an SCF function to pull data from COS; therefore, files could not be pulled every time when a request was initiated. This meant that the content in each pull needed to be retained in the memory; however, the SCF memory could not be managed uniformly, and real-time change could not be guaranteed.
A compromise scheme is adopted where the pull time of file content retained in the memory is compared with last pull time. If the gap between them exceeds 5 minutes, the content will be pulled again to ensure relative real-timeliness and satisfactory performance and meet the current needs as shown below:
private static $fileContent = null;
private static $lastTime = 0;
public static function refresh(){
self::$fileContent = self::readFromCos("words.txt");
}
public static function getFileContent(){
if(time() - self::$lastTime > 300 || empty(self::$fileContent)){
self::refresh();
self::$lastTime = time();
}
return self::$fileContent;
}
At this point, all requirements in the system migration had been satisfied, and the migration was carried out smoothly. After migration to SCF, the customer enjoys the following advantages:
Tencent Cloud SCF has brought various advantages and benefits to RiverGame, which also plans to use the following features in the future:
Was this page helpful?