【ES】ElasticSearch 深入分片
@[toc]
分片是 Elasticsearch 在集群中分发数据的关键。
把分片想象成数据的容器。文档存储在分片中,然后分片分配到集群中的节点上。当集群扩容或缩小,Elasticsearch 将会自动在节点间迁移分片,以使集群保持平衡。
一个分片(shard)是一个最小级别“工作单元(worker unit)”,它只是保存了索引中所有数据的一部分。
这类似于 MySql 的分库分表,只不过 Mysql 分库分表需要借助第三方组件而 ES 内部自身实现了此功能。
分片可以是 主分片(primary shard) 或者是 复制分片(replica shard) 。
在集群中唯一一个空节点上创建一个叫做 blogs 的索引。默认情况下,一个索引被分配 5 个主分片,下面只分配 3 个主分片和一个复制分片(每个主分片都有一个复制分片):
在一个多分片的索引中写入数据时,通过路由来确定具体写入哪一个分片中,大致路由过程如下:
routing 是一个可变值,默认是文档的 _id ,也可以设置成一个自定义的值。routing 通过 hash 函数生成一个数字,然后这个数字再除以 number_of_primary_shards (主分片的数量)后得到余数 。这个在 0 到 number_of_primary_shards 之间的余数,就是所寻求的文档所在分片的位置。
这解释了为什么要在创建索引的时候就确定好主分片的数量并且永远不会改变这个数量: 因为如果数量变化了,那么所有之前路由的值都会无效,文档也再也找不到了 。
索引中的每个文档属于一个单独的主分片,所以 主分片的数量决定了索引最多能存储多少数据 (实际的数量取决于数据、硬件和应用场景)。
复制分片只是主分片的一个副本,它可以 防止硬件故障导致的数据丢失,同时可以提供读请求,比如搜索或者从别的 shard 取回文档 。
每个主分片都有一个或多个副本分片,当主分片异常时,副本可以提供数据的查询等操作。主分片和对应的副本分片是不会在同一个节点上的,所以副本分片数的最大值是 n -1(其中 n 为节点数)。
当索引创建完成的时候,主分片的数量就固定了,但是复制分片的数量可以随时调整,根据需求扩大或者缩小规模。如把复制分片的数量从原来的 1 增加到 2 :
分片本身就是一个完整的搜索引擎,它可以使用单一节点的所有资源。 主分片或者复制分片都可以处理读请求——搜索或文档检索,所以数据的冗余越多,能处理的搜索吞吐量就越大。
对文档的新建、索引和删除请求都是写操作,必须在主分片上面完成之后才能被复制到相关的副本分片,ES 为了提高写入的能力这个过程是并发写的,同时为了解决并发写的过程中数据冲突的问题,ES 通过乐观锁的方式控制,每个文档都有一个 _version (版本)号,当文档被修改时版本号递增。一旦所有的副本分片都报告写成功才会向协调节点报告成功,协调节点向客户端报告成功。
ES 集群中每个节点通过路由都知道集群中的文档的存放位置,所以每个节点都有处理读写请求的能力。
在一个写请求被发送到某个节点后,该节点即为协调节点,协调节点会根据路由公式计算出需要写到哪个分片上,再将请求转发到该分片的主分片节点上。假设 shard = hash(routing) % 4 = 0 ,则过程大致如下:
写入磁盘的倒排索引是不可变的,优势主要表现在:
当然,不可变的索引有它的缺点:
在全文检索的早些时候,会为整个文档集合建立一个大索引,并且写入磁盘。只有新的索引准备好了,它就会替代旧的索引,最近的修改才可以被检索。这无疑是低效的。
因为索引的不可变性带来的好处,那如何在保持不可变同时更新倒排索引?
答案是,使用多个索引。 不是重写整个倒排索引,而是增加额外的索引反映最近的变化。 每个倒排索引都可以按顺序查询,从最老的开始,最后把结果聚合。
这就引入了 段 (segment) :
分片下的索引文件被拆分为多个子文件,每个子文件叫作 段 , 每一个段本身都是一个倒排索引,并且段具有不变性,一旦索引的数据被写入硬盘,就不可再修改。
段被 写入到磁盘 后会生成一个 提交点 ,提交点是一个用来记录所有提交后段信息的文件。一个段一旦拥有了提交点,就说明这个段只有读的权限,失去了写的权限。相反,当段在内存中时,就只有写的权限,而不具备读数据的权限,意味着不能被检索。
在 Lucene 中的索引(Lucene 索引是 ES 中的分片,ES 中的索引是分片的集合)指的是段的集合,再加上提交点(commit point),如下图:
在底层采用了分段的存储模式,使它在读写时几乎完全避免了锁的出现,大大提升了读写性能。
索引文件分段存储并且不可修改 ,那么新增、更新和删除如何处理呢?
ES 是怎么做到 近实时 全文搜索?
磁盘是瓶颈。提交一个新的段到磁盘需要 fsync 操作,确保段被物理地写入磁盘,即时电源失效也不会丢失数据。但是 fsync 是昂贵的,严重影响性能,当写数据量大的时候会造成 ES 停顿卡死,查询也无法做到快速响应。
所以 fsync 不能在每个文档被索引的时就触发,需要一种更轻量级的方式使新的文档可以被搜索,这意味移除 fsync 。
为了提升写的性能,ES 没有每新增一条数据就增加一个段到磁盘上,而是采用 延迟写 的策略。
每当有新增的数据时,就将其先写入到内存中,在内存和磁盘之间是文件系统缓存,当达到默认的时间(1秒钟)或者内存的数据达到一定量时,会触发一次刷新(Refresh),将内存中的数据生成到一个新的段上并缓存到文件缓存系统 上,稍后再被刷新到磁盘中并生成提交点 。
这里的内存使用的是ES的JVM内存,而文件缓存系统使用的是操作系统的内存。新的数据会继续的被写入内存,但内存中的数据并不是以段的形式存储的,因此不能提供检索功能。由内存刷新到文件缓存系统的时候会生成了新的段,并将段打开以供搜索使用,而不需要等到被刷新到磁盘。
在 Elasticsearch 中,这种写入和打开一个新段的轻量的过程叫做 refresh (即内存刷新到文件缓存系统)。默认情况下每个分片会每秒自动刷新一次。 这就是为什么说 Elasticsearch 是近实时的搜索了:文档的改动不会立即被搜索,但是会在一秒内可见。
也可以手动触发 refresh。 POST /_refresh 刷新所有索引, POST /index/_refresh 刷新指定的索引:
没用 fsync 同步文件系统缓存到磁盘,不能确保电源失效,甚至正常退出应用后,数据的安全。为了 ES 的可靠性,需要确保变更持久化到磁盘。
虽然通过定时 Refresh 获得近实时的搜索,但是 Refresh 只是将数据挪到文件缓存系统,文件缓存系统也是内存空间,属于操作系统的内存,只要是内存都存在断电或异常情况下丢失数据的危险。
为了避免丢失数据,Elasticsearch添加了 事务日志(Translog) ,事务日志记录了所有还没有持久化到磁盘的数据。
有了事务日志,过程现在如下:
事务日志记录了没有 flush 到硬盘的所有操作。当故障重启后,ES 会用最近一次提交点从硬盘恢复所有已知的段,并且从日志里恢复所有的操作。
在 ES 中,进行一次提交并删除事务日志的操作叫做 flush 。分片每 30 分钟,或事务日志过大会进行一次 flush 操作。 flush API 也可用来进行一次手动 flush , POST/ _flush 针对所有索引有效, POST /index/_flush 则指定的索引:
通常很少需要手动 flush ,通常自动的就够了。
总体的流程大致如下:
由于自动刷新流程每秒会创建一个新的段 ,这样会导致短时间内的段数量暴增。而段数目太多会带来较大的麻烦。每一个段都会消耗文件句柄、内存和 cpu 运行周期。更重要的是,每个搜索请求都必须轮流检查每个段然后合并查询结果,所以段越多,搜索也就越慢。
ES 通过后台合并段解决这个问题。小段被合并成大段,再合并成更大的段。这时旧的文档从文件系统删除的时候,旧的段不会再复制到更大的新段中。合并的过程中不会中断索引和搜索。
段合并在进行索引和搜索时会自动进行,合并进程选择一小部分大小相似的段,并且在后台将它们合并到更大的段中,这些段既可以是未提交的也可以是已提交的。
合并结束后老的段会被删除,新的段被 flush 到磁盘,同时写入一个包含新段且排除旧的和较小的段的新提交点,新的段被打开可以用来搜索。
1. 全文搜索引擎Elasticsearch,这篇文章给讲透了
2.ElasticSearch 权威指南》
店匠助力智能硬件企业出海——搭载Amazon Web Services,为酷客智能...
店匠SHOPLAZZA所使用的AWS云服务包括Amazon Elastic Kubernetes Service(Amazon EKS)、AWS Identity and Access Management (AWS IAM)、AWS WAF、AWS Shield、Amazon Route 53、Amazon ElastiCache、Amazon Elasticsearch Service (Amazon ES)、AWS Global Accelerator(AWS GA)、Amazon Simple Storage Service (A...
农唐誉利: 首先,在任务栏里右键单击它,选取寻出该软件,之后到“控制面板”里打开“增加或删掉程序”,找到“Windows Search 4.0”单击删掉,就可以了.,
团风县17690812997: elastic querybuilders怎么添加多个参数 - ?
农唐誉利: elastic querybuilders怎么添加多个参数elasticsearch的config文件夹里面有两个配置文 件:elasticsearch.yml和logging.yml,第一个是es的基本配置文件,第二个是日志配置文件,es也是使用log4j来记录日 志的,所以logging.yml里的设置按普通...
团风县17690812997: 怎么关闭Elasticsearch服务 - ?
农唐誉利: 运行services.msc(可以使用win+R键调出“运行”), 找到WindowsSearch,双击,在“启动类型”中选择“禁用”,确定 linux使用命令kill杀掉服务器的ES进程即可 1.查找ES进程 ps -ef | grep elastic 2.杀掉ES进程 kill -9 2382(进程号) 3.重启ES sh elasticsearch -d
团风县17690812997: elasticsearch可以替代数据库吗? - ?
农唐誉利: 不推荐代替数据库哦~ ES团队不推荐完全采用ES作为主要存储,缺乏访问控制还有一些数据丢失和污染的问题 建议还是采用专门的 DB存储方案,然后用ES来做serving.es没有事务,而且是近实时.成本也比数据库高,几乎靠吃内存提高性能.最逆天的是,mapping不能改.
团风县17690812997: 如何修改elasticsearch默认线程池大小 - ?
农唐誉利: 打开es里面的config -》 elasticsearch.yml 文件 这个就是修改线程池的配置文件 添加threadpool.index.queue_size: 500之类的配置 注意:这个配置不一定是你需要的那个.具体查阅其他博客
团风县17690812997: 服务器后台运行elasticsearch怎么重启 - ?
农唐誉利: es启动脚本是bin目录下的elasticsearch.其中需要加载一些环境变量,诸如ES_CLASSPATH JAVA_OPTS ES_JAVA_OPTS等.推荐设置ES_HEAP_SIZE的值,来这只es进程需要的内存(经验值为系统内存的一半以上),同时设置-p参数来...
团风县17690812997: Elasticsearch到底能玩多大的数据量 - ?
农唐誉利: 我们有达到几万亿文档的集群.
团风县17690812997: elasticsearch怎么创建mapping - ?
农唐誉利: 为了支持高可用性与高伸缩性,Elasticsearch本身就是分布式设计的.从顶层的角度来说,Elasticsearch在索引(或者集合) 中保存文档(或者数据记录),每个集合又分解为多个小块,称为分片.索引越大,所需要分配的分片越多(不必担心会创建过多
团风县17690812997: elasticsearch和hadoop集成该怎么做 - ?
农唐誉利: 配置elasticsearch的存储路径为hdfs需要两步,安装插件elasticsearch-hadoop,在联网的情况下在命令窗口运行:plugin -install elasticsearch/elasticsearch-hadoop/1.2.0即可. 如果没有联网解压插件到plugins中即可,目录为/hadoop..... ...
团风县17690812997: 如何在Spring中注入ElasticSearch实例 - ?
农唐誉利: 在 企业级项目开发中,大多数公司都会集成Spring来简化开发成本,要使用Spring自然少不了一大堆需要依赖注入的Bean,通常情况下,我们会选择 在spring的xml中,配置一些类的实例,比如连接池,或者配置文件初始化类,或者集成duboo...