使用Netty模擬發生OOM
我們模擬這麼一個場景,客戶端和服務端都使用Netty進行通訊,客戶端無限迴圈地向服務端傳送資料,過了一會客戶端就會出現OOM,我們分析OOM產生的原因,給我們排查線上問題提供一個思路和角度.
以下所有的分析都是基於以上描述的場景
本文適合對Netty要有一定的基礎
程式碼放在了github上
設定的客戶端虛擬機器引數
-XX:MetaspaceSize=18M
-XX:MaxMetaspaceSize=18M
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=D:\heapdump.hprof
-Xmx1000M
-XX:+PrintGC
-XX:+PrintGCDetails
為了講解方便,我把一些主要程式碼貼上如下
客戶端程式碼
EventLoopGroup group = new NioEventLoopGroup();
EventLoopGroup businessGroup = new NioEventLoopGroup(8);
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(group)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<NioSocketChannel>() {
@Override
protected void initChannel(NioSocketChannel ch) {
ChannelPipeline channelPipeline = ch.pipeline();
channelPipeline.addLast(new StringDecoder());// Netty自帶的字串解碼器
channelPipeline.addLast(new StringEncoder());// Netty自帶的字串編碼器
channelPipeline.addLast(businessGroup, new ClientHandler());// 自定義處理器
}
});
---
public class ClientHandler extends SimpleChannelInboundHandler<String> {
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
// Channel啟用之後,便無限迴圈地向服務端傳送資料
int i = 0;
for (;;) {
ctx.writeAndFlush("這個是客戶端傳送的第" + ++i + "個訊息");
}
}
}
由於服務端只是接收資料,沒有特殊地方,這裡就不貼上程式碼了.
先啟動服務端,在啟動客戶端.
客戶端就會連線服務端,通道建立之後,業務執行緒就會無限迴圈地向服務端傳送資料.
你也可以通過JDK自帶的工具觀察記憶體的變化.
當程式執行一會之後,就會出現OOM異常
我們這裡通過MAT工具分析下堆空間資訊
匯入檔案.(至於怎麼使用MAT工具這裡不做介紹)
我們會發現taskQueue中有非常多的Task,這是因為向對端寫資料的操作必須是IO執行緒來完成,業務執行緒只能把它的需求封裝成一個Task放在IO執行緒的任務佇列中.
// 原始碼位置: io.netty.channel.AbstractChannelHandlerContext#write(java.lang.Object, boolean, io.netty.channel.ChannelPromise)
private void write(Object msg, boolean flush, ChannelPromise promise) {
final AbstractChannelHandlerContext next = findContextOutbound(flush ?
(MASK_WRITE | MASK_FLUSH) : MASK_WRITE);
final Object m = pipeline.touch(msg, next);
EventExecutor executor = next.executor();
if (executor.inEventLoop()) {// 判斷當前執行緒是否是IO執行緒
if (flush) {
next.invokeWriteAndFlush(m, promise);
} else {
next.invokeWrite(m, promise);
}
} else {
final AbstractWriteTask task;
if (flush) {
// 由於當前執行緒不是IO執行緒,所以只能封裝成一個Task,放入到佇列中
task = WriteAndFlushTask.newInstance(next, m, promise);
} else {
task = WriteTask.newInstance(next, m, promise);
}
// Task放入到佇列
if (!safeExecute(executor, task, promise, m)) {
task.cancel();
}
}
}
由於業務執行緒是無限迴圈地寫入資料,導致佇列中的Task一直增多,最後導致OOM
一方面可能是服務端處理的比較慢,導致服務端TCP緩衝區滿了,那麼客戶端的TCP緩衝區也會被寫滿,Netty就不能成功的寫入TCP緩衝區,那麼資料只能放在佇列中,最後導致OOM.(當然我們這裡不是因為這個原因,我們的服務端只是接收資料,沒有任何業務耗時操作)
也有可能是網路等原因,導致客戶端IO執行緒傳送的比較慢(業務執行緒生成的資料比較快).
或者也有其他的原因.
Netty給我們提供了高低水位機制,當我們業務執行緒向Netty寫入的資料過多的時候,一旦達到了高水位值(這個值我們可以設定),Netty就會設定Channel不可能.但是這裡注意了,這裡只是設定成不可能,我們還是依然可以向Netty中寫入資料.但是如果我們忽略它,有可能造成上面這種OOM情況.
因此我們可以基於Netty提供的這種機制,控制我們的業務執行緒向Netty寫入資料的速率.如果達到了高水位值,我們就暫時不要向Netty中寫入資料,也就不會導致OOM發生.
我們改寫客戶端程式碼
public class ClientHandler extends SimpleChannelInboundHandler<String> {
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
// 設定高水位值(當然不一定非要在此處設定)
ctx.channel().config().setWriteBufferHighWaterMark(20 * 1024 * 1024);
int i = 0;
for (;;) {
// 通道可寫
if (ctx.channel().isWritable()) {
ctx.writeAndFlush("這個是客戶端傳送的第" + ++i + "個訊息");
} else {// 通道不可寫
System.out.println("達到高水位,暫時不可寫");
}
}
}
}
以上程式碼也只是作為一個思路.
公眾號
相關文章
- 雷達報文模擬回放/雷達資料模擬發生器
- Openwrt使用Qemu模擬開發。
- Vivado DDS IP核使用和模擬(一、單通道訊號發生器)
- Java使用程式碼模擬高併發操作Java
- 光學數字孿生系統模擬
- 模擬web高併發Web
- JavaScript 模擬事件觸發JavaScript事件
- Oracle模擬併發指令碼Oracle指令碼
- 在 Node 服務中發生 OOM 時,如何監控記憶體?OOM記憶體
- 使用 node 模擬請求介面
- 一次生產環境OOM排查OOM
- Laravel 高併發搶購模擬Laravel
- 併發模擬-程式碼CountDownLatch,SemaphoreCountDownLatch
- 8、SSH埠轉發情景模擬
- 使用模擬器混淆前端程式碼前端
- python使用Cookie模擬登入PythonCookie
- 爬蟲方式(模擬使用者)爬蟲
- 模擬
- 使用JVisualVM分析OOMLVMOOM
- 模擬產生CBC LATCH與buffer busy wait等待事件AI事件
- 精通併發與 Netty (一)如何使用Netty
- iOS開發中,whistle的安裝使用及模擬器代理配置iOS
- 使用 mock 模擬登入介面資料Mock
- 使用 Netcat 模擬 HTTP 請求HTTP
- Mac 安卓Studio使用外部模擬器Mac安卓
- 使用OkHttp模擬登陸LeetCodeHTTPLeetCode
- 使用mumu模擬器抓包 andriod appAPP
- 如何使用ChatGPT模擬MySQL資料庫ChatGPTMySql資料庫
- 夜神安卓模擬器使用介紹安卓
- 使用Docker+Nginx模擬負載均衡DockerNginx負載
- Dynamics 365 Web API模擬使用者WebAPI
- 使用Python中的字典模擬類Python
- 使用PL/SQL模擬SQLLOAD的功能SQL
- 使用KFOD模擬ASM DISK DISCOVERY過程ASM
- Mock 工具使用 - 模擬弱網測試Mock
- 10.6 模擬賽(NOIP 模擬賽 #9)
- 有限元模擬 有限體積模擬
- iOS開發實踐-OOM治理iOSOOM