spring/springboot的整合分布式配置中心(ACM diamond nacos Apollo)

注:本文篇幅有点长,所以建议各位下载源码学习。(如需要请收藏!转载请声明来源,谢谢!)

代码下载:https://gitee.com/hong99/spring/issues/I1N1DF


分布式配置中心是什么?

配置中心指的是将传统的.propertis或.yaml以及项目中些临时需要修改的数据,通过一个配置中心来统一规范管理。

spring/springboot的整合分布式配置中心(ACM diamond nacos Apollo)_第1张图片

分布式配置中心解决了什么问题?

实时更新:线上某些业务需要立即启动,只需要修改下配置几秒钟就更新了;

高可用:有一套行之有效的保障方案;

配置与应用分离:解决了需要修改配置居然还要重启项目....;

统一管理统一标准:规范了各种DIY问题;

个人理解:比如你线上有500台服务器,现在要立刻将某个业务暂时或启动,要是传统要重新修改配置文件->再发版,这时候时间已过...但是有了配置中心,只需要修改一下配置,几秒钟后全部生效,马上开始进行。

有哪些分布式配置中心?

阿里的ACM(收费

应用配置管理ACM(Application Configuration Management)是一款在分布式架构环境中对应用配置进行集中管理和推送的产品。凭借配置变更、配置推送、历史版本管理、灰度发布、配置变更审计等配置管理工具,ACM能帮助您集中管理所有应用环境中的配置,降低分布式系统中管理配置的成本,并降低因错误的配置变更造成可用性下降甚至发生故障的风险。

https://help.aliyun.com/learn/learningpath/acm.html?spm=5176.163362.847321.learning.3d7c2539omBLESDiamond(淘宝钻石)

diamond是淘宝内部使用的一个管理持久配置的系统,它的特点是简单、可靠、易用,目前淘宝内部绝大多数系统的配置,由diamond来进行统一管理。

https://github.com/takeseem/diamond(已经不维护)

https://github.com/gzllol/diamond

Apollo(阿波罗):

Apollo(阿波罗)是携程框架部门研发的分布式配置中心,能够集中化管理应用不同环境、不同集群的配置,配置修改后能够实时推送到应用端,并且具备规范的权限、流程治理等特性,适用于微服务配置管理场景。

https://www.bookstack.cn/read/ctripcorp-apollo/66fd39d228fadcad.md

https://github.com/ctripcorp/apollo

Nacos(阿里巴巴):

Nacos 致力于帮助您发现、配置和管理微服务。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据及流量管理。

https://nacos.io/zh-cn/docs/quick-start.html

各个分布式配置中心对比:

https://juejin.im/entry/6844903846041387016

https://cloud.tencent.com/developer/article/1347918

http://blog.zollty.com/b/archive/config-center-selection.html

代码下载:https://gitee.com/hong99/spring/issues/I1N1DF

代码实现:

diamond使用:

先拉下代码:https://github.com/gzllol/diamond

创建数据库权限和表

create database diamond; 
grant all on diamond.* to CK@'%' identified by 'abc'; 
  
use diamond 
-- 配置表
CREATE TABLE IF NOT EXISTS `config_info` (
  `id` bigint(64) unsigned NOT NULL AUTO_INCREMENT,
  `data_id` varchar(255) NOT NULL DEFAULT '',
  `group_id` varchar(128) NOT NULL DEFAULT '',
  `content` longtext NOT NULL,
  `md5` varchar(32) NOT NULL DEFAULT '',
  `src_ip` varchar(20) DEFAULT NULL,
  `src_user` varchar(20) DEFAULT NULL,
  `gmt_create` datetime NOT NULL DEFAULT now(),
  `gmt_modified` datetime NOT NULL DEFAULT now(),
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_config_datagroup` (`data_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;


-- 组表
CREATE TABLE IF NOT EXISTS `group_info` (
  `id` bigint(64) unsigned NOT NULL AUTO_INCREMENT,
  `address` varchar(70) NOT NULL DEFAULT '',
  `data_id` varchar(255) NOT NULL DEFAULT '',
  `group_id` varchar(128) NOT NULL DEFAULT '',
  `src_ip` varchar(20) DEFAULT NULL,
  `src_user` varchar(20) DEFAULT NULL,
  `gmt_create` datetime NOT NULL DEFAULT now(),
  `gmt_modified` datetime NOT NULL DEFAULT now(),
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_group_address` (`address`,`data_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

登录diamond配置

添加配置

spring/springboot的整合分布式配置中心(ACM diamond nacos Apollo)_第2张图片

spring/springboot的整合分布式配置中心(ACM diamond nacos Apollo)_第3张图片

config: 123456

结果:发现这个diamond还是挺简单的。

接下来进行spring整合diamond。(发现idamond整合资料极少...)

注:先启动diamond-server

    项目结构

spring/springboot的整合分布式配置中心(ACM diamond nacos Apollo)_第4张图片

diamond.properties

diamond.port=8090 
diamond.config.ip=127.0.0.1 
diamond.dataId=hong

com.hong.spring.config.diamond.ApplicationConfigurer

package com.hong.spring.config.diamond;
import com.taobao.diamond.manager.DiamondManager;
import com.taobao.diamond.manager.ManagerListener;
import com.taobao.diamond.manager.impl.DefaultDiamondManager;
import org.apache.commons.configuration.ConfigurationRuntimeException;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.util.StringUtils;

import javax.naming.ConfigurationException;
import java.io.*;
import java.net.URL;
import java.util.*;
import java.util.concurrent.Executor;

/**
 *
 * 功能描述: 动态拉取diamond!
 *
 * @param:
 * @return:
 * @auther: csh
 * @date: 2020/11/9 11:34
 */
@Configuration
public class ApplicationConfigurer {

    private static final Logger logger = LoggerFactory.getLogger(ApplicationConfigurer.class);

    //diamond系统配置的dataId
    String dataId="hong";

    @Bean
    public PropertySourcesPlaceholderConfigurer createPropertySourcesPlaceholderConfigurer() throws ConfigurationException, IOException {
        PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer = new PropertySourcesPlaceholderConfigurer();

        //加载diamond配置信息
        loadDiamondConfig();

        if (!StringUtils.isEmpty(dataId)) {
            String[] dataIds = dataId.split(",");
            for (int i = 0; i < dataIds.length; i++) {
                //diamond客户端调用服务端获取配置信息
                DiamondManager manager = new DefaultDiamondManager(dataIds[i], new ManagerListener() {
                    @Override
                    public Executor getExecutor() {
                        return null;
                    }

                    @Override
                    public void receiveConfigInfo(String configInfo) {
                        //配置信息动态修改将触发此方法
                        System.out.println("receive config: " + configInfo);
                        propertyPlaceholderConfigurer.setProperties(getProperties(new StringReader(configInfo)));
                    }
                });
                /**
                 * 同步获取一份有效的配置信息,按照本地文件->diamond服务器->上一次正确配置的snapshot
                 * 的优先顺序获取, 如果这些途径都无效,则返回null
                 *
                 * @param timeout
                 * 从网络获取配置信息的超时,单位毫秒
                 * @return 配置信息
                 */
                String configInfo = manager.getAvailableConfigureInfomation(1000);
                System.out.println("获取的内容:"+configInfo);
                //关闭
                //manager.close();
                //解析Propertie配置信息
                propertyPlaceholderConfigurer.setProperties(getProperties(new StringReader(configInfo)));
            }
        }
        return propertyPlaceholderConfigurer;
    }


    /**
     *
     * 功能描述: 获取所有属性
     *
     * @param:
     * @return:
     * @auther: csh
     * @date: 2020/11/9 11:34
     */
    private Properties getProperties(StringReader in) {
        Map map = getPropertisMap(in);
        Properties properties = new Properties();
        for (String key : map.keySet()) {
            properties.setProperty(key, map.get(key));
        }
        return properties;
    }

   /**
    *
    * 功能描述: 解析文件内容
    *
    * @param:
    * @return:
    * @auther: csh
    * @date: 2020/11/9 11:35
    */
    private Map getPropertisMap(StringReader in) {
        Map  map = new HashMap();
        PropertiesConfiguration.PropertiesReader reader = new PropertiesConfiguration.PropertiesReader(in);
        try {
            while (reader.nextProperty()) {
                String key = reader.getPropertyName();
                String value = reader.getPropertyValue();
                map.put(key, value);
            }
        } catch (IOException ioex) {
            throw new ConfigurationRuntimeException(ioex);
        } finally {
            try {
                reader.close();
            } catch (IOException e) {
                logger.error("load config exception", e);
            } finally {
                return map;
            }
        }
    }

  /**
   *
   * 功能描述: 加载配置信息
   *
   * @param:
   * @return:
   * @auther: csh
   * @date: 2020/11/9 11:35
   */
    private void loadDiamondConfig() {
        URL url = this.getClass().getClassLoader().getResource("diamond.properties");
        if (url != null) {
            File file = new File(url.getFile());
            Properties prop = new Properties();
            try {
                prop.load(new FileInputStream(file));
                dataId = prop.getProperty("diamond.dataId");
            } catch (IOException e) {
            }
        }
    }
}

修改diamond-client中的loadConfig方法:com.taobao.diamond.client.DiamondConfigure#loadConfig

注意这里的端口配成跟server一样的

URL url = this.getClass().getClassLoader().getResource("diamond.properties");
if (url != null) {
    File file = new File(url.getFile());
    Properties prop = new Properties();
    try {
        prop.load(new FileInputStream(file));
        configServerAddress = prop.getProperty(Constants.CONF_KEY_CONFIG_IP, Constants.DEFAULT_DOMAINNAME);
        String portStr = prop.getProperty(Constants.CONF_KEY_PORT, String.valueOf(port));
        try {
            port = Integer.parseInt(portStr);
        } catch (NumberFormatException nfe) {
            port = 8090;
        }
    } catch (IOException e) {
    }
}

结果:

spring/springboot的整合分布式配置中心(ACM diamond nacos Apollo)_第5张图片

receive config: 777777777777777777777
receive config: 888888888888888888

spring/springboot的整合分布式配置中心(ACM diamond nacos Apollo)_第6张图片

https://blog.hufeifei.cn/2020/04/15/Alibaba/Diamond/

https://github.com/takeseem/diamond

https://my.oschina.net/piorcn/blog/340407

diamond总结该组件算是国内第一个开源分布式配置中心,虽然说挺好用,但是文档极少并且在淘宝已不维护,所以不建议使用,维护成本挺高的!


Apollo(阿波罗)使用:

apollo-configservice:提供配置获取接口,提供配置更新推送接口,接口服务对象为Apollo客户端

apollo-adminservice:提供配置管理接口,提供配置修改、发布等接口,接口服务对象为Portal,以及Eureka

apollo-portal:提供Web界面供用户管理配置

apollo-client:Apollo提供的客户端程序,为应用提供配置获取、实时更新等功能

Quick-Start启动

参考:https://github.com/ctripcorp/apollo/wiki/Quick-Start

先下载网盘链接下载,提取码: 9wwe

下载到本地后,在本地解压apollo-quick-start.zip

spring/springboot的整合分布式配置中心(ACM diamond nacos Apollo)_第7张图片

创建数据库:执行以下两份

spring/springboot的整合分布式配置中心(ACM diamond nacos Apollo)_第8张图片

spring/springboot的整合分布式配置中心(ACM diamond nacos Apollo)_第9张图片

登陆账号密码:apollo/admin

spring/springboot的整合分布式配置中心(ACM diamond nacos Apollo)_第10张图片

到这里可以发现对比diamond这个apollo所支持的功能比diamond多得多,但是复杂程度也是多好几个量级,如果非中大型项目不太建议,的确非常复杂,我们继续...

相关配置说明:

app.id:在配置中心配置的应用身份信息。

apollo.bootstrap.enabled:在应用启动阶段是否向Spring容器注入被托管的properties文件配置信息。

apollo.bootstrap.eagerLoad.enabled:将Apollo配置加载提到初始化日志系统之前。

apollo.bootstrap.namespaces:配置的命名空间,多个逗号分隔,一个namespace相当于一个配置文件。

**apollo.meta:**当前环境服务配置地址,生产环境建议至少双节点,可以填写多个逗号分隔,使用一个单独的域,如 http://config.xxx.com(由nginx等软件负载平衡器支持),而不是多个IP地址,因为服务器可能会扩展或缩小。

新建项目

spring/springboot的整合分布式配置中心(ACM diamond nacos Apollo)_第11张图片

新增属性

spring/springboot的整合分布式配置中心(ACM diamond nacos Apollo)_第12张图片

运行测试客户端:com.ctrip.framework.apollo.demo.api.SimpleApolloConfigDemo

运行配置如下(不配会找不到服务):

-Dapollo.configService=http://localhost:8080

spring/springboot的整合分布式配置中心(ACM diamond nacos Apollo)_第13张图片

结果:

spring/springboot的整合分布式配置中心(ACM diamond nacos Apollo)_第14张图片

动态加载,修改为999:

spring/springboot的整合分布式配置中心(ACM diamond nacos Apollo)_第15张图片

参考文档:https://github.com/ctripcorp/apollo/wiki/Apollo%E4%BD%BF%E7%94%A8%E6%8C%87%E5%8D%97

spring整合Apollo(阿波罗)

结果

18:40:41.371 [http-nio-8081-exec-4] INFO com.hong.spring.controller.IndexController - 获取配置信息{"val":"999"}

修改为:123

spring/springboot的整合分布式配置中心(ACM diamond nacos Apollo)_第16张图片

结果

spring/springboot的整合分布式配置中心(ACM diamond nacos Apollo)_第17张图片

10:08:01.675 [http-nio-8081-exec-1] INFO com.hong.spring.controller.IndexController - 获取配置信息{"val":"123"}

单个节点不算什么,再试试再开一个端口:8082

spring/springboot的整合分布式配置中心(ACM diamond nacos Apollo)_第18张图片

请求结果

spring/springboot的整合分布式配置中心(ACM diamond nacos Apollo)_第19张图片

10:11:54.076 [http-nio-8082-exec-6] INFO  com.hong.spring.controller.IndexController - 获取配置信息{"val":"123"}

再试试修改为:123456789111

spring/springboot的整合分布式配置中心(ACM diamond nacos Apollo)_第20张图片

特别注意,每次修改后要发布:

spring/springboot的整合分布式配置中心(ACM diamond nacos Apollo)_第21张图片

结果

spring/springboot的整合分布式配置中心(ACM diamond nacos Apollo)_第22张图片

关于spring mvc整合完毕~

springboot整合Apollo(阿波罗)

spring/springboot的整合分布式配置中心(ACM diamond nacos Apollo)_第23张图片

pom.xml



    4.0.0
    
        com.hong.springboot
        springboot_all
        0.0.1-SNAPSHOT
        
    
    com.hong.springboot
    springboot_apollo_client
    0.0.1-SNAPSHOT
    springboot_apollo_client
    springboot??apollo

    
        
            com.ctrip.framework.apollo
            apollo-client
            1.1.0
        

    

META-INF/app.properties

#id
app.id=hong
#环境 dev(开发)FAT()
env=DEV
#运行配置
#-Dapollo.meta=http://localhost:8080
apollo.meta=http://localhost:8080
apollo.bootstrap.enabled=true
#spring.application.name = reservation-service
#server.port = 8080
#logging.level = ERROR
#eureka.client.serviceUrl.defaultZone = http://127.0.0.1:8761/eureka/
#eureka.client.healthcheck.enabled = true
#eureka.client.registerWithEureka = true
#eureka.client.fetchRegistry = true
#eureka.client.eurekaServiceUrlPollIntervalSeconds = 60
#eureka.instance.preferIpAddress = true

application.properties

# will inject 'application' namespace in bootstrap phase
apollo.bootstrap.enabled = true
# put apollo initialization before logging system initialization
apollo.bootstrap.eagerLoad.enabled=true
#端口
server.port=8083

Application 

/**
 * @author: csh
 * @Date: 2020/11/21 11:37
 * @Description:
 */
@SpringBootApplication(scanBasePackages = "com.hong.springboot")
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class);
    }
}

注:其他配置与以上一致!建议下载源码学习!

结果

spring/springboot的整合分布式配置中心(ACM diamond nacos Apollo)_第24张图片

再次修改为:111111

spring/springboot的整合分布式配置中心(ACM diamond nacos Apollo)_第25张图片

spring/springboot的整合分布式配置中心(ACM diamond nacos Apollo)_第26张图片

再次请求

spring/springboot的整合分布式配置中心(ACM diamond nacos Apollo)_第27张图片

springboot真的快了倍,并且简洁!

由于考虑篇幅长度,其它配置中心放到下篇文章统一输出!感谢阅读,如有疑问请私聊或下方留言,谢谢!

参考文章:

https://developer.aliyun.com/article/468274

spring/springboot的整合分布式配置中心(ACM diamond nacos Apollo)_第28张图片

你可能感兴趣的:(spring,集成,maven,分布式,java,spring,zookeeper,spring,boot)