答えが一般的な設計パターンにあると思われるため、データベースの詳細なしでこの質問をしています。システム固有のソリューションは必ずしも必要ではありません (私の特定のシステム設定は質問の最後で参照されています)。
ID、URL、および処理フィールドを含む会社のデータベースを取得して、その会社が現在私のクローラーの 1 つによって処理されているかどうかを示します。多くのクローラーを並行して実行します。それぞれが処理する会社を選択し、その会社を処理開始前に設定して、各会社が常に 1 つのクローラーによってのみ処理されるようにする必要があります。
どの企業が処理されているかを追跡するには、システムをどのように構築すればよいですか?
ここでの課題は、データベースで処理されていない会社を検索し、その会社を更新して処理済みとして設定することができないことです。その間に別のクローラーがその会社を選択した可能性があるからです。これは、データを並列処理するときによくある問題のように思えるので、理論上のベスト プラクティスを探しています。
これには MySQL を使用していましたが、プロセッサ間の一貫性を維持するために次のコードを使用しました。しかし、私はシステムを再設計しており、ElasticSearch がメインのデータベースおよび検索サーバーになる予定です。以下の MySQL ソリューションは、常にハックのように感じられ、この並列化の問題に対する適切なソリューションではありませんでした。
public function select_next()
{
// set a temp variable that allows us to retrieve id of the row that is updated during next query
$sql = 'SET @update_id := 0';
$Result = $this->Mysqli->query( $sql );
if( ! $Result )
die( "\n\n " . $this->Mysqli->error . "\n" . $sql );
// selects next company to be crawled, marks as crawling in the db
$sql = "UPDATE companies
SET
crawling = 1,
id = ( SELECT @update_id := id )
WHERE crawling = 0
ORDER BY last_crawled ASC, id ASC
LIMIT 1";
$Result = $this->Mysqli->query( $sql );
if( ! $Result )
die( "\n\n " . $this->Mysqli->error . "\n" . $sql );
// this query returned at least one result and there are companies to be crawled
if( $this->Mysqli->affected_rows > 0 )
{
// gets the id of the row that was just updated in the previous query
$sql = 'SELECT @update_id AS id';
$Result = $this->Mysqli->query( $sql );
if( ! $Result )
die( "\n\n " . $this->Mysqli->error . "\n" . $sql );
// set company id
$this->id = $Result->fetch_object()->id;
}
}