You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hive.apache.org by dk...@apache.org on 2023/01/26 20:42:25 UTC
[hive] branch master updated: HIVE-26794: Explore retiring TxnHandler#connPoolMutex idle connections (dengzh, reviewed by Chris Nauroth, Denys Kuzmenko)
This is an automated email from the ASF dual-hosted git repository.
dkuzmenko pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/hive.git
The following commit(s) were added to refs/heads/master by this push:
new b8016fbcd40 HIVE-26794: Explore retiring TxnHandler#connPoolMutex idle connections (dengzh, reviewed by Chris Nauroth, Denys Kuzmenko)
b8016fbcd40 is described below
commit b8016fbcd4023a610beae02f5dd46ba9eaf29534
Author: dengzh <de...@gmail.com>
AuthorDate: Fri Jan 27 04:42:18 2023 +0800
HIVE-26794: Explore retiring TxnHandler#connPoolMutex idle connections (dengzh, reviewed by Chris Nauroth, Denys Kuzmenko)
Closes #3817
---
.../datasource/DbCPDataSourceProvider.java | 16 +++++-
.../datasource/HikariCPDataSourceProvider.java | 11 ++++
.../hadoop/hive/metastore/txn/TxnHandler.java | 6 +++
.../datasource/TestDataSourceProviderFactory.java | 59 ++++++++++++++++++++++
4 files changed, 91 insertions(+), 1 deletion(-)
diff --git a/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/datasource/DbCPDataSourceProvider.java b/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/datasource/DbCPDataSourceProvider.java
index da8d875bdb6..61937d04998 100644
--- a/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/datasource/DbCPDataSourceProvider.java
+++ b/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/datasource/DbCPDataSourceProvider.java
@@ -18,6 +18,7 @@
package org.apache.hadoop.hive.metastore.datasource;
import java.sql.SQLException;
+import java.util.Collections;
import java.util.Map;
import javax.sql.DataSource;
@@ -112,9 +113,22 @@ public class DbCPDataSourceProvider implements DataSourceProvider {
objectPool.setSoftMinEvictableIdleTimeMillis(softMinEvictableIdleTimeMillis);
objectPool.setLifo(lifo);
+ // Enable TxnHandler#connPoolMutex to release the idle connection if possible,
+ // TxnHandler#connPoolMutex is mostly used for MutexAPI that is primarily designed to
+ // provide coarse-grained mutex support to maintenance tasks running inside the Metastore,
+ // this will make Metastore more scalable especially if there is a leader in the warehouse.
+ if ("mutex".equalsIgnoreCase(poolName)) {
+ if (timeBetweenEvictionRuns < 0) {
+ // When timeBetweenEvictionRunsMillis non-positive, no idle object evictor thread runs
+ objectPool.setTimeBetweenEvictionRunsMillis(30 * 1000);
+ }
+ if (softMinEvictableIdleTimeMillis < 0) {
+ objectPool.setSoftMinEvictableIdleTimeMillis(600 * 1000);
+ }
+ }
String stmt = dbProduct.getPrepareTxnStmt();
if (stmt != null) {
- poolableConnFactory.setValidationQuery(stmt);
+ poolableConnFactory.setConnectionInitSql(Collections.singletonList(stmt));
}
return new PoolingDataSource(objectPool);
}
diff --git a/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/datasource/HikariCPDataSourceProvider.java b/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/datasource/HikariCPDataSourceProvider.java
index 2c41191ea45..b09094cc58a 100644
--- a/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/datasource/HikariCPDataSourceProvider.java
+++ b/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/datasource/HikariCPDataSourceProvider.java
@@ -72,6 +72,17 @@ public class HikariCPDataSourceProvider implements DataSourceProvider {
config.setPoolName(poolName);
}
+ // It's kind of a waste to create a fixed size connection pool as same as the TxnHandler#connPool,
+ // TxnHandler#connPoolMutex is mostly used for MutexAPI that is primarily designed to
+ // provide coarse-grained mutex support to maintenance tasks running inside the Metastore,
+ // add minimumIdle=2 and idleTimeout=10min(default, can be set by hikaricp.idleTimeout) to the pool,
+ // so that the connection pool can retire the idle connection aggressively,
+ // this will make Metastore more scalable especially if there is a leader in the warehouse.
+ if ("mutex".equals(poolName)) {
+ int minimumIdle = Integer.valueOf(hdpConfig.get(HIKARI + ".minimumIdle", "2"));
+ config.setMinimumIdle(Math.min(maxPoolSize, minimumIdle));
+ }
+
//https://github.com/brettwooldridge/HikariCP
config.setConnectionTimeout(connectionTimeout);
diff --git a/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/txn/TxnHandler.java b/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/txn/TxnHandler.java
index b42b25db95f..f9f00c224a4 100644
--- a/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/txn/TxnHandler.java
+++ b/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/txn/TxnHandler.java
@@ -6222,6 +6222,12 @@ abstract class TxnHandler implements TxnStore, TxnStore.MutexAPI {
connectionProps.setProperty("user", username);
connectionProps.setProperty("password", password);
Connection conn = driver.connect(connString, connectionProps);
+ String prepareStmt = dbProduct != null ? dbProduct.getPrepareTxnStmt() : null;
+ if (prepareStmt != null) {
+ try (Statement stmt = conn.createStatement()) {
+ stmt.execute(prepareStmt);
+ }
+ }
conn.setAutoCommit(false);
return conn;
} catch (SQLException e) {
diff --git a/standalone-metastore/metastore-server/src/test/java/org/apache/hadoop/hive/metastore/datasource/TestDataSourceProviderFactory.java b/standalone-metastore/metastore-server/src/test/java/org/apache/hadoop/hive/metastore/datasource/TestDataSourceProviderFactory.java
index 73f8db0ac38..0c4b6d35713 100644
--- a/standalone-metastore/metastore-server/src/test/java/org/apache/hadoop/hive/metastore/datasource/TestDataSourceProviderFactory.java
+++ b/standalone-metastore/metastore-server/src/test/java/org/apache/hadoop/hive/metastore/datasource/TestDataSourceProviderFactory.java
@@ -19,7 +19,10 @@ package org.apache.hadoop.hive.metastore.datasource;
import com.zaxxer.hikari.HikariDataSource;
+import com.zaxxer.hikari.HikariPoolMXBean;
import org.apache.commons.dbcp2.PoolingDataSource;
+import org.apache.commons.lang3.reflect.MethodUtils;
+import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hive.metastore.PersistenceManagerProvider;
import org.apache.hadoop.hive.metastore.annotation.MetastoreUnitTest;
@@ -34,6 +37,8 @@ import javax.jdo.PersistenceManagerFactory;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
@Category(MetastoreUnitTest.class)
public class TestDataSourceProviderFactory {
@@ -143,6 +148,60 @@ public class TestDataSourceProviderFactory {
Assert.assertTrue(ds instanceof PoolingDataSource);
}
+ @Test
+ public void testEvictIdleConnection() throws Exception {
+ String[] dataSourceType = {HikariCPDataSourceProvider.HIKARI, DbCPDataSourceProvider.DBCP};
+ try (DataSourceProvider.DataSourceNameConfigurator configurator =
+ new DataSourceProvider.DataSourceNameConfigurator(conf, "mutex")) {
+ for (final String type: dataSourceType) {
+ MetastoreConf.setVar(conf, ConfVars.CONNECTION_POOLING_TYPE, type);
+ boolean isHikari = HikariCPDataSourceProvider.HIKARI.equals(type);
+ if (isHikari) {
+ conf.unset("hikaricp.connectionInitSql");
+ // The minimum of idleTimeout is 10s
+ conf.set("hikaricp.idleTimeout", "10000");
+ System.setProperty("com.zaxxer.hikari.housekeeping.periodMs", "1000");
+ } else {
+ conf.set("dbcp.timeBetweenEvictionRunsMillis", "1000");
+ conf.set("dbcp.softMinEvictableIdleTimeMillis", "3000");
+ conf.set("dbcp.maxIdle", "0");
+ }
+ DataSourceProvider dsp = DataSourceProviderFactory.tryGetDataSourceProviderOrNull(conf);
+ DataSource ds = dsp.create(conf, 5);
+ List<Connection> connections = new ArrayList<>();
+ for (int i = 0; i < 5; i++) {
+ connections.add(ds.getConnection());
+ }
+ HikariPoolMXBean poolMXBean = null;
+ GenericObjectPool objectPool = null;
+ if (isHikari) {
+ poolMXBean = ((HikariDataSource) ds).getHikariPoolMXBean();
+ Assert.assertEquals(type, 5, poolMXBean.getTotalConnections());
+ Assert.assertEquals(type, 5, poolMXBean.getActiveConnections());
+ } else {
+ objectPool = (GenericObjectPool) MethodUtils.invokeMethod(ds, true, "getPool");
+ Assert.assertEquals(type, 5, objectPool.getNumActive());
+ Assert.assertEquals(type, 5, objectPool.getMaxTotal());
+ }
+ connections.forEach(connection -> {
+ try {
+ connection.close();
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ });
+ Thread.sleep(isHikari ? 15000 : 7000);
+ if (isHikari) {
+ Assert.assertEquals(type, 2, poolMXBean.getTotalConnections());
+ Assert.assertEquals(type, 2, poolMXBean.getIdleConnections());
+ } else {
+ Assert.assertEquals(type, 0, objectPool.getNumActive());
+ Assert.assertEquals(type, 0, objectPool.getNumIdle());
+ }
+ }
+ }
+ }
+
@Test
public void testClosePersistenceManagerProvider() throws Exception {
String[] dataSourceType = {HikariCPDataSourceProvider.HIKARI, DbCPDataSourceProvider.DBCP};