备战大半年秋招资料分享-Elasticsearch篇

<div> 备战秋招大半年,目前已经拿到offer上岸,将半年来的笔记分享给大家。更多 笔记涵盖&nbsp; MYSQL、Elasticsearch、Kafka、设计模式、JVM、Java语言基础、集合原理、并发技术 。 </div> <div> <strong>需要的同学可以加我vx:uukiinternet 私发给你们哦。</strong> </div> <div> <br /> </div> <div> <strong> <h2> Elasticsearch&nbsp;<a href="https://www.yinxiang.com/everhub/note/6ff5dc67-9b48-4b79-9746-ca7f166c6d9c" target="_blank"><strong>:</strong></a>&nbsp;<a href="https://www.yinxiang.com/everhub/note/621b3dfc-e8a6-44bb-a6ea-5f22270510d2" target="_blank">https://www.yinxiang.com/everhub/note/621b3dfc-e8a6-44bb-a6ea-5f22270510d2</a> </h2> <div> <div> <span>Elasticsearch (</span><span><a href="https://my.oschina.net/vivotech/blog/4780497" target="_blank">https://my.oschina.net/vivotech/blog/4780497</a></span><span>)ES6.8</span> </div> <div> <span><br /> </span> </div> <div> <span>注意:</span><span>discovery.zen.minimum_master_nodes=(master_eligible_nodes)/2+1参数在ES7之后废除</span> </div> <div> <span><br /> </span> </div> <div> <span>1、类型(type)的映射(mapping)包含当前索引类型的所有文档的所有字段,但不是所有文档都必须有的字段。而且新索引的文档拥有一个不存在的字段,ES会自动创建字段加入到映射中,并且自动猜测字段类型。生产环境建议索引数据前确定好Mapping。</span> </div> <div> <span><br /> </span> </div> <div> <span>2、一个分片是一个lucene索引:默认存储着原始文档内容加上一些额外信息,比如词条、字典词频等。如 elasticsearch,doc1、doc2,5:3--&gt;doc1| 2---&gt;doc2。</span> </div> <div> <span><br /> </span> </div> <div> <span>3、副本分片可以在运行时动态添加、删除,而主分片不可以(确定后不可变)。</span> </div> <div> <span><br /> </span> </div> <div> <span>4、对于不需要搜索的字段,可以设置index属性为no,则ES不会对该字段分析,也不会产生词条,从而节省空间,缩短索引时间。</span> </div> <div> <br /> </div> <h2> <span><span style="color:#4F4F4F;">触发选举的时机</span></span> </h2> <ol> <li> <div> <span style="color:#4F4F4F;">集群在正常运行过程中,非Master节点探测到Master离开时(MasterFaultDetection)</span> </div> </li> </ol> <ol> <li> <div> <h2> <span style="color:#4F4F4F;">集群启动,从无主状态到产生新主时</span> </h2> </div> </li> <li> <div> <h2> <span style="color:#4F4F4F;">集群在正常运行过程中,Master探测到节点离开<span>导致master所在集群候选主节点数不够</span></span><span>discovery.zen.minimum_master_nodes</span><span style="color:#4F4F4F;">时(NodesFaultDetection)</span> </h2> </div> </li> </ol> <div> <span style="color:#4F4F4F;">Master选主:</span> </div> <div> <span style="color:#4F4F4F;">在所有候选主节点(master:true)中投票,默认都投给ID最小的节点(选主算法对每个node进行id排序),当投票超过候选节点数/2+1的时候,产生最终的master,其他节点向master发起加入集群请求。</span> </div> <div style="color:#4F4F4F;"> </div> <h3> <span><span style="color:#121212;">Elasticsearch是如何实现Master选举的?</span></span> </h3> <div> <span> Elasticsearch的选主是ZenDiscovery模块负责的,主要包含Ping(节点之间通过这个RPC来发现彼此)和Unicast(单播模块包含一个主机列表以控制哪些节点需要ping通)这两部分;</span> </div> <div> <span> 对所有可以成为master的节点(node.master: true)</span>&nbsp;<span><span style="color:#333333;">选主的时候按照集群节点的参数&lt;stateVersion, id&gt; 排序。stateVersion从大到小排序,以便选出集群元信息较新的节点作为Master,id从小到大排序,避免在stateVersion相同时发生分票无法选出 Master。</span></span> </div> <div> <span> </span><span>如果对某个节点的投票数达到一定的值(</span><span>discovery.zen.minimum_master_nodes=(master_eligible_nodes)/2+1,避免脑裂问题</span><span>)并且该节点自己也选举自己,那这个节点就是master。否则重新选举一直到满足上述条件。</span> </div> <div> <span><span>补充:master节点的职责主要包括集群、节点和索引的管理,不负责文档级别的管理;data节点可以关闭http功能</span></span> </div> <div> <br /> </div> <div style="color:#4F4F4F;"> </div> <h2> <span><span style="color:#4F4F4F;">Master节点的特殊性</span></span> </h2> <div> <span style="color:#4D4D4D;">ES中有一项工作是Master独有的:维护集群状态。集群状态信息,只由Master节点进行维护,并且同步到集群中所有节点,其他节点只负责接收从Master同步过来的集群信息而没有维护的权利。集群状态包括以下信息:</span><span style="color:unset;">集群层面的配置,</span><span style="color:unset;">集群内有哪些节点,</span><span style="color:unset;">各索引的设置,映射,分析器和别名等,</span><span style="color:#4F4F4F;">索引内各分片所在的节点位置</span><span style="color:#4F4F4F;">。Master节点定期将集群状态同步给其他节点。</span> </div> <div> <span style="color:#4F4F4F;">索引过程:</span> </div> <div> <span style="color:#4F4F4F;"><img src="https://uploadfiles.nowcoder.com/images/20190919/56_1568900435177_29C080A5413E925FE3B3CCB4048AB99B" id="10387cf2352c09d5c7ce2509049db2a1" style="height:auto;" /></span> </div> <div> <span><span style="color:#121212;">协调节点默认使用文档ID参与计算(也支持通过routing),以便为路由提供合适的分片。</span></span> </div> <div> <span><span style="color:#121212;"> shard = hash(document_id) % (num_of_primary_shards)</span></span> </div> <div> <span><span style="color:#121212;"> 当分片所在的节点接收到来自协调节点的请求后,会将请求写入到Memory Buffer,然后定时(默认是每隔1秒)写入到Filesystem Cache,这个从Momery Buffer到Filesystem   Cache的过程就叫做refresh;</span><span style="color:#121212;">refresh过程相当于从原始文档由lucence进行分词分析,建立倒排索引,生成Segment这样的结构,refresh到页缓存里,可被检索</span><span style="color:#121212;">。</span></span> </div> <div> <span><span style="color:#121212;"> 当然在某些情况下,存在Momery Buffer和Filesystem Cache的数据可能会丢失,ES是通过commitPoint+translog的机制来保证数据的可靠性的。</span><span style="color:#121212;">其实现机制是接收到请求后,同时也会写入到translog(每5s写到磁盘中,</span><span style="color:#121212;font-weight:bold;">一般update、insert等操作都会触发刷新translog到磁盘操作才会返回200,以保证数据安全</span><span style="color:#121212;">)中,当Filesystem cache中的数据写入到磁盘中时,并更新CommitPoint文件,translog才会清除掉,这个过程叫做flush;发生异常时候通过commitPoint+translog文件恢复</span><span style="color:#121212;">。</span></span> </div> <div> <span><span style="color:#121212;"> 在flush过程中,内存中的缓冲将被清除,内容被写入一个新段,段的fsync将创建一个新的提交点,并将内容刷新到磁盘,旧的translog将被删除并开始一个新的translog。</span></span> </div> <div> <span><span style="color:#121212;"> </span><span style="color:#121212;">flush触发的时机是定时触发(默认30分钟)或者translog变得太大(默认为512M)时</span><span style="color:#121212;">;</span></span> </div> <div> <span><span style="color:#121212;">&nbsp; &nbsp; 主分片处理完写入请求后,将数据同步给副本分片,副本分片写完成之后,返回客户端成功。</span></span> </div> <div> <span><span style="color:#121212;"><span style="font-weight:bold;">新的节点是如何加入ES集群的</span>:</span></span> </div> <div> <span style="color:#121212;">单播:</span><span>&nbsp;</span><span style="color:#333333;">当一个节点加入一个现有集群,或者组建一个新的集群时,请求发送到一台机器。当一个节点联系到单播列表中的成员时(通常是候选主节点列表),它就会得到整个集群所有节点的状态,然后它会联系Master节点,并加入集群。</span> </div> <div> </div> <div> <span style="color:#333333;">1、Segment&nbsp;</span><span><a href="https://xie.infoq.cn/article/6e33bf7b6f0defb3962cf5521" target="_blank">https://xie.infoq.cn/article/6e33bf7b6f0defb3962cf5521</a></span> </div> <div> <span style="color:#333333;">2、ES调优:</span> </div> <div> <span style="color:#333333;">&nbsp; &nbsp; 2.1、在对实时性检索要求不高的背景下,把refresh_interval设置成一个比较大的值(甚至是-1,关闭自动刷新),以获取较好的写入性能。</span> </div> <div> <span style="color:#333333;">&nbsp; &nbsp; 2.2、改成bulk批量写入</span> </div> <div> <span style="color:#333333;">&nbsp; &nbsp; 2.3、对于已知不会变、但会查询的索引,为了提升此类索引的查询性能,可以调用optimize API优化静态索引段合并,使得获得最优的段数量,提升查询性能。场景:比如按日期分割的日志索引</span> </div> <div> <span style="color:#333333;">&nbsp; &nbsp; 2.2、</span>&nbsp;<span style="color:#595B66;">线上集群关闭分片自动均衡. 分片的自动均衡主要目的防止更新造成各个分片数据分布不均匀. 但是如果线上一个节点挂掉后, 很容易触发自动均衡, 一时间集群内部的数据移动占用所有带宽. 建议采用闲时定时均衡策略来保证数据的均匀.</span><span style="color:#333333;">&nbsp; &nbsp;&nbsp;</span> </div> <div> <div style="color:#333333;"> <div> <span># 这一项很重要,如果配置了关闭分片分配,没有关闭自平衡,也会在打开分片分配之后出现集群自平衡</span> </div> <div> <span>PUT /_cluster/settings?pretty</span> </div> <div> <span>{</span> </div> <div> <span>&nbsp;&nbsp;"transient" : {</span> </div> <div> <span>&nbsp;&nbsp;&nbsp;&nbsp;"cluster.routing.rebalance.enable" : "none"</span> </div> <div> <span>&nbsp;&nbsp;}</span> </div> <div> <span>}</span> </div> </div> <div> <br /> </div> </div> <div> <span style="color:#333333;">&nbsp; &nbsp; 2.3、</span> </div> <div> <div style="color:#333333;"> <div> index 属性控制怎样索引字符串。它可以是下面三个值: </div> <div> analyzed </div> <div> 首先分析字符串,然后索引它。换句话说,以全文索引这个域。 </div> <div> not_analyzed </div> <div> &nbsp;&nbsp;索引这个域,所以它能够被搜索,但索引的是精确值。不会对它进行分析。 </div> <div> no </div> <div> 不索引这个域。这个域不会被搜索到。 </div> </div> <div> <span>&nbsp;&nbsp; &nbsp;</span> </div> <div> <span>&nbsp; &nbsp; 2.4、过滤器缓存:增大indics.cache.filter.size:30%&nbsp; 过滤器缓存使用的是堆内存,可以设置缓存失效时间,更好利用缓存。</span> </div> <div> <span>·&nbsp; &nbsp; 2.5、对于较多存在相同查询的时候,可以通过index.cache.query.enable缓存,适用于静态索引,因为数据改变会导致此缓存失效。在分片上缓存整个查询语句以及对应结果。</span> </div> <div> <span>&nbsp; &nbsp; 2.6、避免使用脚本</span> </div> <div> <span>&nbsp; &nbsp; 2.7、Filter&nbsp;替代 Query。Filter不需要计算相关性得分</span> </div> <div> <span>&nbsp; &nbsp; 2.8&nbsp;段合并策略,如果允许的段个数越多,段大小越小,此时索引效率越高,因为默认设置每当索引新增文档时候会执行段合并策略,会对索引性能造成影响。段合并会重构一个更大的段,倒排索引会重建,带来性能影响。</span> </div> <div> <span>&nbsp;&nbsp; &nbsp;</span> </div> </div> <div> <div> <br /> </div> </div> <div> <span style="color:#333333;">3、更新删除、版本号。</span> </div> <div> <span><span style="color:#212529;">段是不可改变的,所以既不能从把文档从旧的段中移除,也不能修改旧的段来进行反映文档的更新。 取而代之的是,</span><span style="color:#212529;">每个提交点会包含一个</span></span><span><span style="color:#212529;">&nbsp;</span><span style="color:#555555;">.del</span><span style="color:#212529;">&nbsp;</span></span><span style="color:#212529;"><span>文件,文件中会列出这些被删除文档的段信息</span>。</span><span style="color:#212529;">当一个文档被 “删除” 时,它实际上只是在</span><span style="color:#212529;">&nbsp;</span><span style="color:#555555;">.del</span><span style="color:#212529;">&nbsp;</span><span style="color:#212529;">文件中被</span><span style="color:#212529;">&nbsp;</span><span style="color:#212529;">标记</span><span style="color:#212529;">&nbsp;</span><span style="color:#212529;">删除。一个被标记删除的文档仍然可以被查询匹配到, 但它会在最终结果被返回前从结果集中移除。</span><span style="color:#212529;">文档更新也是类似的操作方式:</span><span style="color:#212529;">当一个文档被更新时,旧版本文档被标记删除,文档的新版本被索引到一个新的段中。 可能两个版本的文档都会被一个查询匹配到,但被删除的那个旧版本文档在结果集返回前就已经被移除</span><span style="color:#212529;">。</span> </div> <div> <span style="color:#212529;">版本号用于解决并发更新冲突:当写入发现版本号不是原本查询的版本号时,返回更新失败;对于文档被更新也没关系的场景,可以使用retry_on_conflict参数来设置重试次数。</span> </div> <div> <span style="color:#212529;">4、相关性得分:TF/IDF,score=TF*IDF*字段长度&nbsp; &nbsp; TF:在该文档该字段中搜索词出现的次数 ,次数越高,值越高 &nbsp;IDF:所有文档该字段包含搜索词的总次数,次数越多,值越低;&nbsp;字段长度比重:该文档该字段越短,值越高</span> </div> <div> <span style="color:#212529;">5、集群缩扩容</span> </div> <div> <span style="color:#212529;">6、异常恢复</span> </div> <div> </div> <h2> <span><span style="color:#121212;">错误检测</span></span> </h2> <h2> <span><span style="color:#121212;">1. MasterFaultDetection与NodesFaultDetection</span></span> </h2> <div> <span><span style="color:#121212;">这里的错误检测可以理解为类似心跳的机制,有两类错误检测,一类是Master定期检测集群内其他的Node,另一类是集群内其他的Node定期检测当前集群的Master。检查的方法就是定期执行ping请求。</span></span><span><span style="color:#121212;">如果Master检测到某个Node连不上了,会执行removeNode的操作,将节点从cluste_state中移除,并发布新的cluster_state。当各个模块apply新的cluster_state时,就会执行一些恢复操作,比如选择新的primaryShard或者replica,执行数据复制等。</span></span> </div> <div> <span><span><span style="color:#121212;">如果某个Node发现Master连不上了,会清空pending在内存中还未commit的new cluster_state,然后发起rejoin,重新加入集群(如果达到选举条件则触发新master选举)。</span></span></span> </div> <div> </div> <div> </div> <div> <span><span><span style="color:#121212;"><span style="font-weight:bold;">ES内存结构</span>:</span></span></span><span><a href="https://blog.csdn.net/laoyang360/article/details/79998974" target="_blank">https://blog.csdn.net/laoyang360/article/details/79998974</a></span> </div> <div> <span style="font-weight:bold;">缓存详解</span><span>:</span><a href="https://www.easyice.cn/archives/367" target="_blank">https://www.easyice.cn/archives/367</a> </div> <div> <span>Shard Request Cache:直接在每个Shard缓存查询语句,Key为查询语句,Value为查询结果;当查询语句稍微有变化的时候/refresh操作导致Shard上数据发生改变,缓存失效,清除;</span> </div> <div> <span>Filter Cache(</span>&nbsp;<span style="color:#424242;">index.queries.cache.enabled</span><span>):在每个Segment里缓存filter字句对应的查询结果,如下图。通过为每个查询子句创建一个位集合bitset,多个查询子句的bitset取交集得到查询结果。</span> </div> <div> <img src="https://uploadfiles.nowcoder.com/images/20190919/56_1568900435177_29C080A5413E925FE3B3CCB4048AB99B" id="7c46e4311a9826cc87a95675468eca62" style="height:auto;" /> </div> <div> </div> <div> <br /> </div> <table style="margin:4.8vw 0&quot;height:auto;color:#000000;background-color:#FFFFFF;"> <tbody> <tr> <td> <div> <span style="color:#424242;">缓存类型</span> </div> </td> <td> <div> <span style="color:#424242;">查询对象</span> </div> </td> <td> <div> <span style="color:#424242;">失效</span> </div> </td> <td> <div> <span style="color:#424242;">访问频率</span> </div> </td> <td> <div> <span style="color:#424242;">缓存 Key</span> </div> </td> <td> <div> <span style="color:#424242;">缓存 Value</span> </div> </td> </tr> <tr> <td> <div> <span style="color:#424242;">&nbsp;Query Cache</span> </div> </td> <td> <div> <span style="color:#424242;">分段</span> </div> </td> <td> <div> <span style="color:#424242;">merge</span> </div> </td> <td> <div> <span style="color:#424242;">与频率有关</span> </div> </td> <td> <div> <span style="color:#424242;">filter 子查询</span> </div> </td> <td> <div> <span style="color:#424242;">FixedBitSet</span> </div> </td> </tr> <tr> <td> <div> <span style="color:#424242;">Request Cache</span> </div> </td> <td> <div> <span style="color:#424242;">分片</span> </div> </td> <td> <div> <span style="color:#424242;">refresh</span> </div> </td> <td> <div> <span style="color:#424242;">与频率无关</span> </div> </td> <td> <div> <span style="color:#424242;">整个客户端请求</span> </div> </td> <td> <div> <span style="color:#424242;">查询结果序列化</span> </div> </td> </tr> </tbody> </table> <div> <br /> </div> <div> <span>JVM&nbsp;调优:</span> </div> <div style="color:#333333;"> <div> 1. 确保堆内存最小值( Xms )与最大值( Xmx )的大小是相同的,防止程序在运行时改变堆内存大小, 这是一个很耗系统资源的过程。 </div> <div> 2.&nbsp;内存不要超过32G,否则指针压缩技术失效,指针需要占用更多空间 </div> <div> 3.&nbsp;:-XX:+AlwaysPreTouch 减少新生代晋升到老年代时停顿。JAVA进程启动的时候,虽然我们可以为JVM指定合适的内存大小,但是这些内存操作系统并没有真正的分配给JVM,而是等JVM访问这些内存的时候,才真正分配,这样会造成以下问题。 </div> <div> GC的时候,新生代的对象要晋升到老年代的时候,需要内存,这个时候操作系统才真正分配内存,这样就会加大young gc的停顿时间; </div> <div> 可能存在内存碎片的问题。 </div> <div> 启动时就把参数里说好了的内存全部舔一遍,可能令得启动时慢上一点,但后面访问时会更流畅,比如页面会连续分配,比如不会在晋升新生代到老生代时才去访问页面使得GC停顿时间加长 </div> <div> 4.&nbsp;-XX:CMSInitiatingOccupancyFraction 设置成75%。主要是因为CMS是并发收集,垃圾回收线程和用户线程同时运行,用户线程运行时可能继续无用的垃圾对象,如果到90%再去回收就太晚了。老年代使用到75%就回收可减少OOM异常发生的概率。 </div> </div> <div> <br /> </div> <div> <span>备份与恢复:</span> </div> <div> <span>1、snapshot API可以快照整个集群索引(或者指定索引),快照过程不会阻塞进程,多次调用snapshot会增量快照集群数据,可以通过restore API进行数据恢复(也可以指定恢复索引)。</span> </div> <div> <span>2、别名和reindex可以实现零停机迁移数据</span> </div> <div> <span><br /> </span> </div> <div> <span style="color:#50A14F;">1</span><span style="color:#383A42;">) “我应该有多少个分片?”</span> </div> <div> <span style="color:#383A42;">答:每个节点的分片数量保持在低于每</span><span style="color:#986801;">1</span><span style="color:#383A42;">GB堆内存对应集群的分片在</span><span style="color:#986801;">20</span><span style="color:#383A42;">-</span><span style="color:#986801;">25</span><span style="color:#383A42;">之间。</span> </div> <div> <span style="color:#986801;">2</span><span style="color:#383A42;">) “我的分片应该有多大?”</span> </div> <div> <span style="color:#383A42;">答:分片大小为</span><span style="color:#986801;">50</span><span style="color:#383A42;">GB通常被界定为适用于各种用例的限制。</span> </div> <div> <span style="color:#383A42;"><br /> </span> </div> <div> <span style="color:#383A42;"><img src="https://uploadfiles.nowcoder.com/images/20210925/95730001_1632547083427/106D7627B56F6EAD459680CC0D40B38C" alt="" /><br /> </span> </div> <br /> </div> </strong> </div>#互联网求职#
全部评论
国阳内部推荐,北京落户
点赞 回复
分享
发布于 2021-10-09 11:22
如果加v没通过的小伙伴可能是忘记看了,请求过期了,可以再起发一下请求哦!
点赞 回复
分享
发布于 2021-11-25 10:55
联想
校招火热招聘中
官网直投

相关推荐

2 13 评论
分享
牛客网
牛客企业服务