Skip to content

Commit 326286a

Browse files
authored
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 b9b863f commit 326286a

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
@@ -28,32 +28,68 @@
2828
import io.netty.channel.ServerChannel;
2929
import io.netty.channel.socket.nio.NioServerSocketChannel;
3030
import org.elasticsearch.common.Booleans;
31+
import org.elasticsearch.common.unit.ByteSizeValue;
3132
import org.elasticsearch.monitor.jvm.JvmInfo;
3233

3334
public class NettyAllocator {
3435

3536
private static final ByteBufAllocator ALLOCATOR;
37+
private static final String DESCRIPTION;
3638

3739
private static final String USE_UNPOOLED = "es.use_unpooled_allocator";
3840
private static final String USE_NETTY_DEFAULT = "es.unsafe.use_netty_default_allocator";
41+
private static final String USE_NETTY_DEFAULT_CHUNK = "es.unsafe.use_netty_default_chunk_and_page_size";
3942

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

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

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

0 commit comments

Comments
 (0)