Apollo在基础架构中的实践经验

2024-05-24 14:32

本文主要是介绍Apollo在基础架构中的实践经验,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

本文来自李伟超同学的投稿,如果你有好的文章也欢迎联系我。

微服务配置中心 Apollo 使用指南,以下文档根据 apollo wiki 整理而来,部分最佳实践说明和代码改造基于笔者的工作经验整理而来,如有问题欢迎沟通。

1 配置中心

在拆分为微服务架构前,曾经的单体应用只需要管理一套配置。而拆分为微服务后,每一个系统都有自己的配置,并且都各不相同,而且因为服务治理的需要,有些配置还需要能够动态改变,如业务参数调整或需要熔断限流等功能,配置中心就是解决这个问题的。

1.1 配置的基本概念

  • 配置是独立于程序的只读变量

    • 同个应用在不同的配置有不同的行为

    • 应用不应该改变配置

  • 配置伴随应用的整个生命周期

    • 初始化参数和运行参数

  • 配置可以有多种加载方式

  • 配置需要治理

    • 权限控制(应用级别、编辑发布隔离等)

    • 多环境集群配置管理

    • 框架类组件配置管理

1.2 配置中心

  • 配置注册与反注册

  • 配置治理

  • 配置变更订阅

1.3 Spring Environment

Environment 是 Spring 容器中对于应用环境两个关键因素(profile & properties)的一个抽象。

  • profile

profile 是一个逻辑的分组,当 bean 向容器中注册的时候,仅当配置激活时生效。

## 配置文件使用spring.profiles.active=xxx
## 硬编码注解形式使用@org.springframework.context.annotation.Profile
  • properties

Properties 在几乎所有应用程序中都扮演着重要的角色,并且可能来自各种各样的来源:properties 文件、JVM系统属性、系统环境变量、JNDI、Servlet Context 参数、ad-hoc Properties 对象、Map 等等。Environment 与 Properties 的关系是为用户提供一个方便的服务接口,用于配置属性源并从它们中解析属性。

  • Spring 中的扩展点

    • spring framework 提供了便捷的方式添加自定义数据源策略添加到 Spring Enviroment 中,如 @PropertySource。https://docs.spring.io/spring/docs/5.1.8.RELEASE/spring-framework-reference/core.html#beans-using-propertysource

    • spring boot 提供了相关的扩展方式,如 EnviromentPostProcessor 相关的。https://docs.spring.io/spring-boot/docs/2.1.6.RELEASE/reference/html/boot-features-external-config.html

    • spring boot 同时也提供在开始之前自定义环境扩展。https://docs.spring.io/spring-boot/docs/2.1.6.RELEASE/reference/html/howto-spring-boot-application.html#howto-customize-the-environment-or-application-context

2 Apollo 简介

2.1 简介

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

Apollo 支持4个维度管理 Key-Value 格式的配置:

  • application (应用)

这个很好理解,就是实际使用配置的应用,Apollo 客户端在运行时需要知道当前应用是谁,从而可以去获取对应的配置。每个应用都需要有唯一的身份标识,我们认为应用身份是跟着代码走的,所以需要在代码中配置,具体信息请参见 Java 客户端使用指南。

  • environment (环境)

配置对应的环境,Apollo 客户端在运行时需要知道当前应用处于哪个环境,从而可以去获取应用的配置。我们认为环境和代码无关,同一份代码部署在不同的环境就应该能够获取到不同环境的配置,所以环境默认是通过读取机器上的配置(server.properties中的env属性)指定的,不过为了开发方便,我们也支持运行时通过 System Property 等指定,具体信息请参见Java客户端使用指南。

  • cluster (集群)

一个应用下不同实例的分组,比如典型的可以按照数据中心分,把上海机房的应用实例分为一个集群,把北京机房的应用实例分为另一个集群。对不同的cluster,同一个配置可以有不一样的值,如 zookeeper 地址。集群默认是通过读取机器上的配置(server.properties中的idc属性)指定的,不过也支持运行时通过 System Property 指定,具体信息请参见Java客户端使用指南。

  • namespace (命名空间)

一个应用下不同配置的分组,可以简单地把 namespace 类比为文件,不同类型的配置存放在不同的文件中,如数据库配置文件,RPC配置文件,应用自身的配置文件等。应用可以直接读取到公共组件的配置 namespace,如 DAL,RPC 等。应用也可以通过继承公共组件的配置 namespace 来对公共组件的配置做调整,如DAL的初始数据库连接数。

同时,Apollo 基于开源模式开发,开源地址:https://github.com/ctripcorp/apollo

2.2 基础模型

如下即是Apollo的基础模型:

  1. 用户在配置中心对配置进行修改并发布

  2. 配置中心通知Apollo客户端有配置更新

  3. Apollo客户端从配置中心拉取最新的配置、更新本地配置并通知到应用

             

3 Apollo 架构说明

Apollo 项目本身就使用了 Spring Boot & Spring Cloud 开发。

3.1 服务端

             

上图简要描述了Apollo的总体设计,我们可以从下往上看:

  • Config Service 提供配置的读取、推送等功能,服务对象是Apollo客户端。

  • Admin Service 提供配置的修改、发布等功能,服务对象是Apollo Portal(管理界面)。

  • Config Service 和 Admin Service 都是多实例、无状态部署,所以需要将自己注册到 Eureka 中并保持心跳

  • 在 Eureka 之上我们架了一层 Meta Server 用于封装 Eureka 的服务发现接口 Client 通过域名访问 Meta Server 获取 Config Service 服务列表(IP+Port),而后直接通过 IP+Port 访问服务,同时在 Client 侧会做 load balance、错误重试

  • Portal 通过域名访问 Meta Server 获取 Admin Service 服务列表(IP+Port),而后直接通过 IP+Port 访问服务,同时在 Portal 侧会做 load balance、错误重试

  • 为了简化部署,我们实际上会把 Config Service、Eureka 和 Meta Server 三个逻辑角色部署在同一个 JVM 进程中。

3.2 客户端

             

  • 客户端和服务端保持了一个长连接,从而能第一时间获得配置更新的推送。

  • 客户端还会定时从 Apollo 配置中心服务端拉取应用的最新配置。

    • 这是一个fallback机制,为了防止推送机制失效导致配置不更新

    • 客户端定时拉取会上报本地版本,所以一般情况下,对于定时拉取的操作,服务端都会返回304 - Not Modified

    • 定时频率默认为每5分钟拉取一次,客户端也可以通过在运行时指定 System Property: apollo.refreshInterval 来覆盖,单位为分钟。

  • 客户端从Apollo配置中心服务端获取到应用的最新配置后,会保存在内存中

  • 客户端会把从服务端获取到的配置在本地文件系统缓存一份

    • 在遇到服务不可用,或网络不通的时候,依然能从本地恢复配置

  • 应用程序从Apollo客户端获取最新的配置、订阅配置更新通知

长连接实现上是使用的异步+轮询实现

4 Apollo 高可用部署

在 Apollo 架构说明中我们提到过 client 和 portal 都是在客户端负载均衡,根据 ip+port 访问服务,所以 config service 和 admin service 是无状态的,可以水平扩展的,portal service 根据使用 slb 绑定多台服务器达到切换,meta server 同理。

 

场景

影响

降级

原因

某台config service下线

无影响


Config service无状态,客户端重连其它config service

所有config service下线

客户端无法读取最新配置,Portal无影响

客户端重启时,可以读取本地缓存配置文件


某台admin service下线

无影响


Admin service无状态,Portal重连其它admin service

所有admin service下线

客户端无影响,portal无法更新配置



某台portal下线

无影响


Portal域名通过slb绑定多台服务器,重试后指向可用的服务器

全部portal下线

客户端无影响,portal无法更新配置



某个数据中心下线

无影响


多数据中心部署,数据完全同步,Meta Server/Portal域名通过slb自动切换到其它存活的数据中心

5 Apollo 使用说明

5.1 使用说明

Apollo使用指南

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

Java客户端使用指南

https://github.com/ctripcorp/apollo/wiki/Java%E5%AE%A2%E6%88%B7%E7%AB%AF%E4%BD%BF%E7%94%A8%E6%8C%87%E5%8D%97

5.2 最佳实践

在 Spring Boot & Spring Cloud 中使用。

  • 每个应用都需要有唯一的身份标识,我们认为应用身份是跟着代码走的,所以需要在代码中配置。关于应用身份标识,应用标识对第三方中间件应该是统一的,扩展支持 apollo 身份标识和 spring.application.name 一致(具体查看 fusion-config-apollo 中代码),其他中间件同理。

  • 应用开发过程中如使用代码中的配置,应该充分利用 Spring Environment Profile,增加本地逻辑分组 local,非开发阶段关闭 local 逻辑分组。同时关闭 apollo 远程获取配置,在 VM options 中增加 -Denv=local。

             

以下代码是扩展 apollo 应用标识使用 spring.application.name,并增加监控配置,监控一般是基础架构团队提供的功能,从基础框架硬编码上去,业务侧做到完全无感知。

import com.ctrip.framework.apollo.ConfigService;import com.ctrip.framework.apollo.spring.config.PropertySourcesConstants;import com.ctrip.framework.foundation.internals.io.BOMInputStream;import com.ctrip.framework.foundation.internals.provider.DefaultApplicationProvider;import lombok.extern.slf4j.Slf4j;import org.springframework.boot.SpringApplication;import org.springframework.boot.SpringApplicationRunListener;import org.springframework.context.ConfigurableApplicationContext;import org.springframework.core.annotation.Order;import org.springframework.core.env.ConfigurableEnvironment;import org.springframework.core.env.EnumerablePropertySource;import org.springframework.core.env.PropertiesPropertySource;import org.springframework.util.StringUtils; import java.io.InputStream;import java.io.InputStreamReader;import java.nio.charset.StandardCharsets;import java.util.Properties;import java.util.Set; 
/** * ApolloSpringApplicationRunListener * <p> * SpringApplicationRunListener 接口说明 * https://blog.csdn.net/u011179993/article/details/51555690https://blog.csdn.net/u011179993/article/details/51555690 * * @author Weichao Li (liweichao0102@gmail.com) * @since 2019-08-15 */@Order(value = ApolloSpringApplicationRunListener.APOLLO_SPRING_APPLICATION_RUN_LISTENER_ORDER)@Slf4jpublic class ApolloSpringApplicationRunListener implements SpringApplicationRunListener { public static final int APOLLO_SPRING_APPLICATION_RUN_LISTENER_ORDER = 1; private static final String APOLLO_APP_ID_KEY = "app.id"; private static final String SPRINGBOOT_APPLICATION_NAME = "spring.application.name"; private static final String CONFIG_CENTER_INFRA_NAMESPACE = "infra.monitor";
public ApolloSpringApplicationRunListener(SpringApplication application, String[] args) { }
/** * 刚执行run方法时 */ @Override public void starting() { }
/** * 环境建立好时候 * * @param env 环境信息 */ @Override public void environmentPrepared(ConfigurableEnvironment env) { Properties props = new Properties(); props.put(PropertySourcesConstants.APOLLO_BOOTSTRAP_ENABLED, true); props.put(PropertySourcesConstants.APOLLO_BOOTSTRAP_EAGER_LOAD_ENABLED, true); env.getPropertySources().addFirst(new PropertiesPropertySource("apolloConfig", props)); // 初始化appId this.initAppId(env); // 初始化基础架构提供的默认配置,需在项目中关联公共 namespaces this.initInfraConfig(env); }
/** * 上下文建立好的时候 * * @param context 上下文 */ @Override public void contextPrepared(ConfigurableApplicationContext context) {

}
/** * 上下文载入配置时候 * * @param context 上下文 */ @Override public void contextLoaded(ConfigurableApplicationContext context) {

}
@Override public void started(ConfigurableApplicationContext context) {

  } 
@Override public void running(ConfigurableApplicationContext context) {

  } 
@Override public void failed(ConfigurableApplicationContext context, Throwable exception) {

  } 
/** * 初始化 apollo appId * * @param env 环境信息 */ private void initAppId(ConfigurableEnvironment env) { String apolloAppId = env.getProperty(APOLLO_APP_ID_KEY); if (StringUtils.isEmpty(apolloAppId)) { //此处需要判断一下 meta-inf 下的文件中的 app id apolloAppId = getAppIdByAppPropertiesClasspath(); if (StringUtils.isEmpty(apolloAppId)) { String applicationName = env.getProperty(SPRINGBOOT_APPLICATION_NAME); if (!StringUtils.isEmpty(applicationName)) { System.setProperty(APOLLO_APP_ID_KEY, applicationName); } else { throw new IllegalArgumentException("config center must config app.id in " + DefaultApplicationProvider.APP_PROPERTIES_CLASSPATH); } } else { System.setProperty(APOLLO_APP_ID_KEY, apolloAppId); } } else { System.setProperty(APOLLO_APP_ID_KEY, apolloAppId); } }
/** * 初始化基础架构提供的配置 * * @param env 环境信息 */ private void initInfraConfig(ConfigurableEnvironment env) { com.ctrip.framework.apollo.Config apolloConfig = ConfigService.getConfig(CONFIG_CENTER_INFRA_NAMESPACE); Set<String> propertyNames = apolloConfig.getPropertyNames(); if (propertyNames != null && propertyNames.size() > 0) { Properties properties = new Properties(); for (String propertyName : propertyNames) { properties.setProperty(propertyName, apolloConfig.getProperty(propertyName, null)); } EnumerablePropertySource enumerablePropertySource = new PropertiesPropertySource( CONFIG_CENTER_INFRA_NAMESPACE, properties); env.getPropertySources().addLast(enumerablePropertySource); } }
/** * 从 apollo 默认配置文件中取 app.id 的值,调整优先级在 spring.application.name 之前 * * @return apollo app id */ private String getAppIdByAppPropertiesClasspath() { try { InputStream in = Thread.currentThread().getContextClassLoader() .getResourceAsStream(DefaultApplicationProvider.APP_PROPERTIES_CLASSPATH); if (in == null) { in = DefaultApplicationProvider.class .getResourceAsStream(DefaultApplicationProvider.APP_PROPERTIES_CLASSPATH); } Properties properties = new Properties(); if (in != null) { try { properties.load(new InputStreamReader(new BOMInputStream(in), StandardCharsets.UTF_8)); } finally { in.close(); } } if (properties.containsKey(APOLLO_APP_ID_KEY)) { String appId = properties.getProperty(APOLLO_APP_ID_KEY); log.info("App ID is set to {} by app.id property from {}", appId, DefaultApplicationProvider.APP_PROPERTIES_CLASSPATH); return appId; } } catch (Throwable ignore) { } }}

 

5.3 动态刷新

支持 Apollo 配置自动刷新类型,支持 @Value @RefreshScope @ConfigurationProperties 以及日志级别的动态刷新。具体代码查看下文链接。

  • @Value

@Value Apollo 本身就支持了动态刷新,需要注意的是如果@Value 使用了 SpEL 表达式,动态刷新会失效。

 

支持动态刷新

@Value("${simple.xxx}")private String simpleXxx;

不支持动态刷新

@Value("#{'${simple.xxx}'.split(',')}")private List<String> simpleXxxs;

 

  • @RefreshScope

RefreshScope(org.springframework.cloud.context.scope.refresh)是 Spring Cloud 提供的一种特殊的 scope 实现,用来实现配置、实例热加载。

动态实现过程:

配置变更时,调用 refreshScope.refreshAll() 或指定 bean。提取标准参数(System,jndi,Servlet)之外所有参数变量,把原来的Environment里的参数放到一个新建的 Spring Context 容器下重新加载,完事之后关闭新容器。提取更新过的参数(排除标准参数) ,比较出变更项,发布环境变更事件,RefreshScope 用新的环境参数重新生成Bean。重新生成的过程很简单,清除 refreshscope 缓存幷销毁 Bean,下次就会重新从 BeanFactory 获取一个新的实例(该实例使用新的配置)。

  • @ConfigurationProperties

apollo 默认是不支持 ConfigurationProperties 刷新的,这块需要配合 EnvironmentChangeEvent 刷新的。

  • 日志级别

apollo 默认是不支持日志级别刷新的,这块需要配合 EnvironmentChangeEvent 刷新的。

  • EnvironmentChangeEvent(Spring Cloud 提供)

当观察到 EnvironmentChangeEvent 时,它将有一个已更改的键值列表,应用程序将使用以下内容:1,重新绑定上下文中的任何 @ConfigurationProperties bean,代码见org.springframework.cloud.context.properties.ConfigurationPropertiesRebinder。2,为logging.level.*中的任何属性设置记录器级别,代码见 org.springframework.cloud.logging.LoggingRebinder。

支持动态刷新

import com.ctrip.framework.apollo.model.ConfigChangeEvent;import com.ctrip.framework.apollo.spring.annotation.ApolloConfigChangeListener;import lombok.extern.slf4j.Slf4j;import org.springframework.beans.BeansException;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.cloud.context.environment.EnvironmentChangeEvent;import org.springframework.cloud.context.scope.refresh.RefreshScope;import org.springframework.context.ApplicationContext;import org.springframework.context.ApplicationContextAware;import org.springframework.context.annotation.Configuration; 
/** * LoggerConfiguration * * @author Weichao Li (liweichao0102@gmail.com) * @since 2019/11/14 */@Configuration@Slf4jpublic class ApolloRefreshConfiguration implements ApplicationContextAware {
private ApplicationContext applicationContext;
@Autowired private RefreshScope refreshScope;
@ApolloConfigChangeListener private void onChange(ConfigChangeEvent changeEvent) { applicationContext.publishEvent(new EnvironmentChangeEvent(changeEvent.changedKeys())); refreshScope.refreshAll(); }

@Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; }}

注意原有配置如果有日志级别需要初始化。

import com.ctrip.framework.apollo.Config;import com.ctrip.framework.apollo.spring.annotation.ApolloConfig;import lombok.extern.slf4j.Slf4j;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.logging.LogLevel;import org.springframework.boot.logging.LoggingSystem;import org.springframework.context.annotation.Configuration; import javax.annotation.PostConstruct;import java.util.Set; 
/** * logging 初始化 * * @author Weichao Li (liweichao0102@gmail.com) * @since 2019/11/14 */@Configuration@Slf4jpublic class LoggingConfiguration {
private static final String LOGGER_TAG = "logging.level.";
private static final String DEFAULT_LOGGING_LEVEL = "info";
@Autowired private LoggingSystem loggingSystem;
@ApolloConfig private Config config;
@PostConstruct public void changeLoggingLevel() { Set<String> keyNames = config.getPropertyNames(); for (String key : keyNames) { if (containsIgnoreCase(key, LOGGER_TAG)) { String strLevel = config.getProperty(key, DEFAULT_LOGGING_LEVEL); LogLevel level = LogLevel.valueOf(strLevel.toUpperCase()); loggingSystem.setLogLevel(key.replace(LOGGER_TAG, ""), level); } } }

private static boolean containsIgnoreCase(String str, String searchStr) { if (str == null || searchStr == null) { return false; } int len = searchStr.length(); int max = str.length() - len; for (int i = 0; i <= max; i++) { if (str.regionMatches(true, i, searchStr, 0, len)) { return true; } } return false; }}

6 Apollo 最佳实践 - 配置治理

6.1 权限控制

由于配置能改变程序的行为,不正确的配置甚至能引起灾难,所以对配置的修改必须有比较完善的权限控制。应用和配置的管理都有完善的权限管理机制,对配置的管理还分为了编辑和发布两个环节,从而减少人为的错误。所有的操作都有审计日志,可以方便地追踪问题

  • everyone 要有自己的账户(最主要的前置条件)

  • 每一个项目都至少有一个 owner(项目管理员,项目管理员拥有以下权限)

    • 可以管理项目的权限分配

    • 可以创建集群

    • 可以创建 Namespace

  • 项目管理员(owner)根据组织结构分配配置权限

    • 编辑权限允许用户在 Apollo 界面上创建、修改、删除配置

      • 配置修改后只在 Apollo 界面上变化,不会影响到应用实际使用的配置

    • 发布权限允许用户在 Apollo 界面上发布、回滚配置

      • 配置只有在发布、回滚动作后才会被应用实际使用到

      • Apollo在用户操作发布、回滚动作后实时通知到应用,并使最新配置生效

  • 项目管理员管理权限界面

             

项目创建完,默认没有分配配置的编辑和发布权限,需要项目管理员进行授权。

1 点击application这个namespace的授权按钮

              

2 分配修改权限

             

3 分配发布权限

             

6.2 Namespace

Namespace 权限分类

apollo 获取权限分类分为私有的和公共的。

  • private (私有的)

private权限的Namespace,只能被所属的应用获取到。一个应用尝试获取其它应用private的Namespace,Apollo会报“404”异常。

  • public (公共的)

public权限的Namespace,能被任何应用获取。

Namespace 的分类

Namespace 有三种类型,私有类型,公共类型,关联类型(继承类型)。

Apollo 私有类型 Namespace 使用说明

私有类型的 Namespace 具有 private 权限。例如服务默认的“application” Namespace 就是私有类型。

1 使用场景

  • 服务自身的配置(如数据库、业务行为等配置)

2 如何使用私有类型 Namespace

一个应用下不同配置的分组,可以简单地把namespace类比为文件,不同类型的配置存放在不同的文件中,如数据库配置文件,业务属性配置,配置文件等

Apollo 公共类型 Namespace 使用说明

公共类型的 Namespace 具有 public 权限。公共类型的 Namespace 相当于游离于应用之外的配置,且通过 Namespace 的名称去标识公共 Namespace,所以公共的 Namespace 的名称必须全局唯一。

1 使用场景

  • 部门级别共享的配置

  • 小组级别共享的配置

  • 几个项目之间共享的配置

  • 中间件客户端的配置

2 如何使用公共类型 Namespace

  • 代码侵入型

@EnableApolloConfig({"application", "poizon-infra.jaeger"})
  • 配置方式形式


# will inject 'application' namespace in bootstrap phaseapollo.bootstrap.enabled = true# will inject 'application', 'poizon-infra.jaeger' namespaces in bootstrap phaseapollo.bootstrap.namespaces = application,poizon-infra.jaeger

Apollo 关联类型 Namespace 使用说明

关联类型又可称为继承类型,关联类型具有 private 权限。关联类型的 Namespace 继承于公共类型的 Namespace,用于覆盖公共 Namespace 的某些配置。

使用建议

  • 基础框架部分的统一配置,如 DAL 的常用配置

  • 基础架构的公共组件的配置,如监控,熔断等公共组件配置

这篇关于Apollo在基础架构中的实践经验的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/998675

相关文章

解析apollo纵向控制标定表程序

百度apollo采用标定表描述车辆速度、加速度与油门/刹车之间的关系。该表可使无人车根据当前车速与期望加速度得到合适的油门/刹车开合度。除了文献《Baidu Apollo Auto-Calibration System - An Industry-Level Data-Driven and Learning based Vehicle Longitude Dynamic Calibrating

李沐讲座:大语言模型的实践经验和未来预测 | 上海交大

本文简介 本博客记录了李沐关于语言模型与职业生涯分享的精彩讲座,涵盖了大语言模型的核心要素、工程实践中的挑战,以及演讲者个人职业生涯中的心得体会。 李沐简介 李沐(Mu Li)是一位在人工智能与深度学习领域具有广泛影响力的计算机科学家。他拥有丰富的学术背景和产业经验,曾在百度和Amazon等知名科技公司工作,并有两次成功的创业经历。李沐以其在深度学习、分布式系统以及大规模机器学习方面的杰出贡

springboot整合Apollo配置中心(四)

这篇文章主要记录搭建生产环境整合Apollo配置中心,搭建高可用的过程. 生产环境相比UAT环境和测试环境,需要更高的稳定性,防止在配置中心宕机的情况下,服务不可用. 详细的搭建过程,官方的分布式环境配置已经写的十分详细,这里只是对搭建过程做的总结. Apollo配置中心分布式部署指南 下面是实际搭配的步骤记录. 搭建配置中心 在另外一台服务器上面,上传configService服务,启动.不

springboot整合Apollo配置中心(三)

这篇文章主要来记录下项目整合Apollo之后,多个环境的配置。 上一篇写了项目测试环境整合了Apollo配置中心。这还远远不够,还缺少了生产环境和UAT环境的配置,其实配置特别也很简单,官方文档写的也很到位,这里对我的整合过程做个总结。 这里仅对生产环境的整合做一次记录,uat环境同样配置。 生产环境数据库导入 上篇文章,测试环境的数据库导入了apolloconfigdb.sql,apollo

springboot整合Apollo配置中心(一)

Apollo介绍及整合需要 Apollo配置中心是携程框架部门研发的分布式配置中心,能够集中化管理应用不同环境,不同集群的配置,配置修改后能够在1秒内将配置推送到服务端,适用于微服务配置管理场景。 这是Apollo配置中心的官方介绍,已经十分的详细清晰了,这次使用springboot整合Apollo主要是为了解决几个困扰我的问题: 项目发布后,碰到需要修改配置的地方,反复发布重启,浪费时间,用

粗浅看 Web基础架构:负载均衡和LVS

背景 在大规模互联网应用中,负载均衡设备是必不可少的一个节点,源于互联网应用的高并发和大流量的冲击压力,我们通常会在服务端部署多个无状态的应用服务器和若干有状态的存储服务器(数据库、缓存等等)。 负载均衡的作用 负载均衡设备的任务就是作为应用服务器流量的入口,挑选最合适的一台服务器,将客户端的请求转发给它处理,实现客户端到真实服务端的透明转发。最近几年很火的「云计算」 以及分布式架构,本质上也是

【ElasticSearch实战】——封装java操作es基础架构

创建ES专栏很久了,但是写的文章非常的少,实在是项目比较忙,2018年最后一天了也该总结一下对es的封装的东西了,这篇博客我们通过java对es批量插入为主流程,来介绍一下java对接es 的全部过程; 需求处理流程:  从mysql中插入手机号7位所有的组合,然后通过程序处理补充后四位所有的可能,然后组成一个庞大的手机号码库,然后在讲手机号加密,为其他的应用提供 手机号明密文转换服务; 1

【实践经验】端口被占用问题:listen tcp:bind:only one usage of each socket address

文章目录 一. 问题描述二. 分析1. 适用错误 三. 解决方法1. 打开控制台2. 查看端口的使用情况2.1 不知道端口号——查看所有运行的端口2.2 知道端口号 3. 查看使用进程的程序4. 杀死进程5. 验证端口是否释放 一. 问题描述 goland启动项目后报错:“listen tcp:bind:only one usage of each socket addr

apollo规划架构

算法的基本架构 我们在最开始直接给出规划决策算法架构框图,然后一一介绍每个框图结构的细节: 模块的入口是 PlanningComponent,在 Cyber 中注册模块,订阅和发布消息,并且注册对应的 Planning 类。Planning 的过程之前是定时器触发,即每隔一段固定的时间执行一次,现已经改为事件触发,即只要收集完成对应 TOPIC 的消息,就会触发执行,这样的好处是提高的实时

Apollo camera 感知部分 目标检测源码阅读分析

障碍物检测分为detector transformer postprocessor tracker几个部分 kitti 基于单目的3D目标检测的预备知识点: 首先是yolo3d 3d目标检测输出结果为kitti的3D格式,(其中3d信息部分是以相机坐标系为参考坐标系的) 首先介绍下kitti 3d object detection障碍物标注的的标注文件格式 KITTI数据集,label文件