y-matsui::weblog

電子楽器、音楽、コンピュータ、プログラミング、雑感。面倒くさいオヤジの独り言

アルゴリズムらしきもの〜並列処理と処理の順番について悩んだ

今度は並列処理(あるモジュールが複数起動していながら、協調動作する)プログラムについて。
これもメール送信プログラムのキュー生成とメール送信処理の部分で頭を悩ませたところ。(実際は、Cプログラマと一緒に仕様をあれこれ考えただけなんだけど・・・汗)

用件は
・メール送信プログラムは複数起動する
・送信リストは送信順を守って送信されなければいけない
・メール送信は、相手先メールサーバーの負荷を考慮し、一度に送信する最大件数を設定し、待ち時間を持たせる
(1万件を一気に送信するよりも、1000通づつ10回に分割した方が高速に処理できる)
・アドレスに携帯電話が含まれている場合には、携帯アドレスを分散することで、時間当たりに送信するメールを減らす
・ジョブ(配布リスト)には同時に複数起動がある
・ジョブには優先順位があり、優先度の高いジョブが入ったらそれより低いジョブは即時に一時停止、優先度の高いジョブを先に処理しなければならない

そこで、考えたのが、メールキューの生成方法と、SMTPモジュールへの割り当て、そして実行方法。
・メールキューはソートした状態でDB上に展開する
・最大送信件数を読み取り、キューに起動するSMTP番号を付与する
・割り当てた件数の中で携帯・PCアドレスを分散する(ここで順番が崩れるが、最大件数の中で前後するだけなので、100通を一気に送る場合でも処理時間としては数秒の差)
SMTPモジュールは自分の送信分が終わったら、自分の番号が付いた次の送信分を自分で取りに行く
・1つの割り当て件数の中で再送が発生したら、すべての再送処理が完了するまで次に移らない

これでどうだ!と書類上で図を描いて順番を検証してみると、待ち時間と携帯/PC種別による分散が順番を狂わせることが分かった。(追い越しが発生するのである)
さぁ、困った

順番を守らせるためには、
・複数のSMTPの性能をそろえる必要がある。(当たり前か)
・一度に送信する件数を減らせば順番は守られるが、コネクション時間のロスが大きい

順番を守らせるか並列処理による高速化が優先か・・・という難しい問題になってしまっている。(汗)
複数モジュール間で順番を守らせるとしたら、1通1通の送信状況を監視し、ウェイトさせないといけなくなる。
これは、並列処理で高速化するメリットを無効化する方向に作用するはずだ。

「うーーん、とりあえず走らせて、実用に問題があるかを評価してみよう」←これ、非常に現実的な考え方。

確かに、1通2通のレベルで見ると、順番は守られていない・・・・がやはり机上の予想通り、わずか数秒早いか遅いかの違いなのである。しかも、メール送信は接続先のSMTPサーバーやネットワークによっていくらでも遅延する。(メールシステムそのものが非同期で、冗長性の高い仕組みなのだ)

オッケー。順番よりも、送出する速度を重視で考えれば良い。

SMTPサーバーの性能によって、かなり送信順が変わってしまうかと思いきや、異なるスペックのサーバーに対して100通づつ送信するくらいであれば、その差は無視しても良いほどの差であった。実際にやってみて初めて分かることもあるってこと。

優先度の高いジョブが挿入された時の動作も問題ないし、送信タイミングもそれほど変わっていない(順番は厳密に守られているわけではない)、そして大事なのは、並列処理によってほぼリニアに送信性能が確保されること。送信エラーも発生していないし、携帯/PCなどメールキャリアによる分散も仕様通りの動き。

ネットワーク環境や接続先SMTPサーバーの性能によっては、最大送信件数や待ち時間を設定すればOK。
うん。これでいいのだ