ElasticSearch
ES是目前很流行的分布式搜索引擎,基于Lucene.
架构设计
主体设计:和一般的分布式思想一致,大的来说即在多个机器或容器上启动多个ElasticSearch进程,进而组成cluster。
主要功能:存储数据。
基本方式:使用索引作为基本单位存储数据,和Mysql类似,将索引与数据表关联,但也有一点不一样,这里的索引只是差不多相当于一张表,实际的情况index下还可以继续分类,一般按照以下层级分类。
index->type->mapping->document->field
具体展开: 一个index代表一个类别,而一个index里面有多个type,type真正相当于mysql设计上的一个表,表示一个类别下具体的实体。每个type下有一个mapping,相当于这个type的表结构,就是数据库设计中的字段、字段类型。document则相当于数据库里的数据,即对应某个表中的一行,而field则相当于一行中的某个字段具体的值。
分布式存储的基本实现:和一般分布式设计类似,将索引拆分成多个shard分片,让数据存储在这些shard上,一方面提高了性能,因为可以分布式的进行操作,提高了吞吐量和性能,另一方面是便于分表拓展,当数据量增加的时候,只需要将索引对应的shard增加即可。
容错与高可用保证:和Kafka类似的方式,每个shard都会有多个备份,也会选举出一个领导primary_shard,专门负责写入,并将数据同步到各个副本上replica_shard。
选举切换方式:主要由集群选出一个master节点用来维护索引切换shard。比方说如果有一个节点挂了,就会由master节点把挂的节点对应的primary shard撤销,并将别的节点设置成primary shard,当节点重启后再将丢失的数据同步过去,此使这个节点是个普通节点。
写入数据
- 由客户端选择一个节点作为coordinating_node来发送请求。
- 由coordinating_node对document进行路由选择转发给primary_shard所在的节点。
- 由primary_shard处理请求并将数据同步到replica_node上
- 由coordinating_node接受操作完成的相应,再返回写入结果给客户端。
读取数据
- 由客户端选择一个节点作为coordinate_node,发送所需要的doc_id
- coordinate_node根据doc_id进行哈希,判断出这个id对应的shard,从而将查询请求转发给对应的node,并且使用round-robin负载均衡算法,随机选择一个shard。
- 这个node将document查询出来返回给coordinate_node。
- 最终由coordinate_node响应客户端。
全文搜索过程
- 由客户端选择一个节点作为coordinate_node,并发送查询请求。
- coordinate_node将请求转发到所有的shard。
- 每个shard将自己的搜索结果doc_id返回给coordinate_node节点,再在coordinate_node节点进行数据的合并与排序。
- 根据所有的doc_id再去按读取过程查询所有的document,最终返回给客户端。
准实时性
写入的数据只有过了1s才能被看到。因为1s才会refresh一次,也可以手动通过restful api或java api,手动执行一次refresh操作,将buffer中的数据刷入cache中,使结果立刻显示出来。
丢失数据
因为存在五秒的数据停留在buffer、cache、segment file中,即内存中而不在磁盘上,会导致有5s的数据丢失。
删除/更新数据
删除主要通过将doc标识成deleted状态进行软删除。
更新主要通过原来的doc删除,再重新写入数据。
lucene
主要是一个封装了各种建立倒排索引的算法代码。可以将已有数据建立索引。
倒排索引
简单说就是关键词到文档id的映射,每个关键词对应出现了所有关键词的文件id。
其中所有词项对应一个或多个文档,根据字典顺序升序排列。
ElasticSearch的性能优化
众所周知,读取内存中的数据比读取磁盘上的数据快很多,因为磁盘有寻址等方面的时间消耗。所以要让ElasticSearch的性能提升就是让数据的读取尽可能多的从内存中读。
因此,一方面可以规范存入的数据,将用于搜索的数据存入ElasticSearch中,将完整的数据存入其他数据库中,比如mysql或hbase这种列数据库。另一方面的话当数据还是足够多,内存远远不够存,可以做下面的进一步优化。
数据预热
顾名思义,就是让Hotspot的数据自己手动提前预热,存入内存。一般的做法是做一个子服务,将热点数据每隔一定时间存入内存中去。
冷热分离
数据预热的过程中还要防止被冷数据重新占据内存,这时可以像mysql一样做一个水平拆分,将数据冷热分离。由于二八原则,热数据一般占据总数据的少部分,但能保证大多数人的搜索性能要求。
不使用联表查询
联表查询在elasticsearch中性能较差,因此对于联表的数据,应在写入前处理好,即dto的时候操作好,并且新建一个表写入。
分页性能优化
一方面可以限定分页的数量,比如之允许访问前XXX条数据,来限制页数。
另一方面类似于淘宝,抖音,微博,使用实时下拉查询分页,使用scroll api一次性给所有数据一个快照,通过游标去分页查询,但是要限制查询时间。也可以通过上一页查下一页的方法,当然这个时候不允许跳页。
集群部署
主要还是在不同集器上的一些配置并选择适当数量的shard分片。