ES學(xué)習(xí)筆記之-ClusterState的學(xué)習(xí)

前面研究過ES的get api的整體思路,作為編寫ES插件時的借鑒。當(dāng)時的重點(diǎn)在與理解整體流程,主要是shardOperation()的方法內(nèi)部的調(diào)用邏輯,就弱化了shards()方法。實(shí)際上shards()方法在理解ES的結(jié)構(gòu)層面,作用更大一些。我們還是從get api入手來理解shards()。

創(chuàng)新互聯(lián)專注于企業(yè)全網(wǎng)整合營銷推廣、網(wǎng)站重做改版、岢嵐網(wǎng)站定制設(shè)計(jì)、自適應(yīng)品牌網(wǎng)站建設(shè)、H5建站、成都商城網(wǎng)站開發(fā)、集團(tuán)公司官網(wǎng)建設(shè)、外貿(mào)網(wǎng)站制作、高端網(wǎng)站制作、響應(yīng)式網(wǎng)頁設(shè)計(jì)等建站業(yè)務(wù),價(jià)格優(yōu)惠性價(jià)比高,為岢嵐等各大城市提供網(wǎng)站開發(fā)制作服務(wù)。

先回顧一下get api的使用流程:

 添加文檔到ES:
 curl -XPUT 'http://localhost:9200/test1/type1/1' -d '{"name":"hello"}'

 根據(jù)文檔ID讀取數(shù)據(jù):
 curl -XGET 'http://localhost:9200/test1/type1/1' 

使用很簡單。但是如果考慮到分布式,背后的邏輯就不簡單了。 假如ES集群有3個節(jié)點(diǎn),數(shù)據(jù)所在的索引也有3個分片,每個分片一個副本。即index的設(shè)置如下:

{
  "test1" : {
    "settings" : {
      "index" : {
        "number_of_replicas" : "1",
        "number_of_shards" : "3"
      }
    }
  }
}

那么id為1的doc該分發(fā)到那個分片呢? 這個問題需要一篇詳細(xì)的博文解答,這里我們先簡單給一個結(jié)論:

默認(rèn)情況下,ES會按照文檔id計(jì)算一個hash值, 采用的是Murmur3HashFunction,然后根據(jù)這個id跟分片數(shù)取模。實(shí)現(xiàn)代碼是MathUtils.mod(hash, indexMetaData.getNumberOfShards()); 最后的結(jié)果作為文檔所在的分片id,所以ES的分片標(biāo)號是從0開始的。

不知存,焉知取。

再整理一下取數(shù)據(jù)的核心流程:

s1: 根據(jù)文檔id定位到數(shù)據(jù)所在分片。由于可以設(shè)為多個副本,所以一個分片會映射到多個節(jié)點(diǎn)。

s2: 根據(jù)分片節(jié)點(diǎn)的映射信息,選擇一個節(jié)點(diǎn),去獲取數(shù)據(jù)。 這里重點(diǎn)關(guān)注的是節(jié)點(diǎn)的選擇方式,簡而言之,我們需要負(fù)載均衡,不然設(shè)置副本就沒有意義了。

上面兩步都關(guān)聯(lián)著一個核心的數(shù)據(jù)結(jié)構(gòu)ClusterState, 我們可以使用_cluster/state?pretty來查看這個數(shù)據(jù)結(jié)構(gòu):

# http://localhost:9200/_cluster/state?pretty

{
  "cluster_name" : "elasticsearch",
  "version" : 4,
  "state_uuid" : "b6B739p5SbanNLyKxTMHfQ",
  "master_node" : "KnEE25tzRjaXblFJq5jqRA",
  "blocks" : { },
  "nodes" : {
    "KnEE25tzRjaXblFJq5jqRA" : {
      "name" : "Mysterio",
      "transport_address" : "127.0.0.1:9300",
      "attributes" : { }
    }
  },
  "metadata" : {
    "cluster_uuid" : "ZIl7g86YRiGv8Dqz4DCoAQ",
    "templates" : { },
    "indices" : {
      "test1" : {
        "state" : "open",
        "settings" : {
          "index" : {
            "creation_date" : "1553995485603",
            "uuid" : "U7v5t_T7RG6rNU3JlGCCBQ",
            "number_of_replicas" : "1",
            "number_of_shards" : "1",
            "version" : {
              "created" : "2040599"
            }
          }
        },
        "mappings" : { },
        "aliases" : [ ]
      }
    }
  },
  "routing_table" : {
    "indices" : {
      "test1" : {
        "shards" : {
          "0" : [ {
            "state" : "STARTED",
            "primary" : true,
            "node" : "KnEE25tzRjaXblFJq5jqRA",
            "relocating_node" : null,
            "shard" : 0,
            "index" : "test1",
            "version" : 2,
            "allocation_id" : {
              "id" : "lcSHbfWDRyOKOhXAf3HXLA"
            }
          }, {
            "state" : "UNASSIGNED",
            "primary" : false,
            "node" : null,
            "relocating_node" : null,
            "shard" : 0,
            "index" : "test1",
            "version" : 2,
            "unassigned_info" : {
              "reason" : "INDEX_CREATED",
              "at" : "2019-03-31T01:24:45.845Z"
            }
          } ]
        }
      }
    }
  },
  "routing_nodes" : {
    "unassigned" : [ {
      "state" : "UNASSIGNED",
      "primary" : false,
      "node" : null,
      "relocating_node" : null,
      "shard" : 0,
      "index" : "test1",
      "version" : 2,
      "unassigned_info" : {
        "reason" : "INDEX_CREATED",
        "at" : "2019-03-31T01:24:45.845Z"
      }
    } ],
    "nodes" : {
      "KnEE25tzRjaXblFJq5jqRA" : [ {
        "state" : "STARTED",
        "primary" : true,
        "node" : "KnEE25tzRjaXblFJq5jqRA",
        "relocating_node" : null,
        "shard" : 0,
        "index" : "test1",
        "version" : 2,
        "allocation_id" : {
          "id" : "lcSHbfWDRyOKOhXAf3HXLA"
        }
      } ]
    }
  }
}

整個結(jié)構(gòu)比較復(fù)雜,我們慢慢拆解, 一步步逐個擊破。 拆解的思路還是從使用場景入手。

  1. IndexMetaData的學(xué)習(xí)
    metaData的格式如下:
    "metadata" : {
    "cluster_uuid" : "ZIl7g86YRiGv8Dqz4DCoAQ",
    "templates" : { },
    "indices" : {
      "test1" : {
        "state" : "open",
        "settings" : {
          "index" : {
            "creation_date" : "1553995485603",
            "uuid" : "U7v5t_T7RG6rNU3JlGCCBQ",
            "number_of_replicas" : "1",
            "number_of_shards" : "1",
            "version" : {
              "created" : "2040599"
            }
          }
        },
        "mappings" : { },
        "aliases" : [ ]
      }
    }
    }

即metadata中存儲了集群中每個索引的分片和副本數(shù)量, 索引的狀態(tài), 索引的mapping, 索引的別名等。這種結(jié)構(gòu),能提供出來的功能就是根據(jù)索引名稱獲取索引元數(shù)據(jù), 代碼如下:

# OperationRouting.generateShardId()

        IndexMetaData indexMetaData = clusterState.metaData().index(index);
        if (indexMetaData == null) {
            throw new IndexNotFoundException(index);
        }
        final Version createdVersion = indexMetaData.getCreationVersion();
        final HashFunction hashFunction = indexMetaData.getRoutingHashFunction();
        final boolean useType = indexMetaData.getRoutingUseType();

這里我們關(guān)注點(diǎn)就是clusterState.metaData().index(index)這句代碼,它實(shí)現(xiàn)了根據(jù)索引名稱獲取索引元數(shù)據(jù)的功能。 通過元數(shù)據(jù)中的分片數(shù)結(jié)合文檔id,我們就能定位出文檔所在的分片。 這個功能在Delete, Index, Get 三類API中都是必須的。 這里我們也能理解為什么ES的索引分片數(shù)量不能修改: 如果修改了,那么hash函數(shù)就沒法正確定位數(shù)據(jù)所在分片。

  1. IndexRoutingTable的學(xué)習(xí)
"routing_table" : {
    "indices" : {
      "test1" : {
        "shards" : {
          "0" : [ {
            "state" : "STARTED",
            "primary" : true,
            "node" : "KnEE25tzRjaXblFJq5jqRA",
            "relocating_node" : null,
            "shard" : 0,
            "index" : "test1",
            "version" : 2,
            "allocation_id" : {
              "id" : "lcSHbfWDRyOKOhXAf3HXLA"
            }
          }, {
            "state" : "UNASSIGNED",
            "primary" : false,
            "node" : null,
            "relocating_node" : null,
            "shard" : 0,
            "index" : "test1",
            "version" : 2,
            "unassigned_info" : {
              "reason" : "INDEX_CREATED",
              "at" : "2019-03-31T01:24:45.845Z"
            }
          } ]
        }
      }
    }
  }

routing_table存儲著每個索引的分片信息,通過這個結(jié)構(gòu),我們能清晰地了解如下的信息:

1. 索引分片在各個節(jié)點(diǎn)的分布
2. 索引分片是否為主分片

假如一個分片有2個副本,且都分配在不同的節(jié)點(diǎn)上,那么get api一共有三個數(shù)據(jù)節(jié)點(diǎn)可供選擇, 選擇哪一個呢?這里暫時不考慮帶preference參數(shù)。
為了使每個節(jié)點(diǎn)都能公平被選擇到,達(dá)到負(fù)載均衡的目的,這里用到了隨機(jī)數(shù)。參考RotateShuffer

/**
 * Basic {@link ShardShuffler} implementation that uses an {@link AtomicInteger} to generate seeds and uses a rotation to permute shards.
 */
public class RotationShardShuffler extends ShardShuffler {

    private final AtomicInteger seed;

    public RotationShardShuffler(int seed) {
        this.seed = new AtomicInteger(seed);
    }

    @Override
    public int nextSeed() {
        return seed.getAndIncrement();
    }

    @Override
    public List<ShardRouting> shuffle(List<ShardRouting> shards, int seed) {
        return CollectionUtils.rotate(shards, seed);
    }

}

也就是說使用ThreadLocalRandom.current().nextInt()生成隨機(jī)數(shù)作為種子, 然后取的時候依次旋轉(zhuǎn)。
Collections.rotate()的效果可以用如下的代碼演示:

    public static void main(String[] args) {

        List<String> list = Lists.newArrayList("a","b","c");
        int a = ThreadLocalRandom.current().nextInt();
        List<String> l2 = CollectionUtils.rotate(list, a );
        List<String> l3 = CollectionUtils.rotate(list, a+1);
        System.out.println(l2);
        System.out.println(l3);

    }

-----
[b, c, a]
[c, a, b]

比如請求A得到的節(jié)點(diǎn)列表是[b,c,a], 那么請求B得到的節(jié)點(diǎn)列表是[c,a,b]。這樣就達(dá)到了負(fù)載均衡的目的。

  1. DiscoveryNodes的學(xué)習(xí)。
    由于routing_table中存儲的是節(jié)點(diǎn)的id, 那么將請求發(fā)送到目標(biāo)節(jié)點(diǎn)時,還需要知道節(jié)點(diǎn)的ip及端口等配置信息。 這些信息存儲在nodes中。
  "nodes" : {
    "KnEE25tzRjaXblFJq5jqRA" : {
      "name" : "Mysterio",
      "transport_address" : "127.0.0.1:9300",
      "attributes" : { }
    }
  }

通過這個nodes獲取到節(jié)點(diǎn)信息后,就可以發(fā)送請求了,ES所有內(nèi)部節(jié)點(diǎn)的通信都是基于transportService.sendRequest()

總結(jié)一下,本文基于get api 梳理了一下ES的ClusterState中的幾個核心結(jié)構(gòu): metadata,nodes, routing_table。 還有一個routing_nodes這里沒有用到。后面梳理清楚使用場景后再記錄。

網(wǎng)頁標(biāo)題:ES學(xué)習(xí)筆記之-ClusterState的學(xué)習(xí)
網(wǎng)站路徑:http://muchs.cn/article12/gescgc.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供搜索引擎優(yōu)化、品牌網(wǎng)站制作、商城網(wǎng)站移動網(wǎng)站建設(shè)、外貿(mào)網(wǎng)站建設(shè)、網(wǎng)站設(shè)計(jì)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

網(wǎng)站優(yōu)化排名