Personalize a alta disponibilidade do Apache ShardingSphere com MySQL
Saiba como e por que o ShardingSphere pode alcançar alta disponibilidade de banco de dados usando MySQL como exemplo.
Os usuários têm muitas opções para personalizar e estender as soluções de alta disponibilidade (HA) do ShardingSphere. Nossa equipe concluiu dois planos de alta disponibilidade: uma solução de alta disponibilidade MySQL baseada em MGR e uma solução de alta disponibilidade de banco de dados openGauss contribuída por alguns committers da comunidade. Os princípios das duas soluções são os mesmos.
Abaixo está como e por que o ShardingSphere pode alcançar alta disponibilidade de banco de dados usando MySQL como exemplo:
(Zhao Jinchao, CC BY-SA 4.0)
Pré-requisito
O ShardingSphere verifica se o ambiente de cluster MySQL subjacente está pronto executando a seguinte instrução SQL. O ShardingSphere não poderá ser iniciado se algum dos testes falhar.
Verifique se o MGR está instalado:
SELECT * FROM information_schema.PLUGINS WHERE PLUGIN_NAME='group_replication'
Veja o número do membro do grupo MGR. O cluster MGR subjacente deve consistir em pelo menos três nós:
SELECT count(*) FROM performance_schema.replication_group_members
Verifique se o nome do grupo do cluster MGR é consistente com o da configuração. O nome do grupo é o marcador de um grupo MGR, e cada grupo de um cluster MGR possui apenas um nome de grupo:
SELECT * FROM performance_schema.global_variables WHERE VARIABLE_NAME='group_replication_group_name'
Verifique se o MGR atual está definido como modo primário único. Atualmente, o ShardingSphere não oferece suporte a cenários de gravação dupla ou gravação múltipla. Ele suporta apenas o modo de gravação única:
SELECT * FROM performance_schema.global_variables WHERE VARIABLE_NAME='group_replication_single_primary_mode'
Consulte todos os hosts de nós, portas e estados no cluster do grupo MGR para verificar se a fonte de dados configurada está correta:
SELECT MEMBER_HOST, MEMBER_PORT, MEMBER_STATE FROM performance_schema.replication_group_members
Descoberta dinâmica de banco de dados primário
O ShardingSphere encontra a URL do banco de dados primário de acordo com o comando SQL do banco de dados mestre de consulta fornecido pelo MySQL:
private String findPrimaryDataSourceURL(final Map<String, DataSource> dataSourceMap) {
String result = "";
String sql = "SELECT MEMBER_HOST, MEMBER_PORT FROM performance_schema.replication_group_members WHERE MEMBER_ID = "
+ "(SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME = 'group_replication_primary_member')";
for (DataSource each : dataSourceMap.values()) {
try (Connection connection = each.getConnection();
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery(sql)) {
if (resultSet.next()) {
return String.format("%s:%s", resultSet.getString("MEMBER_HOST"), resultSet.getString("MEMBER_PORT"));
}
} catch (final SQLException ex) {
log.error("An exception occurred while find primary data source url", ex);
}
}
return result;
}
Compare os URLs do banco de dados primário encontrados acima, um por um, com os URLs dataSources
configurados. A fonte de dados correspondente é o banco de dados primário. Ele será atualizado para a memória atual do ShardingSphere e perpetuado no centro de registro, por meio do qual será distribuído para outros nós de computação no cluster.
(Zhao Jinchao, CC BY-SA 4.0)
Descoberta dinâmica de banco de dados secundário
Existem dois tipos de estados de banco de dados secundários no ShardingSphere: ativar e desativar. O estado do banco de dados secundário será sincronizado com a memória do ShardingSphere para garantir que o tráfego de leitura possa ser roteado corretamente.
Obtenha todos os nós do grupo MGR:
SELECT MEMBER_HOST, MEMBER_PORT, MEMBER_STATE FROM performance_schema.replication_group_members
Desative bancos de dados secundários:
private void determineDisabledDataSource(final String schemaName, final Map<String, DataSource> activeDataSourceMap,
final List<String> memberDataSourceURLs, final Map<String, String> dataSourceURLs) {
for (Entry<String, DataSource> entry : activeDataSourceMap.entrySet()) {
boolean disable = true;
String url = null;
try (Connection connection = entry.getValue().getConnection()) {
url = connection.getMetaData().getURL();
for (String each : memberDataSourceURLs) {
if (null != url && url.contains(each)) {
disable = false;
break;
}
}
} catch (final SQLException ex) {
log.error("An exception occurred while find data source urls", ex);
}
if (disable) {
ShardingSphereEventBus.getInstance().post(new DataSourceDisabledEvent(schemaName, entry.getKey(), true));
} else if (!url.isEmpty()) {
dataSourceURLs.put(entry.getKey(), url);
}
}
}
A desativação do banco de dados secundário depende da fonte de dados configurada e de todos os nós do grupo MGR.
O ShardingSphere pode verificar um por um se a fonte de dados configurada pode obter Connection
corretamente e verificar se a URL da fonte de dados contém nós do grupo MGR.
Se Connection
não puder ser obtido ou a verificação falhar, o ShardingSphere desativará a fonte de dados por um gatilho de evento e a sincronizará com o centro de registro.
Habilite bancos de dados secundários:
private void determineEnabledDataSource(final Map<String, DataSource> dataSourceMap, final String schemaName,
final List<String> memberDataSourceURLs, final Map<String, String> dataSourceURLs) {
for (String each : memberDataSourceURLs) {
boolean enable = true;
for (Entry<String, String> entry : dataSourceURLs.entrySet()) {
if (entry.getValue().contains(each)) {
enable = false;
break;
}
}
if (!enable) {
continue;
}
for (Entry<String, DataSource> entry : dataSourceMap.entrySet()) {
String url;
try (Connection connection = entry.getValue().getConnection()) {
url = connection.getMetaData().getURL();
if (null != url && url.contains(each)) {
ShardingSphereEventBus.getInstance().post(new DataSourceDisabledEvent(schemaName, entry.getKey(), false));
break;
}
} catch (final SQLException ex) {
log.error("An exception occurred while find enable data source urls", ex);
}
}
}
}
Depois que o banco de dados secundário travado for recuperado e adicionado ao grupo MGR, a configuração será verificada para ver se a fonte de dados recuperada é usada. Se sim, o gatilho do evento informará ao ShardingSphere que a fonte de dados precisa ser habilitada.
Mecanismo de batimento cardíaco
O mecanismo de pulsação é introduzido no módulo HA para garantir que os estados primário-secundário sejam sincronizados em tempo real.
Ao integrar o subprojeto ElasticJob do ShardingSphere, os processos acima são executados pela estrutura do agendador ElasticJob na forma de Job quando o módulo HA é inicializado, conseguindo assim a separação entre o desenvolvimento de funções e o agendamento de jobs.
Mesmo que os desenvolvedores precisem estender a função de HA, eles não precisam se preocupar com a forma como os trabalhos são desenvolvidos e operados:
private void initHeartBeatJobs(final String schemaName, final Map<String, DataSource> dataSourceMap) {
Optional<ModeScheduleContext> modeScheduleContext = ModeScheduleContextFactory.getInstance().get();
if (modeScheduleContext.isPresent()) {
for (Entry<String, DatabaseDiscoveryDataSourceRule> entry : dataSourceRules.entrySet()) {
Map<String, DataSource> dataSources = dataSourceMap.entrySet().stream().filter(dataSource -> !entry.getValue().getDisabledDataSourceNames().contains(dataSource.getKey()))
.collect(Collectors.toMap(Entry::getKey, Entry::getValue));
CronJob job = new CronJob(entry.getValue().getDatabaseDiscoveryType().getType() + "-" + entry.getValue().getGroupName(),
each -> new HeartbeatJob(schemaName, dataSources, entry.getValue().getGroupName(), entry.getValue().getDatabaseDiscoveryType(), entry.getValue().getDisabledDataSourceNames())
.execute(null), entry.getValue().getHeartbeatProps().getProperty("keep-alive-cron"));
modeScheduleContext.get().startCronJob(job);
}
}
}
Embrulhar
Até agora, o recurso HA do Apache ShardingSphere provou ser aplicável para soluções MySQL e openGauss HA. No futuro, ele integrará mais produtos MySQL HA e oferecerá suporte a mais soluções de HA de banco de dados.
Como sempre, se você estiver interessado, seja bem-vindo para se juntar a nós e contribuir com o projeto Apache ShardingSphere.
Links do projeto de código aberto Apache ShardingSphere:
- ShardingSphere GitHub
- Twitter do ShardingSphere
- ShardingSphere Slack
- Diretrizes para contribuidores