Original: www.liaochuntao.cn/2019/09/04/…
Problem description
Some users reported that when using nacOS, Java threads were constantly being created as the program ran, resulting in the CPU Load index reaching 100 percent
To solve the process
When you look at nacOS, you see that these threads are created in large numbers and the final object to hook up to is NacosConfigService
public NacosConfigService(Properties properties) throws NacosException {
String encodeTmp = properties.getProperty(PropertyKeyConst.ENCODE);
if (StringUtils.isBlank(encodeTmp)) {
encode = Constants.ENCODE;
} else {
encode = encodeTmp.trim();
}
initNamespace(properties);
agent = new MetricsHttpAgent(new ServerHttpAgent(properties));
agent.start();
worker = new ClientWorker(agent, configFilterChainManager, properties);
}
Copy the code
The actual hook object is ClientWorker
@SuppressWarnings("PMD.ThreadPoolCreationRule")
public ClientWorker(final HttpAgent agent, final ConfigFilterChainManager configFilterChainManager, final Properties properties) {
this.agent = agent;
this.configFilterChainManager = configFilterChainManager;
// Initialize the timeout parameter
init(properties);
executor = Executors.newScheduledThreadPool(1.new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r);
t.setName("com.alibaba.nacos.client.Worker." + agent.getName());
t.setDaemon(true);
returnt; }}); executorService = Executors.newScheduledThreadPool(Runtime.getRuntime().availableProcessors(),new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r);
t.setName("com.alibaba.nacos.client.Worker.longPolling." + agent.getName());
t.setDaemon(true);
returnt; }}); executor.scheduleWithFixedDelay(new Runnable() {
@Override
public void run(a) {
try {
checkConfigInfo();
} catch (Throwable e) {
LOGGER.error("[" + agent.getName() + "] [sub-check] rotate check error", e); }}},1L.10L, TimeUnit.MILLISECONDS);
}
Copy the code
So I initially wondered if the user was creating a lot of NacosConfigService objects
The userjmap
data
As you can see, there are currently more than two thousand ClientWorker objects in the JVM, and as you can see from the nacos source code analysis above, ClientWorker objects hang on thread pools
User self-verification
Firstly, users were asked to check whether they created a large number of NacosConfigService instances by themselves, which indicated that some users did create a large number of NacosConfigService objects due to their misoperations
Spring-Cloub-Alibaba
The component to check
However, some users said that they only relied on the Spring-Cloud-Alibaba-Nacos component and did not operate the NacosConfigService object themselves, and there was still a large number of threads being created. The spring-cloud-Baba-nacos BUG was eventually identified by a user’s self-checking feedback
@ConfigurationProperties(NacosConfigProperties.PREFIX)
public class NacosConfigProperties {...privateConfigService configService; .@Deprecated
public ConfigService configServiceInstance(a) {
if (null! = configService) {return configService;
}
Properties properties = newProperties(); .try {
configService = NacosFactory.createConfigService(properties);
return configService;
}
catch (Exception e) {
log.error("create config service error! properties={},e=,".this, e);
return null; }}}Copy the code
This configuration class caches an instance of the ConfigService object. It is intended to maintain a singleton of the object itself, but in reality, the NacosConfigProperties bean is recreated every time the Spring-Cloud context is refreshed. Once there is a configuration update — >Context refresh — >NacosConfigProperties is recreated — >ConfigService cache lapsed — >ConfigService is recreated
Therefore, because of this causality, the ConfigService cache Context will not work after being refreshed
To solve the PR
public class NacosConfigManager implements ApplicationContextAware {
private ConfigService configService;
public ConfigService getConfigService(a) {
return configService;
return ServiceHolder.getInstance().getService();
}
@Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
NacosConfigProperties properties = applicationContext
.getBean(NacosConfigProperties.class);
configService = properties.configServiceInstance();
ServiceHolder holder = ServiceHolder.getInstance();
if (!holder.alreadyInit) {
ServiceHolder.getInstance().setService(properties.configServiceInstance());
}
}
static class ServiceHolder {
private ConfigService service = null;
private boolean alreadyInit = false;
private static final ServiceHolder holder = new ServiceHolder();
ServiceHolder() {
}
static ServiceHolder getInstance(a) {
return holder;
}
void setService(ConfigService service) {
alreadyInit = true;
this.service = service;
}
ConfigService getService(a) {
returnservice; }}}Copy the code