8

これについてこれ以上見つけることができなかったことに驚いていますが、残念ながら、まだ答えを見つけることができません。最近 AWS に移行し、シンプルなウェブサイトをより堅牢で信頼性の高いシステムに移行しました。現在私を困惑させているのは、分散システムで cron ジョブを管理することです。その cron ジョブは、環境内のすべてのインスタンスにプッシュされます。

ユースケースは次のとおりです。

バックグラウンド

設定

従来の LAMP スタックを実行しています。おそらく最初の問題ですが、それが私たちが得たものです。

DB テーブル

table1

 - id int(11)
 - start date
 - interval int(11) (number of seconds)

table2

 - id int(11)
 - table1_id int(11)
 - sent datetime

ゴール

目標は、スクリプトが毎日 1 回実行され、次のことを確認することです。

  1. 現在の日付は過ぎていますtable1.start
  2. table1.start< 現在の日付
  3. table1.interval> 0
  4. 今日はちょうど間隔全体です (間隔が 7 日 [秒単位] で 6 日目の場合は失敗します)
  5. 今日であり、以前のチェックと一致するtable2ようなエントリはありません。table2.senttable2.table1_id

これらのすべてのチェックに合格した場合、間隔のある table1 ごとに table2 にエントリを挿入します。これは、table2 のデータに基づいて電子メールを送信することも意味します。

問題

基本的に、前述のブロックで表される 2 つのクエリがあります。問題は、分散システムでは、各インスタンスが同時に (または互いに数ミリ秒以内に) cron を実行することです。table2「トランザクション」の概念がないため、他のインスタンスが最初のクエリを実行する前に挿入する機会が得られない場合、各インスタンスは電子メールを送信します。

ソリューション???

私はこれについてかなりの量の調査を行いましたが、私が思いついた唯一の潜在的な解決策は以下に詳述されています:

Cron インスタンス

cron ジョブの実行を担当する単一の独立したインスタンスをセットアップします。これは (私が見る限り) 確実に機能しますが、それほど高価ではなく、せいぜい 1 日に 1 回しか実行する必要がないジョブにとっては、非常にコストがかかります。

PHP スケジューラ

スケジューラとして機能する PHP スクリプトを定期的に実行するように cron を設定します。これは、限られた時間とお金の中で最も簡単な方法であることが調査で示唆された後、私たちがたどり着いたルートでした. 私が遭遇した問題は、これにより同時実行性の問題が、ジョブの消費からジョブのスケジューリングに移行したように見えるということでした。cron を実行している各インスタンスから複数のジョブが同時にスケジュールされないように、いつジョブをスケジュールしますか?

この方法も非常に「不器用」(私の友人の好きな言葉を借りる)のようで、私も同意せざるを得ません。

取引

私はこれをかなり調査しましたが、並行性は常にデータベース上のアトミック トランザクションで解決されていましたが、私が知る限り、これを LAMP で実現するのは簡単ではありません。しかし、私は間違っているかもしれません。そうであることが証明されれば幸いです。

ついに

誰かが私がこれを理解するのを手伝ってくれるなら、私はそれを大いに感謝します. おそらく私のグーグル スキルはさびてきているのでしょうが、この (おそらく単純な) タスクに苦しんでいるのは私だけだとは思えません。

4

3 に答える 3

4

同様の問題がありました。また、毎分実行する必要があるcronジョブもありましたが、単一のホストでのみ実行されました

このハックで解決しました。これは、Amazon 自動スケーリング ツールを実行して、それが実行されているボックスが、この自動スケーリング グループでインスタンス化された最後のボックスであるかどうかを調べます。これは明らかに、自動スケーリングを使用していること、およびホスト名にインスタンス ID が含まれていることを前提としています。

#!/usr/bin/env ruby

AWS_AUTO_SCALING_HOME='/opt/AutoScaling'
AWS_AUTO_SCALING_URL='https://autoscaling.eu-west-1.amazonaws.com'
MY_GROUP = 'Production'

@cmd_out = `bash -c 'AWS_AUTO_SCALING_HOME=#{ AWS_AUTO_SCALING_HOME }\
  AWS_AUTO_SCALING_URL=#{ AWS_AUTO_SCALING_URL }\
  #{ AWS_AUTO_SCALING_HOME }/bin/as-describe-auto-scaling-instances'`

raise "Output empty, should not happen!" if @cmd_out.empty?
@lines = @cmd_out.split(/\r?\n/)
@last = @lines.select {|l| l.match MY_GROUP }.reverse.
  detect { |l| l =~ /^INSTANCE\s+\S+\s+\S+\s+\S+\s+InService\s+HEALTHY/ }
raise "No suitable host in autoscaling group!" unless @last
@last_host = @last.match(/^INSTANCE\s+(\S+)/)[1]
@hostname = `hostname`
if @hostname.index(@last_host)
  puts "It's me!"
  exit(0)
else
  puts "Someone else will do it!"
  exit(1)
end

/usr/bin/lastonly として保存し、cron ジョブで次のようにします。

lastonly && do_my_stuff

明らかに完璧ではありませんが、私にとってはうまくいき、簡単です!

于 2012-09-27T14:31:12.430 に答える
3

Gearman プロジェクトhttp://www.gearman.orgを見てください。基本的なアーキテクチャは、1 台のマシンがジョブ サーバーであり、他のすべてのマシンがサーバーのクライアントになるというものです。

ジョブ サーバーで crontab をセットアップして、Gearman 経由で接続されているすべてのクライアントに実行するコマンドを送信できます。その後、PHP を使用して cron ジョブを細分化し、必要に応じて Map/Reduce を深く掘り下げることができます。

概念とその仕組みに関する優れたチュートリアルを次に示します: http://www.lornajane.net/posts/2011/Using-Gearman-from-PHP

Gearman のようなものをすぐに使用することにがっかりしないでください。分散 cron システムは複雑になる可能性がありますが、理解すれば問題ありません。

FWIW、Amazon の EC2 の Gearman ワーカー ファーム内で毎分数千の cron スクリプトを処理しています。私たちはそれが大好きです。

于 2012-07-21T00:08:40.630 に答える