必要なサーバースペックを求める良い方法・・・

月間PV数とか接続クライアント数などの大雑把な指標から、必要なサーバースペックを求めたいと言う質問は昔からよく見かけます。答えは単純「そんな便利な方法はない。」の一言に尽きます。

必要なサーバスペックを求めるには実測にまさる方法はありません。サーバ行われる一連の処理を想定して適当なモックアップを作り、実際にアクセスして計測すれば良いのです。

なにも想定している最大の負荷を実際にかけて見る必要などは無く、数百回/minとかの適当な回数の処理を行い、CPUやネットワーク、ディスク、メモリの負荷量を計測すれば十分です。CPU使用率(%)、メモリの使用量(MB)、ディスクの読書量(MB/s、IOPS)、ネットワークのトラフィック量(MB/s)等の数値を得ます。

殆どの場合は処理回数が増えると、負荷量も線形に増加します。実運用において数万回/minの処理が行われる思っているなら、単純に数百回/minで計測した数値の100倍の負荷量に耐えられるハードウェアを選定すれば良いわけです。

ハードウェアの理論限界に対しての負荷量、負荷率が低い場合には、負荷量が上昇しても応答速度は殆ど低下しません。負荷率が一定レベルを超えると指数級数的に応答速度が低下します。これは必要なハードウェアリソースを使いたいその瞬間に、他の処理で使われていて使えない、コリジョンが発生する為です。これを踏まえて、CPUやメモリなら80%、ストレージやネットワークなら30%程度の負荷率を超えないように設定していれば、応答速度の低下を許容範囲におさめられるでしょう。

もちろん一度測定してしまえば、処理内容が同じなら流用する事もできます。即座に答えられるエンジニアは過去に似たような条件で実運用したデータを持っているか、あるいは計測した経験があるだけです。

特に実行環境がクラウドの場合には容易に試すことが出来るのですから、机上であれこれ考えるよりも、さっさと試した方が早いですよ。

WordPress 4.7のRSSフィードで日付のフォーマットエラーが発生する

RSSフィードのlastBuildDateの書式がおかしい。「月, 10日 1月 2017年~」って感じになる。コード上は日付を出力するときの書式指定は日本ロケールを意図していないにもかかわらず、日本ロケールの設定に基づいて日付を出力してしまうために、文字列が壊れるということらしい。

修正方法は以下のサイトを参考に・・・
WordPress4.7へアップデート後、Google Search ConsoleのサイトマップにRSSフィードを送信している場合、無効な日付エラーが発生している時の対処法。

ファイルサーバ導入の基本、ライセンス違反はないか?マイナンバーに使ってもよいか?

ファイルサーバ導入の基本、ライセンス違反はないか?マイナンバーに使ってもよいか?
宣伝記事とはいえ、語弊の多い内容なので・・・・

Windows搭載サーバをファイルサーバ用途として利用する際はアクセスするPCやユーザーの数に応じたライセンスが必要となる。そのことを知らずに利用してしまうと、ライセンス違反となってしまうので注意が必要だ。

グループウェアや業務システムを動かすにもユーザーの数に応じたライセンス(CLI)が必要になることが多い。CLIが不要なのはユーザー認証の無いシステムや、インターネットで不特定多数に公開するシステムだけです。業務システムやグループウェアでユーザー認証不要なサーバーと言うのは考えにくい。もしCLIを買っていないなら、ライセンス違反になっている可能性があるか、セキュリティ上問題があると思った方が良い。

とはいえ、「専用機ではなく、扱い慣れたサーバをファイルサーバにしたい」というニーズはもちろんある。それに応えたのが2番目に多い「サーバをベースとしたファイルサーバ専用機」という形態だ。

これらは機器としては一般のサーバと同じだが、「Windows Storage Server」というファイルサーバ向けOSを搭載している。用途が限られるが、PCやユーザーの数に応じたライセンス(Windowsの場合は「CAL(Client Access License)」と呼ばれる)が不要となる。

簡易NAS(LAN接続可能な外付けHDDやストレージ機器によるファイルサーバ専用機)でWindows Storage Serverを搭載している機器は稀である。特に国内ではBuffaloの一部のエディションを除いてほぼ皆無になっている。大部分はLinuxをベースとしたFile Server専用のディストリビューションで構成されている。

簡易NASは10名以下の小規模なチームで使用するには便利で私もお勧めする。これらの機器を単体で使う場合は、ユーザー認証機能が貧弱なことが問題となる。例えばユーザーごとにパスワードを設定しようとすると、従業員を一人一人呼び出してサーバーの管理画面からパスワードを設定してもらという、なかなかに面倒なことになる。Active DirectoryやLDAPを使った認証サーバーと連携することもできるが、Linuxをベースとした機器ではユーザー権限の設計思想が根本的に違うため、Windowsのような柔軟な設定はできない事が多い。従業員ごとにアクセス権を設定する必要がない場合や、ごく限られた人数で使用する場合には良いが、利用者数が増えると運用が難しくなる。

また、そもそも低価格帯の簡易NASは同時接続可能なセッション数を数百と見積もって設計されている。したがって接続するPCが数十台になるとスペック的にも苦しくなっているはずである。

「特定のPCをファイルサーバ用途として利用」は避けるべき選択といえる。WindowsではPCをファイルサーバ用途として利用することはライセンス上、許可されていない。

これは誤り。Windows 10やWindows 7などのクライアント用OSを使ってファイルサーバを構築することはライセンス上許可されている。ただし同時接続可能なユーザーセッション数が20までとなっている。一人のユーザーが複数のセッションを使用する場合もあるので安心して使えるのは5人程度までと思ったほうが良い。

従業員数が20名を超えるようなら、そろそろエンタープライズ向けのサーバーを用意して、クライアント管理機能を使用する事を見当した方が良い。というのも物理的にローカルコンソールにログインしてメンテナンスできる台数が、せいぜい20台が限界だからだ。例えば業務アプリケーションの一斉更新が必要になったとする。もし1台ずつ設定等を確認して構成していては、1台あたり数時間、数十台ともなれば終日頑張っても終えるのが難しくなってくる。セキュリティ更新の適用確認だって時間がかかる。

それにあわせて全社的なファイル共有の仕組みも整えるのが妥当と思う。昔はちょっとパソコンに詳しいだけの人が仕事を任されてしまった悲哀をよく聞いたが、今ならクラウドベースのサービスが多数あるので高度な専門知識がなくとも運用できる環境が整っている。Windows Itune(MicrosoftのクライアントPC管理サービス)やOffice 365といったサービスを使えば難しいことは抜きにできるはずだ。

構造化データエラー「updatedがありません」への対処。

WordPressでテーマにTwentyElevenを使っているとき、Google Webマスターツールで構造化データエラー「updatedがありません」が発生した場合の対処法。

テーマ→テーマの編集の画面に移動し、テーマのための関数(function.php)を編集して、twentyeleven_posted_onにあるclass=”entry-date”をclass=”entry-date date updated”に書き換えて保存します。

変更前:

function twentyeleven_posted_on() {
    printf( __( '<span class="sep">Posted on </span><a href="%1$s" title="%2$s" rel="bookmark"><time class="entry-date" datetime="%3$s">%4$s</time></a><span class="by-author"> <span class="sep"> by </span> <span class="author vcard"><a class="url fn n" href="%5$s" title="%6$s" rel="author">%7$s</a></span></span>', 'twentyeleven' ),
        esc_url( get_permalink() ),
        esc_attr( get_the_time() ),
        esc_attr( get_the_date( 'c' ) ),
        esc_html( get_the_date() ),
        esc_url( get_author_posts_url( get_the_author_meta( 'ID' ) ) ),
        esc_attr( sprintf( __( 'View all posts by %s', 'twentyeleven' ), get_the_author() ) ),
        get_the_author()
    );
}

変更後:

function twentyeleven_posted_on() {
    printf( __( '<span class="sep">Posted on </span><a href="%1$s" title="%2$s" rel="bookmark"><time class="entry-date date updated" datetime="%3$s">%4$s</time></a><span class="by-author"> <span class="sep"> by </span> <span class="author vcard"><a class="url fn n" href="%5$s" title="%6$s" rel="author">%7$s</a></span></span>', 'twentyeleven' ),
        esc_url( get_permalink() ),
        esc_attr( get_the_time() ),
        esc_attr( get_the_date( 'c' ) ),
        esc_html( get_the_date() ),
        esc_url( get_author_posts_url( get_the_author_meta( 'ID' ) ) ),
        esc_attr( sprintf( __( 'View all posts by %s', 'twentyeleven' ), get_the_author() ) ),
        get_the_author()
    );
}

これで徐々に構造化エラーの件数が減っていくので、どうやらうまくいっているようです。

記憶域プールでトライブルに見舞われたので覚書

記憶域プールでトラブルに見舞われたので覚書。

記憶域プールに接続しているドライブが壊れたので削除を試みる。通常であれば新たなディスクを追加して修復したのちに、壊れたディスクを削除すれば記憶域プールは正常な状態に回復する。ところが今回は削除を試みるとエラーとなって削除できない。壊れたディスクの使用済み容量が0.08%となっており、ディスクの一部が使われたままになっているようだ。

記憶域プールの細かな操作はコントロールパネルからは行うことができないのでPowerShellから操作を行う。

PS C:¥WINDOWS¥system32&> Get-PhysicalDisk

FriendlyName                       SerialNumber         CanPool OperationalStatus HealthStatus Usage            Size
------------                       ------------         ------- ----------------- ------------ -----            ----
...
WDC WD10 EARS-00Y5B1 USB Device    801130168383         False   OK                Healthy      Retired     930.75 GB
...

HealthStatusが正常になっているのが気になるが、UsageはRetiredになっているので、既に使われておらず削除できるはずだ。

念のために記憶域プールの修復を実施してみる。次のようにRepair-VirtualDiskを実行してみるが変化はない。

PS C:¥WINDOWS¥system32> Get-VirtualDisk

FriendlyName ResiliencySettingName OperationalStatus HealthStatus IsManualAttach   Size
------------ --------------------- ----------------- ------------ --------------   ----
Mirror       Mirror                Degraded          Warning      False            3 TB

PS C:¥WINDOWS¥system32> Repair-VirtualDisk -FriendlyName Mirror

修復は正常に終わっているにもかかわらず「回復性の低下」の警告が表示されたままになっている。

PowerShell側から物理ディスクの削除を試みることにする。

PS C:¥WINDOWS¥system32> $PDToRemove = Get-PhysicalDisk -Friendlyname "WDC WD10 EARS-00Y5B1 USB Device"
PS C:¥WINDOWS¥system32> Remove-PhysicalDisk -PhysicalDisks $PDToRemove -StoragePoolFriendlyName “記憶域プール”

確認
この操作を実行しますか?
Removing a physical disk will cause problems with the fault tolerance capabilities of the following storage pool:
"記憶域プール".
[Y] はい(Y)  [A] すべて続行(A)  [N] いいえ(N)  [L] すべて無視(L)  [S] 中断(S)  [?] ヘルプ (既定値は "Y"):
Remove-PhysicalDisk : One of the physical disks specified could not be removed because it is still in use.
Activity ID: {8087f98d-bc35-422c-95d2-cfb5777b1637}
発生場所 行:1 文字:1
+ Remove-PhysicalDisk -PhysicalDisks $PDToRemove -StoragePoolFriendlyNa ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (StorageWMI:ROOT/Microsoft/..._StorageCmdlets) [Remove-PhysicalDisk], CimE
   xception
    + FullyQualifiedErrorId : StorageWMI 51004,Remove-PhysicalDisk

“One of the physical disks specified could not be removed because it is still in use.”・・・使用中のために削除できないとのエラーになってしまう。Retiredになっているのに・・・

困ったことにこの時点で記憶域プールのファイルを見ることができなくなっていることに気が付く。ドライブレターは表示されているが、ドライブを開こうとすると長時間待たされた後にエラーとなる。管理者権限でコマンドプロンプトを開きchkdskを実行すると、4KBの不良セクターが検出され、エラーが修復されてドライブを開ける状態には回復した。壊れたディスクに残された0.05%がこのエラーの原因なのだろう。

新たに記憶域を作成し、既存の記憶域を削除するという方針を定める。現在はMirrorになっている記憶域もParityに変更したかったので、よい機会だと割り切ることにした。

PS C:¥WINDOWS¥system32> Get-VirtualDisk

FriendlyName ResiliencySettingName OperationalStatus HealthStatus IsManualAttach   Size
------------ --------------------- ----------------- ------------ --------------   ----
RAID5        Parity                OK                Healthy      False          2.5 TB
Mirror       Mirror                Degraded          Warning      False            3 TB

とりあえずアクセスできる状態にあるMirrorのドライブから、RAID5のドライブにファイルをコピーしていく。壊れたHDDのアクセスランプが時折点滅しており、まだ一部が使われている事を実感する。

Mirror側のデータを全てRAID5側に移動して、Mirrorを削除。その後、コントロールパネルの記憶域から故障したHDDの削除を実施すると、無事に削除された。

もうちょっと強力なエラーリカバリツール提供するか、せめて現状がどうなっているのか類推できるようなエラーメッセージが欲しいよね。今回なら「修復不可能な論理エラーが発生しています。データをバックアップして、記憶域ドライブを削除した後、再作成して下さい。」とか表示してくれると有難い。

Oracleで監査ログを取得する

Oracleの監査ログを監視することになりそうなので、調査内容をメモしておく。

Oracleの監査ログはOracle 11g移行では標準で有効になっており、SYS.AUD$テーブルにデータベースへのログオン/ログオフとスキーマの変更が記録されている。Oracle運用経験の少ない管理者の場合、ログを削除する必要があることを知らずに、システム領域を圧迫することになるので注意。

監査ログを閲覧する場合にはSYS.AUD$を直接参照するのでは無く、DBA_COMMON_AUDIT_TRAILを参照する。以下のSQLで確認出来る。

SELECT * FROM DBA_COMMON_AUDIT_TRAIL

監査対象の追加

監査対象をログオン/ログオフ以外にも拡張するにはAUDIT文を使用する。以下のSQL文を実行するとテーブルに対する閲覧、変更が監査対象となる。

AUDIT SELECT TABLE, INSERT TABLE, DELETE TABLE BY ACCESS

AUDIT ALLとすれば全ての変更を監査対象とする事ができるが、無闇に監査対象を増やすことはサーバーの負荷や、監査ログを精査する業務の負荷を上げるので、必要最小限とする事が望ましい。情報の漏洩や改竄を目的とするのであれば、AUDIT SELECT TABLE, INSERT TABLE, DELETE TABLE BY ACCESSで十分と考えられる。

保存先の変更

標準設定では監査ログをテーブルに保存する。テーブルとして保存されていれば閲覧する分には便利だが、実際に運用する上ではシステム表領域のテーブルに大量のデータが保存される事はあまり好ましくない。
監査ログの保存先をXMLファイルに変更するには、次のSQL文を実行する。EXTENDEDは拡張情報まで収集する事を示す。標準ではSQL文等は保存されないため、どのような操作が為されたのか調査するためにも保存しておいた方が良い。

ALTER SYSTEM SET AUDIT_TRAIL=XML, EXTENDED SCOPE=SPFILE

OSのファイルとして出力する設定もあるが、OSに設定した場合は詳細なログを保存できないのでお勧めしない。

監査ログの削除

監査ログの削除はテーブルに対して直接DELETE文を発行するのではなく、DBMS_AUDIT_MGMT PL/SQLパッケージを使用する。

続:Brandoo WordPressで¥を入力できない。

以前に「Brandoo WordPressで¥を入力できない。」で書いた、/(半角バックスラッシュ)や¥(半角円マーク)を入力していると、更新ボタンを押しても変更内容が保存されない問題について、パッチが提供されていたので適用方法など。

GitHubのBrandoo-WordPress-MSSQLにBugFixが提供されています。バックスラッシュ(円マーク)を含むコンテンツを保存できない不具合に対するパッチ(https://github.com/Brandoo/Brandoo-WordPress-MSSQL/issues/4)です。

FTPなどでサーバーにログインして直接編集します。

JhottMasterさんのGitHubに書かれている修正内容(https://github.com/Brandoo/Brandoo-WordPress-MSSQL/pull/7/files)に従ってwp-content/mu-plugins/wp-db-abstraction/translations/sqlsrv/translations.phpの内容を書き換えます。

Brandoo WordPressを更新したところ「データベースの更新が必要です」が繰り返し表示される

Brandoo WordPressを4.2.2に更新したところ「データベースの更新が必要です(Required Update Database)」が繰り返し表示されて管理者ダッシュボードにログインする事が出来なくなりました。「データベースの更新が必要です」画面で「データベースを更新」を選択して更新が完了しても、続行をクリックすると再び「データベースの更新が必要です」の画面に戻ります。

よくプラグインを無効にするといった対策が紹介されていますが、今回はプラグインを無効にしても解決しません。原因はBrandooのSQL文をMSSQL用に変換する処理に係わる部分でした。

実はGitHubのBrandoo-WordPress-MSSQLにBugFixが提供されています。バックスラッシュ(円マーク)を含むコンテンツを保存できない不具合に対するパッチ(https://github.com/Brandoo/Brandoo-WordPress-MSSQL/issues/4)ですが、データベースの更新に失敗するのも同じ原因によるようで、このパッチを適用する事でデータベースの更新が正常に完了するようになります。

JhottMasterさんのGitHubに書かれている修正内容(https://github.com/Brandoo/Brandoo-WordPress-MSSQL/pull/7/files)に従ってwp-content/mu-plugins/wp-db-abstraction/translations/sqlsrv/translations.phpの内容を書き換えます。

その後、WEBを再起動して再び管理コンソールに接続すると「データベースの更新が必要です」と表示されるので「データベースを更新」を選択します。無事データベースの更新が完了して、管理コンソールにログイン出来るようになります。

Brandoo WordPressで¥を入力できない。

Brandoo WordPressにてコンテンツに/(半角バックスラッシュ)や¥(半角円マーク)を入力していると、更新ボタンを押しても変更内容が保存されずに、元に戻ってしまう。

暫定的な対策としては、テキスト編集画面で&yen;と入力すればBlog上は半角の¥マークを表示することが出来る。だが一度ビジュアルエディタの編集画面に戻ってしまうと、&yen;から¥に変換されてしまうので、あまり現実的な解決方法ではない。

この現象は既に公式にもバグと認識されており、GitHubのCannot add post containing a % characterでも次のリリースにて修正される予定になっている。ただ実は、ちょっと困ったことにGitHubのサイトは放置気味になっている。Text Replacerのプラグインを使ってみたが、プラグインの設定を保存する部分でも¥が失われてしまうため、ちょっと一朝一夕にはいきそうもない。

自作を試みてみるかな・・・

通信プログラムを送信スレッドと受信スレッドに別けては駄目

TCP/IPやシリアル通信において、データの受信と送信を別々のスレッドでおこなえば、アプリケーションを単純化し、パフォーマンスも向上するように感じるかもしれない。これは初級から中級のプログラマがやりがちなことだが、多くの場合は徒労に終わる。

一つ目の問題として、実はOSは送信と受信を同時に実行することが出来ない。アプリケーションからドライバに対する要求はFIFOキューに格納される。デバイスドライバはFIFOキューに格納された命令を順番に処理していく。してがってAスレッドの受信命令と、Bスレッドの送信命令がキューに格納されている場合、Aスレッドの受信命令の処理が終わらない限り、Bスレッドの送信命令も待機することになる。アプリケーション側のスレッドを単純に分けただけでは、送信と受信を非同期におこなう事は出来ない。

送信と受信をほぼ同時に処理するにはノンブロッキングモードを使う必要がある。ノンブロッキングモードなら、ドライバはデータの有無に拘わらず直ちに応答を返して次の処理に進むので、受信と送信をほぼ同時に実行することが出来る。

二つ目の問題として、殆どのプロトコルにおいて、送信が正常に行われたか判断するためには受信データが必要になることにある。送信処理と受信処理は互いに深く関係した密結合となる。そのため送信処理と受信処理との間で情報を交換するためにフラグや排他制御が必要になる。正常処理だけなら良いか、これに異常時のリカバリ処理まで含むと状態遷移が複雑になり、余程慎重に設計しないとスパゲティのように絡み合ったソースコードになってしまうはずだ。

通信プロトコルが送信とその応答を非同期的に処理することを前提に設計されていたり、あるいは非同期的に処理することでパフォーマンスの向上を臨んでいるなら、送信と受信を分離する価値はあるだろう。そうでないなら、止めた方が無難だ。

ではどのような設計なら良いのだろうか。私見だが「他スレッドからFifo Queue等で要求を受付け、コマンドの送信、応答の受信、必要に応じてエラーリカバリ処理を行って、要求元スレッドに応答を返すようなスレッド」を作るのが良いと思う。この方法だと通信に伴って発生する状態遷移を単一スレッドの中に閉じ込めることが出来るので、複雑さが増す事を避けて実装する事が出来る。