Fale sobre como usar a integração de Apollo e Druid para perceber a ânsia dinâmica de fontes de dados

prefácio

A fonte do material para este artigo é uma troca técnica com um amigo.Na época, meu amigo reclamou comigo que o Apollo não é tão fácil de usar quanto o nacos, e eles também tiveram um acidente online por causa do Apollo.

O pano de fundo da história é mais ou menos o seguinte

Há um tempo atrás, o banco de dados do departamento de meu amigo estava fora do ar, o que fazia com que o negócio não funcionasse normalmente. Naquela época, as informações do banco de dados do meu amigo estavam configuradas no Apollo. A ideia do meu amigo era que quando o banco de dados estivesse fora do ar, você poderia trocar as informações do banco de dados configuradas no Apollo para realizar a recuperação de dados. Mudança de calor da fonte. Mas quando o banco de dados caiu, o amigo operou de acordo com sua ideia e descobriu que as coisas não eram como ele imaginava. Depois que eles mudaram a fonte de dados, descobriram que a conexão do serviço comercial ainda era o antigo serviço de banco de dados. Eles não tiveram escolha a não ser para entrar em contato com o processamento dba.

Mais tarde, depois de ouvir a descrição do meu amigo, perguntei a ele como você fazia o banco de dados ansiosamente naquele momento. Sua resposta foi: é muito simples, basta configurar as informações da fonte de dados no Apollo. Se você quiser alterar a fonte de dados, basta Altere-o diretamente no portal da Apollo. Depois de ouvir o que meu amigo disse, perguntei e depois? A resposta do amigo é: e então? Não há mais.

Por meio dessa troca, há o artigo de hoje. Hoje falaremos sobre a integração de Apollo e Druid para realizar a ânsia dinâmica da fonte de dados

Realize a ideia central

Monitoramento dinâmico de mudança de configuração do Apollo + spring AbstractRoutingDataSource método reservado determineCurrentLookupKey para comutação de fonte de dados

Antes de apresentar a implementação da lógica principal, vamos falar sobre o centro de configuração

O que é Centro de Configuração?

O centro de configuração é um componente de serviço básico que gerencia várias configurações de aplicativos de maneira unificada. Seu núcleo é o gerenciamento unificado de configuração . A categoria que ele gerencia é a configuração, já os objetos que dependem de configuração, como as fontes de dados, não são gerenciados pelo centro de configuração. Por que estou trazendo isso sozinho? É porque meu amigo parece ter caído em um mal-entendido, pensando que se a configuração for alterada no apollo, a fonte de dados da qual essa configuração depende também será alterada junto com ela

código principal

1. Crie uma fonte de dados dinâmica e faça proxy da fonte de dados original

public class DynamicDataSource extends AbstractRoutingDataSource {
    
    

    public static final String DATASOURCE_KEY = "db";

    @Override
    protected Object determineCurrentLookupKey() {
    
    
        return DATASOURCE_KEY;
    }

    public DataSource getOriginalDetermineTargetDataSource(){
    
    
        return this.determineTargetDataSource();
    }
}

@Configuration
@EnableConfigurationProperties(BackupDataSourceProperties.class)
@ComponentScan(basePackages = "com.github.lybgeek.ds.switchover")
public class DynamicDataSourceAutoConfiguration {
    
    


    @Bean
    @ConditionalOnMissingBean
    @Primary
    @ConditionalOnClass(DruidDataSource.class)
    public AbstractDataSourceManger abstractDataSourceManger(DataSourceProperties dataSourceProperties, BackupDataSourceProperties backupDataSourceProperties){
    
    
        return new DruidDataSourceManger(backupDataSourceProperties,dataSourceProperties);
    }

    @Bean("dataSource")
    @Primary
    @ConditionalOnBean(AbstractDataSourceManger.class)
    public DynamicDataSource dynamicDataSource(AbstractDataSourceManger abstractDataSourceManger) {
    
    
        DynamicDataSource source = new DynamicDataSource();
        DataSource dataSource = abstractDataSourceManger.createDataSource(false);
        source.setTargetDataSources(Collections.singletonMap(DATASOURCE_KEY, dataSource));
        return source;
    }

}

Uma coisa a observar aqui é que o nome do bean de DynamicDataSource deve ser dataSource, o objetivo é fazer com que o bean buscado pela fonte de dados padrão do spring seja DynamicDataSource

2. Monitorar alterações de configuração e alternar fontes de dados

alternar fonte de dados

 @ApolloConfigChangeListener(interestedKeyPrefixes = PREFIX)
    public void onChange(ConfigChangeEvent changeEvent) {
    
    
        refresh(changeEvent.changedKeys());
    }

    /**
     *
     * @param changedKeys
     */
    private synchronized void refresh(Set<String> changedKeys) {
    
    
        /**
         * rebind configuration beans, e.g. DataSourceProperties
         * @see org.springframework.cloud.context.properties.ConfigurationPropertiesRebinder#onApplicationEvent
         */
        this.applicationContext.publishEvent(new EnvironmentChangeEvent(changedKeys));

        /**
         * BackupDataSourceProperties rebind ,you can also do it in PropertiesRebinderEventListener
         * @see PropertiesRebinderEventListener
         */
        backupDataSourcePropertiesHolder.rebinder();

        abstractDataSourceManger.switchBackupDataSource();

    }
  @SneakyThrows
    @Override
    public void switchBackupDataSource() {
    
    
        if(backupDataSourceProperties.isForceswitch()){
    
    
            if(backupDataSourceProperties.isForceswitch()){
    
    
                log.info("Start to switch backup datasource : 【{}】",backupDataSourceProperties.getBackup().getUrl());
                DataSource dataSource = this.createDataSource(true);
                DynamicDataSource source = applicationContext.getBean(DynamicDataSource.class);
                DataSource originalDetermineTargetDataSource = source.getOriginalDetermineTargetDataSource();
                if(originalDetermineTargetDataSource instanceof DruidDataSource){
    
    
                    DruidDataSource druidDataSource = (DruidDataSource)originalDetermineTargetDataSource;
                    ScheduledExecutorService createScheduler = druidDataSource.getCreateScheduler();
                    createScheduler.shutdown();
                    if(!createScheduler.awaitTermination(backupDataSourceProperties.getAwaittermination(), TimeUnit.SECONDS)){
    
    
                        log.warn("Druid dataSource 【{}】 create connection thread force to closed",druidDataSource.getUrl());
                        createScheduler.shutdownNow();
                    }
                }
                //当检测到数据库地址改变时,重新设置数据源
                source.setTargetDataSources(Collections.singletonMap(DATASOURCE_KEY, dataSource));
                //调用该方法刷新resolvedDataSources,下次获取数据源时将获取到新设置的数据源
                source.afterPropertiesSet();

                log.info("Switch backup datasource : 【{}】 finished",backupDataSourceProperties.getBackup().getUrl());
            }
        }
    }

3. Teste

   @Override
    public void run(ApplicationArguments args) throws Exception {
    
    
        while(true){
    
    
            User user = userService.getById(1L);
            System.err.println(user.getPassword());
            TimeUnit.SECONDS.sleep(1);
        }

    }

Antes de alternar, o console imprime


Após a troca, o console imprime

Resumir

O acima é a ideia geral de realizar a integração de apollo e druid para perceber a ânsia dinâmica das fontes de dados, mas ainda existe um problema na implementação, ou seja, existem conexões antigas que não foram processadas. Embora eu não tenha feito nenhum processamento no código de amostra, getOriginalDetermineTargetDataSource é reservado no código e algumas operações adicionais podem ser feitas por meio de getOriginalDetermineTargetDataSource.

A implementação deste artigo também pode ser implementada usando o caso fornecido por apollo no github, o link é o seguinte

https://github.com/apolloconfig/apollo-use-cases/tree/master/dynamic-datasource

Nesse caso, após a troca de conexão, a fonte de dados antiga será limpa. A fonte de dados nele é HikariDataSource. Se você usar o caso fornecido por apollo, quando usar a fonte de dados do druida, postarei a parte fechada do código-fonte do druida


E obtenha o código-fonte da conexão

Aqui está um ponto a observar que, quando a fonte de dados do druida é fechada, se uma conexão ocorrer neste momento, um DataSourceDisableException será relatado neste momento e, em seguida, o projeto será encerrado de forma anormal

Por fim, gostaria de acrescentar algo a mais. Antes que meu amigo dissesse que o Apollo não é tão fácil de usar quanto os nacos, tenho ressalvas. Na verdade, para medir a qualidade de uma tecnologia, é necessário trazer a cena. Em alguns cenas, as vantagens da tecnologia podem ser uma desvantagem

link de demonstração

https://github.com/lyb-geek/springboot-learning/tree/master/springboot-datasource-hot-switchover

Acho que você gosta

Origin blog.csdn.net/kingwinstar/article/details/127345377
Recomendado
Clasificación