Photonカウンター
Photonは、Windowsパフォーマンスカウンターと、カスタムのインメモリカウンターを使用してサーバーのパフォーマンスや、CPU負荷、メモリ使用量、現在の接続数、 オペレーション実行時間などの統計情報をトラッキングしています。
これらのカウンターを表示するには、 Windowsパフォーマンスモニターまたは他の外部時系列データベースシステムを使用できます。 Photonは、UDP、TCP、PGM またはHTTP経由でカウンター値をパブリッシュします。
Photonパフォーマンスカウンターは簡単に拡張可能です。また、表示オプションは完全にカスタマイズすることができます。
パフォーマンスカウンター
インメモリカウンター
Photonのアプリケーションは、アプリケーション固有の統計情報(例:現在のゲーム数など)のトラッキングに インメモリのパフォーマンスカウンターを使用しています。
これらのカウンターは、Windowsパフォーマンスモニターに表示されません。
Windowsパフォーマンスカウンター
パフォーマンスデータのトラッキングをおこなううえで、PhotonはネイティブのWindowsパフォーマンスカウンターWindows Performance Counters に依存しています。
これらのカウンターを使用するには、Photonの起動前にインストールが必要です。
インストールはPhoton Controlでおこなうか:
または、以下のコマンドをバイナリデプロイフォルダ(PhotonControlと同一のフォルダ)から入力してください:
./PhotonSocketServer.exe /installCounters
また、アプリケーションの設定ファイルでWindowsパフォーマンスカウンターが有効化されている点を確認してください。
有効化するには、以下のようにEnablePerformanceCounters
をTrue
に設定します:
XML
<configuration>
<applicationSettings>
<!-- other settings -->
<Photon.LoadBalancing.Common.CommonSettings>
<!-- other settings -->
<setting name="EnablePerformanceCounters" serializeAs="String">
<value>True</value>
</setting>
<!-- other settings -->
</Photon.LoadBalancing.Common.CommonSettings>
<!-- other settings -->
</applicationSettings>
</configuration>
Windowsパフォーマンスモニターで、インストールされたカウンターを確認します:
起動後、Photonはこれらのカウンターに自動的にデータを書き込みます。
使用方法
概要
Photon Serverは、統計のパブリッシュにWindowsパフォーマンスカウンターとインメモリのPhotonカウンターを使用します。
Photonネイティブコアは、Windowsパフォーマンスカウンターのみに統計情報を書き込みます。
この統計情報は、CounterPublisher.NETアプリケーションによって読み込まれ、他のエンドポイントへとパブリッシュされます。
通常、Photon Serverは複数の.NETアプリケーションを実装しています。
Photon.SocketServer.ApplicationBase
を実装するすべてのPhoton .NETアプリケーションは、設定可能なPhoton.SocketServer.Diagnostics.CounterPublisher
シングルトンによって発行できる、デフォルトの一連のカウンターを含んでいます。
.NETアプリケーションの統計のパブリッシュを有効化するには、特定のアプリケーションに対応する設定ファイルでおこないます。
パブリッシュ率、使用されたプロトコル、エンドポイントの受信、追加オプションの設定を適切におこなうことができます。
デフォルトのパブリッシャーは、様々な種類のプロトコルに対応しています。
これらはプラグインで拡張可能です。
設定で追加カウンターのスキーマを指定すれば、パブリッシャーが作成したカウンターサンプルを拡張することができます。
アーキテクチャ
Photonネイティブコアは、Windowsパフォーマンスカウンターのみに統計情報を書き込みます。
すべてのPhoton .NETアプリケーションは、Photon.SocketServer.ApplicationBase
を実装しています。
後者は、Photon.SocketServer.Diagnostics.CounterPublisher
シングルトンを使用して統計をサンプリングし、パブリッシュします。
パブリッシャーは、アプリケーション構成タイプPhoton.SocketServer.Diagnostics.Configuration.PhotonSettings
、Photon.SocketServer
の
パブリッシャーは「サンプラー」と「センダー」から成ります。
サンプラーは、登録されたすべてのカウンターを (ExitGames.Diagnostics.Counter.ICounter
インターフェースを実装するすべてのソースから) 単純に読み込み、一定時間後にそれらの統計情報を集約します。
センダーはExitGames.Diagnostics.Monitoring.Protocol.ICounterSampleWriter
インターフェースの実装を使用し、設定済みのエンドポイントに集約データを実際に送信します。
センダーは、パブリッシャーからトランスポートレベルとプロトコルレベルを抽出します。
デフォルトでICounterSampleWriter
の抽出の実装があり、 これはディベロッパーが新しいプラグインを作成する際に役立ちます:PhotonBinaryWriterBase
。
設定
Photonカウンターは、Photon Serverアプリケーションの設定ファイルから設定可能です。
デフォルトの挙動でカウンターパブリッシュを有効化するため、設定ファイルには少なくとも以下の行を含む必要があります:
XML
<configSections>
<section name="Photon" type="Photon.SocketServer.Diagnostics.Configuration.PhotonSettings, Photon.SocketServer" />
</configSections>
<Photon>
<CounterPublisher enabled="True" />
</Photon>
Photon.SocketServer.Diagnostics.Configuration.PhotonSettings
タイプ向けの<Photon>
セクションエイリアスを持続することが重要です。それは、これがアプリケーション・パブリッシャーインスタンスのデフォルト設定用に予約された名前であるためです。
設定の一覧
<CounterPublisher>
の属性:
enabled
: 任意。
デフォルト: "False"
カウンターのパブリッシュを切り替え。
カウンターをパブリッシュするには、これを追加して「True」に設定してください。senderType
: 任意。
<Sender>
属性のカスタム設定クラスに使用するタイプのアセンブリ認可された名前を指定。updateInterval
: 任意。
デフォルト: 10.
サンプル率。
秒単位。addDefaultAppCounter
: 任意。
デフォルト: "True"。
デフォルトのアプリケーションカウンターを、デフォルトでパブリッシャーに含めるかどうかを管理します。
非有効化されている場合には、CounterPublisherはデフォルトのApplicationBase
カウンターを省略します。
<Sender>
(ExitGames.Diagnostics.Configuration.CounterSampleSenderSettings
)の属性:
endpoint
: 必須。
デフォルト: "http://127.0.0.1".protocol
: 任意。
デフォルト: "PhotonBinary".
アプリケーションレベルプロトコル。
必須 文字・小文字を区別しないProtocolType(PhotonBinary
、GraphiteText
、InfluxDB090GraphiteText
、StatsDText
)、またはカスタムの Writer タイプの実装。senderId
: 任意。
デフォルト: ""。
カウンターデータとともに送信されるセンダーのID。
"{0}"が発生した場合には、Environment.MachineName
に置換されます。initialDelay
: 任意。
デフォルト: 10。
最初のデータパブリッシングを遅延させる期間。
秒単位。sendInterval
: 任意。
デフォルト: 10。
パブリッシュの間隔。
秒単位。maxQueueLength
: 任意。
デフォルト: 120。
パブリッシュ時にエラーが発生した場合、 再パブリッシュのためにキューに入れる必要があるパッケージ数の値を取得。maxRetryCount
: 任意:
デフォルト: -1.
カウンターパブリッシャーがパブリッシュを停止するまでに、パブリッシュ時に発生する可能性があるエラー数を取得します。
ゼロ又はそれ以下の値が指定された場合、カウンターのパブリッシャーはエラーが発生しても停止しません。
各アプリケーションプロトコルの種類に固有な設定もあります。
トランスポートプロトコル
サポートされるトランスポートプロトコル:
- UDP
- HTTP (またはHTTPS)
- PGM
- サードパーティークライアントが提供する、その他のカスタムトランスポート。TCPはまだサポートされていません。
トランスポートプロトコルは、ExitGames.Diagnostics.Configuration.CounterSampleSenderSettings
の「endpoint」プロパティによって設定できます。
これらのトランスポートタイプはExitGames.Diagnostics.Configuration.TransportType
によって定義されます。
「endpoint」プロパティフォーマットはSystem.Uri
タイプのデフォルトのコンストラクターを指定することで定義されます。
例:「udp://255.255.255.255:40001」または「https://localhost:4000」。
アプリケーションプロトコル
Photon「CounterPublisher」は、様々な時系列のデータベースに データを書き込むことができます。実際のデータパブリッシュは、 ExitGames.Diagnostics.Monitoring.Protocol.ICounterSampleWriter
の実装によって実行されます。
通常、特定の各ライターには対応する設定クラスがExitGames.Diagnostics.Configuration
ネームスペースにあります。
センダーのデフォルト設定は、ExitGames.Diagnostics.Configuration.CounterSampleSenderSettings
によって実装されます。
「ExitGamesLibs」は以下への実装を含みます:
- Photonバイナリプロトコル
- Graphite
- InfluxDB 0.9.0 / Graphite UDP with tags
- StatsD
「CounterPublisher」はICounterSampleWriter
のすべての外部実装を使用できます。
このため、カスタムのライター実装によって すべてのデータベースへの書き込みが可能になります。
また、ICounterSampleWriter
には2つの個別のカスタム実装があり、 以下に対応しています:
- Amazon AWS CloudWatch
(CounterPublisher.AWS.CloudWatch
プラグイン) - NewRelic Platform
(CounterPublisher.NewRelic
プラグイン)
これらのカスタムの外部実装は、カスタムの「プロトコル」タイプを記載すれば設定可能です。以下に例を示します:
XML
<Photon>
<CounterPublisher enabled="True" senderType="ExitGames.Diagnostics.Configuration.AWSCloudWatchSettings, CounterPublisher.AWS.CloudWatch">
<Sender protocol="ExitGames.Diagnostics.Monitoring.Protocol.AWS.CloudWatch.AWSCloudWatchWriter, CounterPublisher.AWS.CloudWatch" />
</CounterPublisher>
</Photon>
重要なのは、通常カスタムのプロトコル実装には特定の設定プロパティを設定する必要がある という点です。
この設定は、ライター固有の「senderType」プロパティクラスタイプ(上記の例のとおり)を指定することでおこなえます。
カウンタースキーマ
「CounterPublisher」は登録されたカウンターの読み込みや書き込みをおこないます。
特別なメソッドであるCounterPublisher.AddCounter(ICounter カウンター、文字列名)
が存在します。
通常、カウンターはPhoton.SocketServer.Diagnostics.PhotonCounter
のような クラスへの論理的な理由によってグループ化されます。
「PhotonCounter」は、すべてのApplicationBase
にもとづく.NETアプリケーションのための デフォルトのカウンターを提供します。
- AvrgOpExecTime
- EventsSentCount
- EventsSentPerSec
- MessagesSentCount
- MessagesSentPerSec
- RawMessagesSentCount
- RawMessagesSentPerSec
- InitPerSec
- OpReceiveCount
- OpReceivePerSec
- OpResponseCount
- OpResponsePerSec
- OperationsFast
- OperationsMaxTime
- OperationsMiddle
- OperationsSlow
- SessionCount
カウンターは静的な読み出し専用のフィールドで、属性 「PublishCounter」をともないます。この属性は、別の名前など追加のプロパティを定義できます。
public static class PhotonCounter
C#
public static class PhotonCounter
{
[PublishCounter("AvrgOpExecTime")]
public static readonly AverageCounter AverageOperationExecutionTime = new AverageCounter();
//...
}
カウンタークラスは「CounterPublisher」に、CounterPublisher.AddCounterClass
または CounterPublisher.AddStaticCounterClass
とともに登録されています。
以下を参照してください:
C#
if (PhotonSettings.Default.CounterPublisher.Enabled)
{
if (PhotonSettings.Default.CounterPublisher.AddDefaultAppCounter)
{
CounterPublisher.DefaultInstance.AddStaticCounterClass(typeof(PhotonCounter), this.ApplicationName);
}
CounterPublisher.DefaultInstance.Start();
}
(Photon.CounterPublisher.SocketServerCounterSchema
):
通常、すべてのカウンタークラスは特別なスキーマクラスと対をなしており、 このスキーマクラスには論理的なネームスペースやカウンター名が含まれます (Photon.CounterPublisher.SocketServerCounterSchema
):
C#
namespace Photon.CounterPublisher
{
public static class SocketServerCounterSchema
{
public static class Common
{
public static readonly string CategoryName = "Photon Socket Server";
public static readonly string BuffersInUseCounter = "IO Buffers In Use";
//...
}
public static class Enet
{
public static readonly string ACKsInCounter = "Acknowledgements in";
public static readonly string ACKsInPerSecondCounter = "Acknowledgements in/sec";
//...
}
//...
}
}
したがって、カウンタークラスはスキーマの観点からカウンターを記述します。
C#
namespace Photon.CounterPublisher
{
[CounterSet(Name = "Photon")]
public static class SocketServerCounter
{
/// <summary>
/// The bytes in per second counter.
/// </summary>
[PublishCounter("BytesInPerSecond")]
public static readonly PerformanceCounterReader BytesInPerSecondCounter =
CreateCounterReader(Schema.Common.CategoryName, Schema.Common.BytesInPerSecondCounter);
//...
}
}
結果的に「CounterPublisher」は、 <Counters/Schema>
設定要素によって追加のカウンターを読み書きするように設定できます。
XML
<Photon>
<CounterPublisher ... >
<Sender ... />
<Counters>
<Schema namespace="TestNamespace" type="Photon.CounterPublisher.SystemCounter, CounterPublisher" />
</Counters>
</CounterPublisher>
</Photon>
メトリック名の選択には注意が必要です。 命名規則は以下にしたがってください:
PascalCaseマッチング[a-zA-Z0-9]+ 記号のセット
1.1. サフィックス「Per」で以下のフォーマット:{ValueUnit}{YourMetricInWordsAction}Per{Interval}
。 例:System.InBytesRecvPerSecond
1.2. サフィックス「Count」で以下のフォーマット:{CountUnit}{YourMetric}Count
。例:CounterPublisher.EventsSentCount
値:
2.1. (値/間隔): Like "bytes in/sec", "Disconnected Peers +/sec". 例:「バイト/秒単位」、TCP: "切断ピア+/秒"
2.1. (値): 例:「サーバー内での経過時間:(ミリ秒)単位」.{ValueUnit}AnyThingInPascalCase
標準的な単位の種類:
- 秒
- マイクロ秒
- ミリ秒
- バイト
- キロバイト
- メガバイト
- ギガバイト
- テラバイト
- Bits ビット
- キロビット
- メガビット
- ギガビット
- テラビット
- パーセント
- カウント
Windowsパフォーマンスカウンターのパブリッシュ
ネイティブのPhotonコアは、Windowsパフォーマンスカウンター(WPC)に統計情報を書き込みます。 そのため、Photonはプロキシの一種として機能する個別の「CounterPublisher」の.NETアプリケーションを使用して出力を行います。 このアプリケーションは、任意の場所(PhotonのWindowsパフォーマンスカウンターを含む)からカウンターを読み込んで一時的にインメモリカウンターに追加し、パブリッシュします。
Photonコアカウンターのほか「CounterPublisher」アプリケーションは、CPU負荷やメモリ使用率などの Windowsシステムカウンターを読み込み、ブロードキャストします。
「CounterPublisher」アプリケーションはデフォルトで有効化されます。 このアプリケーションの挙動は、「/CounterPublisher/bin/CounterPublisher.dll.config」で設定可能です。 内部的には、このアプリケーションは通常のApplicationBase
ベースのPhotonアプリケーションであり、この アプリケーションの標準的な「CounterPublisher」インスタンスは特別に設計されたカウンタークラスを伴い、WPCを 読み込むことができます。
「CounterPublisher」アプリケーションはCounterPublisher.AddStaticCounterClass
メソッドを使用して、2つのカウンタークラスを登録します:
Photon.CounterPublisher.SystemCounter
はCPU、メモリや、ネットワーク全般の統計情報を報告し、Photon.CounterPublisher.SocketServerCounter
はネイティブPhoton Core WPCカウンター固有の事項(ネットワーク(UDP、ENET等)や様々なキューの統計情報等)を報告します。
どのカウンターと値が現在パブリッシュされているかを確認するには、ExitGames.Diagnostics
パッケージに DEBUGログレベルを実施する必要があります。その後、「Photon/Log/CounterPublisher.log」(このパスは 「log4net.config」内のLogFileAppenderの設定で指定されます)でログファイルを参照してください。
XML
<logger name="ExitGames.Diagnostics">
<level value="DEBUG" />
</logger>
Graphiteへのパブリッシュ
PhotonはGraphiteに対応しています。
「ライター」はExitGamesLibs
内に実装されています。
このライターはUDP、TCP、PGM、HTTPなどの任意のトランスポートレイヤーで動作します。
GraphiteのデフォルトのトランスポートレイヤーはUDPです。
「ProtocolType」は「GraphiteText」です。
センダータイプはExitGames.Diagnostics.Configuration.GraphiteTextWriterSettings
です。
ライタータイプはExitGames.Diagnostics.Monitoring.Protocol.Graphite.Text.GraphiteTextWriter
です。
これはテキストベースのプロトコルです。フォーマットを以下に示します:
metric_path value timestamp\n
metric_pathのフォーマットはPATH[.PATH...]
で、.はネームスペースを区切ります。
value
はfloatです。
timestamp
はエポックからのunix時間で、秒単位で示されます。
プロトコルデータの例:
Plain Old Text
EU.RACK01.FIRST.System.Cpu 1.53993 1428332168
EU.RACK01.FIRST.System.CpuTotal 2.981617 1428332168
EU.RACK01.FIRST.System.Memory 5317 1428332168
EU.RACK01.FIRST.System.BytesTotalPerSecond 8103.247 1428332168
EU.RACK01.FIRST.System.BytesSentPerSecond 1784.697 1428332168
EU.RACK01.FIRST.System.BytesReceivedPerSecond 6383.81 1428332168
UDPなどの信頼性の低いトランスポートを使用する際には、ネットワーク通信時の パケットフラグメンテーションを防止するため「MaxPayloadSize」プロパティを設定してください。
ネットワークのMTU内でペイロードの全長を保持するよう留意してください。 使用すべき値はただ1つではありませんが、
一般的なネットワークシナリオ向けのガイドラインを以下に示します:
- ファスト・イーサネット(1432)ーこれは、ほとんどがイントラネット用です。
- ギガビット・イーサネット (8932)ージャンボフレームは、この機能をより効率的に使用できます。
- 商用インターネット(512)ー インターネット経由でルーティングをおこなう場合は、この範囲内の値が妥当です。 より高い値も可能ですが、ルート内のホップを制御できなくなります。
アプリケーションを選択し、以下のように.configを修正してください:
XML
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="Photon" type="Photon.SocketServer.Diagnostics.Configuration.PhotonSettings, Photon.SocketServer"/>
</configSections>
<Photon>
<CounterPublisher enabled="True">
<Sender
protocol="GraphiteText"
endpoint="udp://127.0.0.1:2003"
senderId="{#CloudType#}.{#PrivateCloud#}.{#Region#}.{#Cluster#}.{0}" />
</CounterPublisher>
</Photon>
</configuration>
この「Graphite」プロトコルデータの実装では、「senderId」はパブリッシュされた各メトリックキーをプリペンドします。
InfluxDBへのパブリッシュ
Photonは、UDP上でGraphiteプロトコルを使用するInfluxDBへのパブリッシュに対応しています。
ライターはExitGamesLibs
内に実装されています。元のGraphiteのプロトコルとの主な違いは、InfluxDBが構造化キーを待つことです。
「ProtocolType」は「InfluxDB090GraphiteText」です。
センダータイプはExitGames.Diagnostics.Configuration.InfluxDb090TextWriterSettings
です。
ライタータイプはExitGames.Diagnostics.Monitoring.Protocol.InfluxDB090.Graphite.Text.GraphiteTextWriter
です。
これはテキストベースのプロトコルです。フォーマットを以下に示します。
metric_path value timestamp\n
metric_path
のフォーマットはPATH[.PATH...]
で、.はネームスペースを区切ります。
value
はfloatです。
timestamp
はエポックからのunix時間で、秒単位で示されます。
InfluxDB 0.9.0は以下のフォーマットでキーを待ちます:
Plain Old Text
ex: region.us-west.hostname.server01.cpu -> tags -> region: us-west, hostname: server01, point name -> cpu
use senderId = "CloudType.{#CloudType#}.PrivateCloud.{#PrivateCloud#}.Region.{#Region#}.Cluster.{#Cluster#}.Machine.{0}"
プロトコルデータの例:
Plain Old Text
Region.EU.Rack.RACK01.PC.FIRST.NS.System.Cpu 1.53993 1428332168
Region.EU.Rack.RACK01.PC.FIRST.NS.System.CpuTotal 2.981617 1428332168
Region.EU.Rack.RACK01.PC.FIRST.NS.System.Memory 5317 1428332168
Region.EU.Rack.RACK01.PC.FIRST.NS.System.BytesTotalPerSecond 8103.247 1428332168
Region.EU.Rack.RACK01.PC.FIRST.NS.System.BytesSentPerSecond 1784.697 1428332168
Region.EU.Rack.RACK01.PC.FIRST.NS.System.BytesReceivedPerSecond 6383.81 1428332168
1分あたり2回の更新頻度 InfluxDBでは「seperator」プロパティを使用して、セパレータ.を他のものに変更することができます。
このセパレータは、メトリックキー名とタグを区切るために使用されます。書き換えをおこなうキーは「rewriteKeys」からオフにすることができます。
UDPなどの信頼性の低いトランスポートを使用する際には、ネットワーク通信時の パケットフラグメンテーションを防止するため「MaxPayloadSize」プロパティを設定してください。
ネットワークのMTU内でペイロードの全長を保持するよう留意してください。 使用すべき値はただ1つではありませんが、
一般的なネットワークシナリオ向けのガイドラインを以下に示します:
- ファスト・イーサネット(1432) - これは、ほとんどがイントラネット用です。
- ギガビット・イーサネット(8932) - ジャンボフレームは、この機能をより効率的に使用できます。
- 商用インターネット(512) - インターネット経由でルーティングをおこなう場合は、この範囲内の値が妥当です。 より高い値も可能ですが、ルート内のホップを制御できなくなります。
アプリケーションを選択し、以下のように.configを修正してください:
XML
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="Photon" type="Photon.SocketServer.Diagnostics.Configuration.PhotonSettings, Photon.SocketServer"/>
</configSections>
<Photon>
<CounterPublisher enabled="True">
<Sender
protocol="InfluxDB090GraphiteText"
endpoint="udp://127.0.0.1:2003"
senderId="CloudType.REALTIME.PrivateCloud.BLAH.Region.LOCAL.Cluster.EY.Machine.{0}" />
</CounterPublisher>
</Photon>
</configuration>
この「Graphite」プロトコルの実装では、「senderId」はパブリッシュされた各メトリックキーをプリペンドします。
StatsDへのパブリッシング
PhotonはStatsDに対応しています。 ライターはExitGamesLibs内に実装されています。
このライターはUDP、TCP、PGM、HTTPなどの任意のトランスポートレイヤーで動作します。 StatsDのデフォルトのトランスポートレイヤーはUDPです。
「ProtocolType」は「StatsDText」です。 センダータイプはExitGames.Diagnostics.Configuration.StatsDWriterSettings
です。 ライタータイプはExitGames.Diagnostics.Monitoring.Protocol.StatsD.Text.StatsDTextWriter
です。
エクスポートされるメトリックのフォーマットはUTF-8テキストで、メトリックは新しい行で区切られます。
一般的なメトリックのフォーマットは <metric name>:<value>|<type>
ですが、例外については
メトリックタイプを参照してください。
このプロトコルは整数の値も、浮動小数点の値も許容します。ほとんどの実装では、内部的に値を IEEE 754倍精度浮動小数点で保存しますが、多くの実装やグラフシステムは整数値のみに対応しています。 互換性を保つため、すべての値は(-253, 253)の範囲で整数にする必要があります。
プロトコルデータの例::
Plain Old Text
REALTIME/PUBLIC/LOCAL/FIRST.System.Cpu:0.472394|c
REALTIME/PUBLIC/LOCAL/FIRST.System.CpuTotal:4.921546|c
REALTIME/PUBLIC/LOCAL/FIRST.System.Memory:5040|c
REALTIME/PUBLIC/LOCAL/FIRST.System.BytesTotalPerSecond:274.1134|c
REALTIME/PUBLIC/LOCAL/FIRST.System.BytesSentPerSecond:247.9789|c
REALTIME/PUBLIC/LOCAL/FIRST.System.BytesReceivedPerSecond:25.77675|c
UDPなどの信頼性の低いトランスポートを使用する際には、ネットワーク通信時の パケットフラグメンテーションを防止するため「MaxPayloadSize」プロパティを設定してください。
ネットワークのMTU内でペイロードの全長を保持するよう留意してください。 使用すべき値はただ1つではありませんが、
一般的なネットワークシナリオ向けのガイドラインを以下に示します:
- ファスト・イーサネット(1432)ーこれは、ほとんどがイントラネット用です。
- ギガビット・イーサネット (8932)ージャンボフレームは、この機能をより効率的に使用できます。
- 商用インターネット(512)ー インターネット経由でルーティングをおこなう場合は、この範囲内の値が妥当です。 より高い値も可能ですが、ルート内のホップを制御できなくなります。
アプリケーションを選択し、以下のように.configを修正してください:
XML
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="Photon" type="Photon.SocketServer.Diagnostics.Configuration.PhotonSettings, Photon.SocketServer"/>
</configSections>
<Photon>
<CounterPublisher enabled="True">
<Sender
protocol="StatsDText"
endpoint="udp://127.0.0.1:8125"
senderId="REALTIME/PUBLIC/LOCAL/{0}" />
</CounterPublisher>
</Photon>
</configuration>
この「StatsD」プロトコルを実装するため、「senderId」はパブリッシュされた各メトリックキーをプリペンドします。
NewRelic Platformへのパブリッシュ
NewRelic向けのCounterPublisherプラグインは、こちらから利用可能です。
New RelicのSaaSベースのApplication Performance Monitoringを使用すると、 素晴らしいWebソフトウェアを構築、デプロイ、および維持できます。
メトリックを「CounterPublisher」でNewRelic Platformにパブリッシュするには、CounterPublisher.NewRelic
内の ライタープラグインの個別実装を使用します。
これは、HTTP/HTTPS上でNewRelicのAPIを呼び出すためにネイティブのNewRelic SDKクライアントを使用します。
このプラグインを使用するには、「CounterPublisher」設定の修正のほか、設定をおこなおうとしている アプリケーションの近くにあるすべての依存関係をコピーしてください。 これらの依存関係には以下が含まれます:
Plain Old Text
config/newrelic.json
CounterPublisher.NewRelic.dll
CounterPublisher.NewRelic.dll.config
NewRelic.Platform.Sdk.dll
Newtonsoft.Json.dll
NLog.dll
アプリケーション自体で提供される必要があるExitGamesの依存関係:
Plain Old Text
ExitGames.Logging.Log4Net.dll
ExitGamesLibs.dll
log4net.dll
センダータイプはExitGames.Diagnostics.Configuration.NewRelicAgentSettings
です。
ライタータイプはExitGames.Diagnostics.Monitoring.Protocol.NewRelic.Agent.NewRelicWriter
です。
メトリックデータは、以下のURLを使用してJSONデータのHTTP POSTとして送信されます。
https://platform-api.newrelic.com/platform/v1/metrics
POST用のMIMEタイプはapplication/jsonです。New Relic Plugin製品は、 60秒間に1回の頻度でデータを更新するよう最適化されます。
POSTの頻度と制限は、こちらのドキュメント:に記載されています:
- コンポーネント:現在、アカウントごとにトラッキングされている別個のコンポーネントの500の数。
- コンポーネントごとのメトリック:コンポーネントごとの固有のメトリックの合計数 10,000。
メトリック名の生成が過剰に動的にならないように注意してください。
各ポストで送信されるメトリックの数が少なくても、次第に積算されて大きい数のメトリック数となります。
コンポーネントのメトリック数がこの制限を超えると、サーバーはアスタリスクでメトリック名のセグメントをまとめ、メトリックを集計し始める場合があります。 - 投稿ごとのメトリック:投稿ごとに送信されるメトリック数 20,000。
投稿は、リクエストに含まれるメトリックの合計数が上限を超えない限り、単一のリクエストで複数のコンポーネントのデータを送信することができます。 - 投稿の頻度:1分あたり2回の更新頻度。エージェントは、毎分1回以上データを送信するべきではありません。
開始するには:
- NewRelicアカウントを登録
- プロファイル設定で「LicenseKey」を取得(APM -> .NET agent -> Reveal license key)
- アプリケーションに依存関係をコピー
ファイルとインストラクションはGithubレポジトリから入手可能です。 - 設定をセットアップ
CounterPublisher.NewRelic固有の設定
agentId
: 任意。
デフォルト: "com.exitgames.plugins.newrelic.agent".agentName
: 任意。
デフォルト: "".
人間が読解可能な文字列によって、New Relicサービス内のこのAgentの名前が表示されます。
"{0}"が発生した場合には、Environment.MachineName
に置換されます。
設定されない場合や空欄のままの場合には、以下のフォーマットとなります:「"Agent Name: {agentId}. Agent Version: {version}"」。
agentIdとバージョンの両方が設定されていない場合には、agentNameは「Agent Name: com.exitgames.plugins.newrelic.agent. Agent Version: 1.0.0.」となります。licenseKey
: 必須。
NewRelic (APM -> .NET agent -> Reveal license key)から取得してください。version
: 任意。
デフォルト: "1.0.0".
注: NewRelicエージェントは、agentNameではなくagentIdによって識別されます。
各NewRelicエージェントは複数のインスタンスを持つことができます。
各インスタンスはagentNameによって識別されます
最小限の作業用NewRelic設定
XML
<Photon>
<CounterPublisher enabled="True" senderType="ExitGames.Diagnostics.Configuration.NewRelicAgentSettings, CounterPublisher.NewRelic">
<Sender
protocol="ExitGames.Diagnostics.Monitoring.Protocol.NewRelic.Agent.NewRelicWriter, CounterPublisher.NewRelic"
licenseKey="YOUR_LICENSE_KEY"
sendInterval="60" />
</CounterPublisher>
</Photon>
制限事項
- 送信間隔は60秒未満にはできません。この設定はNewRelicプラグイン設定に必須であるsendInterval設定となっています。
- プラグインは、集約されたデータを送信間隔で常に送信します:分、最大、sqrの合計、カウント
- プラグインは、ルートネームスペースが空のメトリックに対応していません。
- Photon CounterPublisherのカウンターキーフォーマットは、NewRelic固有のメトリック名のフォーマット(
Component/Label[/Attribute/...]
)に変換されます。
Publishing to Amazon AWS CloudWatch
AWS CloudWatch向けのCounterPublisherプラグインはこちらから利用可能です。
Amazon CloudWatchは、AWSクラウドリソースとAWS上で実行するアプリケーションを対象とする監視サービスです。
Amazon CloudWatchを使用すると、メトリックの収集とトラッキング、ログファイルの収集と監視、アラームの設定をおこなうことができます。
Amazon CloudWatchは、アプリケーションやサービスで生成されたカスタムメトリックや、アプリケーションで生成されたログファイルのほか、Amazon EC2インスタンス、Amazon DynamoDBテーブル、Amazon RDS DBインスタンスなどのAWSリソースを監視できます。
Amazon CloudWatchを活用すると、システム全体でのリソースの使用やアプリケーションのパフォーマンス、オペレーションの状態を把握することが可能です。
これらの情報を活用して、アプリケーションの実行を円滑におこなうことができます。
「CounterPublisher」でAmazon CloudWatchにメトリックをパブリッシュするには、 CounterPublisher.AWS.CloudWatch
内のライタープラグインの個別実装を使用します。
これはHTTP/HTTPS上でAPIを呼び出すために、ネイティブのAmazon SDK CloudWatchクライアントを使用します。
このプラグインを使用するには、「CounterPublisher」設定の修正のほか、設定をおこなおうとしている アプリケーションの近くにあるすべての依存関係をコピーしてください。
これらの依存関係には以下が含まれます:
Plain Old Text
CounterPublisher.AWS.CloudWatch.dll
AWSSDK.CloudWatch.dll
AWSSDK.Core.dll
アプリケーション自体で提供される必要がある、ExitGamesの依存関係:
Plain Old Text
ExitGames.Logging.Log4Net.dll
ExitGamesLibs.dll
log4net.dll
センダータイプはExitGames.Diagnostics.Configuration.AWSCloudWatchSettings
です。
ライタータイプはExitGames.Diagnostics.Monitoring.Protocol.AWS.CloudWatch.AWSCloudWatchWriter
です。
Amazon CloudWatchはデータポイントを指定したメトリックに結合します。
指定したメトリックが存在しない場合、Amazon CloudWatchはメトリックを作成します。
メトリックの一覧表示化アクションへの呼び出しに、新しいメトリックが表示されるまでに15分間かかります。
put-metric-datarequestのサイズの上限は、HTTP GETリクエストの場合には8KB、HTTP POSTリクエストの場合には40KBです。
1,000分の1秒ほどの細かいタイムスタンプを使用してデータポイントをパブリッシュすることは可能ですが、 CloudWatchが集約するデータの最小は1分です。 CloudWatchは、1分間に受信された値の平均
(すべてのアイテムの合計を項目数で割る)を記録します。 また、その間のサンプル数、最大値、最小値も記録します。
開始するには:
- Amazon AWSのアカウントを登録
- プロファイル設定で「AccessKey」「SecretKey」を取得
- 希望するリージョンおよびCloudWatchのカスタムのメトリックネームスペースに応じて、サービスURL を選択します。
- アプリケーションに依存関係をコピーします。
ファイルは、Githubレポジトリから取得できます。 - 設定をセットアップします。
制限事項:
- 送信間隔は60秒未満にはできません。
- 送信間隔内で、プラグインは常に集約データを送信します:min、max、sqrの合計、count
- プラグインは、ルートネームスペースが空のメトリックに対応していません。
- プラグインは間隔測定を選択するために、一般的なデータサイズのタイプと、サフィックス「Per」にもとづいてユニットタイプを検出しようとします。
- 適切なメトリック名(通常は
[Namespace.]Key
)を設定することは、非常に重要です。
カウンターの命名規則と適切なフォーマットについてのルールは、 カウンタースキーマを参照してください。
アプリケーションを選択し、.configファイルを以下のように修正してください。
XML
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="Photon" type="Photon.SocketServer.Diagnostics.Configuration.PhotonSettings, Photon.SocketServer"/>
</configSections>
<Photon>
<CounterPublisher
enabled="True"
senderType="ExitGames.Diagnostics.Configuration.AWSCloudWatchSettings, CounterPublisher.AWS.CloudWatch">
<Sender
protocol="ExitGames.Diagnostics.Monitoring.Protocol.AWS.CloudWatch.AWSCloudWatchWriter, CounterPublisher.AWS.CloudWatch"
senderId="{#CloudType#}/{#PrivateCloud#}/{#Region#}/{#Cluster#}/{0}"
awsCloudWatchAccessKey = "..."
awsCloudWatchSecretKey = "..."
awsCloudWatchServiceUrl = "..."
awsCloudWatchNamespace = "..."
sendInterval="60" />
</CounterPublisher>
</Photon>
</configuration>
この「CloudWatch」プロトコル実装では、「senderId」はパブリッシュされた各メトリックキーをディメンション化します。
カスタムのパフォーマンスカウンターの実装
On architecture details take a look at Usage/Counter schemas アーキテクチャの詳細については、 使用方法/カウンタースキーマを参照してください.
まず、アプリケーションは必要な値をトラッキングする必要があります。
この目的のために、ExitGames.Diagnostics.Counter
からインメモリカウンターを使用します。
アプリケーションに「libs\ExitGamesLibs.dll」へのリファレンスがある点を確認してください:
カウンターの宣言
次のステップは、カウンター定義クラスの作成です。以下に示すとおり「using」命令を ExitGames.Diagnostics.CounterとExitGames.Diagnostics.Monitoringに追加して、カスタムカウンターを宣言してください。
一意の名前を持つPublishCounter属性を追加します。 これによって、カウンターパブリッシャーがカウンター値をパブリッシュします(以下を参照ください)。
C#
using ExitGames.Diagnostics.Counter;
using ExitGames.Diagnostics.Monitoring;
public static class MyCustomCounter
{
[PublishCounter("MessagesPerSecond")]
public static readonly CountsPerSecondCounter MessagesPerSecond = new CountsPerSecondCounter();
}
カウンターの命名規則と適切なフォーマットについてのルールは、Counters Schemasカウンタースキーマを参照してください。
カウンターの使用
コード内の適切な箇所で、カウンターをインクリメント/デクリメントしてください。
たとえば、1秒あたりに送信されるメッセージ数をカウントするには、以下のコードをSendMessage
作業を処理するメソッドに追加してください:
C#
protected virtual void HandleSendMessageOperation(LitePeer peer, OperationRequest operationRequest)
{
// [... operation logic ...]
// increment performance counter:
MyCustomCounter.MessagesPerSecond.Increment();
}
以上です。
パフォーマンスデータの収集に必要な設定がすべて完了しました。
カウンターパブリッシャーの初期化
次のステップは収集したパフォーマンスデータのパブリッシュです。
これをおこなうには、アプリケーションの起動中に「CounterPublisher」を初期化する必要があります。
初期化はアプリケーションの「セットアップ」メソッドでおこなうのが適切です。
以下の例では、カウンターパブリッシャーを初期化する方法と、カスタムカウンター定義クラスを追加する方法を示しています。
2番目のパラメータには任意の名前を選択できます。
これは、 後にダッシュボードによって表示されるカウンターのカテゴリーとして使用されます。
C#
protected override void Setup()
{
// [... setup logic ...]
// initialize counter publisher and add your custom counter class(es):
if (PhotonSettings.Default.CounterPublisher.Enabled)
{
CounterPublisher.DefaultInstance.AddStaticCounterClass(typeof(MyCustomCounter), "MyApplication");
CounterPublisher.DefaultInstance.Start();
}
}
または、任意の.NET Photonアプリケーション設定を拡張して、これらのインメモリ・メトリックを<Counters/Schema>
設定要素によってパブリッシュすることが可能です。
XML
<Photon>
<CounterPublisher ... >
<Sender ... />
<Counters>
<Schema namespace="MyApplication" type="...MyCustomCounter, YOUR_LIB_NAME" />
</Counters>
</CounterPublisher>
</Photon>
カウンターパブリッシャーの設定
最後のステップは、カウンターパブリッシャに適切な設定を追加することです。
自分の時系列データベースが稼動しているIP/ポートにデータを送信するよう設定します。
マルチキャストは、同じサブネット内でのみ動作します。 異なるネットワーク間でパフォーマンスデータをパブリッシュするには、 具体的なIPを使用し、ポートがファイアウォールで開かれていることを確認します。
このマニュアルのトピック、使用方法を参照ください。
例:
XML
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="Photon" type="Photon.SocketServer.Diagnostics.Configuration.PhotonSettings, Photon.SocketServer"/>
</configSections>
<Photon>
<CounterPublisher enabled="True">
<Sender
protocol="PhotonBinary"
endpoint="udp://127.0.0.1:40001"
senderId="servers/Realtime/Public/Local/Test/{0}" />
<Counters>
<Schema namespace="MyApplication" type="...MyCustomCounter, YOUR_LIB_NAME" />
</Counters>
</CounterPublisher>
</Photon>
</configuration>
カスタムプロトコルの実装
手順を詳細に理解するにはCounterPublisher.AWS.CloudWatch
プロジェクト、CounterPublisher.NewRelic
プロジェクト、 アプリケーションプロトコルのトピックを参照してください。
カスタムのアプリケーションプロトコルを実装するための基本的な概念では、
個別の.NETライブラリ (dll)を作成するほか、以下をおこないます:
- 必要に応じて、
ExitGames.Diagnostics.Configuration.CounterSampleSenderSettings
にもとづき クラス拡張の設定を実装します。 - ライターインターフェースを実装
ExitGames.Diagnostics.Monitoring.Protocol.ICounterSampleWriter
はメインのエントリーポイントです。 - app.configファイルの設定サンプルは、以下のとおりです:
カウンターライターのインターフェース
ExitGames.Diagnostics.Monitoring.Protocol.ICounterSampleWriter
はプロトコルプラグインへの メインのエントリーポイントです。
この「Writer」ExitGames.Diagnostics.Monitoring.Protocol.PhotonBinaryWriterBase
には基本的な抽象実装があり、スーパーサンプリングされたデータを集約するための追加のキューを提供しています。
ICounterSampleWriter
メソッドの実装:
C#
public interface ICounterSampleWriter : IDisposable
{
/// <summary>
/// Is writer ready to publish any data.
/// IsConnected status is subset of this status.
/// Default implementation is writer started and connected.
/// </summary>
bool Ready { get; }
/// <summary>
/// Start writing.
/// Stop is handled by IDisposable implementation.
/// Can be called once.
/// </summary>
void Start(CounterSampleSenderBase sender);
/// <summary>
/// Called by <see cref="CounterSampleSenderBase"/>
/// to write samples out to some storage.
/// </summary>
void Publish(CounterSampleCollection[] packages);
}
設定
C#
基本的な設定クラスは`ExitGames.Diagnostics.Configuration.CounterSampleSenderSettings`です。
「Writer」に追加パラメータの設定が必要な場合は、拡張することができます。
public class InfluxDB090TextWriterSettings : GraphiteTextWriterSettings
{
/// <summary>
/// Do rewriting of keys provided by sampler to keep them distinct to tags part of the path.
/// </summary>
[ConfigurationProperty("rewriteKeys", IsRequired = false, DefaultValue = true)]
public bool RewriteKeys
{
get
{
return (bool)this["rewriteKeys"];
}
set
{
this["rewriteKeys"] = value;
}
}
/// <summary>
/// Separator used by InfluxDB instead of default DOT(.).
/// </summary>
[ConfigurationProperty("separator", IsRequired = false, DefaultValue = '.')]
public char Separator
{
get
{
return (char)this["separator"];
}
set
{
this["separator"] = value;
}
}
public InfluxDB090TextWriterSettings() { }
public InfluxDB090TextWriterSettings(CounterSampleSenderSettings settings) : base(settings) { }
}
使用方法
プラグインを使用するには:
- アプリケーションに依存関係をコピーします。
- 必要に応じて有効な「Writer」タイプと「Configuration」で設定をセットアップします。
例:
XML
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="Photon" type="Photon.SocketServer.Diagnostics.Configuration.PhotonSettings, Photon.SocketServer"/>
</configSections>
<Photon>
<CounterPublisher enabled="True">
<Sender
protocol="InfluxDB090GraphiteText"
endpoint="udp://127.0.0.1:2003"
senderId="CloudType.REALTIME.PrivateCloud.BLAH.Region.LOCAL.Cluster.EY.Machine.{0}" />
</CounterPublisher>
</Photon>
</configuration>
トラブルシューティング
カウンターのパブリッシングは有効になっていますか?アプリケーションの設定を確認してください。 すなわち:/deploy/CounterPublisher/bin/CounterPublisher.dll.config
"\deploy\log*" でPhotonログファイルを参照し、エラーや移動先データベースログファイルを確認してください。
データがログにパブリッシュしている点を確認してください(log4netでDEBUGを
ExitGames.Diagnostics
に設定):
現在パブリッシュされているカウンターと値を確認するためには、 /CounterPublisher/bin/log4net.config内でExitGames.Diagnostics
用のDEBUGログレベルが実施されている必要があります。
その後、Photon/Log/CounterPublisher.log(このパスは"log4net.config"のLogFileAppenderで指定)でログファイルを確認してください:XML
<logger name="ExitGames.Diagnostics"> <level value="DEBUG" /> </logger>
ファイアウォールで適切なポートが開いていることを確認してください。
スニファを使用するパケットのIP/ポートソース/送信先と、
netstat
を確認してください。移動先データベースがスニファーと拡張ログレベルを使用して、パケットを受信していることを確認します。
データ/プロトコルのフォーマットがデータパケットを調査していることを確認。
データがパケットでパブリッシュしている点を確認します(wireshark snifferを使用)。
ExitGames.Diagnostics.Counterからのカウンターの一覧
このセクションでは、ExitGames.Diagnostics.Counterネームスペースで利用可能なインメモリカウンターのタイプについて詳細に説明します。
全てのカウンターはICounter
インターフェイスを実装しています。
C#
namespace ExitGames.Diagnostics.Counter
{
public interface ICounter
{
string Name { get; }
// Gets the type of the counter.
CounterType CounterType { get; }
// Gets the next value.
float GetNextValue();
// Increments the counter by one and returns the new value.
long Increment();
// Increments the counter by a given value and returns the new value.
long IncrementBy(long value);
// Decrements the counter by one and returns the new value.
long Decrement();
}
}
参照できるとおり、カウンターの値をインクリメント/デクリメントするためのおもなメソッドは、複数あります。
GetNextValue
は、カウンターの実際の「値」を返すメソッドです。
これは計算された値とすることができます。 たとえば、AverageCounterでGetNextValue
を呼んだ場合、カウンターは前回のGetNextValueへのコール以降のすべてのインクリメント/デクリメントの平均値を計算し、その値を返します。
GetNextValueは内部値をリセットします。 パブリッシュされたデータが不正になるので、 コードを手動で呼び出さないでください。「CounterPublisher」は、定期的にGetNextValue
を呼び出します。
NumericCounter
非常にわかりやすいカウンターです。このカウンターは単一の値を保持します: GetNextValue
はその単一の値を返し、カウンターをリセットしません。
Example:10秒間隔の開始時、 NumericCounterの値は5です。1と6の値で2回インクリメントされ、3の値で1回デクリメントされます。
結果的に、この間隔の値は5+1+6-3=9になります。
典型的なユースケース: 現在システムにログオンしているユーザーの数。
C#
public void AddToCache(ArrayList items)
{
foreach (var item in items)
{
Cache.Insert(item);
}
MyCacheItemCounter.IncrementBy(items.Count);
}
public void RemoveFromCache(ArrayList items)
{
foreach (var item in items)
{
Cache.Remove(item);
}
MyCacheItemCounter.IncrementBy( -items.Count);
}
// When the CounterPublisher calls MyCacheItemCounter.GetNextValue(), it always returns the current number of items in cache.
AverageCounter
AverageCounterは、最後のリセット以降に呼ばれた頻度をトラッキングし、任意の値でインクリメントできます。
現在の間隔での1コールあたりの平均量(=合計/コール数)を返します。
例: AverageCounterは、10秒間隔で1、2、4、5の値を使用して4回インクリメントします。 合計は12なので、この間隔の平均は12/4=3になります。
典型的なユースケース:
特定のオペレーションの平均実行時間、 または送信されたメッセージごとの平均テキスト長。
C#
public void WinGame(Player player, int coins)
{
player.Account.Add(coins);
AverageCoinsWonCounter.IncrementBy(coins);
}
public void LoseGame(Player player, int coins)
{
player.Account.Remove(coins);
AverageCoinsWonCounter.IncrementBy( -coins);
}
// When the CounterPublisher calls AverageCoinsWonCounter.GetNextValue(), it returns the average amount a player has won in the interval since the previous call to GetNextValue().
// This amount might as well be negative. The internal counter value is reset afterwards - i.e., if no Game was won or lost between two calls to GetNextValue(), the average is 0.
CountsPerSecondCounter
CountsPerSecondCounterは、任意の値でインクリメント/デクリメントすることができる単一の値を持ちます。
最後の間隔の1秒あたりの平均量を返します。
カウンターをインクリメント/デクリメントすると、これらのコールは自動的に「秒ごと」の値に変換されます。
例: CountsPerSecondCounterは10秒間隔で10、20、70の値を用いて3回インクリメントされます。
合計は100なので、この間隔の場合は毎秒10になります。
典型的なユースケース: ネットワークインターフェース上で送信される1秒あたりのバイト数、
または特定のアクションがおこなわれる1秒あたりの回数。
C#
public void RaiseEvent()
{
// do something to raise an event
EventsPerSecondCounter.Increment();
}
// RaiseEvent can be called at any time - multiple times per second, or only once every few seconds and requires no fixed interval.
// When the CounterPublisher calls EventsPerSecondCounter.GetNextValue(), the counter checks how many seconds have passed since the the last call to GetNextValue().
// It calculates its return value as "CurrentValue / SecondsPassed". The internal value is reset when GetNextValue() is called.
PerformanceCounterReader
PerformanceCounterReaderの目的は、下層のWindowsパフォーマンスカウンターから値を読み込むことです。
これは読み込み専用のカウンターで、インクリメント/デクリメントできません。
これはフェイルセーフです。つまり、パフォーマンスカウンターが存在しない場合、またはアクセスが許可されていない場合にはエラーはスローされません。
WindowsPerformanceCounter
WindowsPerformanceCounter
はWindowsパフォーマンスカウンターのラッパークラスで、下層のカウンターに読み込み/書き込みアクセスを提供します。
パフォーマンスカウンターが存在する必要があり、読み込み/書き込みアプリケーションが適切な権限を持っていなければなりません。さもなければ、例外が発生します。
Windowsパフォーマンスカウンターの詳細情報を参照するには、MSDNが良い導入となるでしょう。
Back to top