Skip to content

Commit 6582ef8

Browse files
committed
Change netty pool chunk size to respect G1 region (#62410)
Currently the netty pool chunk size defaults to 16MB. The number does not play well with the G1GC which causes this to consume entire regions. Additionally, we normally allocated arrays of size 64KB or less. This means that Elasticsearch could handle a smaller pool chunk size to play nicer with the G1GC.
1 parent b2db11d commit 6582ef8

File tree

2 files changed

+76
-6
lines changed

2 files changed

+76
-6
lines changed

modules/transport-netty4/src/main/java/org/elasticsearch/transport/Netty4Plugin.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919

2020
package org.elasticsearch.transport;
2121

22+
import org.apache.logging.log4j.LogManager;
23+
import org.apache.logging.log4j.Logger;
2224
import org.apache.lucene.util.SetOnce;
2325
import org.elasticsearch.Version;
2426
import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
@@ -49,8 +51,14 @@ public class Netty4Plugin extends Plugin implements NetworkPlugin {
4951
public static final String NETTY_TRANSPORT_NAME = "netty4";
5052
public static final String NETTY_HTTP_TRANSPORT_NAME = "netty4";
5153

54+
private static final Logger logger = LogManager.getLogger(Netty4Plugin.class);
55+
5256
private final SetOnce<SharedGroupFactory> groupFactory = new SetOnce<>();
5357

58+
public Netty4Plugin() {
59+
logger.info("creating NettyAllocator with the following configs: " + NettyAllocator.getAllocatorDescription());
60+
}
61+
5462
@Override
5563
public List<Setting<?>> getSettings() {
5664
return Arrays.asList(

modules/transport-netty4/src/main/java/org/elasticsearch/transport/NettyAllocator.java

Lines changed: 68 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,32 +29,68 @@
2929
import io.netty.channel.socket.nio.NioServerSocketChannel;
3030
import io.netty.channel.socket.nio.NioSocketChannel;
3131
import org.elasticsearch.common.Booleans;
32+
import org.elasticsearch.common.unit.ByteSizeValue;
3233
import org.elasticsearch.monitor.jvm.JvmInfo;
3334

3435
public class NettyAllocator {
3536

3637
private static final ByteBufAllocator ALLOCATOR;
38+
private static final String DESCRIPTION;
3739

3840
private static final String USE_UNPOOLED = "es.use_unpooled_allocator";
3941
private static final String USE_NETTY_DEFAULT = "es.unsafe.use_netty_default_allocator";
42+
private static final String USE_NETTY_DEFAULT_CHUNK = "es.unsafe.use_netty_default_chunk_and_page_size";
4043

4144
static {
4245
if (Booleans.parseBoolean(System.getProperty(USE_NETTY_DEFAULT), false)) {
4346
ALLOCATOR = ByteBufAllocator.DEFAULT;
47+
DESCRIPTION = "[name=netty_default, factors={es.unsafe.use_netty_default_allocator=true}]";
4448
} else {
49+
final long heapSizeInBytes = JvmInfo.jvmInfo().getMem().getHeapMax().getBytes();
50+
final boolean g1gcEnabled = Boolean.parseBoolean(JvmInfo.jvmInfo().useG1GC());
51+
final long g1gcRegionSizeInBytes = JvmInfo.jvmInfo().getG1RegionSize();
52+
final boolean g1gcRegionSizeIsKnown = g1gcRegionSizeInBytes != -1;
53+
ByteSizeValue heapSize = new ByteSizeValue(heapSizeInBytes);
54+
ByteSizeValue g1gcRegionSize = new ByteSizeValue(g1gcRegionSizeInBytes);
55+
4556
ByteBufAllocator delegate;
46-
if (useUnpooled()) {
57+
if (useUnpooled(heapSizeInBytes, g1gcEnabled, g1gcRegionSizeIsKnown, g1gcRegionSizeInBytes)) {
4758
delegate = UnpooledByteBufAllocator.DEFAULT;
59+
DESCRIPTION = "[name=unpooled, factors={es.unsafe.use_unpooled_allocator=" + userForcedUnpooled()
60+
+ ", g1gc_enabled=" + g1gcEnabled
61+
+ ", g1gc_region_size=" + g1gcRegionSize
62+
+ ", heap_size=" + heapSize + "}]";
4863
} else {
4964
int nHeapArena = PooledByteBufAllocator.defaultNumHeapArena();
50-
int pageSize = PooledByteBufAllocator.defaultPageSize();
51-
int maxOrder = PooledByteBufAllocator.defaultMaxOrder();
65+
int pageSize;
66+
int maxOrder;
67+
if (useDefaultChunkAndPageSize()) {
68+
pageSize = PooledByteBufAllocator.defaultPageSize();
69+
maxOrder = PooledByteBufAllocator.defaultMaxOrder();
70+
} else {
71+
pageSize = 8192;
72+
if (g1gcEnabled == false || g1gcRegionSizeIsKnown == false || g1gcRegionSizeInBytes >= (4 * 1024 * 1024)) {
73+
// This combined with a 8192 page size = 1 MB chunk sizes
74+
maxOrder = 7;
75+
} else if (g1gcRegionSizeInBytes >= (2 * 1024 * 1024)) {
76+
// This combined with a 8192 page size = 512 KB chunk sizes
77+
maxOrder = 6;
78+
} else {
79+
// This combined with a 8192 page size = 256 KB chunk sizes
80+
maxOrder = 5;
81+
}
82+
}
5283
int tinyCacheSize = PooledByteBufAllocator.defaultTinyCacheSize();
5384
int smallCacheSize = PooledByteBufAllocator.defaultSmallCacheSize();
5485
int normalCacheSize = PooledByteBufAllocator.defaultNormalCacheSize();
5586
boolean useCacheForAllThreads = PooledByteBufAllocator.defaultUseCacheForAllThreads();
5687
delegate = new PooledByteBufAllocator(false, nHeapArena, 0, pageSize, maxOrder, tinyCacheSize,
5788
smallCacheSize, normalCacheSize, useCacheForAllThreads);
89+
ByteSizeValue chunkSize = new ByteSizeValue(pageSize << maxOrder);
90+
DESCRIPTION = "[name=elasticsearch_configured, chunk_size=" + chunkSize
91+
+ ", factors={es.unsafe.use_netty_default_chunk_and_page_size=" + useDefaultChunkAndPageSize()
92+
+ ", g1gc_enabled=" + g1gcEnabled
93+
+ ", g1gc_region_size=" + g1gcRegionSize + "}]";
5894
}
5995
ALLOCATOR = new NoDirectBuffers(delegate);
6096
}
@@ -64,6 +100,10 @@ public static ByteBufAllocator getAllocator() {
64100
return ALLOCATOR;
65101
}
66102

103+
public static String getAllocatorDescription() {
104+
return DESCRIPTION;
105+
}
106+
67107
public static Class<? extends Channel> getChannelType() {
68108
if (ALLOCATOR instanceof NoDirectBuffers) {
69109
return CopyBytesSocketChannel.class;
@@ -80,12 +120,34 @@ public static Class<? extends ServerChannel> getServerChannelType() {
80120
}
81121
}
82122

83-
private static boolean useUnpooled() {
123+
private static boolean useUnpooled(long heapSizeInBytes, boolean g1gcEnabled, boolean g1gcRegionSizeIsKnown, long g1RegionSize) {
124+
if (userForcedUnpooled()) {
125+
return true;
126+
} else if (heapSizeInBytes <= 1 << 30) {
127+
// If the heap is 1GB or less we use unpooled
128+
return true;
129+
} else if (g1gcEnabled == false) {
130+
return false;
131+
} else {
132+
// If the G1GC is enabled and the region size is known and is less than 1MB we use unpooled.
133+
boolean g1gcRegionIsLessThan1MB = g1RegionSize < 1 << 20;
134+
return (g1gcRegionSizeIsKnown && g1gcRegionIsLessThan1MB);
135+
}
136+
}
137+
138+
private static boolean userForcedUnpooled() {
84139
if (System.getProperty(USE_UNPOOLED) != null) {
85140
return Booleans.parseBoolean(System.getProperty(USE_UNPOOLED));
86141
} else {
87-
long heapSize = JvmInfo.jvmInfo().getMem().getHeapMax().getBytes();
88-
return heapSize <= 1 << 30;
142+
return false;
143+
}
144+
}
145+
146+
private static boolean useDefaultChunkAndPageSize() {
147+
if (System.getProperty(USE_NETTY_DEFAULT_CHUNK) != null) {
148+
return Booleans.parseBoolean(System.getProperty(USE_NETTY_DEFAULT_CHUNK));
149+
} else {
150+
return false;
89151
}
90152
}
91153

0 commit comments

Comments
 (0)