インデックスの量とドキュメントの数が一定の場合、.NET NEST クライアントと ElasticSearch を使用したバルク インデックス作成のパフォーマンスが時間の経過とともに低下することを経験しています。
Ubuntu Server 12.04.1 LTS 64 ビットおよび Sun Java 7 を使用して、m1.large Amazon インスタンスで実行ElasticSearch Version: 0.19.11, JVM: 23.5-b02
しています。このインスタンスでは、Ubuntu のインストールに伴うもの以外は何も実行されていません。
Amazon M1 ラージ インスタンス: http://aws.amazon.com/ec2/instance-types/から
7.5 GiB memory
4 EC2 Compute Units (2 virtual cores with 2 EC2 Compute Units each)
850 GB instance storage
64-bit platform
I/O Performance: High
EBS-Optimized Available: 500 Mbps
API name: m1.large
ES_MAX_MEM は 4g に設定され、ES_MIN_MEM は 2g に設定されます。
毎晩、.NET アプリケーションで NEST を使用して、約 15000 のドキュメントをインデックス化/再インデックス化しています。任意の時点で、<= 15000 ドキュメントのインデックスは 1 つだけです。
サーバーが最初にインストールされたとき、最初の数日間はインデックス作成と検索が高速でしたが、その後、インデックス作成はますます遅くなり始めました。一括インデックス作成では、一度に 100 個のドキュメントがインデックス処理され、しばらくすると、一括操作が完了するまでに最大 15 秒かかります。その後、多くの次の例外が発生し始め、インデックス作成が停止しました。
System.Net.WebException: The request was aborted: The request was canceled.
at System.Net.HttpWebRequest.EndGetResponse(IAsyncResult asyncResult)
at System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar, Func`2 endFunction, Action`1 endAction, Task`1 promise, Boolean requiresSynchronization) :
一括インデックス作成の実装は次のようになります
private ElasticClient GetElasticClient()
{
var setting = new ConnectionSettings(ConfigurationManager.AppSettings["elasticSearchHost"], 9200);
setting.SetDefaultIndex("products");
var elastic = new ElasticClient(setting);
return elastic;
}
private void DisableRefreshInterval()
{
var elasticClient = GetElasticClient();
var s = elasticClient.GetIndexSettings("products");
var settings = s != null && s.Settings != null ? s.Settings : new IndexSettings();
settings["refresh_interval"] = "-1";
var result = elasticClient.UpdateSettings(settings);
if (!result.OK)
_logger.Warn("unable to set refresh_interval to -1, {0}", result.ConnectionStatus == null || result.ConnectionStatus.Error == null ? "" : result.ConnectionStatus.Error.ExceptionMessage);
}
private void EnableRefreshInterval()
{
var elasticClient = GetElasticClient();
var s = elasticClient.GetIndexSettings("products");
var settings = s != null && s.Settings != null ? s.Settings : new IndexSettings();
settings["refresh_interval"] = "1s";
var result = elasticClient.UpdateSettings(settings);
if (!result.OK)
_logger.Warn("unable to set refresh_interval to 1s, {0}", result.ConnectionStatus == null || result.ConnectionStatus.Error == null ? "" : result.ConnectionStatus.Error.ExceptionMessage);
}
public void Index(IEnumerable<Product> products)
{
var enumerable = products as Product[] ?? products.ToArray();
var elasticClient = GetElasticClient();
try
{
DisableRefreshInterval();
_logger.Info("Indexing {0} products", enumerable.Count());
var status = elasticClient.IndexMany(enumerable as IEnumerable<Product>, "products");
if (status.Items != null)
_logger.Info("Done, Indexing {0} products, duration: {1}", status.Items.Count(), status.Took);
if (status.ConnectionStatus.Error != null)
{
_logger.Error(status.ConnectionStatus.Error.OriginalException);
}
}
catch(Exception ex)
{
_logger.Error(ex);
}
finally
{
EnableRefreshInterval();
}
}
Elasticsearch デーモンを再起動しても違いはないように見えますが、インデックスを削除してすべてを再インデックス化すると違いが生じます。しかし、数日後には同じようにインデックス作成が遅いという問題が発生します。
インデックスを削除し、各一括インデックス操作の後に更新間隔を再度有効にした後、最適化を追加しました。これにより、インデックスが劣化しないようにすることができます。
...
...
finally
{
EnableRefreshInterval();
elasticClient.Optimize("products");
}
ここで何かひどく間違ったことをしていますか?