ElasticSearch全文检索引擎相关认识

一、Es的分布式架构是怎么样的(如何实现分布式)

我们知道ElasticSearch是一个分布式搜素引擎,底层依赖于lucene全文检索,其中它 的核心思想就是在多台机器上启动es进程实例来组成es集群。es中存储数据的基本单位是index索引,整个结构类似于index->type->mapping->document->field。我们完全可以类比mysql数据库来理解。

index:类似于mysql的建表,我们所说的向es里面写一条订单数据,就要建立一个订单索引,将这些所有的订单数据都写到这个索引里面

type:代表着一个类别,就例如订单索引里面有这么几个type,一个为实物订单,一个为虚拟订单。什么叫实物订单,我们买一些实在的东西可以称为(有点广泛),虚拟的订单可以看做为买游戏点卡之类的;那么在这个订单索引里面可以就会有不同的订单类需要区分,而这个type就代表着在mysql里面的具体的订单表

mapping:在数据库每一张表都会有自己的表结构,字段类型,字段配置,而这个mapping就是负责这些的。

document:就相当于mysql表里面的一行数据

field:就是每行数据的字段对应的属性值

然后我们来分析为什么es是分布式的。假设我们这边有三台机器来装放es实例进程,在es里面有一个分片的概念,他不会将所有的数据都放到一个片区,当我们创建一个索引的时候就会在我们所分配好的机器里面将数据进行分片,每一个片区假设名为shard01,shard02等,我们学过kafka也知道,分布式场景下为了保证高可用会有一个副本的机制,es也一样,它会把已经分好的片区进行备份,并且将这些备份好的片区分布到不同的机器上,防止宕机连主备一起都没有。而且在这个副本机制中也会采取一个主从的概念,把原来的片区定义为primary,备份区定义为replica,只有原片区有写入的权限,如果路由到备份片区它会去找到原片区进行写入操作,然后同步给副本。读权限都有,如果其中一台主机宕机例如图如果shard02主机宕机,若写入数据时路由到shard02上那么会把原来的shard02的replica副本晋升为primary,并且将之前的主机通过选举算法重新选主机。

ElasticSearch全文检索引擎相关认识

二、Es写入数据及查询数据的原理是什么?

首先,写入数据我们可以走一遍流程。客户端写了一条数据一个node协调节点,node通过路由将这条数据document路由到有该相关的片区的primary下进行,然后同步到replica,在给客户端反馈结果。

然后,着重看一下路由到primary片区下都做了什么。首先es进程里面有一个内存buffer用来装这条数据,同时写入一个translog日志文件,那我们也知道数据会源源不断的进来然后放到这个内存buffer中,所以肯定会溢出的,那么es就会将这些数据写入到segmeng磁盘文件。但是在这个过程中不是直接就写到了磁盘文件中而是先写到了os cache系统内存缓存中,es还默认1s之后就将这些数据全部写到segment磁盘文件中然后将buffer里面的数据清空,所以在这1s内数据没有写到os cache里面的时候你是查不到这条数据的。整个过程叫做refresh。但是也提供了对应的api可以进行手动refresh,让数据直接刷入os cache里面立刻就可以被搜索到。

随着数据量的写入虽然内存buffer的问题解决了,translog日志文件也会随着数据量的加大而加大,当这个日志文件达到一定程度的时候会触发commit操作,第一步就是将现有在buffer的数据直接刷入os cache中清空buffer,第二步将一个commit point写入磁盘文件,里面标识了所有commit point 对应的segment field,第三步强行将os cache里面的所有的数据都fsync到磁盘。最后将这个translog文件清空重启一个translog日志文件,整个commit过程就结束了。这个过程也称为flush,其实es每隔30min都会进行一次flush操作,但是如果translog文件过大也会进行flush操作,我们也可以通过手动的形式将os cache里面的数据强刷入磁盘

其实translog文件也是先写入os cache里面的,默认是会有5s左右会刷新到磁盘,所以在默认的情况下在这个5s的间隙中有可能数据停留在内存buffer、translog os cache和segment os cache里面,一旦这个时候发生宕机就有可能会丢失这5s的数据因为这一部分数据还没有被写入磁盘,如果是为了不被丢失可以可以设置一个参数使得每次写入到buffer的数据的同时写入磁盘的translog,但是这样可能性能就下了一个数量级。

ElasticSearch全文检索引擎相关认识

读数据:读数据的话可以分为查找和全文检索。查找就是在当你写入document的时候,document会给分配一个全局的doc id去路由到对应的片区,查找数据就是根据这个doc id来进行查找通过hash找到数据所在片区,通过轮询机制来分配片区,对应的node接受到请求之后返回数据给协调节点,协调节点在反馈给客户端;全文检索与查找就不一样了,假设es中有几条相关java的数据,我要去检索出全部与我java相匹配的数据出来。这个时候客户端给协调节点发送请求要求检索关键字“java”,该node就会向所有的shard片区(primary或replica)发送请求,每一个shard片区将搜索到的结果全部返还给node节点进行合并,排序,分页。按照底层倒排索引匹配最接近的doc id 返回给协调节点,协调节点根据id再去对应的片区取完整的数据 

删除数据:当执行删除操作时会在commit的时候生成一个.del文件,里面将document标识为del状态,这样的话搜索的时候就会将这个doc当做被删除

更新操作:就是将原来的doc标识为del状态然后重新在写一条数据。

整个过程中,因为内存buffer每隔1s或者buffer满了的情况下都会向segment file文件写入(buffer如果为空时不写入),每次写完就创建一个新的segment file文件。这样的话会导致segment积压大量的文件,这时会触发一个过程merge,而且也会定期的进行merge操作。每次进行merge的时候都会将多个segment file文件整合到一个file里面,然后将标识为del的doc删除然后将新的segment file 写入磁盘,这里会写一个commit point标识所有的segment file然后打开segment file供搜索使用同时将原来的旧的segment file文件删除。

 

三、Es在大数据的情况下是如何提高性能的。(结合Es的特点)

我们知道es是处理数据的,怎么提高性能那就要看你怎么读数据了,假如我们走磁盘去把数据读出来然后反馈给用户那肯定是秒级别的,如果数据量在大一点用户可能就没有丝毫体验。那怎么办,完全可以把数据放内存如果读取数据的时候走的是内存那直接就可以反馈回去,es的搜索引擎底层完全依赖于filesystem cache,如果可以分配更多的内存给filesystem file,尽可能的将所有的index segment file文件放入内存然后走内存去读那个性能会非常高。

但是我们知道,什么叫大数据1T数据量算嘛,那全部存入是不是就要1T内存。那得多少台64G物理内存机器做这个集群搭建。来一个例子,假如我有三台64G物理内存机,那么我就有64*3=192G的内存,然后我需要分配给es jvm heap 一半的内存然后其他全部都给filesystem cache这个时候每台机器也就分配到了32G的内存,假设我这里有1T的数据量,三台总内存也就大概100G,也就是说你有10%的概率掉进内存去读数据,但是你有90%的概率是走磁盘的,也就是有大概90%的概率会遇到第一次查找数据的时候出现5-10s才查找出来的情况,对于第一次访问的用户来说根本无法忍受。

所以归根结底我要我的数据能进到我就这么大的内存里面最起码可以来一次50%命中的机会吧,所以一般在往es放数据的时候不要将全部数据都放入进来,就比如我有一行数据有30个字段,但是我只需要其中的3个字段,如果我们采取将全部30个字段都存放进去那每一个字段都会访问一次还占空间,如果就存入我们需要的3个字段空间变小了也加快了查找效率。所以按照这样的思路其实类似的不要将全部无用的数据统统放入内存,内存filesystem cache用来装像上面要查找的3个字段,其他非必要字段可以放入到mysql数据库或者hbase,hbase就是一个海量数据的在线存储,然后通过doc id 去hbase里面去把数据提取出来。

但是这样做虽然可以减少进入内存的数据量,但是如果我的查找字段内存还是顶不住那就可以来一波预热,每个doc在进行写入磁盘的时候,因为es底层是依据Lucene全文检索的,依据倒排索引将各个关键字与id进行索引匹配,我们可以写一个后台程序将这1T的数据分出热数据(访问量多)和冷数据(访问量少)然后分别将这些数据进行分片分区,保证少量的热数据都在内存中,然后后台小程序先把这些热数据全部先刷到filesystem cache内存里面,冷数据如果没有内存剩余那就丢磁盘吧。一般的话既然是热数据80%以上的用户都会走这个数据进行查找,性能上和用户体验上也会增加。

四、Es在生产环境的部署 -- (无项目测试,纯数字运算)

(1)es生产集群部署了5台机器,每台机器是6核64G的,集群总内存是320G

(2)我们es集群的日增量数据大概是2000万条,每天日增量数据大概是500MB,每月增量数据大概是6亿,15G。目前系统已经运行了几个月,现在es集群里数据总量大概是100G左右。

(3)目前线上有5个索引(这个结合你们自己业务来,看看自己有哪些数据可以放es的),每个索引的数据量大概是20G,所以这个数据量之内,我们每个索引分配的是8个shard,比默认的5个shard多了3个shard。