We couldn't find any direct way to log Mongo Connection pool Size. So, we did implement an indirect way as below.
This may be incorrect at times when dealing with Sharded MongoDB having Primaty & Secondary nodes. Because, connection may be used based on read prefrence - Primary, primaryPreferred, Secondary, etc.
But, this gives an understanding if connections are used efficiently and there is no wait to acquire connections from pool. This can be further enhanced to log correct connection pool statistics.
1) Implement MyConnectionPoolListener as below -
import java.util.concurrent.atomic.AtomicInteger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.mongodb.event.ConnectionCheckOutFailedEvent;
import com.mongodb.event.ConnectionCheckOutStartedEvent;
import com.mongodb.event.ConnectionCheckedInEvent;
import com.mongodb.event.ConnectionCheckedOutEvent;
import com.mongodb.event.ConnectionClosedEvent;
import com.mongodb.event.ConnectionCreatedEvent;
import com.mongodb.event.ConnectionPoolListener;
/**
* Connection pool listener
*/
public class MyConnectionPoolListener implements ConnectionPoolListener {
private final AtomicInteger size = new AtomicInteger();
private final AtomicInteger checkedOutCount = new AtomicInteger();
private final AtomicInteger waitQueueSize = new AtomicInteger();
private Logger logger = LoggerFactory.getLogger(MyConnectionPoolListener.class);
/**
* Get Total number of Connections
*
* @return
*/
public int getSize() {
return size.get();
}
/**
* Get number of connections checkedOut or are in use
*
* @return
*/
public int getCheckedOutCount() {
return checkedOutCount.get();
}
/**
* Get Wait Queue Size
* @return
*/
public int getWaitQueueSize() {
return waitQueueSize.get();
}
@Override
public void connectionCheckedOut(final ConnectionCheckedOutEvent event) {
int v = checkedOutCount.incrementAndGet();
int p = waitQueueSize.decrementAndGet();
logger.debug("connectionCheckedOut ID [{}], Active Count [{}], Wait Queue Size [{}]", event.getConnectionId().getServerId(), v, p);
}
@Override
public void connectionCheckedIn(final ConnectionCheckedInEvent event) {
int v = checkedOutCount.decrementAndGet();
logger.debug("connectionCheckedIn ID [{}], Active Count [{}]", event.getConnectionId().getServerId(), v);
}
@Override
public void connectionCreated(final ConnectionCreatedEvent event) {
int v = size.incrementAndGet();
logger.debug("connectionCreated ID [{}], Total Size [{}]", event.getConnectionId().getServerId(), v);
}
@Override
public void connectionClosed(final ConnectionClosedEvent event) {
int v = size.decrementAndGet();
logger.debug("connectionClosed ID [{}], Total Size [{}]", event.getConnectionId().getServerId(), v);
}
@Override
public void connectionCheckOutFailed(ConnectionCheckOutFailedEvent event) {
int v = waitQueueSize.decrementAndGet();
logger.debug("connectionCheckOutFailed ID [{}], Wait Queue Size [{}]", event.getServerId(), v);
}
@Override
public void connectionCheckOutStarted(ConnectionCheckOutStartedEvent event) {
int v = waitQueueSize.incrementAndGet();
logger.debug("connectionCheckOutFailed ID [{}], Wait Queue Size [{}]", event.getServerId(), v);
}
}
2) Implement MongoConfig as below -
import static org.bson.codecs.configuration.CodecRegistries.fromProviders;
import static org.bson.codecs.configuration.CodecRegistries.fromRegistries;
import org.bson.codecs.configuration.CodecRegistry;
import org.bson.codecs.pojo.PojoCodecProvider;
import org.springframework.boot.autoconfigure.mongo.MongoClientSettingsBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import com.mongodb.MongoClientSettings;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.binder.mongodb.MongoMetricsCommandListener;
@Component
public class MongoConfig {
private MyConnectionPoolListener myCpL = new MyConnectionPoolListener();
public final CodecRegistry pojoCodecRegistry = fromRegistries(MongoClientSettings.getDefaultCodecRegistry(),
fromProviders(PojoCodecProvider.builder().automatic(true).build()));
@Bean
public MongoClientSettingsBuilderCustomizer mongoClientSettingsBuilderCustomizer(MeterRegistry meterRegistry) {
return builder -> builder.addCommandListener(new MongoMetricsCommandListener(meterRegistry))
.applyToConnectionPoolSettings(block -> block.addConnectionPoolListener(myCpL));
}
public MyConnectionPoolListener getMyCpL() {
return myCpL;
}
}
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;
@Component
@EnableScheduling
public class PoolMonitor {
public Logger logger = LoggerFactory.getLogger(PoolMonitor.class);
private final MongoConfig mongoConfig;
public PoolMonitor(MongoConfig mongoConfig) {
this.mongoConfig = mongoConfig;
}
@Scheduled(fixedDelay = 20000)
public void monitor() {
MyConnectionPoolListener myConnectionPoolListener = mongoConfig.getMyCpL();
logger.info("MongoDB Created Connection Pool Size [{}], Active Used Connection [{}], Wait Queue Size [{}]",
myConnectionPoolListener.getSize(), myConnectionPoolListener.getCheckedOutCount(), myConnectionPoolListener.getWaitQueueSize());
}
}
Comments
Post a Comment