4

インデックスの量とドキュメントの数が一定の場合、.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");
}

ここで何かひどく間違ったことをしていますか?

4

2 に答える 2

6

申し訳ありません-別の非常に長いコメントを書き始めたばかりで、他の誰かに利益をもたらす場合に備えて、すべてを回答に貼り付けたいと思いました...

ES_HEAP_SIZE

ここで最初に気付いたのは、elasticsearch の最大ヒープ値と最小ヒープ値を異なる値に設定したということです。これらは同じである必要があります。構成 / init.d スクリプトには、設定できる EX_HEAP_SIZE が必要です。最小値と最大値が同じ値に設定されるため、これのみを設定してください (最小値と最大値ではありません)。これを行わないと、より多くのメモリが必要になったときに JVM が Java プロセスをブロックします。最近の github での停止に関する次の素晴らしい記事を参照してください (ここに引用があります)。

JVM が最小メモリと最大メモリに同じ値を使用するように、ES_HEAP_SIZE 環境変数を設定します。異なる最小値と最大値を持つように JVM を構成すると、JVM が (最大まで) 追加のメモリーを必要とするたびに、Java プロセスがそれを割り当てるためにブロックされます。これは、古い Java バージョンと組み合わせると、ノードがパブリック検索に開放されたときに、より高い負荷と継続的なメモリ割り当てが導入されたときにノードが示した一時停止を説明しています。Elasticsearch チームは、システム RAM の 50% の設定を推奨しています。

塹壕からのより多くのelasticsearch構成については、この素晴らしい投稿もチェックしてください.

メモリをロックしてスワッピングを停止する

私の調査から、メモリ スワッピングを回避するために、Java プロセスが使用できるメモリの量もロックする必要があることがわかりました。私はこの分野の専門家ではありませんが、これはパフォーマンスも低下させると言われています。Elasticsearch.yml 構成ファイルで bootstrap.mlockall を見つけることができます。

アップグレード

Elasticsearch はまだかなり新しいものです。使用していたバージョン (0.19.11) と現在のバージョン (0.20.4) の間に導入されたバグ修正は非常に重要であるため、かなり頻繁にアップグレードするように計画してください。詳しくはESサイトをご覧ください。あなたは間違いなく正しい方法であるJava 7を使用しています。私はJava 6から始めて、特に一括挿入には十分ではないことにすぐに気付きました。

プラグイン

最後に、同様の問題を経験した人には、ノードと JVM の概要を表示する適切なプラグインをインストールしてください。bigdeskをお勧めします- bigdesk を実行してから、elasticsearch をいくつかの一括挿入でヒットし、奇妙なヒープ メモリ パターン、非常に多数のスレッドなどに注意してください。

誰かがこれが役に立つことを願っています!

乾杯、ジェームズ

于 2013-02-05T11:28:56.790 に答える
2

推測するだけです:

インデックスのパフォーマンスが低下するにつれて、インデックスがディスク上でより多くのスペースを占めることに気づきましたか?

インデックスを再作成するときに古いインデックスや古いドキュメントを置き換えるのではなく、新しいドキュメントを大量に追加して、データ数が大幅に重複している可能性があるドキュメント数を効果的に2倍にしている可能性があります。古くて遅いインデックスを取得し、それをいくつかのビューアにロードしてデバッグする価値があるかもしれません(たとえば、Luke )。予想よりも多くのドキュメントが表示される場合は、代わりに、再構築によって古いインデックスを置き換える新しいインデックスを作成することを検討してください。

デーモンを再起動しても問題は解決しないため、開いているファイルハンドル、実行中のプロセス、接続などを除外できると思いますが、これらの統計を確認し、疑わしい動作が見られるかどうかを判断します。サーバ。

また、オプティマイズに関しては、確かにパフォーマンスが向上する場合がありますが、これは非常にコストのかかる操作です。各増分バルクインデックス操作の後ではなく、完全な再構築が完了した後にのみ最適化を実行することをお勧めします。

于 2012-12-07T10:37:58.637 に答える