-
-
Notifications
You must be signed in to change notification settings - Fork 10.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
大量配置项场景下应用启动非常慢 #3800
Comments
@nobodyiam Could you please take a look about this? |
Thanks for the proposal, here are some comments:
|
I've made a test with Test environment:
It's caused by the result of |
In the latest version of spring boot, the method Test environment:
Here is my test details:
@RefreshScope
@Configuration
@ConfigurationProperties(prefix = "xxx.abc.caption")
public class ComponentProperties {
private List<CaptionProperties> caption;
private List<CacheProperties> cache;
private List<RedisProperties> redis;
<other fields>
} In the bootstrap process, I'll load config and initialize some components. @Autowired
ComponentProperties componentProperties;
@PostConstruct
void init() {
long start = System.currentTimeMillis();
// this line will fire spring lazy load, read local config cache into properties beans
List<CaptionProperties> captionList = componentProperties.getCaption();
long duration = System.currentTimeMillis() - start;
System.out.printf("duration: %dms\n", duration);
// business logic
}
Test result (duration output):
|
@Shawyeok 你好请问下 你那个看启动耗时的工具是什么? |
描述bug
项目中创建了多个namespace(均为
properties
),由于服务是高度配置化的,因而配置项较多,大约有5000
行配置,应用启动时加载配置文件到Bean
中很慢,拉长了整个启动过程,等待的过程令人沮丧。配置项大致长下面这个样子,层级说多不算多,说少也不算少
项目启动巨慢,给程序员正当理由摸鱼,这样太不好了,启动时抓取了threaddump,如下:
上面可以定位到Apollo的这个方法:com.ctrip.framework.apollo.spring.config.ConfigPropertySource.getPropertyNames
再看内部的com.ctrip.framework.apollo.internals.DefaultConfig#getPropertyNames
看代码不难发现这个方法时间和空间复杂度都是线性的,和PropertySource中的配置项数量正相关。
再看ConfigPropertySource这个类继承了org.springframework.core.env.EnumerablePropertySource,后者覆盖了PropertySource#containsProperty方法
这个方法也是线性的,但是这个方法消耗就很恐怖了,因为PropertySource#containsProperty方法会在启动过程中被
Binder.bind
调用很多次。再通过对启动过程
profiling
验证一下上面的想法:看到上面这个截图首先可能会有这个问题:为啥最终getPropertyNames的时间消耗只占了22%,另外的大头哪去了?因为这个项目用的是SpringBoot
2.1.x
,其内部处理逻辑对于包含大量配置项的项目的效率也很慢,具体可见:#16474。可以先忽略耗时占比,看Apollo部分的时间消耗也有接近
20s
了,对于5000行配置来讲,这个时间似乎太慢了。于是斗胆修改了一下Apollo这部分的实现,基本想法就是缓存
propertyNames
,再使其和properties保持一致。另外考虑其他组件依赖老版本com.ctrip.framework.apollo.Config#getPropertyNames方法(返回一个Set),为保持兼容性新增了一个方法getPropertyNameArray()(返回一个数组)。复现
通过如下步骤可以复现:
期望
天下武功,唯快不破!项目启动还是快一点的好。
如果可以我希望能提交一个PR,因为我司打算放弃自己的Fork了,投入到社区的温暖怀抱中。
截图
如果可以,附上截图来描述你的问题
额外的细节和日志
The text was updated successfully, but these errors were encountered: