当前位置: 首页 > news >正文

上厅房,下厨房,ElasticSearch有的忙

强烈建议先读一下本公众号《也浅谈下分布式存储要点》,对ES会有更好的认识。ES融合了倒排索引、行存、列存的诸多特点,已经不再是一个简单的全文搜索引擎。

ES是从厨房里走出来的,原型是Shay Banon给妻子做的食谱搜索引擎,一开始便充满了爱的味道。

儿女情长什么的,最影响程序员发挥了!

最终,ElasticSearch斩断情愫,成为一个基于Lucene的分布式存储。安装后访问其页面,会显示:”You Know, for Search“,这句平凡的语句无意中透露的自信,深于一切怀疑和平淡。

几点说明

几点说明
索引中的Type定义会引起诸多歧义,已经在6.0版本废弃
作为搜索时,是类实时性系统,写入到读取之间存在延迟,一般为1秒 ;但当作为存储时,是RT的
ES索引的分片数一旦确定不可改变,既成事实的Mapping也是
你优化了写入,就可能干扰了查询和可靠性,大多时候不可兼得
你会经常碰到OOM,显然ES是内存大户,缺乏这方面的保护
ES没有事务

基础概念

ES是典型的分布式系统。包含一到多个内存型节点。有分片,也有副本,可靠性高,自适应能力强。ES采用多机并行能力来进行扩展,是建立在一系列层级数据结构上的。这些抽象作为一个全局的路由表,存在于每个运行的实例上,给了ES强大的功能和扩展能力。

名词解释
Cluster集群,有着统一的名称。包含一个master节点,和落干其他类型节点。一般为对等节点
Node节点,ES运行实例,指定集群中的任意一台即可加入
Index索引,逻辑命名空间。类比DBMS中的
Shard分片,每个索引包含一个或多个分片,用来将数据分布在不同实例上
Replica每个分片又分为主副本和从副本,用来保证HA和Failover。每一个replica为具体lucene实例
Segment段,倒排索引的子集,会不断的合并以减少资源占用
Document文档,为具体存放的某条记录,比如某条订单信息
Feild字段,文档中的某个字段,可以有不同的类型

索引类型

倒排索引

很多同学有一个误解,以为ES是一个全文搜索引擎,那么就只有倒排索引这一种索引类型,那是错的。数据在写入es时,会产生多份数据用于不同查询方式,使用的索引结构也不相同。

ES默认是对所有字段进行索引的(也就是倒排索引),如果不需要,可以在mapping中将index属性设置为no;如果字段需要精确查找,则设置为not_analyzed

为了增加倒排索引的Term查找速度,ES还专门做了Term index,它的本质是一棵Trie(前缀)树(使用FST技术压缩)。

_all是一个特殊的字段,可以根据某个关键词,搜索整个文档内容(而不是某个字段),这个默认是关闭的。

列式存储

按照以上的倒排索引结构,查找包含某个term的文档是非常迅捷的。如果要对这个字段进行排序的话,倒排索引就捉襟见肘了,需要使用其他的存储结构进行索引。

ES使用冗余的方式进行解决这个问题,它存储了另一份数据,也就是Doc Values。可以说Doc Values是一个列式存储结构,适合排序、聚合操作等。放在内存中的fielddata功能和它类似,但没有内存容量的限制,大数据量优先使用。

到此为止,ES已经默认按照不同的结构存储了两份数据了。但如果你不需要,还是可以禁用的。同样是在mapping玩具中,给字段赋予属性"doc_values":false即可。

假如你用的是ELKB系列,倒排索引根本就没用到。

式存储

而作为行存_source字段,以json方式存储了原始文档。一般是不需要关闭的。但如果你的文档字段比较多,根据搜索后查出列表,再根据列表的数据到其他存储获取,那么就可以将_source关掉。类似的,设置"_source"{"enabled":false}即可。

如果只想要几个字段被存储,可以使用include。

"_source":{
    "includes":["field1","field2"]
}
复制代码

ES有太多的这种细化的自定义,不再详叙。

写入过程

找到分片

某个分片具体在哪个节点上,由ES自行决定。每个节点都缓存了这些路由信息,所以,你的请求发送到任何一个ES节点上,都可以执行。

ES选择的分片路由算法是Hash,这决定了它的分片数一旦确定,不可更改。因为一旦变了,路由的数据就完全不正确了。

如果Request中指定了路由条件,则直接使用Request中的Routing,否则使用Mapping中配置的,如果Mapping中无配置,则使用默认的_id字段值。

默认参与Hash计算的字段是 _id,使用ES自带的生成器能较好的平均数据,使用自定义的id可能会产生数据倾斜。

shard = hash(routing) % number_of_primary_shards
复制代码

剩下的,就是单机索引的事了。

单机Shard的写入过程

ES的写入性能可以很高(尤其是批量写入),取决于你的配置。一个文档要写入索引,直到读可见,要经过一系列的缓冲和合并。我们拿ES官方博客的一张图来说明。

ES的底层存储是Lucene,包含一系列的反向索引。这样的一批索引的信息就是上面提到的段(segment)。但记录不会直接写入段,而是先写入一个缓冲区。

当缓冲区满了,或者在缓冲区呆的够久,达到了刷新时间(划重点),会一次性将缓冲区的内容写进段中。这也是为什么refresh_interval属性的配置会严重的影响性能。如果你不要很高的实时性,不妨将其配置的大一点。

缓冲区默认使用堆空间的10%,最小值为48mb(针对于分片的)。如果你的索引多且写入重,这部分内存的占用是可观的,可以适当加大。


问题是Segment是不可变的,删除、更新操作,并不能在原来的段上进行。ES对待所有的操作都是相似的,并不区别对待,删除和更新,有着和写入一样的mege过程。这会生成大量的段,每个段会占用一个文件句柄,会浪费大量资源。ES有专门的进程负责段的自动合并,我们不需要手动干涉。

段的合并会浪费大量的I/O和CPU资源,有tiered(默认)、log_byte_sizelog_doc三种合并策略,每种策略都有各自的配置参数。可惜的是,索引一旦确定,策略就不能更改了。调整这些参数,大多情况下效果显著。

常用的配置参数是执行归并的线程数,max_bytes_per_sec已经不再使用了。

index.merge.scheduler.max_thread_count
复制代码

如果你的I/O过重,可以适量减少此值的大小。


即然是先写到缓冲区,就有丢的可能,比如突然断电。为了解决此问题,ES在写Buffer的同时,也将数据写入一个叫做translog的文件。这个文件是顺序写,所以速度比较快。translog是故障恢复时,回放故障发生前夕数据的唯一途径。这些数据,没有机会能够写入到Lucene中。

将translog的写入周期改成async的,而不是基于请求的,会显著减少I/O占用。

操作系统在将磁盘写入文件时,也会有相应的buffer cache,这与其他DB如MySQL、PG的工作方式是一样的,使用fsync保证文件能够刷到磁盘上,不多描述。

节点类型

ES按照不同的用途和场景,划分了不同的节点类型。

Master Node 有资格被选择为主节点,然后控制整个集群

Data Node 该节点能够保存数据和执行操作

Tribe Node 部落节点,可以连接多个集群,对外提供统一的入口

Ingest Node 定义一个pipeline来处理数据,可以替代logstash中的某些功能

客户端节点 不保存数据也不协调集群,仅响应用户请求,将其发送到其他节点

End

ES通过冗余多份数据达到不同的用途,开箱即用。开箱即用的意思也就是认识成本低,学习成本大,先把你吸引进门再说。

ES不是一匹好驯服的野马。通常,它并不像官方和其他PPT宣传的那样无所不能,你可能经常在OOM和分片移动中度日。

希望在使用ES之前,能够了解它的一些底层设计结构。这样,在遇到一些瓶颈的限制以后,能够了解到它为什么有这样或者那样的反应;另外在做一些解决方案的时候,能够多给自己一点底气。

不过话说回来,上得了厅房,下得了厨房的女人,大家还是都喜欢~

相关文章:

  • Linux安装gitlab
  • 专家齐议尘肺病农民救助难点
  • Codeforces Round #532(Div. 2) A.Roman and Browser
  • 澳大利亚将开启全球人才计划 吸引优秀技术移民
  • kubernetes 设置CA双向数字证书认证
  • 澳门消防局拟购置无人机协助紧急救援
  • spring学习总结(一)_Ioc基础(下)
  • 联邦法官驳回章莹颖案被告所有动议 全案按原计划审理
  • MySQL逻辑架构及性能优化原理
  • mysql 查询的时候没有区分大小写的解决方案
  • 2.python数据类型
  • [译] 讨论 JS ⚡:文档
  • 利用pyecharts做地图数据展示
  • 文件的上传和下载
  • 拼图(九宫格,十六宫格)
  • [ 一起学React系列 -- 8 ] React中的文件上传
  • 【159天】尚学堂高琪Java300集视频精华笔记(128)
  • 【mysql】环境安装、服务启动、密码设置
  • 77. Combinations
  • android 一些 utils
  • Android系统模拟器绘制实现概述
  • CentOS7 安装JDK
  • Laravel 菜鸟晋级之路
  • Mybatis初体验
  • Python_网络编程
  • thinkphp5.1 easywechat4 微信第三方开放平台
  • VuePress 静态网站生成
  • Web Storage相关
  • Yeoman_Bower_Grunt
  • 回顾 Swift 多平台移植进度 #2
  • 名企6年Java程序员的工作总结,写给在迷茫中的你!
  • 浅谈JavaScript的面向对象和它的封装、继承、多态
  • 如何用Ubuntu和Xen来设置Kubernetes?
  • 三分钟教你同步 Visual Studio Code 设置
  • 算法系列——算法入门之递归分而治之思想的实现
  • 小而合理的前端理论:rscss和rsjs
  • 正则与JS中的正则
  • 长三角G60科创走廊智能驾驶产业联盟揭牌成立,近80家企业助力智能驾驶行业发展 ...
  • ​插件化DPI在商用WIFI中的价值
  • #Lua:Lua调用C++生成的DLL库
  • (3)选择元素——(14)接触DOM元素(Accessing DOM elements)
  • (编译到47%失败)to be deleted
  • (第27天)Oracle 数据泵转换分区表
  • (二)丶RabbitMQ的六大核心
  • (分布式缓存)Redis持久化
  • (含react-draggable库以及相关BUG如何解决)固定在左上方某盒子内(如按钮)添加可拖动功能,使用react hook语法实现
  • (生成器)yield与(迭代器)generator
  • (四)JPA - JQPL 实现增删改查
  • (一)appium-desktop定位元素原理
  • (转)linux 命令大全
  • (转载)PyTorch代码规范最佳实践和样式指南
  • * CIL library *(* CIL module *) : error LNK2005: _DllMain@12 already defined in mfcs120u.lib(dllmodu
  • *(长期更新)软考网络工程师学习笔记——Section 22 无线局域网
  • .net on S60 ---- Net60 1.1发布 支持VS2008以及新的特性
  • .net利用SQLBulkCopy进行数据库之间的大批量数据传递