提到Elasticsearch,让笔者最恶心的倒不是它的反人类的DSL设计,而是每次安装都需要修改进程的最大文件描述符。那ES与文件描述符有啥恩怨呢,下面就来唠叨唠叨。首先说说文件描述符、在说说ES为什么要这么多文件描述符。
文件描述符(File descriptor)是操作系统为了高效管理文件所创建的一种索引,用于指向被打开的文件,所有I/O操作都是通过文件描述符来实现。有的地方也会说成是文件句柄,他俩有些区别,这里为了方便理解,暂且认为一样。
如果以文件句柄(File Handle)来理解的话,也很形象。Handle是门把手的意思,我们用门把手操作门,类似的,进程用文件句柄操作底层操作系统的资源。
在linux中,遵循一切皆是文件的原则,磁盘文件、目录、设备、网络套接字、硬件等都是文件。当进程读写文件,在打开时,文件和进程就建立了连接,文件描述符就是这个连接。
文件描述符实际上就是对内核层的一个硬件资源实例的指针的引用。当然啦,它和指针也是有区别的,指针是栈上的变量,用来操作堆内存里的对象。
文件描述符在系统里的位置见下图:
这里还用门把手举例。一扇门如果有多个把手,被不同的人操作,那门往哪儿走就不确定了,很容易出现争论。为了避免这种情况,门只有一个把手。
为了解决系统资源浪费和资源冲突的问题,操作系统不会让每个用户层的进程都在内核层创建一个硬件资源实例。在操作同一个系统硬件资源时,用户层可能有多个进程,但是都对应到内核层的一个进程。
操作系统会为进程设置一个默认的可以操作的文件描述符数量,进程打开的文件数量或者需要的文件数量超过这个数字时就会抛出异常。
通过ulimit -a命令可以查看可操作的文件描述符数量。通过vim /etc/security/limits.con可以修改进程可操作性的文件描述符数量。
在说ES为什么要这么多文件描述符之前,先简单说说ES写入数据的过程。
假设有3个节点:node1、node2、node3,其中node2是主节点,写入数据的主要流程如下:
ES写入数据的细节流程分为4步:Refresh操作、写Transaction Log、Flush操作***、Merge***操作。
通过以上ES写数据的流程可以知道,ES在每次Refresh时都会创建新的Segment,创建索引的过程中会创建大量的Segment。Segment内部一般包含着:词项、词频、文档之间的关系。每个Segment都是一个文件,ES使用了大量的文件。每一个Segment都会消耗文件描述符、内存和CPU运行周期。同时,ES 在节点之间进行通信和数据拷贝、ES在和客户端之间进行通信等,也使用了大量的网络资源。
基于以上原因,ES需要大量的文件描述符。Linux 系统为进程准备了一个默认的文件描述符数量,但是这对ES节点来说有点低了,所以要调大文件描述符数量。
lsof命令是Linux系统管理工具,人如其名,“列出打开文件(lists openfiles)”。
lsof -p pid命令:显示系统中某个进程当前已打开的所有文件列表。
执行lsof -p 29624时,可以看到大量的文件,索引越多,写入的数据越多,文件描述符数量越多。
执行lsof -p 29624|wc -l,可以查看进程打开文件的总数。
1、大量新的数据源源不断的快速写入到ES,造成临时的Segment文件越来越多,ES无法快速合并成一个大的Segment。在查询时,如果查询的数据对应到多个Segment,那么打开的文件描述符就很多了。
2、机器内存过小,资源紧张时内存不够,会触发OOM-Killer将ES进程杀死,其实是一种假死的,因为进程被Kill掉之后,保活进程又会将ES重启,而每次重启后都会产生新的translog文件,并且没有把之前旧的日志文件删除,最终把系统的文件描述符耗尽。
3、如果还有其余场景的话,欢迎朋友们在留言区补充。
本文主要说了 文件描述符 和 ES为什么要这么多文件描述符,希望对你有帮助,核心概念如下:
本篇完结!感谢你的阅读,欢迎点赞 关注 收藏 私信!!!