ElasticSearchは、クラスタの状態を更新する方法

ElasticSearchは、クラスタの状態を更新する方法

多くは、最近も、その技術力を起こっていると学習スタイルは、その記事を更新していなかったいくつかの時間のために、更新の頻度は、単に共有より多くの降水量を持つことが少なくなり、希望になります後に推定されている疑わしいです。私は最近、ESクラスタのステータス更新記事についての記事を見た認識を持っている分散型の一貫性の原則の分析(2)elasticsearch -メタ、および「?スレッドプールに提出したRunnableタスクは、どのような順序で実行され、」この質問をしたがって、マスターノード組合せES6.3.2源、ESは、クラスタの状態を更新する方法で分析します。

クラスター状態の分散システムは、一般的にESのキーワードを作成するために、一般的に言えば、メタデータの各種情報を参照し、設定情報のマッピングインデックス、いくつかの断片率組成物は、これらのフラグメントは、どのノードに分散されていますクラスタの状態の形成にこのような情報。ときに、クライアントに新しいインデックスを作成したり、ケーブルを削除するか、スナップショットバックアップ、またはクラスタは、クラスタの状態の変化につながるマスター選挙を実施しています。集計は、次のとおりイベントが発生した後に、クラスタ状態に至ると、クラスタの新しい状態を生じる、変更されている、どのように新しい各ノードまでのアプリケーションの状態、及び一貫性を確保するためであろう。

ESでは、各モジュールは、イベントの数がでクラスタの状態の変化につながる持つorg.elasticsearch.cluster.service.ClusterService#submitStateUpdateTask(java.lang.String, T)クラスタステータス変更更新タスクを提出します。タスクの実行が完了すると、それは新しいクラスタ状態を作成し、各ノード上の新しいクラスタへのアプリケーションの状態によって「第二相は、コミットプロトコル」。ここでは次のようなモジュール更新タスク、に提出されるべきアクションを知ることができます。

  • MetaDataDeleteIndexService#deleteIndices削除インデックス
  • org.elasticsearch.snapshots.SnapshotsService#createSnapshotスナップショットを作成します
  • org.elasticsearch.cluster.metadata.MetaDataIndexTemplateService#putTemplateインデックステンプレートを作成します

したがって、各サービス(例えば:MetaDataIndexTemplateService)はorg.elasticsearch.cluster.service.ClusterServiceインスタンス参照の所持している、のClusterService#submitStateUpdateTask法によって提出タスクのクラスタの状態を更新します。

今、新しいインデックスを作成し、インデックスを削除し、インデックスは、クラスタのスナップショットを作成するためのテンプレートを変更し、これは、ステータスの更新をトリガーします、そして、これらの更新操作が「安全」であることを確認する方法?このようなインデックスとして削除操作は、インデックス操作Bは、スナップショットバックアップ操作A、B、不適切な順序を行うことです、それはエラーになります!たとえば、インデックスが削除されている、それも行う方法のスナップショットですか?そのため、クラスタステータスの更新のこの同時動作の影響を防ぐために、org.elasticsearch.cluster.service.MasterServiceシングルスレッドの実装では、クラスタの状態を更新する作業から提出されました。org.elasticsearch.cluster.service.MasterService.Batcher.UpdateTaskに代表されるUpdateタスクは、それが本質的な特徴を持ったRunnableタスクの優先度です。

//PrioritizedRunnable 实现了Comparable接口,compareTo方法比较任务的优先级
public abstract class PrioritizedRunnable implements Runnable, Comparable<PrioritizedRunnable> {
    
    private final Priority priority;//Runnable任务优先级
    private final long creationDate;
    private final LongSupplier relativeTimeProvider;
    
     @Override
    public int compareTo(PrioritizedRunnable pr) {
        return priority.compareTo(pr.priority);
    }
}

シングルスレッドの実装は、それがorg.elasticsearch.common.util.concurrent.PrioritizedEsThreadPoolExecutorスレッドプールすることによって達成されます。ルックはorg.elasticsearch.common.util.concurrent.EsExecutors#newSinglePrioritizingスレッドプールを作成します。

public static PrioritizedEsThreadPoolExecutor newSinglePrioritizing(String name, ThreadFactory threadFactory, ThreadContext contextHolder, ScheduledExecutorService timer) {
    //core pool size == max pool size ==1,说明该线程池里面只有一个工作线程
        return new PrioritizedEsThreadPoolExecutor(name, 1, 1, 0L, TimeUnit.MILLISECONDS, threadFactory, contextHolder, timer);
    }

そして、タスクキュースレッドプールの使用である:PriorityBlockingQueueである(底部層が配列され、データ構造は以下の通りである:ヒープヒープ)、タスクのキューイング順序を決定するために、優先度compareToメソッドを比較することによって。

//PrioritizedEsThreadPoolExecutor#PrioritizedEsThreadPoolExecutor
PrioritizedEsThreadPoolExecutor(String name, int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,ThreadFactory threadFactory, ThreadContext contextHolder, ScheduledExecutorService timer) {
        super(name, corePoolSize, maximumPoolSize, keepAliveTime, unit, new PriorityBlockingQueue<>(), threadFactory, contextHolder);
        this.timer = timer;
    }

ここで私が言及したいと思いますシングルスレッドの実行クライアントの操作コマンドを使用して、実行タスクのステータスの更新の唯一つのスレッドを使用して、このアイデアをRedisのと一致しています各RedisのクライアントはRedisのサーバーに操作要求を開始し、Redisのサーバは、各コマンドを実行し、最終的な「ため」にスレッドです。シングルスレッドの実装、同時動作によるデータの矛盾を回避するために、スレッドの同期を必要としません。ロックするすべての同期の必要性の後、しかしロックは、アプリケーションのパフォーマンスに影響を及ぼします。

以下のようなタスクを実行するために、JDKためのスレッドプール:ここで、私は質問を挿入したいと思いますか?Java.util.concurrent.ThreadPoolExecutor#スレッドプールへの第一の方法により提出されたタスクを実行し、それが優先されますか?問題は、多くの場合、ハハ、頼まれました。しかし、本当に理解し、それは容易ではありません。それは、スレッドプールパラメータ、コアプールサイズ、最大プールサイズ、およびタスクキュータスクの到着時間の長さに関連します。実際には、JDKのソースコードのコメントは非常に明確にされています。

        /*
         * Proceed in 3 steps:
         *
         * 1. If fewer than corePoolSize threads are running, try to
         * start a new thread with the given command as its first
         * task.  The call to addWorker atomically checks runState and
         * workerCount, and so prevents false alarms that would add
         * threads when it shouldn't, by returning false.
         *
         * 2. If a task can be successfully queued, then we still need
         * to double-check whether we should have added a thread
         * (because existing ones died since last checking) or that
         * the pool shut down since entry into this method. So we
         * recheck state and if necessary roll back the enqueuing if
         * stopped, or start a new thread if there are none.
         *
         * 3. If we cannot queue task, then we try to add a new
         * thread.  If it fails, we know we are shut down or saturated
         * and so reject the task.
         */
  • スレッドプール内のアクティブなスレッドの数がコアプールサイズよりも小さい場合、スレッドプールへのジョブ投入は、その後、タスクがキューに行くされていない場合には、直接タスクを実行するための新しいスレッドを作成します。
  • プール内のアクティブなスレッドの数がコアプールサイズに達した場合は、タスクを送信し続け、その後、タスクがキューにキューイングされます。
  • タスクキューがいっぱいになると、スレッドプール内のアクティブなスレッドの数が最大プールサイズよりも小さい場合、新たなジョブの投入が、あそこにある場合、それは、新しいスレッドを作成しますわずか提出し、これらのタスクを実行するには、この時間は、タスクができませんキューイング。(注:新しく作成されたスレッドここでは、タスクキューからタスクを取ることはありませんが、ミッションはちょうど直接提出してきて、すでに提出している人は、他の言葉で、彼らが優先することができないことをタスクキューのタスクにキューイング:タスクの実行順序)を実行するために厳密に従って提出されていません

提出後のタスクを、しかし、最初終えて:あなたは見つけるでしょう、以下のコードを確認してください。タスクがキューにキューイング提出するので、その後、スレッドのタスクがキューイングプロセスを排除し、新しく作成された実行さによって直接提出しました。

import com.google.common.util.concurrent.ThreadFactoryBuilder;
import java.util.concurrent.*;

/**
 * @author psj
 * @date 2019/11/14
 */
public class ThreadPoolTest {
    public static void main(String[] args) throws InterruptedException{

        ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat("test-%d").build();
        BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>(4);
        ThreadPoolExecutor executorSevice = new ThreadPoolExecutor(1, 4, 0, TimeUnit.HOURS,
                workQueue, threadFactory, new ThreadPoolExecutor.DiscardPolicy());

        for (int i = 1; i <=8; i++) {
            MyRunnable task = new MyRunnable(i, workQueue);
            executorSevice.execute(task);
            sleepMills(200);
            System.out.println("submit: " + i  + ", queue size:" + workQueue.size() + ", active count:" + executorSevice.getActiveCount());
        }
        Thread.currentThread().join();
    }


    public static class MyRunnable implements Runnable {
        private int sequence;
        private BlockingQueue taskQueue;
        public MyRunnable(int sequence, BlockingQueue taskQueue) {
            this.sequence = sequence;
            this.taskQueue = taskQueue;
        }
        @Override
        public void run() {
            //模拟任务需要1秒钟才能执行完成
            sleepMills(1000);
            System.out.println("task :" + sequence + " finished, current queue size:" + taskQueue.size());
        }
    }

    public static void sleepMills(int mills) {
        try {
            TimeUnit.MILLISECONDS.sleep(mills);
        } catch (InterruptedException e) {

        }
    }
}

OK、完成シーケンス解析スレッドプールは、タスクを実行するには、その後、PrioritizedEsThreadPoolExecutorスレッドプールESのパラメータを見て:この「キューをジャンプ」現象を回避するために、コアプールサイズと最大プールサイズが1に設定されています。各モジュールのクラスタのステータスは、最終的な構成UpdateTaskオブジェクトインスタンスの更新org.elasticsearch.cluster.service.MasterService#submitStateUpdateTasksメソッドをトリガし、タスクをサブミットsubmitTasks法によって行わ。クラスタのステータス更新タスクはバッチ実行中に提出することができ、具体的に実現org.elasticsearch.cluster.service.TaskBatcherそれを見るために:という追加の注意。

        try {
            List<Batcher.UpdateTask> safeTasks = tasks.entrySet().stream()
                .map(e -> taskBatcher.new UpdateTask(config.priority(), source, e.getKey(), safe(e.getValue()), executor))
                .collect(Collectors.toList());
            taskBatcher.submitTasks(safeTasks, config.timeout());
        } catch (EsRejectedExecutionException e) {
            // ignore cases where we are shutting down..., there is really nothing interesting
            // to be done here...
            if (!lifecycle.stoppedOrClosed()) {
                throw e;
            }
        }

最後に、他のモジュールの各々は、いくつかの動作は、クラスタ状態の変更をトリガ実行する場合、ノード#におけるESノード開始start()メソッドは、のClusterServiceを開始すると、org.elasticsearch.cluster.service.ClusterServiceクラスを分析することのClusterServiceを介するものですクラスタステータス更新作業を提出します。ClusterServiceは実際MasterServiceにより及びClusterApplierService、MasterServiceによりをカプセル化されたジョブ送信インターフェイスを提供し、内部には、スレッドプールの更新タスクを維持し、ClusterApplierServiceは、新世代の個々のモジュールアプリケーションクラスタの状態を通知する責任があります。

おすすめ

転載: www.cnblogs.com/hapjin/p/11872863.html