PengJingzhao opened a new issue, #7271:
URL: https://github.com/apache/incubator-seata/issues/7271

   # Background
   
现在的seata的rm在和数据库交互的时候使用到了druid作为数据库连接池,通过druid的DruidDataSource对象可以很方便的知道此时的连接池的各项指标,包括当前活跃连接数,空闲连接数,最大连接数等等。但是seata缺少相应的指标收集和监控机制,使得连接池的实时状态难以知晓。
   
   # Proposal
   
我的大致思路是通过一个定时执行的线程来收集连接池的指标,缓存到一个LinkedBlockingQueue中,并且通过一个sender批量发送到其他服务做进一步的处理和展示。
   
   我编写了一部分代码加以说明:
   
   
   ```java
   public class ConnectionPoolService implements Runnable {
   
       private DruidConnectionPoolManager manager = 
DruidConnectionPoolManager.getInstance();
   
       private ConnectionPoolMetricsSender sender = 
ConnectionPoolMetricsSender.getInstance();
   
       public void init() throws Exception {
           Executors.newSingleThreadScheduledExecutor(r -> {
               Thread thread = new Thread(r);
               thread.setDaemon(true);
               return thread;
           }).scheduleAtFixedRate(this, 0, 1, TimeUnit.SECONDS);
       }
   
   
       @Override
       public void run() {
           List<ConnectionPoolMetrics> metricsList = 
manager.getConnectionPoolMetricsList();
   
           metricsList.forEach(metrics -> sender.offer(metrics));
       }
   }
   ```
   
   ```java
   public class ConnectionPoolMetricsSender {
   
       private final static LinkedBlockingQueue<ConnectionPoolMetrics> queue = 
new LinkedBlockingQueue<>(600);
   
       private static ConnectionPoolMetricsSender INSTANCE;
   
       public static ConnectionPoolMetricsSender getInstance() {
           if (INSTANCE == null) {
               synchronized (ConnectionPoolMetricsSender.class) {
                   if (INSTANCE == null) {
                       INSTANCE = new ConnectionPoolMetricsSender();
                   }
               }
           }
           return INSTANCE;
       }
   
       private ConnectionPoolMetricsSender() {
   
       }
   
       public void offer(ConnectionPoolMetrics metrics) {
           if (!queue.offer(metrics)) {
               queue.poll();
               queue.offer(metrics);
           }
       }
   
   }
   ```
   
   
   ```java
   public class DruidConnectionPoolManager extends 
AbstractConnectionPoolManager {
   
       private static final Logger LOGGER = 
LoggerFactory.getLogger(DruidConnectionPoolManager.class);
   
       private final Map<String, DruidDataSource> druidDataSourceMap = new 
ConcurrentHashMap<>();
   
       private static DruidConnectionPoolManager INSTANCE;
   
       public static DruidConnectionPoolManager getInstance() {
           if (INSTANCE == null) {
               synchronized (DruidConnectionPoolManager.class) {
                   if (INSTANCE == null) {
                       INSTANCE = new DruidConnectionPoolManager();
                   }
               }
           }
           return INSTANCE;
       }
   
       private DruidConnectionPoolManager() {
   
       }
   
       public void registerDataSource(Resource resource) {
           if (resource instanceof DataSourceProxy) {
               DataSourceProxy dataSourceProxy = (DataSourceProxy) resource;
               druidDataSourceMap.put(dataSourceProxy.getResourceId(), 
(DruidDataSource) dataSourceProxy.getTargetDataSource());
           }
       }
   
       public DruidDataSource get(String resourceId) {
           return druidDataSourceMap.get(resourceId);
       }
   
       public List<ConnectionPoolMetrics> getConnectionPoolMetricsList() {
           List<ConnectionPoolMetrics> metricsList = new ArrayList<>();
   
           druidDataSourceMap.forEach((resourceId, druidDataSource) -> {
               ConnectionPoolMetrics metrics = 
getConnectionPoolMetrics(resourceId);
               metricsList.add(metrics);
           });
   
           return metricsList;
       }
   
       public ConnectionPoolMetrics getConnectionPoolMetrics(String resourceId) 
{
           DruidDataSource druidDataSource = druidDataSourceMap.get(resourceId);
           if (druidDataSource == null) {
               return null;
           }
   
           ConnectionPoolMetrics metrics = new ConnectionPoolMetrics();
           metrics.setResourceId(resourceId);
           metrics.setCurrentTimeMillis(System.currentTimeMillis());
           metrics.setActiveCount(druidDataSource.getActiveCount());
           metrics.setMaxActive(druidDataSource.getMaxActive());
           metrics.setIdleCount(druidDataSource.getPoolingCount());
   
           return metrics;
       }
   
       public void adjustPoolConfig(String resourceId, int maxActive, int 
minIdle) {
           DruidDataSource druidDataSource = druidDataSourceMap.get(resourceId);
           if (druidDataSource == null) {
               return;
           }
           if (maxActive >= 0) {
               druidDataSource.setMaxActive(maxActive);
           } else if (minIdle >= 0) {
               druidDataSource.setMinIdle(minIdle);
           }
       }
   
       public boolean checkPoolIsHealthy(String resourceId) {
           DruidDataSource druidDataSource = druidDataSourceMap.get(resourceId);
           if (druidDataSource == null) {
               return false;
           }
           try (Connection conn = druidDataSource.getConnection()) {
               try (PreparedStatement stmt = conn.prepareStatement("SELECT 1")) 
{
                   return stmt.execute();
               }
           } catch (SQLException e) {
               return false;
           }
       }
   
       public void logPoolStatus(String resourceId) {
           DruidDataSource druidDataSource = druidDataSourceMap.get(resourceId);
   
           LOGGER.info("{}-Active Connections: {}", resourceId, 
druidDataSource.getActiveCount());
           LOGGER.info("{}-Idle Connections: {}", resourceId, 
druidDataSource.getPoolingCount());
           if (druidDataSource.getActiveCount() > 
druidDataSource.getMaxActive() * 0.8) {
               LOGGER.warn("{}-Warning: Active connections exceed 80% of max 
allowed connections!", resourceId);
           }
       }
   
   }
   ```
   
   ```java
   
   public class ConnectionPoolMetrics {
   
       private String resourceId;
   
       private Long currentTimeMillis;
   
       private Integer activeCount;
   
       private Integer idleCount;
   
       private Integer maxActive;
   
       public ConnectionPoolMetrics(){
   
       }
   
       public String getResourceId() {
           return resourceId;
       }
   
       public void setResourceId(String resourceId) {
           this.resourceId = resourceId;
       }
   
       public Integer getActiveCount() {
           return activeCount;
       }
   
       public void setActiveCount(Integer activeCount) {
           this.activeCount = activeCount;
       }
   
       public Integer getIdleCount() {
           return idleCount;
       }
   
       public void setIdleCount(Integer idleCount) {
           this.idleCount = idleCount;
       }
   
       public Integer getMaxActive() {
           return maxActive;
       }
   
       public void setMaxActive(Integer maxActive) {
           this.maxActive = maxActive;
       }
   
       public Long getCurrentTimeMillis() {
           return currentTimeMillis;
       }
   
       public void setCurrentTimeMillis(Long currentTimeMillis) {
           this.currentTimeMillis = currentTimeMillis;
       }
   }
   
   ```


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscr...@seata.apache.org.apache.org

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscr...@seata.apache.org
For additional commands, e-mail: notifications-h...@seata.apache.org

Reply via email to