ES6.x默认store为mmapfs(Linux 64位),mmap性能相关分析

ES6.x默认store为mmapfs(Linux 64位):Store | Elasticsearch Guide [6.8] | Elastichttps://www.elastic.co/guide/en/elasticsearch/reference/6.8/index-modules-store.htmlES7.x默认store为hybridfs,对特定的文件使用niofs 或 mmapfs:

Store | Elasticsearch Guide [7.x] | Elastichttps://www.elastic.co/guide/en/elasticsearch/reference/7.x/index-modules-store.html

1.起因:

用户使用ES集群(6.8),在多个数据中心分别部署了同配置的独立集群,在新集群使用的时候用户保障,性能比其他集群差很多。(用户跑了几分钟,写入reject出现后立刻停止写入...即没有现场,只能看当时的监控数据)

2.分析:

由于配置一样,机器性能几乎一致,不考虑机器在cpu架构等方面产生的差异,逐一检查机器是否故障,未发现故障,排除机器原因;

此时有两个方向:

1.索引配置不一样,比如store的设置,niofs,mmapfs在写入性能方面存在较大差异

2.索引数据刚写入,可能是初始写入和稳定后写入由于什么问题导致不一样,(类似于首次查询会比稳定后查询平均要慢,因为缓存的原因)

3.根据方向继续排查:

1.新集群指定了使用mmapfs,其他集群使用默认值(linux 64位,也是mmapfs),排除fs差异导致的问题,但还可能是写入的时候由于初次写入,lucene的大量文件需要构建,在mmapfs架构下会出现性能较差的场景。

2.检查索引配置,并没发现异常,setting与其他集群基本一致,mapping中存在大量字段,而后注意到mapping中存在dynamic_templates,且没有禁止掉dynamic,怀疑是mapping根据dynamic_templates自动生成字段的时候性能损耗(源数据在节点间同步)较大,block了写入。

这个猜想与监控相符,刚写入写入队列打满,出现reject,cpu激增,几分钟后cpu平缓,不再出现reject。(写入请求量几乎一致)

和用户沟通后发现与猜想相符,所有字段靠dynamic_templates自动生成,需要生成大量字段。

提前将mapping中字段构建好,问题解决。

4.mmapfs:

问题虽然解决了,但是mmapfs这个配置给排查带来了一定的误导,需要深入挖掘一下。

发现了一篇查询相关的分析文章:

Mmap fs可能让大索引访问变得缓慢 - Elastic 中文社区Mmap fs可能让大索引访问变得缓慢 - 在一年多以前,我写过Elasticsearch 5 入坑指南一文,其中提到将生产的某个ES集群从2.4升级到5.0以后, 冷数据结点搜索性能变差,对大索引进行搜索的时候,io read会长时间飙高,导致系统load很重,甚至到无法响应的程度。 通过进一...https://elasticsearch.cn/article/754结论是查询时候,大数据、查询随机(日志)情况下会有预读被频繁踢出缓存导致io增大的情况。(page cache内存有限--->数据离散、查询随机--->page cache缓存频繁被替换--->IO增大--->抵消了零拷贝带来的优化)

大部分业务查询场景不会出现这个问题,这也是ES6.x在linux默认使用mmapfs的原因。

基本概念整理:

1.CPU不会从磁盘读取数据(原因是磁盘的读取速度慢)

2.磁盘缓存【假想的磁盘,实际是内存】:指的是把磁盘中读取的数据存到内存中,再次访问同一数据时,通过访问内存【磁盘缓存】,提高访问速度

3.虚拟内存【假想的内存,实际是磁盘】:把磁盘的一部分作为假想内存来使用,但是实际上正在运行的程序在当下时刻还是必须得存在于内存中,虚拟内存中的数据不是当前正在运行的程序(正在使用的文件)

4.虚拟内存技术:一种内存管理的技术

5.虚拟地址空间:是连续的地址,虽然把硬盘那部分“内存”当成物理内存来用,但是它和真正的物理内存不是连续的,虚拟地址空间就是把这两部分的地址统一连续起来

6.页表:存储虚拟地址到物理地址的映射关系,页表存储在物理内存中

7.操作系统、进程、与虚拟地址的关系

操作系统维护一个链表,每个进程是其中一个节点,进程访问虚拟地址(每个进程都一样,只是通过不同的映射,找到不一样的物理内存地址),经过多级页表,找到物理内存地址

虚拟地址到物理地址逻辑图(此处为32位操作系统,只有2级页表,64位则有4级页表) 

mmap理解:

进程访问数据:页表记录映射位置,当访问到某个地址的时候,通过页表中的有效位,可以得知此数据是否在内存中,如果不是,则通过缺页中断,将磁盘对应的数据拷贝到内存中,如果没有空闲内存,则选择牺牲页面,替换其他页面。

mmap是用来建立从虚拟空间到磁盘空间的映射的,可以将一个虚拟空间地址映射到一个磁盘文件上,当不设置这个地址时,则由系统自动设置,函数返回对应的内存地址(虚拟地址),当访问这个地址的时候,就需要把磁盘上的内容拷贝到内存了,然后就可以读或者写,最后通过manmap可以将内存上的数据换回到磁盘,也就是解除虚拟空间和内存空间的映射,这也是一种读写磁盘文件的方法,也是一种进程共享数据的方法。

1.write

  • 进程(用户态)将需要写入的数据直接copy到对应的mmap地址(内存copy)
  • 若mmap地址未对应物理内存,则产生缺页异常,由内核处理;若已对应,则直接copy到对应的物理内存
  • 由操作系统调用,将脏页回写到磁盘(通常是异步的)

因为物理内存是有限的,mmap在写入数据超过物理内存时,操作系统会进行页置换,根据淘汰算法,将需要淘汰的页置换成所需的新页,所以mmap对应的内存是可以被淘汰的(若内存页是"脏"的,则操作系统会先将数据回写磁盘再淘汰)。这样,就算mmap的数据远大于物理内存,操作系统也能很好地处理,不会产生功能上的问题。

2.read

普通的read调用,需要从磁盘读数据到内核态,再从内核态copy到用户态。

mmap的方式,进程可以直接访问mmap的数据(page cache)。

application在用户态,page cache在内核态,mmap直接把Page Cache映射到了用户态的地址空间里了,所以mmap的方式从磁盘读文件是没有内核态到用户态的拷贝过程的。 

其他方式补充:

 ES中的mmapfs:

1.会预读(印象中是2m,需要确认,根据局部性原理,预读出来的会比正常的页要大)到pageCache,提高查询性能

2.读写都是零拷贝,pageCache中的数据不是常驻内存的,容易出现置换,置换的时候会影响IO,性能降低,所以不是所有场景都适合使用mmapfs。所以7.x版本store默认设置为hybridfs。

----------------------------------------------------------------------------------------------------------------

如果存在理解有误的地方,欢迎指正~

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值