テスターですが何か?

ホビープログラマ略してHPです

クラウド環境で処理効率のいいプログラムを実行するということ

leave a comment »

2011年5月ころから、1年近く個人的にWindows Azureを使ってきました。趣味プログラマ的な観点ですが、気付いたことを書きたいと思います。
自分が使っていたのはクラウドサービスのWebロール+TableStorageが中心で、作成したWebアプリをアップしていました。ローカルでデバッグした後にデプロイして思うことはいつも

遅い

です。何せXSインスタンスを使っていたので、スペックがあまりよくないんですよ。もちろん自分のプログラムが悪いこともあるんですが、ローカルに比べてハードウェアスペックに差がありすぎるので、明らかに遅いと感じてしまいます。ちなみにローカルとXSインスタンスの簡単なハードウェアスペックを記載しておきます。

ローカル
CPU: Core i5-520M 2.40GHz (2コア×2スレッド)
Memory: 8GB
SSD 128GB

Azure XSインスタンス
CPU: 1.0GHz(コア共有)
Memory: 768MB
ストレージ 20GB(I/Oパフォーマンス低)

ちょっと重めの処理をローカルで実行してそれなりのスピードがでて「何とかなるかな」と思ってデプロイすると、レスポンスが返ってくるまでに秒単位の時間がかかったりします。とくに、LinqでTableStorageにアクセスするときに遅延評価のことをすっかり忘れていて、ループの中で何度もTableStorageにアクセスしてしまうと遅くてイライラします。なので、Azureにアップするアプリは自分なりに効率性を考えてプログラミングをしていました。この時代にXSインスタンスのようなハードウェアスペックのサーバーで動作するプログラムを書くというのはいい経験になりました。とくに意識したのは以下の2点です。

Linqの実行タイミング
Linqは遅延実行されます、メソッドの行を通ったタイミングではなくIEnumerable<T>オブジェクト以外の結果が必要になった時に実行されます。
たとえば、以下のようなデータベースやストレージにアクセスするコードを書いたとします。
var hogeList = Db.HogeTable.Where(x => x.Code == code);

foreach(var h in hogeList)
{
    Console.WriteLine(h.Name);
}

ぱっと見、1回のアクセスを行っているように見えますが、ループの回数分アクセスが行われます。メモリ内のコレクションに対するアクセスであればそれほどパフォーマンスに差が出ませんが、外部ストレージ(SQL Azure/Table Storage)へのアクセスの場合一気にパフォーマンスが劣化します。自分が一番ハマったのもこのパターンです。アクセスを1回に抑えるためには、Whereメソッドの後にToListやToArrayなどで、データの型を確定させる必要があります。

Linqの細かいことはこちらの@ITの記事を参考にしてください。
LINQの仕組み&遅延評価の正しい基礎知識
http://www.atmarkit.co.jp/fdotnet/chushin/greatblogentry_06/greatblogentry_06_01.html

外部ストレージへのアクセスタイミング
1つめと関連する内容ですが、1回のアクセスで大量の件数のデータを取得する方が速いのか、1件のデータを複数回のアクセスで取得する方が速いのかです。具体的には
・1回のアクセスで多めにデータを取得し、ループではメモリにのみアクセスする
・ループの中で都度データを1づつ取得して処理を行う
のどちらが速いかということです。これはケースバイケースで、しかも実機でしか確認できないので、少し書き換えて何度もデプロイして確認していました。ローカルのSQLServerやストレージエミュレーターでは何度もアクセスした方が速いのに、実機ではネットワークアクセスが伴うので、1回のアクセスで多めのデータを取得したほうが速いことが多かったです。

あと、.NET4から導入されたParallelを使って並列処理を行うと大幅にパフォーマンスを改善できることがありました。特に、単純ループでデータを登録する処理は1ケタ速くなります。1コアのCPUでも並列処理は効果がありました。今見るといい加減なデータの取り方ですが、昨年TableStorageに並列アクセスして高速化に挑戦したブログを書いています。

Azure TableStorageの高速化(2) -処理の並列化-
https://david9142.wordpress.com/2011/10/26/azure-tablestorage%E3%81%AE%E9%AB%98%E9%80%9F%E5%8C%962-%E5%87%A6%E7%90%86%E3%81%AE%E4%B8%A6%E5%88%97%E5%8C%96/

AzureTableStorageの高速化(3) -打倒SQLAzure!!!-
https://david9142.wordpress.com/2011/10/26/azuretablestorage%E3%81%AE%E9%AB%98%E9%80%9F%E5%8C%963-%E6%89%93%E5%80%92sqlazure%EF%BC%81%EF%BC%81%EF%BC%81/

最新のハードウェアでは些細な、ほとんど気づかないパフォーマンス差であっても、低速なハードウェア環境では大きな差になることを身に染みて感じましたし、パフォーマンスを改善するのはなかなか楽しいものです。

最後にプログラムのパフォーマンスとクラウドの関係について考えてみます。オンプレミス環境ではリソース不足を防ぐために余裕をもってハードウェアスペックを調達することが多いです、想定される負荷に耐えられるスペックの1.3~1.5倍とか。そしてハードウェア調達後にプログラムを改修してパフォーマンスを改善して必要なサーバー台数が少なくなると、運がよければ感謝されるかもしれません。ただ、見えないところで

「なんで最初から速いプログラムにしなかったの?」

「誰がこんな余分なスペックを見積もったんだ!」

と揉めることになるかもしれません。そして誰かが責任を取ることになることになるかもしれません。ハードウェア購入費用は返ってきませんから。運用・サポート費用がそれほど変わることも稀ですし。パフォーマンスが悪くてハードウェアを追加購入して増強した後に、プログラムを改修してパフォーマンスが改善した場合はもう目も当てられません、パフォーマンスがよくなったこと自体はいいことなのですが、大惨事です。誰がハードウェア増強の判断をしたのか、もとのプログラムを作ったのは誰なのか、と犠牲者が増えていきます。

そういった経験をすると、別の機会では

「プログラムの改修は必要ない、ハード増強で対応する」

という判断になるのかもしれません。

クラウド環境であれば、必要なサーバー(インスタンス)数が少なくなれば、直接的に運用コストを下げることができます。クラウド環境のメリットにスケールアウトが挙げられることが多いのですが、個人的には一番のメリットはスケールインだと思っています。クラウドのプログラマにとってのメリットは、環境構築・サービスイン後にパフォーマンスを改善してもみんなが幸せになれることでしょう。サービスイン時点で完璧なプログラムを作るのって難しいです、あとから改善して幸せになれることが分かれば、改善しようと努力しますよね。今まで余裕を見てハードウェアスペックを見積もって、処理が非効率であってもハードウェアのパワーに頼って目を瞑ってきたプログラムは結構あると思います。購入後にそのハードウェアが不要になる状況は作りたくないので、あえてパフォーマンスの見直しを行わないプログラムも結構あると思います。

今後クラウド上で動作するプログラムが増えると、こういったプログラムを見直すメリットが増えてきます。また、処理効率のいいプログラムを書けるスキルは運用コストに直接響いてくるので、今まで以上に重要視されるかもしれません。

Written by david9142

2012年12月15日 @ 9:48 PM

カテゴリー: 未分類

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中

%d人のブロガーが「いいね」をつけました。