一、ElasticSearch介绍
一个主要应用于大数据场景下的近实时的全文搜索引擎。
近实时:从添加一个文档到能搜索到这个文档,有一个微小的延迟(通常是1s)。
二、ES核心 —— 倒排索引
倒排索引是类似于哈希表一样的数据结构,完成由词条到文档id的映射。可以根据搜索词条快速找到该词条对应的所有文档id,然后根据id直接获取文档。
三、基础概念
(一)集群
一个集群就是由一个或多个节点组织在一起,它们共同持有你整个的数据,并一起提供索引和搜索功能。
green | 所有主分片和副分片都可用 |
yellow | 所有主分片可用,但不是所有副分片都可用 |
red | 不是所有的主分片都可用 |
普通集群:master处理写请求,master、slave都可以处理读请求
es集群:master负责集群的分片管理。写请求由主分片处理,读请求主分片、副分片都可以处理。
(二)节点(Node)
集群中的一个服务器,作为集群的一部分,它存储你的数据,参与集群的索引和搜索功能。
(1)node.master
具有主节点选举资格的节点,但不一定是主节点,需要选举后成为主节点。
(2)node.data
这个属性表示节点是否存储数据。
(三)索引(Index)
逻辑概念,包括配置信息mapping和倒排正排数据文件,一个索引的数据文件可能会分布于一台机器,也有可能分布于多台机器。索引的另外一层意思是倒排索引文件。
(四)文档
一个可被索引的基础信息单元,以JSON格式来表示。
(五)分片(Shard)
为了支持更大量的数据,索引一般会分成多个部分,每个部分就是一个分片,分片被节点管理。一个节点一般会管理多个分片,这些分片可能是属于同一份索引,也有可能属于不同索引,但是为了可靠性和可用性,同一个索引的分片尽量会分布在不同节点上。
分片有两种,主分片和副本分片。
副本(Replica):一个分片(Shard)的备份数据,一个分片可能会有0个或多个副本,这些副本中的数据保证强一致或最终一致。
默认情况下,Elasticsearch中的每个索引被分片5个主分片和1个复制,这意味着,如果你的集群中至少有两个节点,你的索引将会有5个主分片和另外5个复制分片(1个完全拷贝),这样的话每个索引总共就有10个分片。
四、文档的写入过程
- 客户端向es集群发送文档写请求
- 集群的某个节点接收到请求,通过路由算法确定该文档所属的主分片,将请求转发给该主分片所在节点
- 主分片执行写请求,成功后将请求同时转发给多个对应副分片所在节点
- 副本分片执行请求,将执行结果通知主分片所在节点
- 如果所有副分片都执行(同步)成功,主分片节点通知接受请求的接待您操作成功,接收请求的节点向客户端返回操作成功
只要有副本在,写入延时最小也是两次单Shard的写入时延总和,写入效率会较低,但是这样的好处也很明显,避免写入后,单机或磁盘故障导致数据丢失,在数据重要性和性能方面,一般都是优先选择数据,除非一些允许丢数据的特殊场景。
路由算法:
Index Request中可以设置使用哪个Filed的值作为路由参数,如果没有设置,则使用Mapping中的配置,如果mapping中也没有配置,则使用_id作为路由参数,然后通过_routing的Hash值选择出Shard(在OperationRouting类中),最后从集群的Meta中找出出该Shard的Primary节点。
五、文档的读取过程
- 集群的某个节点接收到读取请求
- 根据路由算法确定文档所在分片的节点列表
- 根据负载均衡算法(默认轮询)确定转发给主分片还是副本分片,分片所在节点将数据返回给接收到请求的节点,接收到请求的节点将数据返回给客户端。
查询的时候需要查询所有Shard,同一个Shard的Primary和Replica选择一个即可,查询请求会分发给所有Shard,每个Shard中都是一个独立的查询引擎,比如需要返回Top 10的结果,那么每个Shard都会查询并且返回Top 10的结果,然后在Client Node里面会接收所有Shard的结果,然后通过优先级队列二次排序,选择出Top 10的结果返回给用户。
这里有一个问题就是请求膨胀,用户的一个搜索请求在Elasticsearch内部会变成Shard个请求,这里有个优化点,虽然是Shard个请求,但是这个Shard个数不一定要是当前Index中的Shard个数,只要是当前查询相关的Shard即可,这个需要基于业务和请求内容优化,通过这种方式可以优化请求膨胀数。
写入和读取请求都是可以任意节点接收,但是经过路由算法转发后,写入请求必须转发到主分片,读取的话主副都可以。
六、es中的乐观锁
悲观锁:每次操作时都认为别⼈会修改数据,所以操作时会先加锁。eg. 关系数据库的行锁、表锁,都是在做操作之前先上锁。
乐观锁:每次操作时都认为别⼈不会修改数据,不上锁,但提交更新时会检测操作期间数据是否已被修改。
悲观锁适合写多读少、并发量小的场景,乐观锁适合读多写少、并发量大的场景。
es读多写少,常使用乐观锁解决并发问题,使用乐观锁也可以提⾼系统吞吐量。
七、常用分词器
Standard Analyzer:
标准分词器,也是ES的默认分词器,按词切分,小写处理,默认停用词默认是关闭的。
Keyword Analyzer:
不分词,直接将输入的文档当做一个词输出。
八、优化建议
- 一般情况下一个shard维护5千万到2亿数据即可
- 不要把ES当数据库用,ES只存索引字段和排序字段
- 禁用模糊查询和正则匹配,禁用深度分页
- 深度分页考虑searchAfter SearchScroll
- 不需要范围查询的字段,改为keyword
- 全量索引时关闭副本
- 全量新建索引,通过别名指向新索引,后删除老索引
十、脑裂
(一)定义
一个集群有两个或两个以上以上的主节点的情况,可以理解为一个大集群分裂成了多个小集群,这些小集群各自有各自的master,能够自己对数据进行操作,导致大集群产生了数据不一致的现象。
(二)避免
大多数原则: n/2 + 1张选票才能成为主节点。
但是es不像raft有任期的概念,所以一次投票中,一个节点是有可能投两次票的。
减少误判:discovery.zen.ping_timeout节点状态的响应时间,默认为3s,可以适当调大,如果master在该响应时间的范围内没有做出响应应答,判断该节点已经挂掉了。调大参数(如6s),可适当减少误判。
两个master节点解决方案:就是可以将数据和主节点分离,还有当只有两个节点时:设置其中一个为主节点,nodedata为false,另一个nodedata为true,master为false。
十一、生产配置举例
一共27个节点(27台服务器),其中3个master节点,24个data节点,一个节点只设置为一种角色。每个节点3个分片,每个分片一个副本分片。
十二、es选举机制
(一)选举触发
集群启动、Master失效
(二)步骤
- 每个节点ping集群下的其他节点
- 根据其他节点的返回,过滤掉没有资格参加选举的节点
- 如果集群中已经有master,那么加入它,否则,开始选举
- 对所有可以成为master的节点根据nodeId排序,每次选举每个节点都把自己所知道节点排一次序,然后选出第一个(第0位)节点,进行投票。
- 如果对某个节点的投票数达到一定的值(可以成为master节点数n/2+1)并且该节点自己也选举自己,那这个节点就是master。否则重新选举。
十三、评分计算机制
(一) boolean model
boolean model是相关度分数计算的第一步操作。
Elasticsearch搜索时,首先根据搜索条件,过滤出符合条件的document,仅仅只记录true或false,标记document是否满足搜索要求
(二) TF/IDF
TF: term frequency,词频算法。对搜索条件进行分词后,各词条在整个index的所有document中出现的次数越多,则权重越高。
举例:搜索条件为"hello es",document1对应 {“field_test”: “hello world, I am learning es”},document2对应{“field_test”: “hello Wuhan”}。
分析:由于搜索条件分词后,document1包含了2个关键词,而document2只包含了1个关键词,因此在计算TF这一项相关度分数算法指标时,document1比document2高。
IDF: inverse document frequency,逆文本频率指数算法。对搜索条件进行分词后,统计各词条在所有(已过滤的)document中出现的次数,出现的次数越多,词条的特性越弱,该词条在后续用于评定相关度分数时,起到的作用也越低。
举例:搜索条件为hello es,document1对应 {“field_test”: “hello world, I am learning something new”},document2对应{“field_test”: “java es”} 其中,hello在index中出现了1000次,es出现了100次。
分析:即便document1和document2中出现词条的次数相同,由于"hello"的相关度评定价值比"es"低,因此,在计算IDF这项相关度算法的权重时,document1比document2低。
length norm: 长度规范。对已匹配目标词条的document而言,document的长度越长,则相关度分数阅读。
举例:搜索条件为hello es,document1对应 {“field_test”: “hello world, I am learning something new”}, document2对应{“field_test”: “heelo es”}
分析:虽然两个document都只包含了一个目标词条,但document1内的无用数据比document2多,因此在计算length norm这项相关度算法的权重时,document1比document2低。
(三) 空间向量算法
经过TF/IDF算法后,仅仅只是为每一个(过滤后的)document计算出每一个term的相关度分数,那么怎样求得一个"总分"呢?空间向量算法(Vector space model)就派上用场了。
首先,我们从document出发。document由若干个term组成(忽略停用词),通过TF/IDF算法计算后,我们可以得知每一个term在document中的权重,而不同的term又会根据自己的权重影响当前document的相关度得分。
在这里,我们将当前document中出现的所有term的权重组合起来,形成一条向量——Document Vector
最后,我们把所有计算出的向量(文档向量和查询向量)放在同一个N维空间中,如图所示:
现在的关键是计算每一个Document Vector对于Query Vector的相似度。Elasticsearch认为,若两个向量之间的夹角越小,则相似度越高。