Optimize the logic in HA Validation.

This commit is contained in:
DigitalSonic
2019-02-25 14:49:45 +08:00
parent 865d052a21
commit c1e73f2fa9
5 changed files with 50 additions and 13 deletions
@@ -31,7 +31,8 @@ import java.sql.Connection;
public class RandomDataSourceRecoverThread implements Runnable {
private final static Log LOG = LogFactory.getLog(RandomDataSourceRecoverThread.class);
private RandomDataSourceSelector selector;
private int sleepSeconds = 30;
private int sleepSeconds = 60;
private int validationSleepSeconds = 0;
public RandomDataSourceRecoverThread(RandomDataSourceSelector selector) {
this.selector = selector;
@@ -61,6 +62,7 @@ public class RandomDataSourceRecoverThread implements Runnable {
Connection connection = null;
try {
connection = dataSource.getConnection();
sleepBeforeValidation();
dataSource.validateConnection(connection);
LOG.info(dataSource.getName() + " is available now.");
selector.removeBlacklist(dataSource);
@@ -75,6 +77,17 @@ public class RandomDataSourceRecoverThread implements Runnable {
}
}
private void sleepBeforeValidation() {
if (validationSleepSeconds > 0) {
try {
LOG.debug("Sleep " + validationSleepSeconds + " second(s) before validation.");
Thread.sleep(validationSleepSeconds * 1000);
} catch (InterruptedException e) {
// ignore
}
}
}
private void sleep() {
try {
Thread.sleep(sleepSeconds * 1000);
@@ -90,4 +103,12 @@ public class RandomDataSourceRecoverThread implements Runnable {
public void setSleepSeconds(int sleepSeconds) {
this.sleepSeconds = sleepSeconds;
}
public int getValidationSleepSeconds() {
return validationSleepSeconds;
}
public void setValidationSleepSeconds(int validationSleepSeconds) {
this.validationSleepSeconds = validationSleepSeconds;
}
}
@@ -51,7 +51,7 @@ public class RandomDataSourceSelector implements DataSourceSelector {
private RandomDataSourceRecoverThread recoverThread;
private int checkingIntervalSeconds = 15;
private int recoveryIntervalSeconds = 30;
private int recoveryIntervalSeconds = 60;
private int validationSleepSeconds = 0;
private int blacklistThreshold = 3;
@@ -118,6 +118,10 @@ public class RandomDataSourceSelector implements DataSourceSelector {
return blacklist;
}
public boolean containInBlacklist(DataSource dataSource) {
return dataSource != null && blacklist.contains(dataSource);
}
public void addBlacklist(DataSource dataSource) {
if (dataSource != null && !blacklist.contains(dataSource)) {
blacklist.add(dataSource);
@@ -128,7 +132,7 @@ public class RandomDataSourceSelector implements DataSourceSelector {
}
public void removeBlacklist(DataSource dataSource) {
if (dataSource != null && blacklist.contains(dataSource)) {
if (containInBlacklist(dataSource)) {
blacklist.remove(dataSource);
if (dataSource instanceof DruidDataSource) {
((DruidDataSource) dataSource).setTestOnReturn(highAvailableDataSource.isTestOnReturn());
@@ -161,14 +165,19 @@ public class RandomDataSourceSelector implements DataSourceSelector {
}
private void initThreads() {
validateThread = new RandomDataSourceValidateThread(this);
validateThread.setCheckingIntervalSeconds(checkingIntervalSeconds);
validateThread.setValidationSleepSeconds(validationSleepSeconds);
validateThread.setBlacklistThreshold(blacklistThreshold);
new Thread(validateThread, "RandomDataSourceSelector-isValid-thread").start();
if (validateThread == null) {
validateThread = new RandomDataSourceValidateThread(this);
validateThread.setCheckingIntervalSeconds(checkingIntervalSeconds);
validateThread.setValidationSleepSeconds(validationSleepSeconds);
validateThread.setBlacklistThreshold(blacklistThreshold);
}
new Thread(validateThread, "RandomDataSourceSelector-validate-thread").start();
recoverThread = new RandomDataSourceRecoverThread(this);
recoverThread.setSleepSeconds(recoveryIntervalSeconds);
if (recoverThread == null) {
recoverThread = new RandomDataSourceRecoverThread(this);
recoverThread.setSleepSeconds(recoveryIntervalSeconds);
recoverThread.setValidationSleepSeconds(validationSleepSeconds);
}
new Thread(recoverThread, "RandomDataSourceSelector-recover-thread").start();
}
@@ -89,7 +89,8 @@ public class RandomDataSourceValidateThread implements Runnable {
for (Map.Entry<String, Integer> e : errorCounts.entrySet()) {
if (e.getValue() <= 0) {
selector.removeBlacklist(dataSourceMap.get(e.getKey()));
} else if (e.getValue() >= blacklistThreshold) {
} else if (e.getValue() >= blacklistThreshold
&& !selector.containInBlacklist(dataSourceMap.get(e.getKey()))) {
LOG.warn("Adding " + e.getKey() + " to blacklist.");
selector.addBlacklist(dataSourceMap.get(e.getKey()));
}
@@ -105,6 +106,11 @@ public class RandomDataSourceValidateThread implements Runnable {
continue;
}
if (selector.containInBlacklist(e.getValue())) {
LOG.debug(e.getKey() + " is already in blacklist, skip.");
continue;
}
tasks.add(new Callable<Boolean>() {
@Override
public Boolean call() {
@@ -40,6 +40,7 @@ public class RandomDataSourceSelectorTest extends BaseRandomDataSourceSelectorTe
assertEquals(10, selector.getValidationSleepSeconds());
assertEquals(10, selector.getValidateThread().getValidationSleepSeconds());
assertEquals(10, selector.getRecoverThread().getValidationSleepSeconds());
assertEquals(5, selector.getBlacklistThreshold());
assertEquals(5, selector.getValidateThread().getBlacklistThreshold());
@@ -31,13 +31,13 @@ public class RandomDataSourceSelectorWithValidationTest {
@Test
public void testOneDataSourceFailAndRecover() throws Exception {
RandomDataSourceSelector selector = ((RandomDataSourceSelector) highAvailableDataSource.getDataSourceSelector());
selector.setCheckingIntervalSeconds(3);
selector.getValidateThread().setCheckingIntervalSeconds(3);
selector.getRecoverThread().setSleepSeconds(3);
selector.init();
DruidDataSource dataSource = (DruidDataSource) highAvailableDataSource.getDataSourceMap().get("foo");
dataSource.setValidationQuery("select xxx from yyy");
Thread.sleep(6 * 1000);
Thread.sleep(10 * 1000);
assertTrue(dataSource.isTestOnReturn());
for (int i = 0; i < 100; i++) {
assertNotEquals(dataSource, selector.get());