34. 服务器管理Part 2: 服务器监控

34.1. Counter

iFun引擎在游戏服务器内通过Counter显示。利用它,可以直接创建外部监控工具。同时,iFun引擎还提供了可以运用counter监控多种信息的 iFun引擎dashboard 。(具体内容请参考 iFun引擎dashboard。 )

34.1.1. 计数器的读取和写入

34.1.1.1. 计数器的写入

利用以下3个函数写入计数器值。

Note

当不存在单独的注册函数,而调用上面的写入函数时,将注册计数器。

34.1.1.2. 读取计数器

已创建好的计数器可在服务器内通过Integer、String、Double的形式读取。 读取外部计数器时,请参考 通过REST形式读取外部计数器

34.1.1.3. 计数器使用示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
#include <funapi.h>

void example(){

  UpdateCounter("server", "item_count", 150);

  UpdateCounter("server", "monster_count", "The number of monsters", 150);

  IncreaseCounterBy("server", "item_count", 1);

  DecreaseCounterBy("server", "item_count", 1);

  int64_t item_count = ReadCounterAsInteger("server", "item_count");
  BOOST_ASSERT(item_count == 150);

  UpdateCounter("server", "connection_per_second", 77.7);

  UpdateCounter("billing", "purchase_per_second", 7.1);
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
using funapi;

public void Example()
{
  Counter.Update ("server", "item_count", 150);

  UpdateCounter("server", "monster_count", "The number of monsters", 150);

  Counter.Increase ("server", "item_count", 1);

  Counter.Decrease ("server", "item_count", 1);

  Int64 item_count = Counter.ReadInteger ("server", "item_count");

  Counter.Update ("server", "connection_per_second", 77.7);

  Counter.Update ("billing", "purchase_per_second", 7.1);
}

34.1.1.4. 通过REST形式读取外部计数器

前面定义的counter,可按如下方式访问。

GET http://localhost:8014/v1/counters/

导入全部计数器category列表。

GET http://localhost:8014/v1/counters/funapi/

显示作为已预约的计数器category的iFun引擎category内的计数器列表。

GET http://localhost:8014/v1/counters/server/item_count/

读取程序员创建的server category内的 item_count 计数器值。上述示例中为 150

GET http://localhost:8014/v1/counters/billing/purchase_per_second/

读取程序员创建的billing category内的 perchase_per_second 计数器值。上述示例中为 7.1

GET http://localhost:8014/v1/counters/server/monster_count/description/

读取程序员创建的server category内的 monster_count 计数器值。上述示例中为 “The number of monsters”

Tip

如果为Counter添加注释,则可在与外部系统联动时向外部作业人员提供更加明确的涵义。

34.1.2. 监测计数器变化

对于 IntegerDouble 类型的计数器,当计数器的值为特定值以上时,可以输出日志。 利用该功能,有助于监测游戏内金币的急剧变化等。

下面的示例中通过Counter计算玩家每小时收集的金币量,超过10万时,会显示提示消息。

34.1.2.1. 计数器变化感测示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
void OnResetGoldCounterTimerExpired(const Timer::Id &, const WallClock::Value &) {
  UpdateCounter("game", "gold_per_hour", 0);
}

void Install() {
  UpdateCounter("game", "gold_per_hour", 0);

  MonitorCounter("game", "gold_per_hour", 100000);

  Timer::ExpireRepeatedly(WallClock::FromSec(3600), OnResetGoldCounterTimerExpired);
}


// Assume this function is called when user pick gold.
void PickGold(int64_t gold) {
  IncreaseCounterBy("game", "gold_per_hour", gold);
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
void OnResetGoldCounterTimerExpired(UInt64 timer_id, DateTime clock)
{
  Counter.Update ("game", "gold_per_hour", 0);
}

void Install()
{
  Counter.Update ("game", "gold_per_hour", 0);

  Counter.Monitor ("game", "gold_per_hour", 100000);

  Timer.ExpireRepeatedly (WallClock.FromSec (3600), OnResetGoldCounterTimerExpired);
}

// Assume this function is called when user pick gold.
void PickGold(UInt64 gold)
{
  Counter.Increase ("game", "gold_per_hour", gold);
}

Note

如示例所示,为了注册监控器,须要调用 UpdateCounter()IncreaseCounterBy()DecreaseCounterBy() 函数等,提前注册好计数器。

现在每小时金币量超出10万金币时,就会显示如下日志。

W0818 11:03:06.520730 18324 counter.cc:160] The 'gold_per_hour of game' counter exceeded threshold: value=123456, threshold=100000

34.1.2.2. 输出变化感测日志

为防止生成过多的日志,每次输出的日志不会超出已在 MonitorCounter() 函数中输入的 threshold 值。 但会以已在 计数器的设置参数counter_monitoring_interval_in_sec 输入的秒数为单位,定期确认计数器值,输出日志。

34.1.2.3. 引擎中默认感测变化的计数器

引擎中默认进行监控的计数器如下。

34.1.2.3.1. Event
  • event_queue_length: 实施监控,确认由待处理事件所组成的事件队列长度 是否超出指定的 threshold 值。

34.1.2.3.2. ORM
  • outstanding_fetch_query: 实施监控,确认与调取待处理对象有关的Query个数 是否超出指定的 threshold 值。

  • outstanding_update_query: 实施监控,确认与变更待处理对象有关的Query个数 是否超出指定的 threshold 值。

Tip

这些计数器的警告threshold不可在 计数器的设置参数 中变更。

34.1.3. 默认提供的计数器列表

以下是引擎默认提供的计数器列表。

34.1.3.1. process

用于查询iFun引擎正在运行的进程信息的计数器。

Counter名称

说明

vsz

进程占用的虚拟内存大小。

cpu

进程的cpu使用率。

nivcsw

上下文切换之前任务未结束的次数。

nswap

当前不使用的字段。

oublock

文件系统已输出数。

minflt

在没有I/O的情况下出现的缺页故障数。

idrss

未共享的rss大小。

isrss

未共享的栈内存大小。

ixrss

共享的rss内存大小。

nsignals

收到响应的信号数。

majflt

因I/O而发生的缺页故障数。

maxrss

曾使用的rss最大值。

msgsnd

IPC消息传输数。

msgrcv

IPC消息响应数。

nvcsw

上下文切换之前任务结束的次数。

stime

进程以Kernel模式运行的总时间。

updated

最近一次更新的UTC时间。

utime

进程以用户模式运行的总时间。

inblock

文件系统已输入数。

refresh_interval

计数器更新周期(秒)。

34.1.3.2. os

查询服务器os信息的计数器。

Counter名称

说明

procs

正在运行的所有进程数。

freeswap

可使用的内存大小(byte)。

bufferram

作为缓冲区使用的内存大小(byte)。

load15

15分钟内的load average。

totalswap

全部内存大小(byte)。

load5

5分钟内的load average。

load1

1分钟内的load average。

updated

最近一次更新的UTC时间。

uptime

服务器启动时间与当前时间的间隔(秒)。

freeram

空闲RAM大小(byte)。

cpus

cpu核数。

totalram

全部RAM大小(byte)。

refresh_interval

计数器更新周期(秒)。

sharedram

全部共享内存大小(byte)。

type

os类型种类。

34.1.3.3. funapi

查询服务器的引擎信息。

Counter名称

说明

concurrent_user

当前访问服务器的用户数。须运用 AccountManager 做登录处理。具体内容请参考 查找客户端访问的服务器

sessions

当前访问服务器的会话数。

object

查询服务器中缓存的对象数、待处理的读取和写入Query数。

object_database_stat

各数据库对象相关Query的处理时间统计。具体内容请参考 (高级) ORM 性能分析

rpc_stat

RPC性能统计。

zookeeper_stat

为了共享对象而使用的 Zookeeper 的处理时间统计。具体内容请参考 Zookeeper处理的性能分析

event/performance/queue

查询服务器的事件流入量、处理量,以及正在等待的事件数等。

event/profiling/all

各事件的处理时间统计。具体内容请参考 事件性能分析: 详细信息

event/profiling/summary

所有事件的处理时间的统计。具体内容请参考 事件性能分析: 概要信息

event/profiling/reset

对事件性能解析进行重置。

event/profiling/outstanding

正在处理中的事件统计。

34.1.3.4. funapi_object_model

按model查询服务器中缓存的各对象数。

34.1.4. (高级)Callback型计数器

除了单纯注册并返回数字值以外,有时也须要为了计算计数器的值 而进行追加运算,或返回多个值。

例如,在须要返回平均值的情况,通常先在内部计算所有值的和与个数, 当需要平均值时,会返回用和除以个数后得到的值。

为进行这种运算,可以在counter中注册callback。

34.1.4.1. Callback型计数器使用示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <funapi.h>

http::StatusCode OnAverageQueried(
    const string &counter_group,  // "server" when called
    const string &counter_name,   // "average_users_per_room" when called.
    Json *ret) {
   if (total_rooms == 0) {
     return http::kNoContent;
   }

   double average = total_users / total_rooms;
   ret->SetDouble(average);

   return http::kOk;
}


void example() {
  RegisterCallableCounter(
      "server",
      "average_users_per_room",
      "Returns the average number of users per game room",
      OnAverageQueried);
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
using funapi;

funapi.http.StatusCode OnAverageQueried(
    string counter_group,  // "server" when called
    string counter_name,   // "average_users_per_room" when called
    JObject ret)
{
  if (total_rooms == 0) {
    return funapi.http.StatusCode.kNoContent;
  }

  double average = total_users / total_rooms;
  ret->SetDouble(average);

  return funapi.http.StatusCode.kOk;
}

void Example()
{
  Counter.RegisterCallableCounter (
      "server",
      "average_users_per_room",
      "Returns the average number of users per game room",
      OnAverageQueried);
}
GET http://localhost:8014/v1/counters/server/average_users_per_room/

调用该API后,将调用 OnAverageQueried() ,计算平均值后返回。

34.1.5. 计数器的设置参数

  • counter_flush_interval_in_sec: 定期更新外部显示的counter值时的时间间隔,单位为秒(type=uint64, default=0)

几乎不需要直接更改设置的参数

  • counter_monitoring_interval_in_sec: 对除了向外部发送的值以外的所有值进行监控的时间间隔,单位为秒(type=uint64, default=30)

  • warning_threshold_event_queue_length: 监控计数器时,若事件队列比该值长,将显示警告框(type=uint64, default=3000)

  • warning_threshold_outstanding_fetch_query: 监控计数器时,若DB读取队列比该值长,将显示警告框(type=uint64, default=3000)

  • warning_threshold_outstanding_update_query: 监控计数器时,若DB写入队列比该值长,将显示警告框(type=uint64, default=3000)

  • warning_threshold_slow_query_in_sec: 카운터 모니터링 시 DB 읽기 또는 쓰기에 소요되는 시간(단위: 초)이 기준 값보다 길어질 때 경고 메세지를 출력함(type=uint64, default=1)

  • warning_threshold_slow_distribution_in_sec: 카운터 모니터링 시 분산 처리에 사용되는 Zookeeper/Redis 처리 시간(단위: 초)이 기준 값보다 길어질 때 경고 메세지를 출력함(type=uint64, default=3)

34.2. iFun引擎dashboard

iFun引擎提供了可以便利监控游戏服务器的单独仪表盘(dashboard)程序。 该仪表盘程序通过 Counter 实现。 具体内容请参考 iFun引擎dashboard手册

iFun引擎仪表盘提供以下几种代表性的功能。

34.2.1. OS级别的源代码使用量监控

通过图表显示CPU、RAM、访问会话数、已做登录处理的用户数。

OS级别的源代码使用量监控

34.2.2. 监控iFun引擎事件处理性能

通过图表显示iFun引擎内每秒发生的事件数、事件处理速度、事件队列长度变化。

监控iFun引擎事件处理性能

34.2.3. 监控iFun引擎ORM处理性能

通过图表显示各个DB(已shard时,为shard DB)的读取/写入性能、待读取/待写入请求数、内存上缓存的ORM对象数。

监控iFun引擎ORM处理性能

34.2.4. 监控iFun引擎分布式处理性能

通过图表显示用于跨服通信的RPC流量。

监控iFun引擎分布式处理性能

34.2.5. 各Stage的处理时间及Queue time性能分析

34.2.5.1. Overview

_images/dash-summary-1.png
_images/dash-summary-2.png

34.2.5.2. 数据表形式

_images/dash-tabular.png

34.2.5.3. 执行时间分析

_images/dash-exec-time.png

34.2.5.4. 待机时间分析

_images/dash-wait-time.png