ラベル FileMaker Server の投稿を表示しています。 すべての投稿を表示
ラベル FileMaker Server の投稿を表示しています。 すべての投稿を表示

2017-06-14

FileMaker WebDirect 16 のロードバランス

 前回は FileMaker Server 16 の WebDirect (WebDirect 16)の構成をマスタサーバ 1 台構成にした場合と、ワーカマシン 5 台構成にした場合とで、スレッド数(接続数)や Ramp-up(全スレッドを生成するまでの時間)の条件を変更しながらパフォーマンス計測を行いました。 
 本稿では ワーカマシン 5 台構成で WebDirect 16 のロードバランスがどのように機能するのかを見てみます。
【ワーカマシン5台構成のイメージ】

サーバ 5 台構成時 のロードバランス

 複数のワーカマシンで構成される WebDirect 16 は Webクライアント(ブラウザ)からリクエストを受信すると、より負荷の低いマシンにそのリクエストを割り当てます(ロードバランス)。
 下図は異なる 5 台のクライアント PC のブラウザから WebDirect にログインしたところですが、より負荷の低いワーカマシンにリクエストが割り振られていることがわかります。
FileMaker Server 16 Admin Console のステータス画面
 上図のような低負荷の状態では WebDirect のロードバランスが適正に機能していることが確認できます。ちなみに、ワーカマシン 1 は Webサーバ機能の他に、データベースサーバ機能とロードバランスの機能も担うため、他のワーカマシンの負荷が相当程度高くなるまでの間、自身では HTTPリクエストを処理しないようです。
 次に、WebDirect の負荷を増減させるとどうなるのか、Apache JMeter を使ってテストしてみました(下図)。

【表1】
No ワーカ数 スレッド ループ Ramp
(秒)
 
リクエスト/秒 所要時間(秒) 失敗数 1Recの平均作成時間(秒) 備考
1 5 500 1 0.5 1000 46 128 0.092  1回計測
2 5 500 1 2 250 58.5 1.5 0.117  2回計測
3 5 500 1 5 100 60 0 0.120  1回計測
4 5 500 1 7 71.4 49 0 0.098  1回計測
5 5 500 1 30 16.7 48 0 0.096  5回計測
6 5 500 1 40 12.5 48 0 0.096  5回計測
7 5 500 1 60 8.3 60 0 0.120  1回計測
8 5 500 1 90 5.6 92 0 0.184  1回計測

 本テストは 500 スレッド(≒500ユーザ)から 、出庫伝票(出庫ヘッダレコード1と出庫明細レコード1)を作成する FileMaker スクリプトを実行し、最初のリクエスト発行から 500 件目の出庫伝票の作成が完了するまでの[所要時間(秒)]を計測しています。Ramp は 500 スレッドを生成する時間です。
 たとえば、テスト No.1 では 500 のスレッドを 0.5 秒の間に作成し、最後のレコードが作成し終わるまでの[所要時間(秒)]が 46 秒であったことを示しています。[失敗数]は本来 500 件の出庫伝票が作成されるべきところ作成に失敗した件数を示しており、No.1 では 128 件の失敗(伝票未作成)が発生しました。下図は No.1 実行時のワーカ割り振りの状態です。


Ramp が 0.5 では接続がワーカマシン 1 に極端に集中してしまう

 0.5 秒間に 500 スレッドが発生する高負荷状態ではワーカマシン 2 に割り振りが集中し、ロードバランスが適正に機能せず、128件のレコード作成処理が失敗しています。

 次にテスト No.4 ( Ramp:7秒)のロードバランスを見てみましょう(下図)。ワーカマシン 3、5 への割り振りが大分多いですが、ワーカ 2、4 にも 80 程度のスレッドが割り振られています。
 
500 同時接続で Ramp 7 秒 のときのサーバ割り当ての様子

 下図は Ramp を 60 秒にしたときの割り振り状態です。ワーカマシン 2~4 にはほぼ均等にスレッドが割り振られていて、ワーカマシン 1 (マスタ)は若干少なめに割り振られています。

500 同時接続で Ramp 60 秒 のときのサーバ割り当ての様子

  以上のように、WebDirect 16 は短い時間に極端にアクセスが集中すると、ロードバランスが適に機能しない可能性があります。アクセスの間隔が長くなるに従い、HTTP リクエストが各ワーカマシンに均等に割り振られるようになると思われます。

エラーが発生しない適正なリクエスト頻度

 下図は表1 をグラフ化したものです。Ramp が 2 秒迄だとエラーが発生しますが、Rampが 5 秒になると全 500 スレッドがエラー無く終了します。500 スレッド÷ 5 秒で 100 スレッド/秒、つまり1秒間に 100 のリクエストであればエラーが発生しません。
 ただ、所要時間は 60 秒なので、この結果を実運用に適用できると仮定すると、ユーザがリクエストを発行してから 60 秒程度、待たされることになります。Ramp が 60 秒、つまり 1 秒に 10 弱のリクエストの場合は、ユーザの待ち時間が数値上はほぼ無くなります。1 秒あたり 10~100 リクエスト程度の範囲に、安定運用可能なリクエスト頻度の目安があるのかもしれません。



マスタ1台構成 vs ワーカ5台構成

 最後に、下図は500スレッドの処理を完了するまでの時間を、1 サーバ構成と 5 ワーカマシン構成でパフォーマンスを比較した折れ線グラフです。折れ線の左の部分は、7 秒間に 500 のスレッドからのリクエストを処理する場合、1 サーバ構成の方が 5 ワーカ構成より有利であることを示しています。
 本テストは 7 秒~90 秒という短い時間内で終了してしまうテストなので、より長い時間、継続的に負荷がかかるようなケースには当てはまらないかもしれませんが、ワーカを増やせば実行速度も増す、と単純に想定することはできないことを示していると思います。



(亀)

2017-06-09

WebDirect 16 ワーカマシン構成による500+スレッド 同時接続テスト


  FileMaker Server 15 の WebDirect (WebDirect 15)では、最大同時接続数は 100、構成サーバは最大2台まででしたが、FileMaker Server 16 の WebDirect (WebDirect 16)では最大同時接続数が500、構成サーバは最大5台までとなりました。

 前稿では Apache JMeter を使用し、WebDirect 16 に対して25セッションでレコードを作成するテストを行いました。結果、旧版 WebDirect に比べパフォーマンスが向上し、エラー(レコードの作成失敗)が発生しないことを確認しました。 WebDirect 16 が実用段階に近づいていることを実感しました。

 今回は前回と同じく JMeter を使用し10~500+ のスレッドからレコードを作成するテストを実施しました。 

WebDirect 16 で 500 同時接続を実現するためのワーカマシン構成

 最初にインストールについて少しだけ触れます。WebDirect 16 では、1台のマスタマシンと 最大4 台迄のワーカマシンを構成できます。インストール自体は、下図のようにマスタマシンかワーカマシンを選択するだけなのでとてもシンプルです。 

マスタマシンかワーカマシンかをインストール時に選択すればよい

 ワーカマシン展開の詳細は、FileMaker 16 WebDirect ガイドの『展開オプション』の項をご覧ください(p20~30) 。以下の抜粋イメージが参考になると思います。


FileMaker® Server16インストールおよび構成ガイド『第 3 章 複数のマシンでの FileMaker Server の展開』(P.22)より

 

サーバ構成

 今回のテストでは、 Hyper-Vを 搭載する2台の物理マシンを用意し、1台に3つの仮想サーバ(ワーカマシン 1~3)、もう1台に2つの仮想サーバ(ワーカーマシン 4 と 5)を入れています。

  • マスタマシン(兼ワーカマシン1):
       CPU: 3.0Ghz
       コア数/メモリ: 4core 8GB RAM(FileMaker社推奨構成)
       Windows Server 2012 R2 (64bit)
  • ワーカマシン2:
       CPU: 3.0Ghz
       コア数/メモリ: 4core 8GB RAM
       Windows Server 2012 R2 (64bit)
  • ワーカマシン3:
       CPU: 3.0Ghz
       コア数/メモリ: 4core 8GB RAM)
       Windows Server 2012 R2(64bit)
  • ワーカマシン4:
       CPU: 2.93Ghz
       コア数/メモリ: 4core 8GB RAM
       Windows Server 2016 (64bit)
  • ワーカマシン5:
       CPU: 2.93Ghz
       コア数/メモリ: 4core 8GB RAM
       Windows Server 2016 (64bit)

WebDirect のロードバランス

 JMeter によるテストに入るまえに、異なる 5 台のクライアントマシンの Web ブラウザから WebDirect 16に同時アクセスし、WebDirect がどのようにロードバランスを行うのか ― どのようにマスタ機が接続をワーカマシンに割り振るのか ― を観察してみました。
 JMeter のような負荷テストツールではなく、実際のブラウザで WebDirect のリアルな動きを確認しておくことは、意味があると思われます。
 結果として、マスタマシン(兼ワーカマシン1)にクライアント接続が割り当てられることはなく、ワーカマシン ワーカマシン2 に 2 接続、ワーカ3、4、5 にそれぞれ 1 接続ずつ割り当てられました。
5台のクライアント PC から WebDirect にアクセスしたときのサーバ割り当て状況

 また、ひとつのWebクライアントが複数の 5つのブラウザタブを開いた状態で、WebDirect にアクセスした場合にも、ワーカマシン2 に  2 接続、ワーカマシン3、4、5 にそれぞれ 1 接続が割り当てられましたが、この時もワーカマシン1 に割り当てられることはありませんでした。
1台のクライアント PC の Web ブラウザで 5 つのタブから同時接続したときのサーバ割り当て状況
 このように、WebDirect は基本的に、接続先のワーカマシンの負荷状態を判断し、より負荷の低いワーカにルートします。
 ※ワーカマシン1(マスタ) はデータベースサーバおよび管理ツールが稼働しており、他のワーカマシンに比べると負荷が高いため、WebDirect 割当先になりにくいと考えられます。もちろん、マスタ1台の構成では、 このマシンがWebDirect の処理も併せて行います。

 

JMeterシナリオ

 JMeter を使用しセッションを10~500+作成、各セッションから FileMaker のスクリプトを実行して出庫伝票(ヘッダレコード1、明細レコード1)するシナリオを作成しました。
 

1 台構成でのテストと結果

 さて、JMeterによるテストを見ていきます。最初にマスタ1台だけの構成で上記のJMeterシナリオを実行してテストを行いました。結果は下表のとおりです。表中、Ramp(秒) はすべてのスレッドを送信し終わるまでの所要秒数を示しています。

 表の見方 を テストNo 4(スレッド=100)を例に説明します。No.4 は、0.5秒間に100のスレッドを作成し、開始から終了までに 6.4 秒かかっていることを示しています。失敗数は作成されなかったレコード数(エラー)で、No.4は 100 すべてのスレッドが成功し、100 件の出庫伝票が作成されました。  尚、各テストは特に記載が無ければ 5 回ずつ実施し、所要時間と失敗数はその平均値をとっています。
【表1】
No ワーカ数 スレッド ループ Ramp
(秒)
 
所要時間(秒) 失敗数 1Recの平均作成時間(秒) 備考
1 1 10 1 0.5 1 0 0.100 
2 1 20 1 0.5 1.2 0 0.060 
3 1 50 1 0.5 3.4 0 0.068 
4 1 100 1 0.5 6.4 0 0.064 
5 1 200 1 0.5 14 0 0.070  2回計測
6 1 300 1 0.5 23 0 0.077  1回計測
7 1 350 1 0.5 19 76 0.054  1回計測
8 1 400 1 0.5 17 142 0.043  1回計測
イタリック(斜体)部分は1回または2回のみテストを実施

  FileMaker社はマスタ1台構成下での最大接続数 を100 としているだけあり、スレッド数 10 ~ 100 は安定して動作しました。
 さらにスレッド数 100超のテストも行いました。 その結果が No.5以降ですが、100 を超過しても同時接続ライセンスがあれば接続を受け付けるしくみになっているようです。
 300 スレッドまでは接続、レコード作成ともに成功しましたが、350を超えるとサーバが高負荷状態となり、接続の失敗が目立つようになっていることがわかります。

マスタマシン 1 台 + ワーカマシン 4 台構成でのテスト

 つづいて FileMaker Server を 5 台構成のテスト展開してテストを実行しました。

【サーバ5台構成のイメージ】
本テストはプレビュー(ETS)版(詳細はTechNet)を使用して行いました

 テスト内容と結果は以下のとおりです。

【表2】
No ワーカ数 スレッド ループ Ramp
(秒)
 
所要時間(秒) 失敗数 1Recの平均作成時間(秒) 備考
50 5 10 1 0.5 4.6 0 0.460 
51 5 20 1 0.5 4.2 0 0.210 
52 5 50 1 0.5 6.2 0 0.124 
53 5 100 1 0.5 13.4 0 0.134 
54 5 100 1 10 11 0 0.110  1回計測
55 5 200 1 未実施
56 5 300 1
57 5 400 1
58 5 500 1 0.5 46 128 0.092  1回計測
59 5 500 1 2 58.5 1.5 0.117  2回計測
60 5 500 1 5 60 0 0.120  1回計測
61 5 500 1 7 49 0 0.098  1回計測
62 5 500 1 10 63 0 0.126  1回計測
63 5 500 1 30 48 0 0.096  1回計測
64 5 500 1 40 48 0 0.096  1回計測
65 5 500 1 7 54 0 0.108 
66 5 600 1 40 59 0 0.098  1回計測
67 5 1000 1 55 98 130 0.098  1回計測
イタリック(斜体)部分は1回または2回のみテストを実施

考察


 以下、今回行ったテストからの考察となります。

高い処理能力

 表1 のテストNo.6 は、1台構成(マスタのみ)環境下で、0.5 秒間に 300 スレッドからクエリを発行し、エラーを出すことなく、23 秒の間に 300 の出庫伝票の作成に成功しています。中規模程度の環境であれば、パフォーマンス的に WebDirect 16 は Webアプリケーション構築の選択肢になると思われます。

適切なワーカマシン数

 表1のテストNo.6 と表2 のテストNo.53 を見てください。他の条件は同じで、ワーカ数が 1 から 5 に増えているにもかかわらず、所要時間はマスタ 1 台の構成のほうが速くなっています。このテストに関しては、おそらくマスタがロードバランスに費やすオーバーヘッドが高いため、ロードバランスを行わない 1 台構成が有利になるものと思われます。

 本テストは短い時間に多くのスレッドから1回のみリクエストを発行するというもので、すべての運用環境に適用できるものではありませんが、単純にワーカマシンを増やせば実行速度が上がるわけではないという可能性を示しています。幸い、ワーカマシンの増設は簡単に行えるので、業務状況やユーザの意見を参考に、ワーカマシンを適時増設していくことも可能と思います。


 ワーカマシンの接続On/Offについて


 ワーカマシンの接続On/Offは、FileMaker Server 16 の Admin Console ページで簡単に行えます。

 下図は、ワーカマシン 2 および 3 の接続を停止したときの様子です。

WebDirect ワーカマシン 2 および 3 の接続を停止したときの様子

  ワーカマシン 2~5 は接続をOn/Offすることのほかに、ゴミ箱アイコンをクリックすることにより、マスタマシンとの接続設定を消去することもできます。
 これに対し、ワーカマシン 1 はマスタサーバ兼用のため、WebDirect ワーカマシンとしての接続停止はできますが、削除はできないようになっています。



短い時間内で大量のクエリが実行された場合のエラー

 上表で赤字の部分は出庫伝票の作成に失敗した件数を示しています。短い時間に多くのクエリが発行されると、エラーが発生しやすくなります。下図は高負荷状態の時に商品画面にアクセスしたのですが、フィールドに < File Missing > が表示されるエラーが発生しました。



 また、サーバが高負荷状態になると、Admin Console が以下のように無応答状態になることがあります。




 さらにアクセスが集中すると、Web サーバ上側でエラー 503 (Service Temporarily Unavailable) が発生し、接続を受け付けなくなることもあります。
 よって、WebDirect の運用を始める前に、最大接続ユーザ数の見積やピーク時の負荷を想定してのテストはやっておくに越したことはありませんね!

ロードバランス

 記事が長くなってまいりましたので、WebDirect 16 のロードバランスについては、別稿を設けたいと思います。



 アプリケーションを高速に開発できる FileMaker。 WebDirect 16 の登場によって Web上の500 ユーザがブラウザから同時接続できるようになりました。 WebDirect は Webアプリケーションの開発において、新たな選択肢を提供する段階に入ったように思います。



 土屋企画では WebDirect の受託開発及び導入支援コンサルティングを請けたまわっております。 WebDirect の導入を検討されているお客様は、こちらよりご相談いただければと思います。



(亀)

2017-06-02

大容量のSQLテーブルもOK! ― FileMaker 16 を帳票作成ツールとして使う

 FileMaker Server 16 (以下、FMS16)ではPDF出力をサポートするようになりました。FileMaker Pro はもともと帳票/レポートを簡単に作成できるツールして利用されてきましたが、サーバサイドでPDFが作成できるようになり、面倒なWeb帳票の設計・実装が実に簡単、且つ短時間のうちに行えるようになりました。 データベースは FileMaker でも SQL/XMLデータベースでもOKです。 本稿では MySQL の1500万件のテーブルからデータを抽出し、遅延無くPDFを出力する方法の概要を記します。

開発・運用環境

FileMaker Pro (Advanced) 16 ― 帳票作成ツール*1
FileMaker Server 16/IIS/PHP ― サーバ*2

 *1 帳票を作り、簡単なスクリプトを書くだけであればFileMaker Pro 16(¥4万前後)で事足りますが、複雑なスクリプトを書くには開発用(デバッガ付)の FileMaker Pro Advanced (¥7万前後)が必要です。
 *2 FileMaker Server 16 はFM社直売で¥99,000 (税抜)です。

 FileMaker Server 16 (の カスタムWeb公開 =CWP)の理論上の最大接続数は 2,000、検証接続数は500 ですので(詳細はこちら)、¥20万弱で本格的な帳票開発・運用環境が構築できる可能性があります。

本稿の目的と概要図

Webブラウザ上でから 入出庫システム(バックエンドはMySQL)にアクセスし、入庫伝票をPDF形式で作成・表示することを目的とします。 帳票を構成するテーブルに1000万件単位レコードが存在する場合にも、ユーザにストレスを与えない程度の実行速度で、入庫伝票PDFを表示することも目指します。以下が実装手法の概要図となります。



実装手法

入出庫明細テーブルには 約1500万のレコードがあります。 FileMaker で数十万件を超すテーブルからデータを抽出してPDF帳票を遅延無く作成するには、上図の FMS ⇔ MySQL 間の設計がキモとなります。今回は一般的な FileMaker ESS(External SQL Source 機能)を使う手法 と、原始的な ODBC データ取込を使う2つの手法を実装・テストしました。

実装手法1 ―  FileMaker ESS を使用  データ件数が多くなると低速化する

  1. 本手法では ESS を使用し、MySQLのテーブルを FileMaker のファイル内に直接配置します。下図の「_入庫」や「_取引先_入庫」などがそれに相当し、これらはシャドウテーブルとも呼ばれます。
    ESSは FileMaker 内から直接 MySQL のテーブルを読み書きでき便利なのですが、数十万行を超す大きなテーブルを扱う時には速度が低下するなどの問題があります。ESSの問題点については、古い記事になりますがこちらを参考にしてください。

  1. 入庫伝票レイアウトの開発は FileMaker Pro (Advanced) のGUIを利用し、テーブル内のフィールドや罫線、テキストなどのオブジェクトを配置しながら作成すると、慣れた人なら 短時間で完成すると思います。  
FileMaker Pro により作成した入庫伝票イメージ

  1. 次に FileMaker のスクリプトメーカーで、PHP から渡ってきた入庫No による検索、入庫伝票レイアウトの選択、PDF保存などを行うスクリプト(「実装手法概要図」の「特定のスクリプト」)を作成します。
  2. 最後に PHPファイルからそのスクリプトを実行するように指定します。

実装手法2 ― ODBCデータ取込 を使用 データ件数にかかわらず高速

  1. 本手法では独立した FileMaker ファイルを一つ用意し、その中に FileMaker のテーブル(vw入庫伝票、下図参照)を用意します。

    このテーブルに MySQL から必要最低限のデータを取り込み、そのデータを FileMaker レイアウトを使用してPDF形式で出力します。

    注:ESS は使用せず、したがって MySQL のシャドウテーブルも配置しません。
  2. MySQL側に入庫伝票に必要なテーブル(本例では、入出庫明細、取引先、入庫、商品の4テーブル)を結合した入庫伝票用ビューを作成します。

    ビューの作成は必須ではありませんが、ビューが無いとFileMaker内に4つのテーブルを用意し、4回SELECTクエリを発行して用意したテーブルに対応するMySQLのテーブルデータを取り込む必要があります。ビューを使用すれば、テーブル、クエリー、取込とも1つ/1回で済むので、実行速度的にも有利です。特別な事情がなければ、ビューを使用しましょう。

  3. FileMaker を使用して入庫伝票レイアウトの作成します。テーブル構成が異なるので実装手法1とはその作成方法は異なりますが、FM開発者にとっては容易な作業と思います。
  4. 次にPHPから渡ってきた 入庫No を使用し、 ビューに対して SELCTクエリーを発行し、結果を vw入庫伝票テーブルに取り込み、入庫伝票レイアウトを選択して、PDFを保存するスクリプトを作成します。
  5. PHPからこの FileMaker スクリプトを実行して、PDFを作成・表示する部分は実行手法1と同様です。

テスト結果

上記2つの手法による実装をブラウザからテストしてみました。HTTPリクエストからPDFが表示されるまでの時間は以下の通りです(テストは各5回ずつ実行し、その平均値を記載しています)。

実装手法1: 77秒
実装手法2: 1.2秒 

 その差は圧倒的でした。シャドウテーブルを配置するESSは、SQLクエリーの発行を FileMaker がすべてやってくれるので便利な反面、膨大なクエリーを発行するため速度低下を招きます。 その点、 ファイル内にESSシャドウテーブルを配置せず、SQL SELECT文を自身で指定し、その結果を FileMaker テーブルに取り込む ODBCデータ取込は大きなSQLテーブルに対しては圧倒的に有利です。

思ったこと

実装手法2であれば、数千万件のデータを持つSQLデータベースの帳票作成環境として、その使用に耐えそうです。 実装手法1は10万~20万件程度のテーブルであれば利用可能と思われます。

本稿では SQLデータベースを取り上げましたが、旧FileMaker Server の Webシステムを温存しつつ、下図のように FMS16 を併行運用し、FMS 16 は PDF出力用サーバとして使用する方法も考えられます。

PDF出力をしたいが、 FM16へのアップグレードはできない場合、検討の価値はあるかと思います。





(土屋)




2016-11-17

Slim フレームワークの REST による FileMaker データベースへのアクセス

 FileMaker では API for PHP、FX.php、XML、ODBC を介して Webプログラミングを行うのが通常ですが、昨今巷で REST なる言葉を聞くようになりました。 そこで今回は REST を使用した FileMaker DB アクセスにトライしてみました。

 開発環境は以下のとおりです。

Slim フレームワークを使った REST 構成で FileMaker Server にアクセス

 ご覧のように、Microsoft IIS  Web サーバに FileMaker Server 15 と PHP をインストールしたうえで、 Slim フレームワークをインストールしています。


REST についてモヤモヤっとしがちなところ


  REST (REpresentational State Transfer) とは、サーバ上の情報(リソース)に対し、一意の URI を提供するためのアーキテクチャ(仕組み)です。 
 この 一意の URI と、Web クライアントから渡ってきた HTTP メソッドの組み合わせにより、リソースを操作します。

メソッド処理
GET取得。idempotent
POST新規作成。not idempotent
PUT更新。idempotent
DELETE削除。idempotent (限定的)

 表中の idempotent は冪等(べきとう)性を指します。これは、何度操作しても同じ結果が返ってくるという意味です。これはステートレスという、REST の特徴になっています(ステートレスについては後述します)。

 idempotent について例を簡単に示します。

 GET メソッド  --- Amazon でたとえば PlayStation 4 Pro という商品の情報を得るためのGET リクエストは、https://www.amazon.co.jp/dp/B01LRHPUZ4/ です。

 これは固有の URI として一般公開されているため、Web ユーザがこの URI に何度アクセスしても、このリンクが存在するかぎりは同じ商品にたどりつくことを意味します。よって、この処理は idempotent (冪等性がある)となります。

 POST メソッド ---  Amazon の例でたとえると、出品者が Amazon に商品情報を追加したいときの URI は専用のものを使いますが、その URI だけでは、追加された商品(リソース)にたどりつくことができません。
このため、この URI そのものはリソースの一意性を保障できないため、not idempotent (冪等性がない)となります。
 
 PUT メソッド ---  特定のリソースを更新しますので、この URI は idempotent (冪等性がある)となります。

 DELETE メソッド --- 削除処理が完了するまでの間はリソースの URI は有効なため、 idempotent (冪等性がある)ですが、削除が完了するとそのリソース自体が消滅するため、not idempotent (冪等性がない)になります。これが限定的に idempotent とな理由です。


 アクション部分は HTTP メソッドで指定し、URI 各項目を名詞で表現するというルールを実装することによって、URI の一意性がもたらされます。
 また、実際の操作を実行するファイル名や引数名の隠匿性も高くなります。

ステートレスとステートフル

 REST の特徴としてステートレスな通信であることが挙げられます。
 しかし、Web アプリケーションの目的によっては、ステートレスですべての要求がまかなえない、つまり REST だけではシステム設計に無理が出てくることもあります。

 以下に例を示します。

 ニュースサイトでニュースを見るとき、見たいニュースのリンクをクリックすると、ニュースの内容が表示されたら処理は完結します。ユーザが今の時点まで どんなニュースを見てきたかという処理の流れについてはサーバは関知しません。 このような通信はステートレスであるといいます。

 ユーザが条件を指定するというパターンでは、Google Map サービスが良い例となるでしょう。
 住所を入力すれば、その住所の地図が即座に表示されますが、Web サーバはユーザとのやり取りを保持しません。しがたって、この通信もステートレスです。

 それでは、オンラインでショッピングカートに入れた商品を買う場合はどうでしょうか?
 ユーザは購入内容の確認からクレジットカード決済の処理にいたるまでの一連の処理をサーバと対話形式で行っていく必要がありますね。処理が完了するまで、サーバはユーザとのやりとりを保持しますので、この通信はステートフルになります。


 REST に関する参考リンク:

REST [WikiPedia]
CHAPTER 5 Representational State Transfer (REST) [REST を提唱したロイ・フィールディングの博士論文] 英語


Slim フレームワーク を使った REST 環境の構築


 Slim フレームワークは、REST 対応の軽量 PHP フレームワークです。
 HTTP メソッド別の処理のルーティングがあらかじめ想定されているため、比較的少ないコード量でデータベースアクセスルールと応答処理の実装ができます。

 インストール方法は公式サイトをご覧ください。

 Slim フレームワーク 公式サイト[英語]


Microsoft IIS 向け REST 構成のためのルート URL 書き換え


 Apache の .httaccess 書き換え方法は割といろいろなところで見つかりますが、IIS 向けの情報があまりないようですので、まとめてみました。
 
 たとえば、Web アプリケーションのルートディレクトリが inventory のとき、出庫ID=123 の商品を照会するための index.php へのアクセスはこのようになるでしょう。

 http://hostname/inventory/index.php?act=outgoing&id=123

 REST 構成の URI は、スラッシュで文字列を区切った形式となります。
 このため、GET リクエストを発行するユーザに提供する URI は以下のようになります。

 http://hostname/inventory/outgoing/123

  上記の赤色の URI は、本来は http://hostname/inventory/index.php ですが、これを http://www.hostname/inventory/ と書き換えることによって、ユーザに index.php ファイルを通知しないようにするとともに、後続のスラッシュで区切られた文字列をそのまま index.php に通知するように URLを書き換える必要があります。

  http://hostname/inventory/index.php
 ↓
  http://hostname/inventory/


【操作手順】
  1. あらかじめ、ユーザに公開する inventory ディレクトリを wwwroot 配下に作成しておきます。
  2. Windows Server のインターネット インフォメーション サービス(IIS) マネージャを起動します。
  3. 左ペインで、ユーザに公開する inventory までディレクトリを展開し、「URL書き換え」アイコンをダブルクリックします。

    inventory ディレクトリの「URL書き換え」アイコンをダブルクリック

     「URL 書き換え」ペインが表示されますので、右ペインのメニュー項目より「規則の追加...」リンクをクリックし、「受信規則と送信規則」のセクションの中から[ユーザフレンドリ URL]を選択して“OK”ボタンをクリックします。

    ユーザーフレンドリ URL を選択


  4. 「ユーザーフレンドリ URL を有効にする規則の追加」ダイアログが表示されますので、[動的 Web アプリケーションで使用される内部 URL の例を入力してください]のボックスに、index.php への URL をフルで入力します。
    たとえば、下図のように入力します。




    [Web サイト訪問者のブラウザーに表示される、タイプするパブリック URL の例を選択してください]の項目は、ここでは無視してください。
  5. 受信規則の URL 書き換えリストに、前述の規則が追加されます。この規則をダブルクリックします。
    今追加した規則をダブルクリック

    URL 書き換えの詳細ペインが表示されます。
    [パターン(T)]のボックスには、^inventory/index.$ という記述になっていますが、これを ^(.*) という記述に書き換えます。

    受信規則のパターンの書き換え

     つぎに、画面下部の「アクション」のセクションで、URL書き換えの不要な文字列を取り除きます。現在、inventory/index.php という記述になっていますが、これを index.php という記述に変更します。

    アクション URL の書き換え


    ここまで終わったら、右ペインの「適用」リンクをクリックすることによって、修正を反映させます。
    この規則は、inventory ディレクトリの中に、web.config という xml 形式のファイルで保存されます( Apache でいう .htaccess ファイルに相当するファイルです)。
  6. アクセステストしてみましょう。

    ためしに、Hello World! と記述した html ファイルを index.php という名前で保存し、inventory ディレクトリに配置します。

    このファイルに、以下のリンクパターンでアクセスしてみましょう。

    http://hostname/inventory/
    http://hostname/inventory/outgoing/
    http://hostname/inventory/outgoing/123

    このように、各パラメータを渡したときにも、ページが見つからないというエラーが返ってこなければ、URL 書き換えは成功です。


    パラメータ別に所定の処理が動作するようにするには、Slim フレームワーク側でそれぞれのパラメータを受け取るようにコード記述を行います。


Slim フレームワークで FileMaker に接続するためのコード記述例


 ここでは、Slim フレームワークから FileMaker データベースに PDO(ODBC) 接続し、GET 要求されたデータを返すためのコード記述例を簡単に説明します。

 ユーザに公開するための出庫データ取得用 URI の形式は以下を想定します。

  http://hostname/inventory/outgoing/123

 赤で示した部分は、URL 書き換え設定を行った URI です。つまり内部的には http://hostname/inventory/index.php にアクセスすることになります。

 outgoing/123 は パラメータ1/パラメータ2 という並びになりますので、ここではoutgoing(出庫)と123(ID)という、2つのパラメータを取ることになります。

 
【コードの記述】

  ここでは、Slim フレームワーク公式サイトにあるコード記述方法にできるだけ沿った形でコード例をご紹介します。

  1. 接続情報の事前設定をします。

     以下は、ローカルホストの FileMaker Server 15 で公開中のデータベースファイルへの接続情報となります。
     将来的にこの接続設定を複数のファイルで使いまわしたい場合は、以下の部分を外部ファイル化( config.php など)しておいて、実装時にインクルードするとよいでしょう。

    <?php

        $config['displayErrorDetails'] = true;
        $config['addContentLengthHeader'] = false;
        $config['db']['host']   = "localhost";         //ホスト名
        $config['db']['user']   = "webuser";          //ユーザ名
        $config['db']['pass']   = "password";             //パスワード
        $config['db']['dbname'] = "testdatabase";   //データベース名

    ?>


  2. Slim フレームワークオブジェクトのインスタンスを生成します。


     いよいよ、 Slim REST API の本体となる index.php ファイルを書いていきます。ユーザへのURI を提供するのがこのファイルとなります。

     $app = new \SlimApp(); で $app という名前の Slim オブジェクトのインスタンスが生成されますが、あらかじめ接続情報を読み込ませておく場合は、$app = new \Slim\App( ['settings' => $config] ); のように記述します。

    <?php

        use \Psr\Http\Message\ServerRequestInterface as Request;    //要求インタフェース
        use \Psr\Http\Message\ResponseInterface as Response;       //応答インタフェース

        require_once '../slim/vendor/autoload.php';    //Slim への相対パス
        require_once 'config.php';                            //外部ファイル化された接続情報(任意)

                                                                    //Slim インスタンス生成
        $app = new \Slim\App( ['settings' => $config] );

    ?>

  3. データベース接続の準備をします。

    $app に実装済のデータベース接続情報の取り出しは、getContainer() メソッドで行います。
    そして、コンテナの db 要素に PDO オブジェクトを返すように設定しておきます。

                            //コンテナ取り出し
    $container = $app->getContainer();

                            //コンテナにデータベース接続を定義しておく
    $container['db'] = function ( $c ) {

        $db = $c['settings']['db'];
        $pdobj = new PDO("odbc:Driver={FileMaker ODBC};host=" . $db['host'] . ";Database=" . $db['dbname'],$db['user'], $db['pass']);
        $pdobj->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        $pdobj->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);

        return $pdobj;

    };


  4. GET リクエストを受信したときの動作を記述します。

     GET リクエストを受信した場合に応答する場合は、get メソッドを使います。
     $app->get(); が原形となりますが、GET で受け取る引数と処理の記述は、たとえば以下のような形式となります。

     赤字がユーザから受け取る引数のリスト(スラッシュ区切り)、青字が処理内容です。
     引数のリストの可変部分は中カッコ{}で囲み、中にその識別名を入れておきます。
     以下の場合は、出庫ID を想定した識別名を id とし、{id} のように記述しています。

     ユーザから渡された id を取り出すには、要求オブジェクト $request から getAttribute メソッドを呼び出すことで実現します。
     以下のコードのように書くことで、ユーザから渡された id が $id にセットされます。

    $app->get( '/outgoing/{id}', function ( Request $request, Response $response )   {
                                //パラメータ取り出し
            $id = $request->getAttribute( "id" );
        }

    );

    $app->run();

    最後の $app->run(); でユーザからのリクエストを受け付けます。

    上記は GET 要求に対する処理を無名関数の中で行うように記述していますが、別途名前つきの関数を作って呼び出すようにしてもかまいません。
  5.  データベースに接続し、クエリを発行します。

     データベースの接続は、$this->db; で行います。これにより、3. のデータベース接続が実行されるとともに、PDO オブジェクトが返ってきますので、それを使ってデータベース操作を行います。

     たとえば、前述の get メソッドの部分をまとめて書くと、以下のようになります。
    最後に結果を return することで呼び出し元に json フォーマットのデータを返しています。

    $app->get( '/outgoing/{id:[0-9]+}', function ( Request $request, Response $response ) {

                            //パラメータ取り出し
        $id = $request->getAttribute( "id" );
           
        try {

                            //$this->db の形で接続確立し、$pdo オブジェクトを生成
                $pdo = $this->db;

                $sql = 'SELECT * FROM "出庫" WHERE "出庫ID"='.( int )$id;
                $stmt = $pdo->prepare( mb_convert_encoding( $sql, "shift-jis" ) );
                $stmt->execute();

                                //対象レコードカウント
                $recordCount = $stmt->rowCount();
               
                if( $recordCount == 0 ){

                            //レコードなし
                    $result = 401;

                }else{
           
                            //レコード取り出し
                    $data = $stmt->fetchAll();
               
                    if( isset( $data ) ){

                        mb_convert_variables( 'UTF-8','shift-jis',$data );

                        $result =  json_encode( $data );

               
                    }else{

                            //レコードなし
                        $result = 401;
                   
                    }
                }

                $pdo = null;
           
            } catch( PDOException $e ) {

                $result = '{"error":{"text":'. $e->getMessage() .'}}';
               
            }

            return $result;
           
        });

    重要:
    • PDO(ODBC) でクエリを発行する際は、文字コードは shift-jis 形式で渡さなければエラーが発生します。
    • 戻りデータの文字コード shift-jis になりますので、必要に応じて文字コードを変換してから使用する必要があります。
    • PDO(ODBC) では bindParamやbindValue による引数のバインドがうまくいかない模様です。このため、SQL インジェクション対策として、{id} で受け取る引数を数値に限定するように {id:[0-9]+} と書き換えてあります。

  6. テストしてみましょう。

    Web ブラウザからhttp://hostname/inventory/outgoing/任意の数字 を入力して送信したとき、json 形式の結果がブラウザページに表示されれば成功です。


 応用編として、Web インタフェースを作り、出庫ID指定による一覧呼び出しを行った例が、以下のようになります。 内部的に Slim アクセスへの URI を呼び出しを行い、戻ってきた json データを整形して一覧表示しています。

内部的に Slim URI を呼び出している Web インタフェースの例

 Slim は軽量とはいえ、間にフレームワークを挟めば処理速度は低下します。
 こちらの記事でパフォーマンスについてご紹介しておりますので、併せてご覧いただけると幸いです。
 Slim フレームワークの REST(PDO) および RESTfm を使って CRUD のテストをしてみた


 Slim フレームワーク以外でも FileMaker で使用できるオープンソースの REST 環境がいくつかあるようです。
 

参考リンク:
 
 RESTfm (Goya)
 RESTfmがオープンソースに (Not only FileMaker)
 fmEasyAPI  開発者はサポートやめちゃったみたい...