elastic 内存

1、JVM heap

ES 建议分配不超过 50% 的内存给 JVM,同时总量不要大于 32 GB。

# 设置 max heap size
export ES_HEAP_SIZE=10g

# 查看当前 max heap size
GET /_cat/nodes?h=heap.max

JVM 使用的内存越小,留给 Lucene 的内存就越多,就可以有更多的内存作为缓存,提高性能。但是 JVM 的内存也不能太小,否则会导致 OOM 或 FullGC,而这会导致节点超时被移出,shards reallocate 又会极大的影响性能。

ES 有两个组件需要使用内存:

  • JVM
  • Lucene

JVM 主要存放各种 in-memory 的数据结构,Lucene 负责底层的存储。因为 Lucene 依赖操作系统的缓存机制,而操作系统会把所有的空闲内存分配为 page cache,所以如果 JVM heap 过大,会导致 segment 没有足够的 cache。

64 位的指针会带来额外的性能开销,为了提高性能,Java 会采用 compressed oops 的技术,依然使用 32 位的指针,不过指针用来表示 object offsets,此时一个 32 位指针可以表示 4 G 的 object,而不是 4 G 的 bytes,这种情况下,可以让 heap 的空间达到 32 GB。但如果给 heap 分配的空间超过 32 GB,Java 就会采用 64 bit 的 ordinary object pointers(OOP),运行性能会出现显著下降,据估测,heap 大小达到 40-50 GB 时,性能才与 32 GB 时相同。

如果机器内存远大于 32 GB,也建议不要给 heap 设置超过 32 GB 的内存,可以考虑把机器划分为多个 64 GB 内存的节点,然后每个节点分配 32 GB heap。

2、GC

JVM 会申请一大块内存,称为 heap。heap 中的所有对象会被分为两个集合:Young(Eden)和 Old,一般来说 Old 的空间会显著的大于 Young。

每当 Young 的空间耗尽时,就会启动 young gc,所有幸存的对象会被标记为 survivor,如果一个对象连续两次被标记为 survivor,就会被放入 Old。Old 类似,空间耗尽时会触发 old gc。这两种 GC 都会导致 stop-the-world。不过因为 young 空间较小,gc 耗时一般也很短。带来严重暂停的一般都是 old gc。

ES 默认当 JVM heap 超过 75% 的时候启动 GC,所以应该监控 heap 使用率超过 80% 的情形,此时 gc 已无法有效的清理内存。默认的 heap 是 1GB,这个值太小,实际上线时要根据内存大小进行调整(一般小于 50% 内存)。但是 JVM heap 太大时,会导致 GC 时间过长。如果超过 30s 无响应,就会被 master 移出集群。

相关指标:

  • jvm.gc.collectors.young.collection_count
  • jvm.gc.collectors.young.collection_time_in_millis
  • jvm.gc.collectors.old.collection_count
  • jvm.gc.collectors.old.collection_time_in_millis
  • jvm.mem.heap_used_percent
  • jvm.mem.heap_committed_in_bytes

CMS & G1

ES 默认使用 CMS,在 Heap 较大时性能会比较差(更长的 Stop-the-world),相较之下 G1 在大 heap 时性能更好,但是 ES 官方不推荐使用 G1,因为 Lucene 在 G1 下会出现数据丢失的 bug。

Do not, under any circumstances, run Lucene with the G1 garbage collector. Lucene’s test suite fails with the G1 garbage collector on a regular basis, including bugs that cause index corruption. There is no person on this planet that seems to understand such bugs (see https://bugs.openjdk.java.net/browse/JDK-8038348, open for over a year), so don’t count on the situation changing soon.

3、swap

要尽一切可能避免系统 swap 内存。

不建议直接关闭 swap,应该调整 swappiness 来让系统降低 swap 的频率。swappiness 的取值范围为 0-100,0 表示仅在 OOM 时 swap,100 表示系统会尽一切可能 swap,默认值为 60,ES 建议设置为 1。

# 查询 swappiness
cat /proc/sys/vm/swappiness

# 设置
sudo vi /etc/sysctl.conf
vm.swappiness = 1

如果无法修改系统参数,可以修改 ES 的参数 mlockall,该参数会让 JVM 锁定进程的地址空间始终在内存内,避免被 swap:

bootstrap.memory_lock: true

# 查看是否启用 mlockall
GET _nodes?filter_path=**.mlockall

发表评论

邮箱地址不会被公开。 必填项已用*标注