[ 
https://issues.apache.org/jira/browse/HDDS-9032?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Duong reassigned HDDS-9032:
---------------------------

    Assignee: Duong

> CodecBuffer results in Ozone Datanode using 2 separate Netty memory pool 
> instances
> ----------------------------------------------------------------------------------
>
>                 Key: HDDS-9032
>                 URL: https://issues.apache.org/jira/browse/HDDS-9032
>             Project: Apache Ozone
>          Issue Type: Bug
>            Reporter: Duong
>            Assignee: Duong
>            Priority: Major
>
> Ozone datanode today uses 2 separated Netty memory pool (or 
> PooledByteBufAllocator) instances.
> {code:java}
> [root@myserver ~]# /usr/java/jdk-11.0.17/bin/jmap -histo 33437 | grep 
> PooledByteBufAllocator
> 2249:             2            128  
> org.apache.ratis.thirdparty.io.netty.buffer.PooledByteBufAllocator
> 3564:             2             48  
> org.apache.ratis.thirdparty.io.netty.buffer.PooledByteBufAllocator$PoolThreadLocalCache
> 4181:             2             32  
> org.apache.ratis.thirdparty.io.netty.buffer.PooledByteBufAllocator$1
> 4182:             2             32  
> org.apache.ratis.thirdparty.io.netty.buffer.PooledByteBufAllocatorMetric 
> {code}
> First pool instance is created with NettyServer (used by Ratis server and 
> Replication server). All NettyServer instances share the same 
> PooledByteBufAllocator instances (or the same direct memory pool) which is 
> created and cached by  ByteBufAllocatorPreferDirectHolder.allocator.  This 
> resolves to the usage of "io.grpc.netty.Utils#getByteBufAllocator".
> {code:java}
> public static ByteBufAllocator getByteBufAllocator(boolean forceHeapBuffer) {
>   if (Boolean.parseBoolean(
>           
> System.getProperty("org.apache.ratis.thirdparty.io.grpc.netty.useCustomAllocator",
>  "true"))) {
>     boolean defaultPreferDirect = 
> PooledByteBufAllocator.defaultPreferDirect();
>     logger.log(
>         Level.FINE,
>         String.format(
>             "Using custom allocator: forceHeapBuffer=%s, 
> defaultPreferDirect=%s",
>             forceHeapBuffer,
>             defaultPreferDirect));
>     if (forceHeapBuffer || !defaultPreferDirect) {
>       return ByteBufAllocatorPreferHeapHolder.allocator;
>     } else {
>       return ByteBufAllocatorPreferDirectHolder.allocator;
>     } {code}
> The second instance is created from the usage of 
> [CodecBuffer|https://github.com/apache/ozone/blob/master/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/utils/db/CodecBuffer.java#L85-86].
>  This CodecBuffer uses the default Netty memory pool, created and cached by 
> PooledByteBufAllocator.DEFAULT, to create temporary caches to decode/encode 
> data (from/to storage like RocksDb or network).
> {code:java}
>   private static final ByteBufAllocator POOL
>       = PooledByteBufAllocator.DEFAULT; {code}
>  
> Netty has a decent set of config to ensure its memory pool usage doesn't 
> exceed the JVM limits, aka, maxMemory and maxDirectMemory. However, as 
> there're multiple pool instances exists, Ozone service instances are prone to 
> OutOfMemoryError.
> Below are some examples of OOME we've seen from Netty.
> E1: from sending container for re-replication.
> {code:java}
> Exception in thread "ContainerReplicationThread-2" 
> java.lang.OutOfMemoryError: Direct buffer memory
>         at java.base/java.nio.Bits.reserveMemory(Bits.java:175)
>         at 
> java.base/java.nio.DirectByteBuffer.<init>(DirectByteBuffer.java:118)
>         at java.base/java.nio.ByteBuffer.allocateDirect(ByteBuffer.java:318)
>         at 
> org.apache.ratis.thirdparty.io.netty.buffer.PoolArena$DirectArena.allocateDirect(PoolArena.java:701)
>         at 
> org.apache.ratis.thirdparty.io.netty.buffer.PoolArena$DirectArena.newChunk(PoolArena.java:676)
>         at 
> org.apache.ratis.thirdparty.io.netty.buffer.PoolArena.allocateNormal(PoolArena.java:215)
>         at 
> org.apache.ratis.thirdparty.io.netty.buffer.PoolArena.tcacheAllocateNormal(PoolArena.java:197)
>         at 
> org.apache.ratis.thirdparty.io.netty.buffer.PoolArena.allocate(PoolArena.java:139)
>         at 
> org.apache.ratis.thirdparty.io.netty.buffer.PoolArena.allocate(PoolArena.java:129)
>         at 
> org.apache.ratis.thirdparty.io.netty.buffer.PooledByteBufAllocator.newDirectBuffer(PooledByteBufAllocator.java:396)
>         at 
> org.apache.ratis.thirdparty.io.netty.buffer.AbstractByteBufAllocator.directBuffer(AbstractByteBufAllocator.java:188)
>         at 
> org.apache.ratis.thirdparty.io.netty.buffer.AbstractByteBufAllocator.buffer(AbstractByteBufAllocator.java:124)
>         at 
> org.apache.ratis.thirdparty.io.grpc.netty.NettyWritableBufferAllocator.allocate(NettyWritableBufferAllocator.java:51)
>         at 
> org.apache.ratis.thirdparty.io.grpc.internal.MessageFramer.writeKnownLengthUncompressed(MessageFramer.java:230)
>         at 
> org.apache.ratis.thirdparty.io.grpc.internal.MessageFramer.writeUncompressed(MessageFramer.java:169)
>         at 
> org.apache.ratis.thirdparty.io.grpc.internal.MessageFramer.writePayload(MessageFramer.java:142)
>         at 
> org.apache.ratis.thirdparty.io.grpc.internal.AbstractStream.writeMessage(AbstractStream.java:65)
>         at 
> org.apache.ratis.thirdparty.io.grpc.internal.ForwardingClientStream.writeMessage(ForwardingClientStream.java:37)
>         at 
> org.apache.ratis.thirdparty.io.grpc.internal.DelayedStream.writeMessage(DelayedStream.java:278)
>         at 
> org.apache.ratis.thirdparty.io.grpc.internal.RetriableStream.sendMessage(RetriableStream.java:545)
>         at 
> org.apache.ratis.thirdparty.io.grpc.internal.ClientCallImpl.sendMessageInternal(ClientCallImpl.java:521)
>         at 
> org.apache.ratis.thirdparty.io.grpc.internal.ClientCallImpl.sendMessage(ClientCallImpl.java:507)
>         at 
> org.apache.ratis.thirdparty.io.grpc.internal.DelayedClientCall.sendMessage(DelayedClientCall.java:324)
>         at 
> org.apache.ratis.thirdparty.io.grpc.stub.ClientCalls$CallToStreamObserverAdapter.onNext(ClientCalls.java:374)
>         at 
> org.apache.hadoop.ozone.container.replication.SendContainerOutputStream.sendPart(SendContainerOutputStream.java:46)
>         at 
> org.apache.hadoop.ozone.container.replication.GrpcOutputStream.flushBuffer(GrpcOutputStream.java:136)
>         at 
> org.apache.hadoop.ozone.container.replication.GrpcOutputStream.write(GrpcOutputStream.java:96)
>         at 
> org.apache.commons.io.output.ProxyOutputStream.write(ProxyOutputStream.java:92)
>         at 
> org.apache.commons.compress.utils.CountingOutputStream.write(CountingOutputStream.java:48)
>         at 
> org.apache.commons.compress.utils.FixedLengthBlockOutputStream$BufferAtATimeOutputChannel.write(FixedLengthBlockOutputStream.java:244)
>         at 
> org.apache.commons.compress.utils.FixedLengthBlockOutputStream.writeBlock(FixedLengthBlockOutputStream.java:92)
>         at 
> org.apache.commons.compress.utils.FixedLengthBlockOutputStream.maybeFlush(FixedLengthBlockOutputStream.java:86)
>         at 
> org.apache.commons.compress.utils.FixedLengthBlockOutputStream.write(FixedLengthBlockOutputStream.java:122)
>         at 
> org.apache.commons.compress.archivers.tar.TarArchiveOutputStream.write(TarArchiveOutputStream.java:462)
>         at org.apache.commons.io.IOUtils.copyLarge(IOUtils.java:1310)
>         at org.apache.commons.io.IOUtils.copy(IOUtils.java:978)
>         at org.apache.commons.io.IOUtils.copyLarge(IOUtils.java:1282)
>         at org.apache.commons.io.IOUtils.copy(IOUtils.java:953)
>         at 
> org.apache.hadoop.ozone.container.keyvalue.TarContainerPacker.includeFile(TarContainerPacker.java:265)
>         at 
> org.apache.hadoop.ozone.container.keyvalue.TarContainerPacker.includePath(TarContainerPacker.java:255)
>         at 
> org.apache.hadoop.ozone.container.keyvalue.TarContainerPacker.pack(TarContainerPacker.java:167)
>         at 
> org.apache.hadoop.ozone.container.keyvalue.KeyValueContainer.packContainerToDestination(KeyValueContainer.java:940)
>         at 
> org.apache.hadoop.ozone.container.keyvalue.KeyValueContainer.exportContainerData(KeyValueContainer.java:650)
>         at 
> org.apache.hadoop.ozone.container.keyvalue.KeyValueHandler.exportContainer(KeyValueHandler.java:1046)
>         at 
> org.apache.hadoop.ozone.container.ozoneimpl.ContainerController.exportContainer(ContainerController.java:167)
>         at 
> org.apache.hadoop.ozone.container.replication.OnDemandContainerReplicationSource.copyData(OnDemandContainerReplicationSource.java:62)
>         at 
> org.apache.hadoop.ozone.container.replication.PushReplicator.replicate(PushReplicator.java:67)
>         at 
> org.apache.hadoop.ozone.container.replication.MeasuredReplicator.replicate(MeasuredReplicator.java:83)
>         at 
> org.apache.hadoop.ozone.container.replication.ReplicationTask.runTask(ReplicationTask.java:122)
>         at 
> org.apache.hadoop.ozone.container.replication.ReplicationSupervisor$TaskRunner.run(ReplicationSupervisor.java:357)
>         at 
> java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
>         at 
> java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
>         at java.base/java.lang.Thread.run(Thread.java:834)
>         Suppressed: java.io.IOException: This archive contains unclosed 
> entries.
>                 at 
> org.apache.commons.compress.archivers.tar.TarArchiveOutputStream.finish(TarArchiveOutputStream.java:291)
>                 at 
> org.apache.commons.compress.archivers.tar.TarArchiveOutputStream.close(TarArchiveOutputStream.java:309)
>                 at 
> org.apache.hadoop.ozone.container.keyvalue.TarContainerPacker.pack(TarContainerPacker.java:169)
>  {code}
> E2: From processing readChunk command (Ratis)
> {code:java}
> 2023-07-16 23:07:11,132 [ChunkReader-14] ERROR 
> org.apache.hadoop.ozone.container.common.transport.server.GrpcXceiverService: 
> Got exception when processing ContainerCommandRequestProto cmdType: ReadChunk
> traceID: ""
> containerID: 10047
> datanodeUuid: "eb5580f7-03cf-4b14-a19e-8c350fb90a6e"
> readChunk {
>   blockID {
>     containerID: 10047
>     localID: 111677748019225467
>     blockCommitSequenceId: 0
>   }
>   chunkData {
>     chunkName: "111677748019225467_chunk_13"
>     offset: 12582912
>     len: 1048576
>     checksumData {
>       type: CRC32
>       bytesPerChecksum: 1048576
>       checksums: "\334}w\374"
>     }
>   }
>   readChunkVersion: V1
> }
> encodedToken: 
> "VgoCZG4SJmNvbklEOiAxMDA0NyBsb2NJRDogMTExNjc3NzQ4MDE5MjI1NDY3GJjz7byWMSgBKAIoBDCc2Kp_OhYIg4_B_obNkNywARDIgtLMovHGp4IBIHmmC2gLI4CkpaO54_a4aoIAqmeczb5AmGk9RWEurGBHEEhERFNfQkxPQ0tfVE9LRU4mY29uSUQ6IDEwMDQ3IGxvY0lEOiAxMTE2Nzc3NDgwMTkyMjU0Njc"
> java.lang.OutOfMemoryError: Direct buffer memory
>       at java.base/java.nio.Bits.reserveMemory(Bits.java:175)
>       at java.base/java.nio.DirectByteBuffer.<init>(DirectByteBuffer.java:118)
>       at java.base/java.nio.ByteBuffer.allocateDirect(ByteBuffer.java:318)
>       at 
> org.apache.ratis.thirdparty.io.netty.buffer.PoolArena$DirectArena.allocateDirect(PoolArena.java:701)
>       at 
> org.apache.ratis.thirdparty.io.netty.buffer.PoolArena$DirectArena.newChunk(PoolArena.java:676)
>       at 
> org.apache.ratis.thirdparty.io.netty.buffer.PoolArena.allocateNormal(PoolArena.java:215)
>       at 
> org.apache.ratis.thirdparty.io.netty.buffer.PoolArena.tcacheAllocateNormal(PoolArena.java:197)
>       at 
> org.apache.ratis.thirdparty.io.netty.buffer.PoolArena.allocate(PoolArena.java:139)
>       at 
> org.apache.ratis.thirdparty.io.netty.buffer.PoolArena.allocate(PoolArena.java:129)
>       at 
> org.apache.ratis.thirdparty.io.netty.buffer.PooledByteBufAllocator.newDirectBuffer(PooledByteBufAllocator.java:396)
>       at 
> org.apache.ratis.thirdparty.io.netty.buffer.AbstractByteBufAllocator.directBuffer(AbstractByteBufAllocator.java:188)
>       at 
> org.apache.ratis.thirdparty.io.netty.buffer.AbstractByteBufAllocator.buffer(AbstractByteBufAllocator.java:124)
>       at 
> org.apache.ratis.thirdparty.io.grpc.netty.NettyWritableBufferAllocator.allocate(NettyWritableBufferAllocator.java:51)
>       at 
> org.apache.ratis.thirdparty.io.grpc.internal.MessageFramer.writeKnownLengthUncompressed(MessageFramer.java:230)
>       at 
> org.apache.ratis.thirdparty.io.grpc.internal.MessageFramer.writeUncompressed(MessageFramer.java:169)
>       at 
> org.apache.ratis.thirdparty.io.grpc.internal.MessageFramer.writePayload(MessageFramer.java:142)
>       at 
> org.apache.ratis.thirdparty.io.grpc.internal.AbstractStream.writeMessage(AbstractStream.java:65)
>       at 
> org.apache.ratis.thirdparty.io.grpc.internal.ServerCallImpl.sendMessageInternal(ServerCallImpl.java:172)
>       at 
> org.apache.ratis.thirdparty.io.grpc.internal.ServerCallImpl.sendMessage(ServerCallImpl.java:154)
>       at 
> org.apache.ratis.thirdparty.io.grpc.stub.ServerCalls$ServerCallStreamObserverImpl.onNext(ServerCalls.java:380)
>       at 
> org.apache.hadoop.ozone.container.common.transport.server.GrpcXceiverService$1.onNext(GrpcXceiverService.java:58)
>       at 
> org.apache.hadoop.ozone.container.common.transport.server.GrpcXceiverService$1.onNext(GrpcXceiverService.java:50)
>       at 
> org.apache.ratis.thirdparty.io.grpc.stub.ServerCalls$StreamingServerCallHandler$StreamingServerCallListener.onMessage(ServerCalls.java:262)
>       at 
> org.apache.ratis.thirdparty.io.grpc.ForwardingServerCallListener.onMessage(ForwardingServerCallListener.java:33)
>       at 
> org.apache.hadoop.hdds.tracing.GrpcServerInterceptor$1.onMessage(GrpcServerInterceptor.java:49)
>       at 
> org.apache.ratis.thirdparty.io.grpc.internal.ServerCallImpl$ServerStreamListenerImpl.messagesAvailableInternal(ServerCallImpl.java:333)
>       at 
> org.apache.ratis.thirdparty.io.grpc.internal.ServerCallImpl$ServerStreamListenerImpl.messagesAvailable(ServerCallImpl.java:316)
>       at 
> org.apache.ratis.thirdparty.io.grpc.internal.ServerImpl$JumpToApplicationThreadServerStreamListener$1MessagesAvailable.runInContext(ServerImpl.java:835)
>       at 
> org.apache.ratis.thirdparty.io.grpc.internal.ContextRunnable.run(ContextRunnable.java:37)
>       at 
> org.apache.ratis.thirdparty.io.grpc.internal.SerializingExecutor.run(SerializingExecutor.java:133)
>       at 
> java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
>       at 
> java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
>       at java.base/java.lang.Thread.run(Thread.java:834){code}
>  
> {*}Solution{*}: CodecBuffer should use the same memory pool from 
> io.grpc.netty.Utils#getByteBufAllocator.
>  



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to