単一インスタンスから Solr Cloud クラスターへの移行後にアプリケーションの動作が不安定になっている | KandaSearch Community Support Forum

単一インスタンスから Solr Cloud クラスターへの移行後にアプリケーションの動作が不安定になっている

トピック作成者:ks-solruserml-bot (2025/10/24 18:42 投稿)
6
OpenOpen

(The bot translated the original post https://lists.apache.org/thread/m54bp1d2c40pf7xz5bno8rn6d53w8q52 into Japanese and reposted it under Apache License 2.0. The copyright of posted content is held by the original poster.)

皆さん、こんにちは。

私は最近、長年にわたって単一の SOLR インスタンス上で動作していたアプリケーションとチームを引き継ぎました。
そのアプリケーションを 10 ノード構成のクラスターへ移行しようとしたところ、すぐにいくつかの問題に直面しました。
どうやら、データのレプリケーションがまだ完了していないノードからデータを読み込んでしまっていることが原因のようです。
以下が主な状況です:

  • 10 ノードクラスター構成(各データセンターに 5 インスタンス配置、NRT と TLOG の混在)
  • データは別システムから 1 日を通して大きなバッチ単位で取り込まれる
    (別システムが随時トリガーし、それを受けて当システムが上流システムからデータを更新)
  • この更新処理には数分〜最大 2 時間かかる
  • autoCommit は 1 分ごと、autoSoftCommit は 1 秒ごとに設定
  • また、バックグラウンド処理が多数あり、定期的に実行される(15 分ごと、1 時間ごと、1 日ごとなど)
    • これらはクエリを実行し、データの状態に基づいて様々なアクションを実施
    • 例:新しいレコード → ユーザーに「対応が必要」とメール通知
    • 例:削除されたレコード → ユーザーに「更新があった」とメール通知
    • (実際はもっと複雑)
  • バックグラウンドジョブは、データ更新(上記最初の項目)が進行中かどうかを把握していない
  • 調査の結果、データ更新中または直後にクエリを実行すると不完全な結果を取得している可能性があり、
    その結果、誤った判断(例:実際には削除されていないのに「削除された」と通知、後で「戻った」と再通知)をしているように見える

上記のような状況に基づいて、考慮すべき点やアドバイスをいただけると助かります。

ありがとうございます。

返信投稿者:ks-solruserml-bot (2025/10/24 18:43 投稿)

私ならこうします(あくまで一つの意見として聞いてください)。
この方法は実際に安定して動作しています。


🔧 推奨構成

まず、単一のマスター Solr ノードを用意し、すべてのデータをこのノードでインデックス化します。
他のノードは「レプリカ(以前は“スレーブ”と呼ばれていましたが、今はそう呼びません)」として扱います。
ユーザー検索やレポート用途にはこのレプリカを使用します。

こうすると、そのノードのインデックスが頻繁にアクセスされることでキャッシュが温まり、メモリ内に保持されやすくなります。

それらのノードを nginx のようなプロキシの背後に置いて、どのサーバーを「ホット状態(使用中)」にするかを制御し、必要に応じて他のノードへフェイルオーバーできるようにします。


☁️ SolrCloud について

SolrCloud は理論上は良い仕組みですが、
速度面・信頼性の面ではスタンドアロン構成のほうが上です。

これは私自身の経験に基づくもので、他の人は異なる意見を持つかもしれませんが、
十分なハードウェアを用意すれば、スタンドアロン Solr は非常に高速かつ堅牢です。
(十分なメモリと SSD ストレージがあれば、SolrCloud では到底太刀打ちできません。)


🔁 構成例(旧式の用語で説明)

  1. 1台の Solr マスター(インデクサー)
  2. 1台の “ライブマスター”/“スレーブ”(必要に応じてレプリケーション)
  3. 約10台のスレーブ
    (10台は多すぎるので、まずは3台から試すのが良い)
    これらは 5分おき程度でレプリケーションを実施。

👥 アクセス構成

  • ユーザーnginx プロキシスレーブノード(順番にアクセス)
    • ラウンドロビンは使わず、1台のみを使用。障害時のみ次のノードにフェイルオーバー。
  • レポート処理別のスレーブノード
    • データはユーザー向けと同じなので問題なし。
      ただし、リソース競合を防ぐために分離する。

⚙️ 最適化のポイント

これらの3種類のノード(インデクサー、検索用、レポート用)は、
それぞれの役割に特化して最適化することが重要です。

インデックス作成サーバーは検索サーバーとは用途が異なるため、
同じ設定で動かしてはいけません。


💡 その他の注意点

  • 数テラバイト規模のインデックスでこの構成を実際に運用しています。
  • 各マシンには、インデックス全体の3倍のディスク容量を確保してください。
  • Java ヒープサイズは 32GB 以下に保つこと。
  • サーバー、SSD、メモリは安価です。
  • マスター・スレーブ方式のレプリケーションは最も信頼性が高い構成です。
返信投稿者:ks-solruserml-bot (2025/10/24 18:43 投稿)

この問題の主な原因は、レプリカが同時にコミットを完了する保証がないことにあります。
Solr は 最終的整合性(eventually consistent) のモデルを採用しています。
👉 参考ドキュメント

たとえば、短時間に 3 回リクエストを送ったとします:
[Replica A, Replica B, Replica A]

このとき、Replica B が Replica A より先にコミットを完了していると、
最後のリクエストがまだコミットしていない Replica A に当たった場合、
ドキュメントが消えたように見えることになります。


✅ 対策案

各レコードに いつインデックスされたかを示すフィールドを追加し、
リクエスト時に「ある程度古いデータ」だけを検索対象にする方法があります。

例:

<field name="indexedDate" type="pdate" indexed="true" stored="true"
       default="NOW" />
<!-- このフィールドには値を送らないこと! Solr に自動で埋めさせる -->

そしてクエリ側で次のようにフィルタします:

indexedDate:[NOW-2MINUTES TO *] OR -indexedDate:*

このフィルタは、

  • 以前にインデックスされたデータ(否定条件部分)
  • 2分以上前にインデックスされたデータ(範囲指定部分)

の両方を対象とするため、整合性が取れたデータのみを取得できます。
ただし、もしシステム負荷が高く、レプリカが追いつけていない場合は、
この方法でも整合性を保てず、さらに大きな問題に発展する可能性があります。


⚠️ 補足

あなたの設定している コミット間隔(autoCommit / autoSoftCommit) はかなり短いです。
おそらく今回のような問題を回避するための措置かと思われますが、
もしコミット間隔を緩和する場合は、上記のフィルタ条件も合わせて変更する必要があります。


🖋️
http://www.needhamsoftware.com(仕事)
https://a.co/d/b2sZLD9(私のファンタジー小説)

返信投稿者:ks-solruserml-bot (2025/10/24 18:44 投稿)

実は(送信ボタンを押した直後に気づいたのですが)、
先ほどのようにフィールドを使う方法にも問題があるかもしれません。

というのも、そのフィールド値はサブリクエストがレプリカに届いたタイミングで作成される可能性があり、
その結果、ローカルの時計のずれ(タイムスキュー)の影響を受けてしまうことがあります。

したがって、より安全な方法としては、
TimestampUpdateProcessorFactory
を追加し、最初にリクエストを受け取ったノード側でタイムスタンプを処理させるのが良いと思います。


http://www.needhamsoftware.com(仕事)
https://a.co/d/b2sZLD9(私のファンタジー小説)

返信投稿者:ks-solruserml-bot (2025/10/24 18:45 投稿)

最後にもう一点補足ですが、
NRT(Near Real Time)と TLOG(Transaction Log)を混在させていることが、
データの反映速度にばらつきが出る原因になっている可能性もあります。

そのため、以下のドキュメントにあるように、
推奨されているレプリカタイプの組み合わせに従うのが最善です:
https://solr.apache.org/guide/solr/latest/deployment-guide/solrcloud-shards-indexing.html#combining-replica-types-in-a-cluster


http://www.needhamsoftware.com(仕事)
https://a.co/d/b2sZLD9(私のファンタジー小説)

返信投稿者:ks-solruserml-bot (2025/10/24 18:45 投稿)

とても参考になりました。問題解決のために、いくつかの変更を進めています。

もう一つ質問があります。
エンジニアから「クエリに distrib=true を含めるべきだ」と提案がありました。
しかし、私の理解では、SolrCloud クラスターに対する呼び出しでは
distrib=true は暗黙的に設定されているはずです。

この点について、実際にはどのように動作するのかご意見をお聞かせください。

ありがとうございます。

返信投稿者:ks-solruserml-bot (2025/10/24 18:45 投稿)

あなたの理解は正しいです。Solr はデフォルトでリクエストを分散処理します(クエリについての質問だと仮定しています)。以下は SearchHandler のコードです:

rb.isDistrib = isDistrib(req);

private boolean isDistrib(SolrQueryRequest req) {
  boolean isZkAware = req.getCoreContainer().isZooKeeperAware();
  boolean isDistrib = req.getParams().getBool(DISTRIB, isZkAware);
  if (!isDistrib) {
    // 後方互換性のため、"localhost:8983/solr" のような URL を含む
    // shards パラメータが存在する場合は分散検索とみなす
    final String shards = req.getParams().get(ShardParams.SHARDS);
    isDistrib = ((shards != null) && (shards.indexOf('/') > 0));
  }
  return isDistrib;
}

SolrCloud を使用している場合、isZookeeperAware()true を返すため、
この「true」が DISTRIBdistrib)パラメータのデフォルト値になります。

通常、この値を明示的に設定するのは(false にする場合)、
クラスタ内のシャード間で結果を分散させたくない特別な状況に限られます。
これは多くの場合、内部リクエストやトラブルシューティングなど、
特定のレプリカがどのような応答を返しているかを正確に確認したい場合などです。


http://www.needhamsoftware.com (仕事用)
https://a.co/d/b2sZLD9 (私のファンタジー小説)

トピックへ返信するには、ログインが必要です。

KandaSearch

Copyright © 2006-2025 RONDHUIT Co, Ltd. All Rights Reserved.

投稿の削除

この投稿を削除します。よろしいですか?