日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

ES学习笔记之-ClusterState的学习

發(fā)布時(shí)間:2025/3/15 编程问答 14 豆豆
生活随笔 收集整理的這篇文章主要介紹了 ES学习笔记之-ClusterState的学习 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

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

先回顧一下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個(gè)節(jié)點(diǎn),數(shù)據(jù)所在的索引也有3個(gè)分片,每個(gè)分片一個(gè)副本。即index的設(shè)置如下:

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

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

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

不知存,焉知取。

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

s1: 根據(jù)文檔id定位到數(shù)據(jù)所在分片。由于可以設(shè)為多個(gè)副本,所以一個(gè)分片會(huì)映射到多個(gè)節(jié)點(diǎn)。s2: 根據(jù)分片節(jié)點(diǎn)的映射信息,選擇一個(gè)節(jié)點(diǎn),去獲取數(shù)據(jù)。 這里重點(diǎn)關(guān)注的是節(jié)點(diǎn)的選擇方式,簡而言之,我們需要負(fù)載均衡,不然設(shè)置副本就沒有意義了。

上面兩步都關(guān)聯(lián)著一個(gè)核心的數(shù)據(jù)結(jié)構(gòu)ClusterState, 我們可以使用_cluster/state?pretty來查看這個(gè)數(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"}} ]}} }

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

  • 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中存儲(chǔ)了集群中每個(gè)索引的分片和副本數(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,我們就能定位出文檔所在的分片。 這個(gè)功能在Delete, Index, Get 三類API中都是必須的。 這里我們也能理解為什么ES的索引分片數(shù)量不能修改: 如果修改了,那么hash函數(shù)就沒法正確定位數(shù)據(jù)所在分片。

  • 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存儲(chǔ)著每個(gè)索引的分片信息,通過這個(gè)結(jié)構(gòu),我們能清晰地了解如下的信息:

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

    假如一個(gè)分片有2個(gè)副本,且都分配在不同的節(jié)點(diǎn)上,那么get api一共有三個(gè)數(shù)據(jù)節(jié)點(diǎn)可供選擇, 選擇哪一個(gè)呢?這里暫時(shí)不考慮帶preference參數(shù)。
    為了使每個(gè)節(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);}@Overridepublic int nextSeed() {return seed.getAndIncrement();}@Overridepublic List<ShardRouting> shuffle(List<ShardRouting> shards, int seed) {return CollectionUtils.rotate(shards, seed);}}

    也就是說使用ThreadLocalRandom.current().nextInt()生成隨機(jī)數(shù)作為種子, 然后取的時(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ù)載均衡的目的。

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

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

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

    創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)

    總結(jié)

    以上是生活随笔為你收集整理的ES学习笔记之-ClusterState的学习的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。