Is there any plan to support monitoring queue size of EventLoopGroup?
See original GitHub issueExpected behavior
Although it is clear that we should never block a thread in the EventLoopGroup, sometimes you will have to invoke some RPC methods or query something from a redis server, this blocks your thread. I can avoid this by make these time costing calls executed in a separate thread pool, but by doing this way, it will result in more context switches. But if i invoke time costing methods in the thread of the EventLoopGroup, i would like to monitor the status of these threads.
The methods provided now is pendingTasks()
, but when it comes to NioEventLoop or EpollEventLoop, it is forced to be invoked in the current event loop, which will be scheduled to be invoked later if you call the method in a separate thread, and if all the threads are busy, you will get the result after quite long time, and the result is not accurate at all.
I have tried another way to monitor the EventLoopGroups, like this:
public class EventLoopMonitor {
static class ThreadInfo {
private String threadName;
private int pendingTasks;
private long updateTime;
public ThreadInfo(String threadName, int pendingTasks) {
this.threadName = threadName;
this.pendingTasks = pendingTasks;
}
public String getThreadName() {
return threadName;
}
public int getPendingTasks() {
// if haven't been updated for more than 5 seconds, set pendingTasks to 0
if (pendingTasks > 0 && (System.currentTimeMillis() - updateTime) > 5000) {
pendingTasks = 0;
}
return pendingTasks;
}
public void updatePendingTasks(int pendingTasks) {
this.pendingTasks = pendingTasks;
this.updateTime = System.currentTimeMillis();
}
}
private static final Map<String, ThreadInfo> threadInfoMap = new HashMap<String, ThreadInfo>();
private static ThreadLocal<ThreadInfo> threadInfoCache = new ThreadLocal<ThreadInfo>() {
@Override
protected ThreadInfo initialValue() {
ThreadInfo threadInfo = new ThreadInfo(Thread.currentThread().getName(), 0);
threadInfoMap.put(threadInfo.getThreadName(), threadInfo);
return threadInfo;
}
};
static Map<String, Object> monitor() {
if (threadInfoMap.isEmpty()) {
return Collections.emptyMap();
}
Map<String, Object> result = new HashMap<String, Object>();
int total = 0;
for (ThreadInfo threadInfo : threadInfoMap.values()) {
int pendingTasks = threadInfo.getPendingTasks();
result.put("task-" + threadInfo.getThreadName(), pendingTasks);
total += pendingTasks;
}
result.put("task-total", total);
return result;
}
public static void monitor(EventLoop eventLoop) {
if (!eventLoop.inEventLoop()) {
return;
}
if (eventLoop instanceof SingleThreadEventLoop) {
ThreadInfo threadInfo = threadInfoCache.get();
int pendingTasks = ((SingleThreadEventLoop) eventLoop).pendingTasks();
threadInfo.updatePendingTasks(pendingTasks);
}
}
}
and it will be invoked like this:
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
EventLoopMonitor.monitor(ctx.channel().eventLoop());
...
and this:
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise)
throws Exception {
EventLoopMonitor.monitor(ctx.channel().eventLoop());
But i think it is better that the netty provides a better way for us, what do you guys think?
Netty version
4.1.5 Final
Issue Analytics
- State:
- Created 5 years ago
- Comments:6 (2 by maintainers)
Top GitHub Comments
@medusar upgrade to the latest netty 4.1.x version. You can call
pendingTasks()
from any threads these days.Great, thank you very much