ES报错too-many-open-files解决

ElasticSearch 服务挂了,挂可不是进程没了,因为有 Supervisor 保护,而是服务不可用了。以前曾经出现过一次因为 ES_HEAP_SIZE 设置不当导致的服务不可用故障,于是我惯性的判断应该还是 ES_HEAP_SIZE 的问题,不过登录服务器后发现日志里显示大量的「Too many open files」错误信息。那么 ElasticSearch 设置的最大文件数到底是多少呢?可以通过 proc 确认:

shell> cat /proc/<PID>/limits

结果是「4096」,我们还可以进一步看看 ElasticSearch 打开的都是什么东西:

shell> ls /proc/<PID>/fd

问题看上去非常简单,只要加大相应的配置项应该就可以了。此配置在 ElasticSearch 里叫做 MAX_OPEN_FILES,可惜配置后发现无效。按我的经验,通常此类问题多半是由于操作系统限制所致,可是检查结果一切正常:

shell> cat /etc/security/limits.conf

* soft nofile 65535
* hard nofile 65535

问题进入了死胡同,于是我开始尝试找一些奇技淫巧看看能不能先尽快缓解一下,我搜索到 @-神仙- 的一篇文章:动态修改运行中进程的 rlimit,里面介绍了如何动态修改阈值的方法,虽然我测试时都显示成功了,可惜 ElasticSearch 还是不能正常工作:

shell> echo -n 'Max open files=65535:65535' > /proc/<PID>/limits

此外,我还检查了系统内核参数 fs.file-nr 及 fs.file-max,总之一切和文件有关的参数都查了,甚至在启动脚本里硬编码「ulimit -n 65535」,但一切努力都显得毫无意义。正当山穷水尽疑无路的时候,同事 @轩脉刃 一语道破玄机:关闭 Supervisor 的进程管理机制,改用手动方式启动 ElasticSearch 进程试试看。结果一切恢复正常。为什么会这样呢?因为使用 Supervisor 的进程管理机制,它会作为父进程 FORK 出子进程,也就是 ElasticSearch 进程,鉴于父子关系,子进程允许打开的最大文件数不能超过父进程的阈值限制,但是 Supervisor 中 minfds 指令缺省设置的允许打开的最大文件数过小,进而导致 ElasticSearch 进程出现故障。此故障原因本来非常简单,但我却陷入了经验主义的固定思维,值得反思。


在Linux下面部署应用的时候,有时候会遇上Socket/File: Can’t open so many files的问题;这个值也会影响服务器的最大并发数,其实Linux是有文件句柄限制的,而且Linux默认不是很高,一般都是1024,生产服务器用其实很容易就达到这个数量。下面说的是,如何通过正解配置来改正这个系统默认值。

查看方法

我们可以用ulimit -a来查看所有限制值
[root@centos5 ~]# ulimit -a
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
max nice                        (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 4096
max locked memory       (kbytes, -l) 32
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
max rt priority                 (-r) 0
stack size              (kbytes, -s) 10240
cpu time               (seconds, -t) unlimited
max user processes              (-u) 4096
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited||<

其中 "open files (-n) 1024 "是Linux操作系统对一个进程打开的文件句柄数量的限制

(也包含打开的SOCKET数量,可影响MySQL的并发连接数目)。

 

正确的做法,应该是修改/etc/security/limits.conf
里面有很详细的注释,比如
Hadoop  soft   nofile   32768
hadoop hard nofile 65536

hadoop soft   nproc   32768
hadoop hard nproc 65536
就可以将文件句柄限制统一改成软32768,硬65536。配置文件最前面的是指domain,设置为星号代表全局,另外你也可以针对不同的用户做出不同的限制。

注意:这个当中的硬限制是实际的限制,而软限制,是warnning限制,只会做出warning;其实ulimit命令本身就有分软硬设置,加-H就是硬,加-S就是软
默认显示的是软限制,如果运行ulimit命令修改的时候没有加上的话,就是两个参数一起改变。

RHE6及以后 nproc的修改在/etc/security/limits.d/90-nproc.conf中


补充说明:

soft nproc: 可打开的文件描述符的最大数(软限制)

hard nproc: 可打开的文件描述符的最大数(硬限制)

soft nofile:单个用户可用的最大进程数量(软限制)

hard nofile:单个用户可用的最大进程数量(硬限制)



在使用 Java 和 Elasticsearch 时遇到 "too many request" 问题,通常与请求处理的资源限制或系统配置有关。以下是几种常见的解决方法: ### 1. **调整断路器设置** Elasticsearch 的断路器机制用于防止内存溢出(OOM),但如果设置不合理,可能导致请求被拒绝。可以通过调整以下参数来优化断路器设置: - `indices.breaker.total.limit`:控制整个断路器的最大堆内存使用比例,默认为 70%。可以适当提高此值,例如设置为 `80%`。 - `indices.breaker.fielddata.limit`:控制 fielddata 断路器的最大堆内存使用比例,默认为 50%。 - `indices.breaker.request.limit`:控制请求断路器的最大堆内存使用比例,默认为 30%。 ```yaml indices.breaker.total.limit: 80% indices.breaker.fielddata.limit: 60% indices.breaker.request.limit: 40% ``` 这些设置可以避免因为内存不足而导致请求被拒绝的问题 [^3]。 ### 2. **优化 Fielddata 缓存** Fielddata 是 Elasticsearch 中用于存储字段值的内存结构,尤其在进行聚合操作时会大量使用。可以通过以下方式优化: - 使用 `indices.fielddata.cache.size` 来限制 Fielddata 缓存的大小,确保不会占用过多内存。 - 设置 `indices.breaker.total.use_real_memory: false` 来避免断路器基于实际内存使用情况进行计算,从而减少内存压力 [^3]。 ```yaml indices.fielddata.cache.size: 10% indices.breaker.total.use_real_memory: false ``` ### 3. **增加 Elasticsearch 节点资源** 如果当前 Elasticsearch 集群的硬件资源(如 CPU、内存)不足,可能会导致请求处理速度变慢,进而引发请求堆积。可以考虑以下措施: - 增加更多的 Elasticsearch 节点,以提高集群的处理能力。 - 提升现有节点的硬件资源(如增加内存、使用更快的 CPU)。 ### 4. **优化查询和聚合操作** 某些查询或聚合操作可能非常耗资源,导致请求处理缓慢。可以通过以下方式优化: - 减少不必要的聚合操作。 - 使用过滤器(filter)代替查询(query)来减少计算开销。 - 避免使用高基数字段进行聚合,因为这会显著增加内存消耗。 ### 5. **调整线程池设置** Elasticsearch 使用线程池来管理请求处理。如果线程池配置不合理,可能会导致请求排队或拒绝。可以调整以下参数: - `thread_pool.bulk.queue_size`:控制批量操作的队列大小。 - `thread_pool.index.queue_size` 和 `thread_pool.search.queue_size`:控制索引和搜索操作的队列大小。 ```yaml thread_pool.bulk.queue_size: 2000 thread_pool.index.queue_size: 1000 thread_pool.search.queue_size: 1000 ``` 这些设置可以确保 Elasticsearch 能够处理更多的并发请求 [^4]。 ### 6. **使用异步请求处理** 在 Java 应用中,使用异步请求处理可以减少阻塞,提高请求处理效率。可以使用 Jest 客户端的异步功能来发送请求: ```java JestAsyncClient client = new JestAsyncClient.Builder() .multiThreaded(true) .build(); ``` 通过异步处理,可以有效减少请求等待时间,避免请求堆积 [^1]。 ### 7. **监控和日志分析** 定期监控 Elasticsearch 集群的健康状态和资源使用情况,及时发现潜在问题。可以使用以下命令检查健康状态: ```bash curl "http://localhost:9200/_cluster/health?pretty" ``` 同时,查看 Elasticsearch 的日志文件,寻找类似 "Too many open files" 或 "Thread pool full" 的错误信息,以便进一步优化配置 [^4]。 ### 8. **限制客户端请求频率** 在客户端,可以通过限制请求频率来避免对 Elasticsearch 造成过大的压力。可以使用限流算法(如令牌桶或漏桶算法)来控制请求速率。 ```java RateLimiter rateLimiter = RateLimiter.create(100.0); // 100 requests per second for (int i = 0; i < 1000; i++) { rateLimiter.acquire(); // throttle the requests client.execute(new Index.Builder(document).build()); } ``` 通过限流,可以有效避免请求过载问题 [^1]。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值