• Dubbo学习系列之十九(Apollo分布式部署)


     

    说一个人是武林高手:十八般武艺,样样精通!如今,后端技术层出不穷,让人眼花缭乱,如果看官不能达到样样精通,至少

    拿起方天画戟能耍几下才行,比如削个苹果。言归正传,配置中心属于基础设施,当然必须玩得溜,不论Nacos还是Config,

    今天我们来耍下Apollo,看好玩否。

     

    作者原创文章,谢绝一切转载,违者必究!

    本文只发表在"公众号"和"博客园",其他均属复制粘贴!如果觉得排版不清晰,请查看公众号文章。 

     

    准备:

    Idea2019.03/Gradle6.0.1/Maven3.6.3/JDK11.0.4/SpringBoot2.3.0RELEASE/Mysql8.0.11/Apollo1.7.0/RHEL8.0/ VMwareWorkstation15Pro

    难度: 新手--战士--老兵--大师

    目标:

    1.完成Apollo分布式部署和简单应用

    说明: 为了遇见各种问题,同时保持时效性,我尽量使用最新的软件版本,源码地址,其中的day31:https://github.com/xiexiaobiao/dubbo-project

    1 部署图(单服务)

    Apollo基础知识,略!请先安装好Maven和JDK环境!Linux内存建议4G以上!

    注:Apollo自带Eureka组件,可以自动组成集群,当然,如果希望使用外部Eureka组件,需修改配置即可!

    2 步骤

    我使用最纯粹的源码编译部署方式,其他如Docker、QuickStart,略!

    2.1 Git clone 项目源码文件到本地,Window下构建修改文件apolloscriptsuild.bat(Linux下则修改apolloscriptsuild.sh):

    2.2 然后直接双击运行build.bat:

    2.3 复制apollo-adminservice,apollo-configservice,apollo-portal三个模块的 target 文件夹下的 zip 文件到Linux下,我这里分别放三个目

    录admin-service, config-service, portal-service下:

    解压:

    [root@server226 config-service]# unzip apollo-configservice-1.7.0-SNAPSHOT-github.zip
    [root@server226 admin-service]# unzip apollo-adminservice-1.7.0-SNAPSHOT-github.zip
    [root@server226 portal-service]# unzip apollo-portal-1.7.0-SNAPSHOT-github.zip
    

    启动服务,注意顺序:

    [root@server226 portal-service]# bash /usr/apollo1.7.0/config-service/scripts/startup.sh
    [root@server226 portal-service]# bash /usr/apollo1.7.0/admin-service/scripts/startup.sh
    [root@server226 portal-service]# bash /usr/apollo1.7.0/portal-service/scripts/startup.sh 
    

    (常见启动异常问题,请见文末部分)

    注:如果 ApolloConfigDB.ServerConfig 的 eureka.service.url 只配了当前正在启动的机器的话,在启动apollo-configservice的过程中会在日志

    中输出eureka注册失败的信息,如com.sun.jersey.api.client.ClientHandlerException: java.net.ConnectException: Connection refused

    需要注意的是,这个是预期的情况,因为apollo-configservice需要向Meta Server(它自己)注册服务,但是因为在启动过程中,自己还没起来,

    所以会报这个错。后面会进行重试的动作,所以等自己服务起来后就会注册正常了。

     

    2.4 在启动config-service成功后,即可打开http://192.168.2.226:8080/,(修改端口见后文),可以查看eureka界面:

    如果src/main/config/application-github.properties中,开启以下两项:

    apollo.eureka.server.enabled=true
    apollo.eureka.client.enabled=true
    

     

    2.5 验证是否全部启动成功:http://192.168.2.226:8070/ 账号/密码:apollo/admin 登录:

    2.6 优雅关闭服务,注意顺序:

    [root@server226 portal-service]# bash /usr/apollo1.7.0/portal-service/scripts/shutdown.sh
    [root@server226 portal-service]# bash /usr/apollo1.7.0/admin-service/scripts/shutdown.sh 
    [root@server226 portal-service]# bash /usr/apollo1.7.0/config-service/scripts/shutdown.sh
    

    2.7 修改config-service默认端口8080为8085

    1. src/main/resources/application.yml 中修改 server:port: 8085
    2. src/main/resources/configservice.properties 中修改server.port= 8085
    3. src/main/scripts/startup.sh 中修改SERVER_PORT:=8085
    4. 数据库apolloconfigdb.serverconfig 中eureka.service.url 字段修改http://192.168.2.226:8085/eureka/

    3 部署图(高可用)

    架构部署图:

    注:这里未画出client,client会先访问metaService,获取configService的列表,再从configService获取配置数据,可以使用SLB(Software Load Balancer)对client访问多个metaService做负载均衡。

    同上方法,我修改config-service端口为8086,需修改(共5处) src/main/resources/application.yml,src/main/resources/configservice.properties,src/main/scripts/startup.sh,src/main/resources/configservice.properties, 数据库apolloconfigdb.serverconfig 中eureka.service.url 字段添加http://192.168.2.224:8086/eureka/,并使用同上apolloscriptsuild.bat脚本进行构建打包,放到另一Linux(192.168.2.224)上运行:

     

    然后,可以访问:http://192.168.2.224:8086/

    访问:http://192.168.2.226:8085/

    由以上两图,可见eureka实例已组成集群,互为备份!

     

    打开:http://192.168.2.226:8070/system_info.html,可以看到 portal 能管理所有的 configService和adminService实例:

    4 客户端应用

    apollo客户端,即在应用中访问apollo的配置数据,引入相关依赖包即可。具体依赖,略!

    4.1 API方式(此方式不依赖spring框架)

    配置appID和 metaService, src/main/resources/META-INF/app.properties

    配置metaService,如果是多environment,通过src/main/resources/apollo-env.properties

    指定env,Windows文件位置为 C:optsettingsserver.properties (对于Mac/Linux,文件位置为/opt/settings/server.properties) ,内容为:

    env=DEV

    通过portal UI创建一个配置,最后效果如下:

    测试代码(java):

    public class ApiMain {
    
        private static final Logger logger = LoggerFactory.getLogger(ApiMain.class);
        private String DEFAULT_VALUE = "undefined";
        // config instance is singleton for each namespace and is never null
        private Config config;
    
        ConfigChangeListener changeListener = configChangeEvent -> {
            for (String key: configChangeEvent.changedKeys()
                 ) {
                ConfigChange change = configChangeEvent.getChange(key);
                logger.info("Config Change >>>>> key: {}, oldValue: {}, newValue: {}, changeType: {}",
                        change.getPropertyName(), change.getOldValue(), change.getNewValue(),
                        change.getChangeType());
            }
        };
    
        public ApiMain() {
            this.config = ConfigService.getAppConfig();
            this.config.addChangeListener(changeListener);
        }
    
        public static void main(String[] args) throws IOException {
            ApiMain apiMain = new ApiMain();
            // getConfig("key"); key为配置数据中的key
            apiMain.getConfig("name");
        }
    
        private String getConfig(String key){
            String result = config.getProperty(key,DEFAULT_VALUE);
            logger.info(String.format("Loading key >>>> %s with value: %s", key, result));
            return result;
        }
    }
     

    以上代码解析: 通过 Config config 成员变量注入,并添加一个 ConfigChangeListener 做配置变化的监听器,可以在配置变化时得到通知,如数据库连接串变化后需要重建连接等。

    运行输出:

    读取到的配置信息:

    在portal界面,进行“修改”->“发布”,监听到的配置变化:

     

    4.2 Springboot方式

    修改src/main/resources/config/application.yml:

    注:多namespace的情况下,应用会默认读取非‘application’的配置;

    写一个测试用bean,使用SPEL表达式就可以实现自动属性注入,冒号后数值为超时时间

    public class ConfigBean {
    
        private String school;
    
        @Value("${timeValue:100}")
        private String timeValue;
    
        public String getSchool() {
            return school;
        }
    
        @Value("${school:200}")
        public void setSchool(String school) {
            this.school = school;
        }
    ...
    }
     

    另外我还写了一个注解方式的:

    @ConfigurationProperties(prefix = "redis.cache")
    public class SampleRedisConfig {
        private int expireSeconds;
        private int commandTimeout;
    ...
    }
     

    配合spring机制实现bean注入:

    @Configuration
    //@EnableApolloConfig(value = {"FX.apollo", "application.yml"}, order = 1)
    public class SomeConfig {
    
        @Bean
        public ConfigBean getConfigBean(){
            return new ConfigBean();
        }
    
        @Bean
        public SampleRedisConfig sampleRedisConfig() {
            return new SampleRedisConfig();
        }
    }
     

    最后给个应用的入口:

    @SpringBootApplication
    @RestController
    public class AppMain {
        private ConfigBean configBean;
        private SampleRedisConfig redisConfig;
    
        @Autowired
        public AppMain(ConfigBean configBean,SampleRedisConfig redisConfig){
            this.configBean = configBean;
            this.redisConfig = redisConfig;
        }
    
        public static void main(String[] args) {
            SpringApplication.run(AppMain.class,args);
            System.out.println("AppMain app started >>>>>>>>>>>>");
        }
        @RequestMapping("/config")
        public String apollo(){
            System.out.println("config 1 >>>> " + configBean.getSchool() +"/"+ configBean.getTime());
            System.out.println("config 2 >>>> " + redisConfig.getCommandTimeout()+"/"+ redisConfig.getExpireSeconds());
            return "config >>>> " + configBean.getSchool() +"/"+ configBean.getTime();
        }
    }
     

    在portal界面配置KV值:

    运行应用并URL访问:

    控制台输出:

    5 常见问题

    5.1 查看config-service启动日志,发现mysql连接异常:

    [root@server226 admin-service]# less /opt/logs/100003171/apollo-configservice.log
    

    另一种查看mysql连接是否成功方法是启动apollo服务前后分别运行,比较连接数:

    问题解决,注意window机器防火墙规则,可以直接关闭,或添加出入规则。

    5.2 查看config-service启动日志,发现端口冲突异常:

    解决问题,先查看端口占用情况:

    [root@server226 config-service]# lsof -i:8080
    

    直接kill 命令关闭,或者找到对应的应用进行关闭即可!

    5.3 查看config-service启动日志,发现Eureka连接异常:

    问题解决:Linux使用了hostname,导致localhost解析异常,修改 src/main/resources/bootstrap.yml :

    注意需同步修改 apolloapollo-adminservice 模块下的 src/main/resources/bootstrap.yml,内容同上。

     

    遗留问题

    1."访问密钥"开启的情况下,一直访问失败;

    2.使用@ConfigurationProperties如果需要在Apollo配置变化时自动更新注入的值,需要配合使用EnvironmentChangeEventRefreshScope。相关代码实现,可以参考官方apollo-use-cases项目;

    后记:在以上各个部署的每个步骤中,几乎都有多种实现方式,我只是使用了其中的1-2种,其他可参考官方说明!

     

    全文完!


    我近期其他文章:

           只写原创,敬请关注 

  • 相关阅读:
    一LWIP学习笔记之数据包管理
    智能家居的发展趋势
    break和continue的区别
    TCP与UDP区别总结
    C语言变量和函数命名规范
    常用电子元件
    php 1018
    php 1016
    mysql 应用查询 三个表(学生表,课程表,学生课程分数表) student, course, score表
    mysql 聚合函数
  • 原文地址:https://www.cnblogs.com/xxbiao/p/13153735.html
Copyright © 2020-2023  润新知