Windows Azure上のWindowsをGUIなしにする

多少でも仮想マシンの利用料を下げるために、GUIを削除して軽くしたいと思います。これで仮想マシンのサイズを下げても、使用メモリ量が減っている分、それなりに使えるようになるはずです。

仮想OSのPowershellのリモート接続を有効にする

GUIを持たないWindowsの操作は主にPowerShellから行う事になります。まずはPowerSheelに対してリモート接続出来る状態にします。Azure仮想OSにRemote Desktopで接続して、PowerShellを管理者権限で起動してEnable-PSRemoteingを実行します。これにより必要なサービスの起動やファイアウォールの設定等が自動で行われますので「[A] Yes to All」を選択して継続してください。

PS C:\Users\username> Enable-PSRemoting
WinRM Quick Configuration
Running command "Set-WSManQuickConfig" to enable remote management of this computer by using the Windows Remote
Management (WinRM) service.
 This includes:
    1. Starting or restarting (if already started) the WinRM service
    2. Setting the WinRM service startup type to Automatic
    3. Creating a listener to accept requests on any IP address
    4. Enabling Windows Firewall inbound rule exceptions for WS-Management traffic (for http only).

Do you want to continue?
[Y] Yes  [A] Yes to All  [N] No  [L] No to All  [S] Suspend  [?] Help (default is "Y"):

クライアントへのSSL証明書のインストール

次にPowerShellのリモート接続で使用するためのSSL証明書のダウンロードとインストールを行います。少々変則的ですがhttps://[仮想マシン名].cloudapp.net:5986のURLにGoogle Chromeを使用してアクセスし、画面赤丸の部分をクリックして証明書を表示します。
chrome#1

次に↓画面の赤丸の部分をクリック。
chrome#2

最後に↓画面の赤丸部分をクリックして、後はウィザードに従ってデフォルト設定のままファイルに保存します。
chrome#3

証明書をダウンロードしたら、証明書ファイルを右クリックしてインストールを選択します。
inport#1

インストールはウィザードに従って勧めていきますが、証明書ストアの選択で「信頼されたルート証明機関」に保存するように設定をしてください。それ以外はデフォルトのままで進めます。
inport#3

クライアントから仮想OSにPowerShellで接続する

これでPowerShellでリモート接続する準備が整ったので、PowerShellを起動して次のコマンドを実行します。プロンプトに接続先コンピュータ名が表示され、リモート接続していることが分かります。

PS C:\Users\username> Enter-PSSession -ComputerName computername.cloudapp.net -Credential knarita -UseSSL
[computername.cloudapp.net]: PS C:\Users\username\Documents>

 

仮想OSからGUIを削除する

せっかくなので、このままAzure仮想OSからGUIをアイインストールしてしまいます。次のコマンドを実行してください。

Uninstall-WindowsFeature Server-Gui-Mgmt-Infra –restart
Success Restart Needed Exit Code      Feature Result
------- -------------- ---------      --------------
True    Yes            SuccessRest... {Windows PowerShell ISE, Graphical Managem...
警告: You must restart this server to finish the removal process.

これで再起動するとGUIが無い状態で起動します。

ちなみにGUIを戻すにはPowerShellから次のコマンドを実行すると、いつでも元に戻せます。

Install-WindowsFeature Server-Gui-Mgmt-Infra,Server-Gui-Shell –restart

apt-get upgradeでThe following packages have been kept backが発生

Ubuntu 15.10にてapt-get upgradeを実行したときに、下記のようにThe following packages have been kept backと表示されアップデートが行われない。既存パッケージの依存関係に問題が発生しているのが原因。

$ sudo apt-get upgrade
Reading package lists... Done
Building dependency tree
Reading state information... Done
Calculating upgrade... Done
The following packages have been kept back:
  linux-cloud-tools-virtual linux-generic linux-headers-generic
  linux-headers-virtual linux-image-extra-virtual linux-image-generic
  linux-image-virtual linux-virtual sosreport
0 upgraded, 0 newly installed, 0 to remove and 9 not upgraded.

sudo apt-get dist-upgradeを実行すると依存関係の問題が処理される。longer required: linux-cloud-tools-4.2.0-16と表示されているようにlinux-cloud-toolsのupdateを自動で処理できなかったのが原因。このままYとするとlinux-cloud-tools-4.2.0-22に更新されてインストールが完了する。

$ sudo apt-get dist-upgrade
Reading package lists... Done
Building dependency tree
Reading state information... Done
Calculating upgrade... The following packages were automatically installed and are no longer required:
  linux-cloud-tools-4.2.0-16 linux-cloud-tools-4.2.0-16-generic
Use 'apt-get autoremove' to remove them.
Done
The following NEW packages will be installed:
  libpython3.5-minimal libpython3.5-stdlib linux-cloud-tools-4.2.0-22
  linux-cloud-tools-4.2.0-22-generic linux-headers-4.2.0-22
  linux-headers-4.2.0-22-generic linux-image-4.2.0-22-generic
  linux-image-extra-4.2.0-22-generic python3.5 python3.5-minimal
The following packages will be upgraded:
  linux-cloud-tools-virtual linux-generic linux-headers-generic
  linux-headers-virtual linux-image-extra-virtual linux-image-generic
  linux-image-virtual linux-virtual sosreport
9 upgraded, 10 newly installed, 0 to remove and 0 not upgraded.
Need to get 70.8 MB of archives.
After this operation, 311 MB of additional disk space will be used.
Do you want to continue? [Y/n]

linux-cloud-toolsは不用意に更新すると接続が出来なくなったり、クラウドの管理コンソールから制御できなくなる恐れがあるので、自動更新を取り止めたのかと思われる。

Microsoft Azureの無料枠を超えてしまったので問い合わせてみた

以前にコンテストの参加賞で貰ったMicrosoft Azureの無料枠の範囲で使うつもりでいたのだが請求が発生していたので問い合わせてみた。

Microsoft Azure Machine Learningで作った機械学習結果を使って、数日連続処理をさせておいたところ3万円強の請求が発生してしまっていた。「使用制限オプション」も有効にしていたのだが、高い負荷で使っていたため、制限がかかる前に突き抜けてしまったのかもしれない。

サポートの問い合わせ画面はわかりにくいところにあるのですが、新しいポータルに移動した後、画面右上のサポートをクリックするとサポート画面に行けます。ここからメッセージを書き込み、問い合わせをします。

問い合わせ後、2~3日待つと「対象の請求期間でご利用いただいていたサービスの使用量が表示されず、明確な使用実績が確認出来ない状況であることを確認いたしました。~」とのことで、全額返金して貰えることになりました。問いああわせてみてよかった。

あらためて使ってみて分かる、Azure Machine Learningのコンピューティングフィーの高さ。実際にどの程度の計算リソースが割り当てられているのかは分かりませんが、大量のデータを常時計算させ続けた場合は、普通に8Coreの仮想マシンを借りるくらいの金額がかかるんですね。

Cloud上の仮想マシンの最適化

Cloud上の仮想マシンの最適化の鍵はローカルストレージの活用にあります。

一般的に仮想マシンはディスクIOがボトルネックになりやすいです。動作速度に物理的な制約があるデバイスを複数の仮想マシンで共有する上に、実際に物理的に書き込まれるまでの階層も多いので、ボトルネックになるのは避けられません。

Amazon RDSやSQL AzureもEC2やと同じく仮想マシンを提供している事にはかわりありません。通常提供している仮想マシンに比較して、データベースのようにディスクIOが頻繁に発生する用途に特化して最適化が施されています。

Amazon RDSやSQL Azureを使うことで、通常の仮想マシン上にデータベースを構築した場合よりも高速になるか否かは、場合によるので一概には言えません。

Cloud上の仮想マシンの最適化を試みる場合、仮想マシンに割り当てられる揮発性ストレージの活用が鍵になると思います。揮発性ストレージは仮想ディスクとオンプレミスのストレージと遜色ない速度で動作します。障害時に直近のデータが失われてもかまわないログデータや、通常は読み取り専用にしか使わないデータを揮発性ストレージに配置することで大幅にパフォーマンスが変わってきます。

またローカルストレージを使わないにしても、活用する見込みのないログ出力を抑制するだけでも大きく変わってきます。もしクラウド上の仮想マシンでパフォーマンスを問題としているなら、まずは仮想ディスクへのアクセスを減らせないか検討しましょう。

WebJobsのスケジュール設定を変更する

.Net FrameworkのWebJobsのスケジュール設定はプロジェクトフォルダ内のwebjob-publish-settings.jsonに保存されています。

{
  "$schema": "http://schemastore.org/schemas/json/webjob-publish-settings.json",
  "webJobName": "YourWebJobName",
  "startTime": "2015-10-25T00:00:00+09:00",
  "endTime": "2015-10-26T00:00:00+09:00",
  "jobRecurrenceFrequency": "Minute",
  "interval": 10,
  "runMode": "Continuous"
}

webJobNameはJobの名称、startTime、endTimeは開始時刻と終了時刻、intervalは周期なので説明は不要でしょう。
runModeはTriggered、Scheduled、Continuousの何れかを指定します。Triggeredは外部からの指示で起動するもので自動では起動されません。Scheduledはスケジュール設定に従って自動で起動するもの。Continuousはスケジュール設定に関係なく常に起動するものを示します。
jobRecurrenceFrequencyはSecond、Minute、Hour、Day、Week、Monthの何れかを選択します。

Recovery ServiceでCentOSを復元するとSSHが繋がらない

Microsoft AzureのRecovery ServiceでCentOSを復元したところ、SSHに接続できなくなった。復元後最初の起動時には問題なく接続できるのだが、仮想マシンを再起動するとSSHの認証を通らなくなる。

かなり肝を冷やしたのだが、原因はSSHでパスワード認証を使用していた事と、復元後の再起動時にsshの設定ファイルが初期化されてしまう事にある。sshの設定ファイル(ssh_config)が初期化されることでパスワード認証によるログインが無効にされていた。

次のようなコマンドでRSA公開鍵を使った認証を行うように設定変更して対応した。

$ ssh_keygen -t rsa
$ cd .ssh
$ cat id_rsa.pub >> authorized_keys

もちろんssh_configを編集してPasswordAuthenticationのコメントを解除し、再びパスワードによる認証を有効にしても良いが、今回は再発の可能性を考慮してRSA公開鍵を使った認証に設定を変更した。

Microsoft Azure上のUbuntuにHadoopをインストール

1.仮想ネットワーク(Azure Private Network)の構築

1.1.仮想ネットワークの新規作成

Sparkのノードをインターネットからアクセス可能な場所に設置するわけにもいきませんので、最初に仮想ネットワーク(Azure Private Network)を構築します。

新規→仮想ネットワーク→カスタム作成を選択して、適当に名前を設定します。
vpn1
“ポイントからサイト間VPNの構築”にチェックして次へ。
vpn2
ここは変更なし。vpn4
“ゲートウェイサブネットを追加”をクリックしてデフォルト設定のゲートウェイサブネットを追加して確定。vpn3

1.2.証明書の作成と登録

続いてルート証明書を作成します。Windowsには標準では証明書を作成する機能がないため、オープンソースのツールを使ったり、開発用のツールを使ったりして証明書を作成することになります。ここではVisual Studio 2013に付属する開発ツールを使用してルート証明書を作成します。まずは”C:¥Program Files¥Microsoft Visual Studio 12.0¥Common7¥Tools¥Shortcuts”にある”開発者コマンド プロンプト for VS2013″を開いてコマンドプロンプトを表示します。そして次のコマンドを実行して下さい。”SparkVirtualPrivateNetwork”の所は適当な名称に置換えて下さい。

makecert -sky exchange -r -n "CN=SparkVirtualPrivateNetwork" -pe -a sha256 -len 2048 -ss My "SparkVirtualPrivateNetwork.cer"

“SparkVirtualPrivateNetwork.cer”と言うファイルが出来上がります。これを証明書にアップロードします。
次にクライアント証明書を作成します。次のコマンドを実行します。
“ClientCertificateName”は適当な名称に置換えて下さい。

makecert -n "CN=ClientCertificateName" -pe -sky exchange -m 96 -ss My -in "SparkVirtualPrivateNetwork" -is my -a sha256

登録されている証明書を確認します。コマンドプロンプトから”certmgr.msc”を実行します。最初に”信頼されたルート証明機関”の”証明書”に先ほど作成したSparkVirtualPrivateNetworkが登録されているか、”個人”の”証明書”に”ClientCertificateName”が登録されているか確認します。
もしmakecertを実行した以外の環境から仮想ネットワークに接続する場合は、先ほど作成したSparkVirtualPrivateNetworkとClientCertificateNameを登録する必要があります。makecertを実行した環境で、それぞれの証明書の秘密鍵をエクスポートして、新たな環境にてインポートします。

1.3.VPNクライアントのインストール

仮想ネットワークのダッシュボードからクライアントVPNパッケージをダウンロードしてきてインストールします。インストールするとコントロールの”ネットワークと共有センター”に仮想ネットワークへの接続が追加されるので、接続を実行します。このとき使用する証明書を聞いてくるので、先ほど作成したClientCertificateNameを選択して下さい。

2.Apatch Hadoopのインストール

Apatch Sparkを動作させるには、その前にApatch Hadoopを動作させておく必要があります。
と言うわけでUbuntu 14.10の仮想マシンが起動している所から作業をスタートします。

2.1.スタンドアローンで動作する所まで…

hadoopの動作にはJavaが必要になります。OpenJDKでも問題なく動作するそうなので、標準のOpenJDKをインストールしていきます。

sudo apt update
sudo apt upgrade
sudo apt-get install -y default-jdk

最新版のhadoopをダウンロードしてきて展開します。

wget http://ftp.tsukuba.wide.ad.jp/software/apache/hadoop/common/hadoop-2.6.0/hadoop-2.6.0.tar.gz
tar xvfx hadoop-2.6.0.tar.gz

“/etc/profile”を編集して展開したhadoopへのパスを設定します。

...
export PATH=/<展開したディレクトリ>/hadoop-2.6.0/bin:$PATH
...

“hadoop-2.6.0/etc/hadoop/hadoop-env.sh”を編集してJAVA_HOMEのパスを設定します。

...
# set to the root of your Java installation
export JAVA_HOME=/usr/lib/jvm/default-java
...

この時点でスタンドアロンモードでhadoopが動作します。試しに”hadoop”とコマンドを打ってみて下さい。hadoopコマンドが起動するなら、先の設定へと進んでいきましょう。

2.2.疑似分散(Pseudo-Distributed)モードで動作する所まで…

今度は”ssh localhost”とコマンドを打って下さい。hadoopはノード間の接続にsshを使用します。もし”ssh localhost”で接続できないなら、sshがパスワードなどを入力しなくても繋がるように証明書を作成します。

ssh localhost
ssh-keygen -t dsa -P '' -f ~/.ssh/id_dsa
cat ~/.ssh/id_dsa.pub >> ~/.ssh/authorized_keys

hadoop-2.6.0/etc/hadoop/core-site.xmlを編集します。
“hadoop.tmp.dir”で指定している”/var/opt/hadoop-2.6.0/cash”はhadoopが生成するファイルの保存先となるディレクトリです。デフォルトでは”/tmp”以下に保存されるために、OSを再起動すると全ての設定やHDFSに格納したデータが失われます。



...


        hadoop.tmp.dir
        /var/opt/hadoop-2.6.0/cash
        fs.defaultFS
        hdfs://localhost:9000


hadoop-2.6.0/etc/hadoop/hdfs-site.xmlを編集します。



...


        dfs.replication
        1


次のコマンドを実行して、HDFS(Hadoop Distributed File System)のnamenodeを初期設定します。

hdfs namenode -format

次のコマンドを実行して、hadoopのデーモンを起動します。

hadoop-2.6.0/sbin/start-dfs.sh

MapReduceで使用するユーザーディレクトリを作成します。

hadoop fs -mkdir /user
hadoop fs -mkdir /user/

最後にサンプルプログラムを実行して、hadoopが疑似分散(Pseudo-Distributed)モードで動作する事を確認します。

cd hadoop-2.6.0
hadoop fs -put etc/hadoop input
hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-2.6.0.jar grep input output 'dfs[a-z.]+'
hadoop fs -cat output/*

2.3.YARN(Pseudo-Distributed)モードで動作する所まで…

“etc/hadoop/”フォルダにある”mapred-site.xml.template”を”mapred-site.xml”にコピーして編集します。

cd etc/hadoop/
cp mapred-site.xml.template
mapred-site.xml

mapreduce.framework.nameにはhadoop




          mapreduce.framework.name
          yarn


再び同じようにサンプルプログラムを実行するとyarn上で動作します。

cd hadoop-2.6.0
hadoop fs -put etc/hadoop input
hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-2.6.0.jar grep input output 'dfs[a-z.]+'
hadoop fs -cat output/*

3.雑記

本当はSprkを動作するところまで行きたかったのだけど、思った以上に面倒で挫折。Sparkの機能であるSparkSQLを動作させるにはHiveのインストールが必要で、Hiveをちゃんと動作させるにはMySQLが必要で・・・。CDHやMapR、HDPの有用性を改めて思い知ったのでした。
というわけで、次はCDHをベースにして再スタートしようと思う。でもきっとこの経験は無駄にはならないと思うんだ。CDHを構成する過程で、Hadoopの知識は再び要求されるはずだしね。

Azure上のUbuntuにRemote Desktopで接続する

Microsoft Azure上にインストールしたUbuntuにRemote Desktopで接続する手順を記しておきます。
実は普通のパソコンにインストールしたUbuntuであれば、Remote Desktopで接続できるように設定を変更するのは難しくありません。以下のコマンドを実行するだけです。

sudo apt install ubuntu-desktop
sudo apt install xrdp

ところがMicrosoft Azure上ではこれだけではRemote Desktopで接続することができません。Remote Desktopから接続してログインしても白黒チェックの背景に、×のマウスカーソルが表示された状態・・・素のX-Serverに接続された状態のまま、グラフィカルシェルが起動しません。
これはMicrosoft Azure上の仮想マシンにはビデオアクセラレータボードが提供されていない事が原因です。Ubuntuの標準グラフィカルシェルのUnityは3Dアクセラレータボードが必須となるために、そのままでは上手く機能しないのです。Unityは3Dアクセラレータがない場合には、OpenGLをソフトウェアでエミュレーションして起動するのですが、2Dのアクセラレータすら提供されてませんので起動しません。ではgnomeならどうかというと、フォントのレンダリングエンジンがアクセラレータボードを必要としてしまうために、やはりそのままでは起動しないのです。
これを回避するにはMicrosoft Azure上のUbuntuにxfceやlubuntuといった軽量グラフィカルシェルをインストールする必要があります。ここではUbuntu用の軽量グラフィカルシェルのlubuntuを使って設定したいと思います。

sudo apt install lubuntu-desktop
sudo apt install xrdp

のようにして必要なパッケージをインストールした後、次のコマンドを実行して.xsessionを作成しlubuntuをグラフィカルシェルとして設定します。

echo lxsession -s Lubuntu -e LXDE > ~/.xsession

Microsoft Azureの管理ポータルから仮想マシンを選択して、エンドポイントにRemote Desktopを追加し、通信を許可します。
以上でRemote Desktopによる接続が可能な状態になります。Windows上でRemote Desktopを起動してURLを入力し接続してログインしてみてください。

クラウドのデメリット

クラウドって時と場合によって意味が変わったりしますよね。広い意味では「複数のユーザーやソフトウエアシステムで、複数の機器を共有することにより、可用性(アベイラビリティ)と拡張性(スケーラビリティ)を高めつつ、運用コストを下げる技術。」と言ったところでしょうか。クラウドだって魔法の弾丸ではないのです。クラウドで出来る事、出来ないことをちゃんと認識しているでしょうか?
機器を共有することでコスト削減
CPUやネットワーク帯域等のリソースは常に100%使っているわけではありません。必ず使っていない時間が発生するため、リソースを共有することによってコストを削減することができます。逆にいえばストレージのように長時間占有するようなリソースについては、クラウドを使ってもたいして安くはなりません。
使った分だけ購入することでコスト削減
新たな機器を購入する場合には、償却期間を定めたうえで、将来必要になるであろうスペックの機器を購入します。普通に予想するなら、今よりも将来の方が高い性能が要求されるでしょうから、現時点においてはオーバースペックとなります。
クラウドでは現在使用する分だけを購入することが出来ます。現時点においてオーバースペック分となるコストを負担する事が無くなります。また、処理の集中する平日は処理能力を高め、処理の少ない休日は処理能力を下げてコストを下げると言った使い方も可能です。必要な量だけをきめ細かく購入する事により、その分安く購入することができます。
国内ベンダーには不思議なことに月額固定の料金を提示するところが多いです。一見するとお買得に見えるますが、月額固定ではパブリッククラウドを利用するメリットの一つを捨てている事になります。
可用性向上のためのコストを削減
クラウド側でハードウェアが冗長化され、信頼性が確保されています。そのため信頼性を向上するためにハードウェアを追加購入する必要がありません。正確には冗長化にかかるコストを他のユーザーやシステムと共有しているわけです。その分、コストを削減することができます。
ただし信頼性が向上しているといっても、サーバー用ハードウェアを専用に用意した場合と同程度のものです。また障害時には自動的にマイグレーションが行われますが、この間数分~数十分程度の停止は避けられません。
もしそれ以上の信頼性を望なら、動作させるソフトウェア側での対応が必要です。分散処理に対応するなり、フェイルオーバーに対応するなりしなくてはなりません。
拡張性の向上
クラウド上では性能を向上させたり、サーバーを追加したり、ハードウェアの拡張を容易に行えます。ですが、それによってシステム全体の性能が向上するかはソフトウェア次第です。
たとえCPUの性能を上げたとしても、ソフトウェアが複数のCPUコアを有効に使えなければ性能は向上しません。たとえCPUとメモリを増やしたとしても、仮想サーバーのディスクIO性能は低い事が多く、ディスクIOの多いソフトウェアの性能は向上しません。CPUやメモリを増やしても性能を向上できないなら、台数を増やせばよいのですが、ソフトウェアが分散処理に対応していなければ台数を増やすにも限界があります。
最初から分散処理を念頭においてソフトウェアを選定、開発しないと如何にクラウド上で動いていると言っても、性能向上の限界に直に突き当たってしまいます。
パブリッククラウドを使うことのリスク
パブリッククラウドを使うことの大きなリスクに、事業の継続性について、SaaSやPaaSサービスの提供企業に握られてしまう事があげられます。パブリッククライド事業者がサービス内容の変更や、あるいは撤退を決断したとき、これを止める手段はありません。自社のサービスも撤退するのか、ほぼ設計からやり直すのに近いコストを払って自社のサービスの再構築をおこなうのか、判断を迫られることになります。
たとえばGoogleのトップページから二つほどリンクを辿った所に、Googleが提供しているサービスの一覧があります。最近、この一覧に並んでいるアイコンの数が大きく減っりました。2年ほど前から予告していたとおり、サービスの提供を取りやめたのです。その中にはGoogle Maps API(Flash用)などのSaaSも含まれていました。Googleの例では計画的に行われたサービスの廃止であっため、2年ほどの移行期間が設けられていました。万が一、倒産に伴う事業停止の場合には、突然サービスが止まる可能性もあるのです。
運用の難しさ
専用サーバーを10台運用した場合の複雑さを10としましょう。4台のサーバー上で10台の仮想サーバーを動かした場合の複雑さは10*4で40にもなります。実は同じ10台のサーバーを運用する場合でも、クラウドだとその複雑さは何倍にもなるのです。10台なら複雑さは4倍で済みますが、数百台数千台規模のパブリッククラウドになるとその複雑さは想像を絶します。
こういったシステムの運用には高い技術と経験がもとめられるものです。さてここで問題となるのは、そんな複雑なシステムを問題なく運用できるだけの、高い技術を持った企業がどれだけあるでしょうか?「そんな複雑なもの、運用できるのか?」と言うのは、クラウド黎明期から指摘されていたことなのです。
クラウドは数を沢山まとめればまとめるほど全体のコストを下げる事ができます。もはや専用サーバーや仮想サーバーのレンタル事業では、AmazonやGoogle、Micorosoftの提供するパブリッククラウドと価格競争するのは困難になっているのです。もし価格で互角に渡り合おうとするなら、たとえ技術が追いつかなくとも、同レベルの巨大なクラウドを作らざるえません。最近立て続けに起きたクラウドがらみの大きなトラブルは、ベンダーが背伸びして巨大なクラウドを構築したことに遠因があるように思うのです。
と言う訳で、クラウドを使う上で分かってなければいけない、欠点を上げてみました。クラウドを使うメリットや良い点はメーカーがこぞってアピールしてくれるのですが、欠点についてはまず説明してくれません。出来ないことを知った上で、正しくクラウドと付きあいましょう。

Google App Engineでインデックスを使う

Google App Engineのキーバリューストア(DataStore)の特徴はSQLライクな構文による検索と、インデックスを使える事です。といっても、一般的なDBMSほどの機能を提供してくれるわけではありません。Google App EngineのDataStoreの特徴を踏まえて上手に使いましょう。
インデックスの制限
DataStoreのインデックスはstlのmapと同様の構造になっており、ソートの為に使用するインデックスと検索のために使用するインデックスは共有されているようです。そのために様々な制限が加わります。
制約1
検索条件で不等号を指定した場合には、検索条件と異なる並べ替えの指定をできません。where区で指定したフィールドは、order by区でも指定する必要があります。

×・・・WHERE col1 > 1 ORDER BY col2
○・・・WHERE col1 > 1 ORDER BY col1, col2

制約2
複数の不等号による比較条件を持つクエリーを実行できません。

×・・・WHERE col1 >= 10 AND col2 > 10

制約3
OR演算子がありません。代わりにIN演算子が用意されていなすが、異なるフィールドを指定したOR検索は出来ません。
制約4
ひとつのアプリケーションで作成できるインデックスの数は  個に制限されている。制限3と合わせて、無闇にインデックスを作成すると規模の大きなアプリケーションでは制約に引っかかる可能性があります。
制約5
セッション分離をサポートしません。一般的なDBMSは他のセッションから更新が行われても、他のセッションは新しいセッションを始めるまで影響を受けませんが、DataStoreでは即時に反映されます。
これらの制約を踏まえて如何にして旨く活用していくかが問題になります。
DataStoreを使いこなすには?
施策1 スクリーニングに留める
GQLによる検索はスクリーニングに留めます。例えば特定条件に一致するデータを日付順で取得したい場合には、日付によるソートのみをGQLで行い、条件に一致するか否かはコードで記述します。
施策2 頁番号フィールドを作る
大量のデータをすべて読み出しながら処理を行う場合には、一度に全てのレコードを読み出すことは出来ません。先頭レコードと読み出すレコード数を指定して、数百レコードずつ読み出して処理を行うことになります。この場合、処理中に他のプロセスからレコードの追加、削除が行われると、同じ行を二回処理したり、処理されないレコードが発生する恐れがあります。
これを防ぐために頁番号フィールドを作成して、数百レコード格納する毎に頁番号を繰り上げるようにします。読み出すときには、頁番号を指定することで一度に処理可能なレコード数を読み出します。頁番号を繰り上げながら順次読み出すことで、途中でレコードが追加されても最後まで読み出すことが出来ます。
施策3 検索条件、ソート条件の分離
検索条件やソート条件を別のエンティティに分離します。それぞれのエンティティ毎に検索・ソートを行うことで、全体として目的の結果を得ます。
例えば会員情報を格納したエンティティから年齢18歳以上の人を都道府県毎にソートして取得したい場合を考えてみます。都道府県を格納したエンティティからソートした状態でレコードを読み出します。次に会員情報に対して県名と年齢を検索条件として読み出します。ソートされた県名順にデータを読み出していくので、結果的に件名でソートされた18歳以上の会員一覧を得られます。
このように複数回の検索に分離することで望んだ結果を得ます。
施策4 検索を使わないように設計する
実は王道かもしれません。GQLに頼らなくても望みのデータを取得出来るようにエンティティを設計します。
この話は、別の記事にて。