« Atlassian製品による「No Ticket, No fork!」 | トップページ | アーキテクチャに対応する日本語がない »

2012/12/29

同期・非同期処理に関するアーキテクチャ

同期・非同期処理に関するアーキテクチャで良い記事があったのでメモ。

【元ネタ】
ITシステムで見られるシーケンス データベースコンサルタントのノウハウちょい見せ

ダメな設計は、シーケンスが階段状ではなく、一つのオブジェクトに全ての処理を任せる「責任が肥大化したオブジェクト」がある。
特に初心者が、設計を考えずにいきなりプログラムを書いたり、システムを作ってしまう場合によく見られる。
この設計では、スパゲティコードになりやすく、一つのプログラムが千行を超えて保守しにくかったり、スケールアップや性能要件で壁にぶつかる時が多いだろう。

Webシステムは基本は、上記記事の「三角形」シーケンスに相当する。
メッセージを階段の図のように渡して、処理の結果を受け取るイメージ。
オブジェクト指向の権限移譲では、この設計手法がよく使われる。
MVC2モデルと呼ばれるように、Webシステムはオブジェクト指向ととても相性が良い。

但し、「三角形」シーケンスは同期を取るのに優れているが、リクエストが返ってくるまでに3秒以上かかるような場合では、タイムアウトが頻発したり、性能改善しにくかったりする。
つまり、同期処理の信頼性や性能に問題が出る場合に、「中継方式のシーケンス」のように、非同期処理を混ぜたアーキテクチャ設計で実現したりする場合が多い。

「中継方式のシーケンス」を使う非同期パターンとしては、幾つかのケースがある。
例えば、ユーザに画面から膨大なデータの帳票出力(例えばPDF)をキックして、バックグラウンドで帳票を生成し、後でユーザが帳票を取り出すケース。
あるいは、月末にユーザが締め処理のボタンを押したら、翌朝に勘定元帳、損益計算書、貸借対照表などの帳票が出力されるケース。
あるいは、ユーザが株を注文したら、しばらくした後にその取引が決済されるケース。
あるいは、ユーザがクレジットカード決済した後、オーソリ認証や与信チェックが行われて、カード決済の実行可否を回答するケース、など。

非同期処理は基本はバッチ処理になる場合が多いと思う。
何故なら、大量のデータを一括処理するには、リアルタイム処理よりもバッチ処理で一気に実施した方が信頼性が高まる場合が多いから。

しかし、非同期処理の欠点が上記の記事に書かれている。

(引用開始)
落とし穴1

普段は問題ないものの、ある時、障害になり、DBにリクエストが溜まりすぎて、性能不足(たまったものが掃けるのに時間がかかる)になるケースがあります。

落とし穴2

中継のためにデータを取り出す処理があります。そのDBを検索する際には、「残っているもの全部」という取りだし方が多くなります。テーブルをフルスキャンしてしまうため、一時的にデータが溜まった後は、再編成しないと性能が悪くなることがあります(OracleでいうHWM(ハイウォータマーク)が上がってしまい、スキャンが長くなった状態です)。インデックスで検索するようにしておくか、再編成の手段を用意しておきましょう。

落とし穴3

中継のためにデータを取り出す処理は、定期的にポーリングするプログラムが通常です。数分や数秒といった間隔であれば問題ないかもしれませんが、たまに、「早く処理したいので、数msecが要件です」と言われることがあります。そのような処理では、DBへの問い合わせ回数も多くなり、CPU使用率が高騰しやすくなりますし、性能要件を達成するのも難しいかもしれません。
これイベント処理(インメモリDBやCEP:Complex Event Processingと呼ばれる製品が得意)が最適なケースがあります。
(引用終了)

非同期処理では、大量データを一括処理するために、事前にデータを再編成(DBMSならカタログ化)しておいたり、ポーリングで定期的に実行できるようにインメモリDBやmemcachedのようなキャッシュメモリを使うとか、色々な代替手法を容易しておく必要がある。

また、非同期処理の最大の落とし穴は、障害発生時のロールバック処理だろうと思う。
数十万~数千万件のデータを一括コミットしようとして失敗した時、ロールバックしようとすると、ロールバック処理そのものにも時間がかかって、DBMSがハングアウトしてしまう危険もある。
だから、例えば1千件起きにコミットして、途中で障害が発生したら途中までのコミット結果は保持しておき、復帰する時は途中のコミット結果から実行し直すような仕掛け(とあるシステム開発では、リカバリーコミット、リカバリーロールバックなどと呼んでいた)を作っておく必要がある。
つまり、非同期処理のトランザクションの信頼性を保持するフレームワークを別途実装しておくコストも必要。

アーキテクチャ設計では、機能要件よりも非機能要件の方が重要。
すなわち、信頼性や性能などの非機能要件や制約がアーキテクチャに強固な枠をはめる。

アーキテクチャではトレードオフは避けられない: プログラマの思索に書いたけれども、インフラ構築では、品質特性のシナリオの観点でアーキテクチャ設計すべきだと思う。
その意味では、アーキテクチャ設計はプログラミングとは別の観点が必要。

業務フローで非同期キューが現れる理由: プログラマの思索

非同期処理のアーキテクチャとは: プログラマの思索

この辺りも今後もまとめてみる。

|

« Atlassian製品による「No Ticket, No fork!」 | トップページ | アーキテクチャに対応する日本語がない »

ソフトウェア工学」カテゴリの記事

コメント

コメントを書く



(ウェブ上には掲載しません)


コメントは記事投稿者が公開するまで表示されません。



« Atlassian製品による「No Ticket, No fork!」 | トップページ | アーキテクチャに対応する日本語がない »