Nacos+Springloadbalancer realizes fast online and offline

development environment

frame Version
Springcloud 2020.0.2
Nacos 2.2.1.RELEASE

Goals

Since loadbalancerthe default load balancing cache is 30s , if a service occurs 上下线, the service consumer cannot know the acquisition at the first time, and the call will 远程服务fail. Therefore, we want to realize that when the service goes online and offline, the service consumer can be notified as soon as possible, and then it can perform a series of operations.

main idea

My idea is to use Nacosthe monitoring service transformation interface to modify the loadbalance cache list to realize real-time modification of the service cache list

Read the source code

org.springframework.cloud.loadbalancer.configTwo classes were found by looking at the configuration classes under the package

@Configuration(proxyBeanMethods = false)
    @ConditionalOnClass({ Caffeine.class, CaffeineCacheManager.class })
    protected static class CaffeineLoadBalancerCacheManagerConfiguration {
        @Bean(autowireCandidate = false)
        @ConditionalOnMissingBean
        LoadBalancerCacheManager caffeineLoadBalancerCacheManager(LoadBalancerCacheProperties cacheProperties) {
            return new CaffeineBasedLoadBalancerCacheManager(cacheProperties);
        }
    }
    @Configuration(proxyBeanMethods = false)
    @Conditional(OnCaffeineCacheMissingCondition.class)
    @ConditionalOnClass(ConcurrentMapWithTimedEviction.class)
    protected static class DefaultLoadBalancerCacheManagerConfiguration {
        @Bean(autowireCandidate = false)
        @ConditionalOnMissingBean
        LoadBalancerCacheManager defaultLoadBalancerCacheManager(LoadBalancerCacheProperties cacheProperties) {
            return new DefaultLoadBalancerCacheManager(cacheProperties);
        }
    }

You can see that by default, Spring LoadBalancer will use the DefaultLoadBalancerCacheManagerimplementation class as cache management, so let's take a look at its source code.

public class DefaultLoadBalancerCacheManager implements LoadBalancerCacheManager {
    private final ConcurrentMap<String, Cache> cacheMap = new ConcurrentHashMap<>(16);
    public DefaultLoadBalancerCacheManager(LoadBalancerCacheProperties loadBalancerCacheProperties,
            String... cacheNames) {
        cacheMap.putAll(createCaches(cacheNames, loadBalancerCacheProperties).stream()
                .collect(Collectors.toMap(DefaultLoadBalancerCache::getName, cache -> cache)));
    }
    public DefaultLoadBalancerCacheManager(LoadBalancerCacheProperties loadBalancerCacheProperties) {
        this(loadBalancerCacheProperties, SERVICE_INSTANCE_CACHE_NAME);
    }
    private Set<DefaultLoadBalancerCache> createCaches(String[] cacheNames,
            LoadBalancerCacheProperties loadBalancerCacheProperties) {
        return Arrays.stream(cacheNames).distinct()
                .map(name -> new DefaultLoadBalancerCache(name,
                        new ConcurrentHashMapWithTimedEviction<>(loadBalancerCacheProperties.getCapacity(),
                                new DelayedTaskEvictionScheduler<>(aScheduledDaemonThreadExecutor())),
                        loadBalancerCacheProperties.getTtl().toMillis(), false))
                .collect(Collectors.toSet());
    }
    private ScheduledExecutorService aScheduledDaemonThreadExecutor() {
        return Executors.newSingleThreadScheduledExecutor(runnable -> {
            Thread thread = Executors.defaultThreadFactory().newThread(runnable);
            thread.setDaemon(true);
            return thread;
        });
    }
    @Override
    @Nullable
    public Cache getCache(String name) {
        return cacheMap.get(name);
    }
    @Override
    public Collection<String> getCacheNames() {
        return Collections.unmodifiableSet(cacheMap.keySet());
    }
}

It can be seen that the storage cache list is implemented through cacheMapthis object, so if we clear the cache map, we can achieve the effect of modifying the cache service list in real time. We can get its cacheMap through reflection for clear operation.

Main code implementation

        @Override
        public void onEvent(Event event) {
            try {
                if (event instanceof NamingEvent){
                    nacosWeightRandomLoadBanlancer = (NacosWeightRandomLoadBanlancer) applicationContext.getBean(ReactorLoadBalancer.class);
                    LoadBalancerCacheManager loadBalancerCacheManager = applicationContext.getBean(LoadBalancerCacheManager.class);
                    log.info("bean:{}",loadBalancerCacheManager);
                    ConcurrentMap<String, Cache> cacheMap = (ConcurrentMap<String, Cache>) ReflectUtil.getFieldValue(loadBalancerCacheManager, "cacheMap");
                    for (Map.Entry<String, Cache> stringCacheEntry : cacheMap.entrySet()) {
                        String key = stringCacheEntry.getKey();
                        Cache cache = stringCacheEntry.getValue();
                        log.info("key:{}\tvalue:{}",key,cache);
                        cache.clear();
                    }
                }
            } catch (Exception e) {
                log.error("e:{}",e);
                e.printStackTrace();
            }
        }
    }

By implementing the Nacos monitoring service transformation interface, the cached service list is cleared, so as to realize the monitoring transformation of real-time service online and offline.

Extraction optimization

to be written

Guess you like

Origin juejin.im/post/7116743190681485349