Perforceのパフォーマンス調整

Perforceサーバは、通常、システムリソースをあまり多く消費しません。ただし、システムの規模が拡大するにつれ、あらためてシステム構成を見直し、最適なパフォーマンスが得られる構成になっているかどうか確認する必要が生じます。

この章では、Perforceサーバのパフォーマンスに影響するおそれのあるいくつかの要因について簡潔に概説するとともに、ネットワーク関連障害の原因追究に役立つ情報を提供し、システムの大型化に起因するサーバ負荷を軽減する方法を説明します。

パフォーマンスを調整する

一般に、Perforceはいかなるサーバクラスのハードウェアプラットフォームにおいても良好なパフォーマンスを発揮します。以下に、Perforceサーバのパフォーマンスに影響するおそれがある要因を示します。

メモリ

サーバのパフォーマンスは、メモリが十分に確保されているかどうかに大きく依存します。これには2つの問題があります。第1の問題を回避するには、大量のクエリを実行中のサーバにページングをさせないようにします。第2の問題を回避するには、db.revテーブル(またはそのうち少なくとも実際に使用する分量)がメインメモリにキャッシュされるようにします。

  • 大量のクエリの実行に必要なメモリ容量は、簡単に割り出せます。サーバがページングしないようにするには、1ファイルにつき1KBのRAMが必要です。10,000ファイルある場合には、10MBのRAMが必要です。

  • db.revをキャッシュするには、既存のインストレーションのdb.revファイルのサイズを確認し、1つの目安として利用すればよいでしょう。新しくインストレーションのPerforceでは、db.revは1リビジョンにつき150~200バイトを必要とします。概算のために1ファイルにつき3リビジョンとした場合、1ファイルにつき0.5KBのRAMが必要です。

したがって、1ファイルにつき1.5KBのRAM(100,000ファイルに対して150MBのRAM)が利用可能であれば、たとえすべてのファイルに関わる動作を実行しても、サーバはページングを行いません。もちろん、大規模な動作が複数同時に実行される可能性もありますから、ページングを回避するにはより多くのメモリが必要です。ただし、大多数の動作では、小規模なサブセットのファイルしか使用しません。

通常のインストレーションの場合、ディポの中で1ファイルにつき1.5KBのRAMがあれば十分です。

ファイルシステムのパフォーマンス

Perforceは、ディスクI/Oの使用に関して優れています。使用しているメタデータは検索しやすいうえに、データへアクセスする際には概してデータのなかでも限られたサブセットを順番にスキャンするという方法をとります。ディスクにもっとも負担がかかる動作はファイルのチェックインです。Perforceサーバがアーカイブのファイルの書き込みとリネームをしなければならない場合です。サーバのパフォーマンスは、オペレーティングシステムのファイルシステム実装に依存しており、とくに、ディレクトリの更新が同期式であるかどうかによって大きく左右されます。また、サーバのパフォーマンスは、基盤を成すハードウェアのI/Oサブシステムの性能にも大きく左右されます。

Perforceが特定のハードウェア構成やファイルシステムを推奨することはありません。とはいえ、Linuxサーバは(Linuxの非同期的ディレクトリ更新のおかげで)概して最も速く動作しますが、不適切なタイミングで電源が切れると、復旧に手間取ることがあります。それに比べると、(Solarisでも使用されている)BSDファイルシステムの動作は遅いですが、より信頼できます。NTFSのパフォーマンスは、LinuxとBSDの間の範囲に落ち着きます。

データベースとバージョンファイルがNFSマウント済みボリュームに保存されている場合、システムのパフォーマンスは、通常そのNFSの実装か、その基盤を成すストレージハードウェアに依存します。PerforceはSolarisのNFS環境でテストされ、サポートされています。

LinuxおよびFreeBSD上では、ファイルロッキングが比較的遅いので、NFSを介するデータベース更新に問題が生じるおそれがあります。これらのプラットフォーム上では、ジャーナルがNFSマウントされている場合、すべての動作が遅くなります。一般に(LinuxやFreeBSDでは特に)、Perforceのデータベース、ディポ、ジャーナルのファイルを、Perforceサーバプロセスを実行するマシンのローカルディスク上に保存することを推奨します。

上記の問題は、Perforceサーバプロセス(p4d)のみに影響します。Perforceアプリケーション(p4、Perforceコマンドラインクライアントなど)は、これまで常に、ユーザのホームディレクトリ中のクライアントワークスペースなどの、NFSマウント済みドライブ上のクライアントワークスペースでの稼働実績を挙げてきています。

ディスク容量の割り当て

Perforceが使用するディスク容量は、以下の3つの要素に依存します。

  • クライアントワークスペースの数とサイズ

  • サーバデータベースのサイズ

  • サーバ上にあるすべてのバージョン化ファイルのアーカイブのサイズ

以上の3つの要素すべてが、使用中のデータの性質と、Perforceの使用度によって変わります。

必要なクライアントファイルスペースは、ユーザが任意の時点でクライアントワークスペース内に必要とするファイルのサイズと一致します。

サーバのデータベースサイズはかなりの精度で計算できます。推定で、1ユーザ1ファイルにつき0.5KB必要です。(例えば、1つのシステムにファイルが10,000個あり、ユーザが50人いれば、データベースに250MBのディスク容量が必要です。)データベースは、時間の経過とともに個々のファイルの履歴が増加するにつれて、規模を増していくことが予想されます。

サーバにあるバージョン化ファイルのアーカイブのサイズは、保存されているオリジナルファイルのサイズに依存するので、リビジョンの増加に応じて規模を増していきます。大多数のサイトでは、少なくともオリジナルファイルのサイズの3倍にあたるディスク容量を割り当てておきましょう。

db.haveファイルには、クライアントワークスペースで作業状態になっているファイルのリストが記録されています。したがってこのファイルのサイズはデータベース内の他のファイルと比べて急速に増大していく傾向があります。db.haveファイルのサイズに関する問題に直面しており、かつ大きなファイルを適切にサポートしているサーバにすぐに切り換えられない場合、使っていないクライアントワークスペース仕様を削除することでクライアントワークスペースのビューの範囲を狭めると、問題を多少改善できることがあります。

ディスクの空き容量を監視する

ディスク空き容量を監視するには、p4 diskspaceコマンドを使用します。デフォルトでは、p4 diskspaceを実行すると、ディスクの空き容量、使用中の容量、およびPerforceによって使用されるファイルシステムの総容量が表示されます。

デフォルトでは、P4ROOTP4JOURNALP4LOGTEMPを保持するファイルシステムの空き容量が10MBを下回ると、Perforceサーバがコマンドを受け付けなくなります。この動作を変更するには、filesys.P4ROOT.min構成可能変数(およびその他の関連する構成可能変数)に、希望の上限値を指定してください。

構成可能変数

デフォルト値

意味

filesys.P4ROOT.min

10M

サーバのルート・ファイルシステムに必要な最少ディスク空き容量。これより少なくなると、サーバはコマンドを拒否します。

filesys.P4JOURNAL.min

10M

サーバのジャーナル・ファイルシステムに必要な最少ディスク空き容量。これより少なくなると、サーバはコマンドを拒否します。

filesys.P4LOG.min

10M

サーバのログ・ファイルシステムに必要な最少ディスク空き容量。これより少なくなると、サーバはコマンドを拒否します。

filesys.TEMP.min

10M

一時的な処理に必要な最少ディスク空き容量。これより少なくなると、サーバはコマンドを拒否します。

filesys.depot.min

10M

ディポに必要な最少ディスク空き容量。これより少なくなると、サーバはコマンドを拒否します。(1つのディポで使用できる空き容量がfilesys.depot.minよりも少ない場合、すべてのディポに関わるトランザクションに対するコマンドが拒否されます。)

Perforceサーバプロセスを動作させるユーザアカウントにディスククオータが適用される場合、当該ファイルシステムに実際に残っている物理的な空き容量にかかわらず、filesys.*.min構成可能変数にはそれらのクオータが反映されます。

ディポ内の特定のファイルに現在占有されているディスク容量を見積もるには、管理中のサイトのデータ保存方法で使用されるのと同じブロックサイズをp4 sizesコマンドに指定します。例えば、

p4 sizes -a -s -b 512 //depot/...

というコマンドを使用すると、ブロックサイズを512バイトとして計算した場合の、//depot/...内にあるすべてのリビジョン(-a)の合計値(-s)が表示されます。

//depot/... 34161 files 277439099 bytes 5429111 blocks

p4 sizesにより報告されるデータは、実際にはファイルとクライアントワークスペースの同期に必要なディスク容量を反映しているのですが、それでもサーバ側でのディスク使用量の概算として参考にすることができます。

ネットワーク

PerforceはTCP/IPネットワーク上で動作可能です。ネットワークの制約はまだ見つかっていませんが、帯域幅が広くなるほど動作は良好になるでしょう。

Perforceは各クライアントとサーバの通信にTCP/IP接続を使用します。サーバのポートアドレスはP4PORTで定義されますが、クライアントのポート番号はTCP/IPによって決められます。コマンドが完了して接続が閉じると、ポートはその後2分間にわたってTIME_WAITという状態になります。ポート番号は1025から32767までの範囲に及びますが、ふつう数100から数1000の番号だけが同時に使用される可能性があります。したがって、例えばスクリプトを使用してPerforceコマンドを何度も立て続けに呼び出すと、使用可能なポートがすべてふさがれる可能性があります。

デフォルトでは、アイドル接続中のキープアライブは行われません。ネットワークによってアイドル接続がサイレントに切断されると、その動作が原因となって想定外の接続の問題が発生するおそれがあります。(p4 pullスレッドがマスターサーバとリモートサイトのレプリカとの間でデータを転送する場合に注意しましょう。この場合、各サイトの営業時間やユーザの作業負荷しだいでは、1日に数時間にわたるアイドル接続が発生する可能性があります。)以下の4つの構成可能変数を使用して、アイドル接続の状態を管理することができます。

構成可能変数

デフォルト値

意味

net.keepalive.disable

0

ゼロ以外を指定すると、TCPキープアライブパケットの送信が無効になります。

net.keepalive.idle

0

キープアライブパケットの送信を開始するまでのアイドル時間(秒)です。

net.keepalive.interval

0

キープアライブパケットの送信間隔(秒)です。

net.keepalive.count

0

キープアライブパケットが確認されなかった回数がこの構成可能変数に指定された数を超えると、接続失敗と判断されます。

ネットワーク構成でキープアライブパケットが必要な場合は、例えば3600秒(1時間)や数十分単位の間隔など、適切な長さの値をnet.keepalive.idleに指定してください。

CPU

Perforceバージョン化サービスは、CPUのリソース消費量という観点からいえば、比較的軽量です。通常、Perforceサーバのインストール先プラットフォームを決定する際に、CPUの処理能力が主な懸案事項となることはありません。

ロックなしの読み取りを使用して同時並行処理を改善する

リリース2013.3よりも前のリリースでは、データベースからデータのみを読み取るコマンドを呼び出すと、1つ以上のデータベーステーブルがロックされて読み取り専用になります。他のコマンドは同時にテーブルからデータを読み取ることができますが、任意のコマンドが読み取り専用にロックされたテーブルに書き込みを試みると、ロックの解除後に書き込みを開始できるようになるまで強制的に待機させられます。現在、デフォルトでは、一部のコマンドで、前述のようなテーブルをロックせずに読み取ることができるようになっています。この動作と引き換えに一貫性や独立性が損なわれることはありません。この機能により、前述のようなテーブルに対して、読み取り専用ロックが解除されるまで書き込み操作を保留するのではなく、書き込みを即座に実行できるようになったため、パフォーマンスが大幅に改善されています。

Note

ロックなしの読み取り操作を実行するには、サーバロックを有効にしておく必要があります。この機能は長期にわたる同期に関する問題を引き起こすおそれがあるので、「sync」サーバロック(server.locks.sync)を制御するためのデフォルト値は、現在デフォルトでは無効になっています。

Perforceサーバでロックなしの読み取りに関する設定を変更するには、p4 configure set db.peeking=Nコマンドを使用します。

db.peekingに変更を加えると、いかなる変更でもそれを有効にするには、サーバを再起動する必要が生じます。

db.peekingに指定できる値は以下のとおりです。

db.peeking

意味

0(デフォルト)

db.peekingの値として何も指定されていないか、もしくは0が指定されている場合、旧式のデータベースロック方式が使用され、ロックなしの読み取り機能(ピーキング)が無効になります。

この動作は、Perforceリリース2013.2以前の動作と一致します。

1

db.peekingに1が指定されている場合、新しいデータベースロック方式が使用されますが、ピーキングは依然として無効のまま変わりません。

この構成は、主に障害の原因追究のために使用されます。

2

db.peekingに2が指定されている場合、新しいデータベースロック方式が使用され、しかもロックなしの読み取り(ピーキング)ができるようになります。

この構成により、大半のサイトで最良のパフォーマンス結果が得られることが期待されます。これがデフォルト値です。

3

db.peekingに3が指定されている場合、新しいデータベースロック方式が使用され、ロックなしの読み取り(ピーキング)ができるようになりますが、db.revhxおよびdb.revdxテーブルの最適化は回避されます。

この構成にすると、同時並行処理は改善されますが、コマンド完了速度が低下します。通常、リポジトリが1ファイルにつき多数のリビジョンを有している場合、db.peeking=3を使用すると一部のコマンドの完了速度が遅れますが、db.revhxおよびdb.revdxテーブルに対する読み取り専用ロックはもはや必要なくなります。前述のテーブルに対する読み取り専用ロックが実際に障害になっている場合、db.peeking=3を使用してパフォーマンス全体を改善できる可能性が残されています。ヒント: 履歴が大量にある場合は、デフォルト値を使用してください。単一のリビジョンブランチデータが大量にある場合は、db.peeking=3を試行してください。CPUの処理限界に達した場合は、既定値(2)に戻してください。

ロックなしの読み取りを実装しているコマンド

ピーキングが有効になっている場合、以下のコマンドは読み取り専用ロックなしで実行されます。

コマンド

備考

annotate

 

branches

 

changes

 

clients

 

counters

 

depots

 

describe

 

diff

 

diff2

 

dir2

 

filelog

 

files

files -aに適用

fixes

 

fstat

db.peeking=3の使用時

have

 

interchanges

 

integ

 

integed

 

istat

 

jobs

 

keys

 

labels

 

merge

 

streams

 

sizes

sizes -aに適用

sync

db.peeking=3使用時

print

print -aに適用

resolved

 

users

 

verify

 

以下のコマンドは一定条件下ではロックなしで動作します。大半の場合これらのコマンドは対象ファイルをロックせずに読み取りますが、いつも必ずロックなしで動作するという保証はありません。

コマンド

備考

copy

 

cstat

 

fstat

db.peeking=2使用時

interchanges

copy操作に関連する場合

istat

copy操作に関連する場合

opened

 

sync

db.peeking=2使用時

デフォルトの動作をオーバーライドする

db.peeking設定をコマンド単位でオーバーライドすることができます。それには、-Zpeeking=フラグを使用し、その後に任意の値を指定します。例えば、1つのコマンドのピーキングを無効にするには、以下のコマンドを実行します。

p4 -Zpeeking=1 fstat

そして以下の結果と比較します。

p4 -Zpeeking=2 fstat

ロックなしの読み取りによる効果を計測する

読み取り専用ロックがパフォーマンスに悪影響を及ぼしているかどうか(また、ロックなしの読み取りを有効にした後でパフォーマンスがどれほど改善したか)判断するには、サーバログを検証するか、任意のコマンドに対し-Ztrackフラグを使用してP4LOGに書き込まれたはずの行を出力するとよいでしょう。例:

p4 -Zpeeking=1 -Ztrack sync

以上によって、11のデータベーステーブルの出力が生成されます。ここで重要な行は「locks read/write」を呼び出している行です。

...
--- db.counters
---   pages in+out+cached 3+0+2
---   locks read/write 1/0 rows get+pos+scan put+del 1+0+0 0+0
--- db.user
---   pages in+out+cached 3+0+2
---   locks read/write 1/0 rows get+pos+scan put+del 1+0+0 0+0
...

(「locks read/write 1/0」)各テーブルのロック結果に現れている1は、1つのテーブルにつき1つの読み取り専用ロックがかかっていることを示しています。これに対して、

p4 -Zpeeking=2 -Ztrack sync

...
--- db.counters
---   pages in+out+cached 3+0+2
---   locks read/write 0/0 rows get+pos+scan put+del 1+0+0 0+0
...

からの診断出力は、db.countersで必要な読み取り専用ロックも書き込み専用ロックも行われることなく同期操作が完了したことを示しています。ピーキングを有効にしておくと、多数のコマンドでread/write 0/0ロックがかかっていること(あるいは少なくとも、ほとんどロックがかかっていなかったこと)がわかるでしょう。

サイドトラックサーバでは、db.peekingレベルを同一の設定にしておく必要があります。

単一のPerforceインスタンスは、db.peekingを意図せずオーバーライドする不適切な試行を検出し、無視します。そのような試行がテーブルロック方式を変更することによりデッドロックの危険を生むおそれがあるためです。(例えば、db.peekingに0を指定する(または値を指定せずにいる)ことでピーキングを無効にしているサーバに対し、db.peeking=3の使用を試行すると、サーバはその試行を完全に無視し、コマンドは古い方式で実行されます。)

以下のナレッジベース記事で説明している「サイドトラックサーバ」の場合、

http://answers.perforce.com/articles/KB_Article/Perforce-Metadata-Replication

このプロテクションは使用できません。

Warning

すべてのサイドトラックサーバでは、db.peekingの設定をメインサーバと同一の設定にしておく必要があります。さもなければ、サーバのデッドロックが発生するおそれがあります。

応答時間の遅延の原因を突き止める

通常、Perforceはネットワークリソースをあまり使用しません。ユーザが極端に大規模な操作を行った場合にPerforceサーバの応答が遅延する可能性はありますが、p4コマンドに対する応答がずっと遅れている場合、その原因はたいていネットワークの問題にあります。応答時間の遅延を引き起こす可能性があるのは、以下のうちいずれかです。

  1. ドメインネームシステム(DNS)構成の誤り

  2. Windowsネットワークキング構成の誤り

  3. ネットワーク化されたファイルシステム上で発生しているp4実行ファイルへのアクセス障害

まず行うべきテストは、p4 infoの実行確認です。それに対する応答が即座に得られない場合、ネットワークに問題が発生しています。ネットワークの問題を解決することはこのマニュアルの対象外ですが、以下に若干のトラブルシューティングのヒントを紹介しておきます。

ホスト名をIPアドレスに変えてみる

P4PORTに、サービスのホスト名ではなくサービスのIPアドレスを指定してみます。例えば、

P4PORT=host.domain:1666

とする代わりに、

P4PORT=1.2.3.4:1666

などと、サイト特定のIPアドレスとポート番号を指定してみてください。

大半のシステムでは、以下のコマンドを使用するとホストのIPアドレスを特定できます。

ping hostname

p4 infoがIPアドレスの使用時に即座に応答する一方で、ホスト名の使用時に即座に応答しない場合は、問題はDNSに関連している可能性があります。

Windowsのワイルドカード

Windows上でp4コマンドを使用すると、ある条件の下では応答時間の遅延が生じるおそれがあります。その条件とは、そのコマンドがディポシンタックスとワイルドカードの組み合わせから成るファイルパターンを使用していること、かつそのファイルパターンが引用符で囲まれていないことです。

p4 files //depot/*

以下のようにファイルパターンの前後を二重引用符で囲むことによって、遅延を防ぐことができます。

p4 files "//depot/*"

この問題の原因は、p4コマンドがWindowsのワイルドカード拡張機能を使用することにあります。二重引用符を使用しなければ、この機能は//depotをネットワーク接続されたコンピュータのパスとして解釈するので、depotというマシンの検索のために時間をむだに使ってしまうことになります。

DNSルックアップとホストファイル

Windowsでは、%SystemRoot%\system32\drivers\etc\hostsファイルを使用して、IPアドレスホスト名のホスト名の組み合わせをハードコード化することができます。このファイルへのエントリを追加することによって、DNSの問題を回避することができます。これに対応するUNIXファイルは、/etc/hostsです。

p4実行ファイルの場所

以上の原因追究の手順をすべて試しても応答時間の遅延の原因を明らかにできない場合は、p4の実行ファイルそのものが、きわめてパフォーマンスの低いネットワークファイルシステム上に存在している可能性があります。この可能性を確認するには、以下のコマンドを試行してください。

p4 -V

これは、ネットワークアクセスを試みずにただバージョン情報を出力するだけのコマンドです。応答が遅延する場合、問題はp4実行ファイルそのものへのネットワークアクセスにある可能性があります。ローカルのファイルシステムにp4のコピーを作成するかダウンロードすると、応答速度が向上するはずです。

信頼性の低いネットワークでの作業

ネットワーク上の個々の読み取りまたは書き込みを待機する接続時間に上限を設定するには、ネットワークエラーとして接続を切断するまでに待機する秒数を構成可能変数net.maxwaitに設定します。信頼性の低い接続状態で作業するユーザは、net.maxwaitP4CONFIGファイル内で設定するか、-vnet.maxwait=tをコマンド単位で使用し、タイムアウトのまでの待機秒数をtに指定するとよいでしょう。

Note

net.maxwaitをPerforceサーバ上に設定することもできますが、通常はそうしないことを推奨します。例えば、サーバ上でnet.maxwaitに60を指定すると、コマンドラインクライアントのユーザは対話式フォームへの入力を1分以内に完了しなければなりません。そうしなければコマンドがタイムアウトしてしまいます。これに対して、各ユーザが各自の(ワークステーション内の)P4CONFIGファイルのなかでnet.maxwaitを設定すると、そのユーザの接続は上記の制限の対象にはなりません。バージョニングサービスがリクエストに対する応答に60秒を超える時間を要した場合のみ、コマンドが失敗します。

net.maxwaitをグローバルオプションである-rNと組み合わせて、ネットワークのタイムアウト時に再接続を試行する回数をNに指定すると便利です。例:

p4 -r3 -vnet.maxwait=60 sync

というコマンドは、ユーザのワークスペースの同期が中断された場合に、同期を3回まで再試行します。3回目に60秒間でタイムアウトすると、コマンドは失敗します。

タイムアウトして再試行されるコマンド(ネットワーク接続が出力行の途中で失われた場合など)の出力形式は保証されないため、標準入力から読み込みを行うコマンドに-rを使用するのは避けてください。例えば、以下は、標準入力からファイルのリストを読み込み、それをp4 addに送るコマンドです。このコマンドの動作の結果として、中途半端な名前のファイルをディポに追加する操作が試みられるおそれがあります。

find . -print | p4 -x - -r3 add

(例えば、信頼性が極めて低い接続状態でファイルを多数追加しなければならない状況で)このような現象を回避するには、以下のようなアプローチを検討してください。

find directoryname -type f -exec p4 -r5 -vmax.netwait=60 add {} \;

このコマンドは、directoryname内のすべてのファイル(-type f)を検出したうえで、個々のファイルに対して「p4 -r5 -vmax.netwait=60 add」コマンドを実行することでファイルを1つずつ追加します。

すべてのファイルが追加されたら、p4 changeを使用してチェンジリストにチェンジリスト番号を割り当て、番号付きチェンジリストを最小単位でサブミットします。

p4 -r5 -vmax.netwait=60 submit -c changenum

接続が中断されると、番号付きチェンジリストのサブミットは再試行されます。

サーバの停滞を防止する

通常、Perforceのパフォーマンスは、ディポのサイズにではなく、ユーザが1回のコマンド実行で処理しようとするファイルの個数に左右されます。言い換えれば、3,000,000個のファイルを持つディポのうち30個のファイルのクライアントビューを同期するのにかかる時間は、30個のファイルを持つディポのうち30個のファイルのクライアント・ビューを同期するのにかかる時間と比べて、それほど長くはならないはずです。

1つのコマンドによって影響を受けるファイルの数は、おおまかにいって以下の要素によって決定されます。

  • p4コマンドラインの引数(GUI操作の場合は選択したフォルダ)

    引数を使用しなければ、ほとんどのコマンドはクライアントワークスペースビュー内のすべてのファイルに対して実行されるか、さもなければ少なくともそれらすべてのファイルを参照します。

  • クライアントビュー、ブランチビュー、ラベルビュー、プロテクション

    引数を指定されていないコマンドはワークスペースビュー内のすべてのファイルに対して動作するので、ビューとプロテクションに制限を設定していない場合、そのようなコマンドはディポ内のすべてのファイルに対して実行されることになります。

サーバがリクエストに応えて処理を開始すると、その間データベースをロックします。通常の操作の場合は、この方法は成功します。なぜならサーバはリクエストのバックログを十分回避できるほどすばやく入出力を行うことができるからです。しかし異常なほど大規模なリクエストの処理には、数秒から数分かかることもあります。いらいらしたユーザがCTRL+Cキーを押して再試行すると、問題はよけいに悪化してしまいます。つまり、サーバがさらにメモリを消費するので、応答がますます遅くなってしまうのです。

極めて大規模なディポを持つサイトでは、ビューの範囲を無制限にしたり、引数を指定しないでコマンドを実行すると、Perforceサーバは必要以上のリソースを消費して稼働します。ユーザと管理者は、以下の方法により、サーバにかかる負荷を緩和することができます。

  • ビューの範囲を絞り込んで使用する

  • プロテクションを割り当てる

  • maxresultsに制限をかける

  • server.maxcommandsを使用して同時接続数を制限する

  • 使用頻度の低いメタデータをアンロードする

  • 効率のいいスクリプトを作成する

  • 効率よく圧縮を活用する

  • その他のサーバ構成可能変数

ビューの範囲を絞り込んで使用する

以下の「ゆるく制限されている」ビューは、簡単に設定できますが、きわめて大規模なディポでは問題を引き起こすおそれがあります。

//depot/...        //workspace/...

以上のビューでは、ディポ全体がクライアントワークスペースへマッピングされていました。大半のユーザにとって、このビューは著しく「絞り込む」ことができます。例えば、以下のビューの範囲は、ディポの特定の領域に限定されています。

//depot/main/srv/devA/...          //workspace/main/srv/devA/...
//depot/main/drv/lport/...         //workspace/main/dvr/lport/...
//depot/rel2.0/srv/devA/bin/...    //workspace/rel2.0/srv/devA/bin/...
//depot/qa/s6test/dvr/...          //workspace/qa/s6test/dvr/...

クライアントビューについてはとくに言えることですが、ブランチビューやラベルビューもまた、ユーザにとって必要な作業を行うのに十分な範囲だけを表示するように設定する必要があります。

クライアント、ブランチ、ラベルビューは、Perforce管理者または個々のユーザがそれぞれp4 clientp4 branchp4 labelコマンドを使用することにより、設定されます。

スクリプトを最適化する方法(ブランチビューを使用するおよび一時クライアントワークスペースの活用を参照)のうち2つは、同様のテクニックに基づいています。コマンドに使用できるビューのサイズを制限することにより、実行する必要のあるコマンドの数を減らすとともに、コマンドの実行に必要なリソースの消費量も減らします。

プロテクションを割り当てる

プロテクション(“Perforceの管理: 保護”を参照)は、もうひとつのタイプのPerforceビューです。プロテクションは、p4 protectコマンドで設定され、ユーザが実行するコマンドによって影響を受けるディポファイルを制御します。

ただしクライアントビュー、ブランチビュー、ラベルビューとは異なり、プロテクションによって使用されるビューは、Perforceスーパーユーザによってしか設定できません。(プロテクションは、ディポファイルに対する読み取り権限と書き込み権限も制御しますが、権限レベルそのものはサーバのパフォーマンスに影響しません。)Perforce内でプロテクションを割り当てることにより、たとえユーザが「ゆるく制限されている」クライアント仕様を使用している場合であっても、ユーザのビューのサイズを効果的に制限することができます。

プロテクションは、以下のように、ユーザにもグループにも割り当てることができます。例:

write     user       sam           *     //depot/admin/...
write     group      rocketdev     *     //depot/rocket/main/...
write     group      rocketrel2    *     //depot/rocket/rel2.0/...

Perforceグループは、スーパーユーザがp4 groupコマンドを使用することにより、作成されます。Perforceグループによって、プロテクションの割り当てが簡単になるだけではなく、次のセクションで説明するように、maxresultsおよびmaxscanrowsによって便利なエラー防止メカニズムが使用できます。

データベースへのクエリを制限する

各Perforceグループには、相互に関連するmaxresultsmaxscanrowsmaxlocktimeという値があります。それぞれデフォルトでは、unset(無制限)に設定されていますが、スーパーユーザは、p4 groupコマンドを用いて特定グループに対してこれらの値を制限することができます。

MaxResultsは、コマンド実行中にバッファリングされるデータの量を制限することにより、サーバがメモリを過剰に使用しないようにします。制限されたグループのユーザは、そのグループのMaxResultsの制限値より多くデータベース行をバッファリングするようなコマンドを実行することはできません。(ほとんどのサイトでは、MaxResultsを各ユーザのクライアントワークスペースで想定されるファイルの最大数よりも大きく設定する必要があります。)

MaxResultsと同様に、MaxScanRowsもサーバへ過度の要求がなされるような特定のユーザコマンドを制限します。(通常、一回の操作でスキャンされる行の数は、ディポ内のファイルの平均リビジョン数をMaxResultsに積算した数とほぼ等しくなっています。)

最後に、ある種のコマンドがデータベースを長期間にわたってロックし続けないようにするためには、MaxLockTimeを使用します。ミリ秒単位の数値でMaxLockTimeを設定し、データベースのロックを許容する最大時間を指定します。

これらの制限を設定するには、p4 groupのフォーム内の当該フィールドに数値を入力します。1人のユーザが複数のグループに登録されている場合、それらのグループのMaxResults(またはMaxScanRowsもしくはMaxLockTime)制限値の最大値(unlimitedを含むがデフォルトのunset設定を除く最大値)がそのユーザのMaxResults(またはMaxScanRowsもしくはMaxLockTime)値とみなされます。

Example 28. maxresults、maxscanrowsおよびmaxlocktimeの動作。

管理者として、グループrocketdevのメンバーの操作を20,000ファイル以下に、さらにスキャンを100,000リビジョン以下に、そしてデータベーステーブルを30秒以上ロックしないように制限するものとします。

Group:        rocketdev
MaxResults:   20000
MaxScanRows:  100000
MaxLockTime:  30000
Timeout:      43200
Subgroups:
Owners:
Users:
        bill
        ruth
        sandy

ここで、クライアントビューが無制限、loose(「ゆるい」)に設定されているルースが

p4 sync

とコマンド入力すると、ディポにファイルが20,000以上ある場合、このsyncコマンドは拒否されます。この制限を回避するには、ルースのクライアントビューを限定するか、あるいはクライントビューで全ファイルが必要であるようなら、次のようにファイルを小セットに分けて同期させます。


p4 sync //depot/projA/... p4 sync //depot/projB/...

いずれの方法でも、サーバを極端に負荷の大きい1つのコマンド処理に専念させることなく、ルースは目的のファイルを自分のワークスペースに同期させることができます。

次のように、ルースが全ファイルの全リビジョンをスキャンするようなコマンドを試行したと仮定します。

p4 filelog //depot/projA/...

このとき、ファイル数が20,000より少なく、リビジョン数が100,000より多い場合(例えば、projAのディレクトリにファイルが1,000存在し、その各ファイルにリビジョンが20未満で、それぞれに50を超えるブランチが存在するとき)、MaxResultsの制限は適用されませんが、MaxScanRowsの制限が適用されます。

また、どちらの制限が有効であるかにかかわらず、30,000ミリ秒のMaxLockTimeを超えてデータベースをロックするようなコマンドの実行は許可されません。

特定のグループについて、結果として処理される行数(またはスキャンされるデータベースの行数、もしくはデータベースロック時間を示すミリ秒)の制限を解除するには、そのグループのMaxResultsMaxScanRows、またはMaxLockTimeの値をunlimitedに設定します。

これらの制限はユーザに不便を強いることになる可能性があるため、特定の操作がサーバの動作を遅くしているのでない限りは使用しないでください。Perforceアプリケーションの中には大規模な処理を行うものもあるため、通例MaxResultsの値を10,000より小さくすることはありません。また、MaxScanRowsは50,000より小さくせず、MaxLockTimeの値は1,000から30,000(1秒から30秒)の範囲内に設定します。

各Perforceコマンドで影響を受けるファイル数などの詳細については、コマンドラインで以下を実行してください。


p4 help maxresults p4 help maxscanrows p4 help maxlocktime

複数グループに含まれるユーザを対象とする場合のMaxResults、MaxScanRowsおよびMaxLockTime

前述のように、ユーザが複数のグループに登録されている場合、所属するすべてのグループのMaxResultsの制限値のうち最大値がそのユーザに適用されます。

デフォルト値unsetは数値上の制限ではありませんMaxResultsunsetに設定されているグループに属するユーザであっても、他のグループに所属していればそのグループのMaxResults(またはMaxScanRowsもしくはMaxLockTime)値の最大値によって制限されます。

ユーザのコマンドが実際に無制限になるのは、そのユーザがどのグループにも属さないとき、あるいは、そのユーザが属するすべてのグループのMaxResultsunlimitedに設定されている場合に限られます。

同時接続を制限する

監視機能が有効(p4 configure set monitor=1またはそれ以上)の場合、構成可能変数server.maxcommandsを設定して、サービスが同時に処理できるコマンド要求の数を制限できます。

理想的には、この値は、ベースとなるハードウェアリソースが過負荷になる前に暴走スクリプトやサービス不能を検出できる程度に十分低く設定すると同時に、平均接続数とサイトでのピーク処理量との間に十分なゆとりが保たれる程度に高く設定します。

P4LOGが設定されている場合、サーバログには次の形式の行が含まれます。

Server is now using nnn active threads.

サーバログで、サイトにおける通常時の処理量レベルを知ることができます。一般的には、server.maxcommandsはサイトでの予想される処理量のピークの200~500%以上に設定します。

使用頻度の低いメタデータをアンロードする

時間を経るにつれ、Perforceサーバにはアクティブな開発モードでなくなった古いプロジェクトに関連するメタデータが蓄積されていきます。大規模なサイトでは、使用されるデータ群(特にdb.havedb.labelsテーブルに格納されたデータ)を減らすことにより、パフォーマンスを大幅に向上することができます。

アンロードディポを作成する

//unloadという名前のアンロードディポを作成するには、p4 depot unloadと入力し、表示されるフォームに次のように入力します。

Depot:       unload
Type:        unload
Map:         unloaded/...

この例では、アンロードされたメタデータはサーバルートの下にある(Map:フィールドにより指定される)/unloadedディレクトリ内のフラットファイルに格納されます。

このようにアンロードディポを作成した後は、p4 unloadp4 reloadを使用して、環境内のワークスペースおよびラベルに関連するメタデータの処理方法を管理できます。

古いクライアントワークスペース、ラベル、タスクストリームをアンロードする

p4 unloadコマンドは、使用頻度の低いメタデータをバージョン化エンジンのdb.*ファイルからアンロードディポ内のフラットファイルのセットへ転送します。

ユーザは各自-c-l-sの各オプションを使用して、自身が所有するワークスペース、ラベル、またはタスクストリームをアンロードできます。例えば、ビルドを連続して開発する環境下で、ワークスペースやラベルを1ビルドにつき1つずつ作成するビルドスクリプトの保守担当者は、各ビルドの終了時にその都度ラベルをアンロードすることが推奨されます。


p4 unload -c oldworkspace p4 unload -l oldlabel

同様に、開発者は使用し終えたタスクストリームをその都度アンロード(p4 unload -s oldtaskstream)または削除(p4 stream -d oldtaskstream)することが推奨されます。

古くなった、または使われなくなったメタデータをまとめて管理するには、管理者は-a-al-acフラグを-d dateおよび/または-u userフラグと併用します。これにより、特定のdateより古いか、特定のuserが所有する、あるいは両方の条件に該当するすべてのラベルおよびワークスペースをアンロードできます。

デフォルトでは、ロックが解除されたラベルまたはワークスペースしかアンロードされません。ロックされたラベルまたはワークスペースをアンロードするには、-Lフラグを使用します。

ワークスペースやラベルのアンロードまたはリロードを行うには、ワークスペースのhaveリストにあるすべてのファイルおよび/または当該ラベルによってタグ付けされているファイルを、ユーザがスキャンできなくてはなりません。MaxScanrowsおよびMaxResultsを十分な大きさの値に設定して(複数グループに含まれるユーザを対象とする場合のMaxResults、MaxScanRowsおよびMaxLockTimeを参照してください)、ユーザがp4 unloadまたはp4 reloadの操作にサポートを要求しなくて済むようにする必要があります。

アンロードされたデータへのアクセス

デフォルトでは、p4 clientsp4 labelsp4 filesp4 sizesp4 fstatなどのPerforceコマンドは、アンロードされたメタデータを無視します。アンロードされたワークスペースやラベル(またはアンロードされたその他のメタデータ)を調べる必要のあるユーザは、それらのコマンドの使用時に-Uオプションを使用できます。詳細については、『P4コマンドリファレンス』を参照してください。

ワークスペースとラベルをリロードする

アンロードされたメタデータをdb.haveテーブルまたはdb.labelsテーブルに戻すことが必要になった場合は、p4 reloadコマンドを使用します。

効率的なスクリプトを用いる

Perforceのコマンドラインクライアントであるp4では、対話形式で実行可能なコマンドすべてをスクリプトにより実行できます。Perforceサーバは、ユーザのコマンド発行よりもはるかに速くコマンドを処理できるため、完全な対話形式の環境では、優れた応答時間が期待できます。ただし、例えばトリガ、レビューデーモン、コマンドラッパなどのスクリプトにより発行されたp4コマンドは、スクリプトの効率を考慮していないとパフォーマンス上の問題を引き起こすことがあります。これはp4コマンドが本来非効率的だからではありません。対話形式でユーザが実行したp4が、場合によっては繰り返し操作に適したものではないためです。

このセクションでは、よくある効率上の問題とその解決法をいくつか紹介します。

ファイルに対する繰り返し

Perforceの各コマンドを発行すると接続スレッドが生じ、p4dサブプロセスが起動します。スクリプトの効率を改善する第一歩は、スクリプトによって実行されるPerforceコマンドの数を減らすことです。

スクリプトでは、各ファイルに対して同じPerforceコマンドを繰り返し実行するような記述は避けます。可能であれば常に、ファイルのリストに対して1つのPerforceコマンドを実行し、その実行結果に対して繰り返し処理を行うようにします。

例えば、より効率的な方法は以下のようになります。

for i in `p4 diff2 path1/... path2/...`
do
    [process diff output]
done

以下のような非効率な方法は避けます。

for i in `p4 files path1/...`
do
    p4 diff2 path1/$i path2/$i
    [process diff output]
done

リスト入力ファイルを利用する

Perforceコマンドが、コマンドラインの引数にファイルのリストを指定できる場合は常に、あるファイルから同じ引数のリストを読み取ることもできます。最初にファイルのリストを作成し、そのリストファイルをp4 -xに引き渡すことにより、スクリプトでリスト入力ファイルを利用することができます。

例えば、スクリプトが以下のように記述されている場合が挙げられます。

for components in header1 header2 header3
do
    p4 edit ${component}.h
done

効率を改善するには以下のように記述します。

for components in header1 header2 header3
do
    echo ${component}.h >> LISTFILE
done
p4 -x LISTFILE edit

-x fileフラグは、p4に対して指定のファイルから1行ずつ引数を読み取ることを指示します。ファイル名が-(ダッシュ)の場合は、標準入力から読み取られます。

デフォルトでは、サーバは-x fileからの引数を一回につき128個まとめて処理します。サーバによって処理される引数の数を-b batchsizeフラグを用いて変更すると、異なるバッチサイズで引数を渡すことができます。

ブランチビューを使用する

Perforceコマンドの実行回数を減らすために、p4 integrateまたはp4 diff2でブランチビューを使用できます。例えば、以下のようなコマンドを実行するスクリプトが挙げられます。


p4 diff2 pathA/src/...   pathB/src/... p4 diff2 pathA/tests/... pathB/tests/... p4 diff2 pathA/doc/...   pathB/doc/...

このとき、以下のようなブランチビューを作成すれば効率を改善できます。

Branch:        pathA-pathB
View:
        pathA/src/...      pathB/src/...
        pathA/tests/...    pathB/tests/...
        pathA/doc/...      pathB/doc/...

また上記の3つのコマンドは次のように1つにまとめることができます。

p4 diff2 -b pathA-pathB

ラベル参照を制限する

大きなラベルへの反復参照は特に無駄を増やします。リビジョンにラベルを使用するファイルへの参照コマンドは、各ファイル引数ごとラベル全体のスキャンが行われることになります。Perforceサーバの回線を占有しないためには、サーバからラベルの適用されているファイルを取得し、それらのファイルに対してスキャンを行うスクリプトを使用します。

例えば、次のスクリプトでサーバへの負荷を軽くすることができます。

p4 files path/...@label | egrep "path/f1.h|path/f2.h|path/f3.h"

次のスクリプトよりも負荷は軽くなります。

p4 files path/f1.h@label path/f1.h@label path/f3.h@label

または次のスクリプトよりも負荷は軽くなります。


p4 files path/f1.h@label p4 files path/f2.h@label p4 files path/f3.h@label

以下に説明する「一時クライアントワークスペースの活用」も、ラベルによりファイルを参照する回数を減らすことに役立ちます。

大規模なサイトでは、参照頻度が低いか、または使用されていないラベルをデータベースからアンロードすることを検討してください。詳細については、使用頻度の低いメタデータをアンロードするを参照してください。

一時クライアントワークスペースの活用

ほとんどのPerforceコマンドは、現在のワークスペースビューのすべてのファイルを1つのコマンドライン引数で処理できます。作業したいファイルだけが含まれる一時クライアントワークスペースビューを利用すれば、実行するコマンドの数や、各コマンドに与えるファイル引数の数を減らすことができます。

例えば、次のコマンドを実行するスクリプトを仮定します。


p4 sync pathA/src/...@label p4 sync pathB/tests/...@label p4 sync pathC/doc/...@label

この場合、以下のようなクライアントワークスペース仕様を使えば、一度にまとめてコマンドを実行し、ラベルのスキャンを3回から1回に減らすことができます。

Client:        XY-temp
View:
        pathA/src/...      //XY-temp/pathA/src/...
        pathB/tests/...    //XY-temp/pathB/tests/...
        pathC/doc/...      //XY-temp/pathC/doc/...

このワークスペース仕様は、次のように入力して実行します。

p4 -c XY-temp sync @label

効率よく圧縮を活用する

デフォルトでは、binaryタイプのファイルのリビジョンは、Perforceサーバに保存される際に圧縮されます。.GIFや.JPG画像、.MPGや.AVIのメディアコンテンツ、.gzで圧縮されたファイルなどは、ファイルフォーマットの一部に圧縮を含みます。Perforceサーバでこのようなファイルを圧縮しようとすると、ディスク容量の節約がほとんどできない割に、サーバのCPUリソースを消費する結果となります。

これらのファイルタイプに対してサーバストレージでの圧縮を無効にするには、コマンドラインまたはp4 typemapテーブルを用いて、ファイルタイプにbinary+F(圧縮せずに「+F」、サーバへ格納するバイナリ)を指定します。

サンプルのタイプマップテーブルを含め、p4 typemapについての詳細は、p4 typemapでファイルタイプを定義するを参照してください。

その他のサーバ構成可能変数

Perforceサーバには、パフォーマンス改善のために変更可能な多くの構成可能変数があります。

p4 help configurablesを実行すると、構成可能変数の完全なリストを表示できます。

並列処理

ワークスペースを同期するとき、転送するファイルの数とサイズに応じて、p4 syncコマンドは実行に時間がかかる場合があります。このコマンドで複数のスレッドを使用してファイルを転送することにより、処理を速くすることができます。これは構成変数net.parallel.maxを1より大きい値に設定し、--parallelオプションをp4 syncコマンドに使用することにより行うことができます。並列処理は、距離が長く待機時間が長いネットワークや、単一のTCPフローを使用した帯域幅を使用できないネットワーク構成で使用すると最も効果的です。また、クライアントでファイルの解凍にかなりの作業を必要とする大規模な圧縮バイナリファイルを使用している場合にも役立ちます。

詳細については、『P4コマンドリファレンス』のp4 syncコマンドの解説を参照してください。

データベースツリーのバランス回復のためのチェックポイント

Perforceの内部データベースでは、データは通称BツリーとよばれるBayerツリーという構造で保存されます。Bツリーは高速アクセスが可能なきわめて一般的なデータ構成方法ですが、時間の経過とともに、ツリーに対するエレメントの追加や削除により、次第にデータ構造がアンバランスになってくることがあります。

最終的に、そのツリーがアンバランスになるあまり、パフォーマンスに悪影響が出る場合もあります。Perforceのチェックポイントと復旧のプロセス(バックアップとリカバリに関する基本的な考え方を参照してください)を実行することで、ツリーはバランスのとれた状態に再生されます。結果的に、バックアップ、db.*ファイルの削除、チェックポイントからのdb.*ファイルの再生の後、サーバのパフォーマンスにある程度の改善が得られます。

このツリーのバランス回復は、通常はデータベースファイルがチェックポイントのサイズの10倍以上になったときに初めて効果が得られます。Perforceを通常通り使用している限り、ツリーがアンバランスになるまでに長い時間を要します。大多数のサイトでは、パフォーマンス改善のためにチェックポイントからデータベースの復旧(つまりツリーのバランス回復)を行う必要はありません。

Perforce 2013.3のリリースのBツリーの変更により、db.*ファイルのサイズが16TBに拡張されたほか、その他の点でもスケーラビリティが大きく向上しました。

Perforce 2013.2から2013.3でBツリーへ加えられた変更により、このリリースにまたがるすべてのアップグレードに関しては、古いリリースによりチェックポイントが作成され、新しいリリースによりそのチェックポイントが回復されなければなりません。詳細については、p4dをリリース2013.2から2013.3へアップグレードするを参照してください。