Nacos 설정 센터 디자인 분석 - 클 라 이언 트

46028 단어
Nacos 설정 센터 디자인 분석 - 클 라 이언 트
  • 주요 기능
  • 클 라 이언 트 초기 화
  • 중요 데이터 구조
  • NacosConfigService
  • EventDispatcher
  • ServerListManager
  • ClientWorker
  • CacheData
  • 전형 적 인 장면
  • 프로필 내용 가 져 오기
  • 프로필 내용 발표
  • 프로필 감청 추가
  • 프로필 감청 삭제
  • 스 레 드 모델
  • Nacos 서버 로그 인 라인
  • Nacos 서버 목록 업데이트 스 레 드
  • 클 라 이언 트 작업 스 레 드
  • 프로필 추출 스 레 드
  • 버 전
  • Nacos 설정 센터 는 NameSpace, Group, DataId 3 급 구조 에 따라 설정 파일 을 구성 합 니 다. 그 중에서 NameSpace 는 환경 을 구분 할 수 있 습 니 다. 예 를 들 어 dev, test 등 입 니 다.Group 은 서비스 그룹 으로 표지 응용 에 사용 할 수 있 습 니 다.DataId 는 프로필 이름 입 니 다.실제 응용 프로그램 에서 NameSpace 와 Group 을 응용 프로그램 과 연결 하여 응용 프로그램의 시작 매개 변 수 를 고정 적 으로 기록 할 수 있 습 니 다.
    주요 기능
    Nacos 설정 센터 클 라 이언 트 는 주로 다음 과 같은 능력 을 가지 고 있 습 니 다.
  • 프로필 내용 가 져 오기
  • 프로필 내용 발표
  • 프로필 감청 추가
  • 프로필 감청 삭제
  • 클 라 이언 트 초기 화
  • HTTP 프 록 시 MetricsHttpAgent 초기 화: HttpAgent 에 대한 추가 패 키 징 은 응답 시간 을 통계 하 는 능력 을 증가 시 켰 습 니 다. HttpAgent 에서 서버 목록 을 유지 하고 스 레 드 를 시작 하여 서버 에 계속 로그 인 요청 을 하여 클 라 이언 트 의 합 법성 을 확보 합 니 다.또한 서버 목록 이 지정 되 지 않 으 면 서버 목록 을 계속 조회 하 는 스 레 드 를 시작 합 니 다. 서버 에 변동 이 있 으 면 서버 변경 이 벤트 를 발표 하고 이 스 레 드 에서 해당 하 는 모니터
  • 를 호출 합 니 다.
  • 클 라 이언 트 작업 스 레 드 를 만 듭 니 다. Client Worker: 모니터링 이 필요 한 프로필 이 추가 되 었 는 지 정기 적 으로 확인 합 니 다. 있 으 면 이 파일 이 업 데 이 트 된 모니터링 작업 을 스 레 드 에 할당 하고 서버 에서 최신 파일 내용 을 계속 끌 어 옵 니 다. 파일 이 더 바 뀌 는 것 을 발견 하면 클 라 이언 트 프로필 내용 을 업데이트 하고 해당 하 는 모니터 를 호출 합 니 다.(지정 한 스 레 드 탱크 가 있 으 면 이 스 레 드 탱크 를 사용 하고 지정 되 지 않 으 면 자체 스 레 드 로 모니터 호출 을 수행 합 니 다)
  • 초기 화 코드 는 다음 과 같 습 니 다.
        // 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);
            //    HTTP  MetricsHttpAgent
            agent = new MetricsHttpAgent(new ServerHttpAgent(properties));
            agent.start();
            //          ClientWorker
            worker = new ClientWorker(agent, configFilterChainManager, properties);
        }
    

    중요 데이터 구조
    NacosConfigService
    // NacosConfigService
    public class NacosConfigService implements ConfigService {
        ......
        // http  MetricsHttpAgent
        private HttpAgent agent; 
        //        
        private ClientWorker worker;
        ......
    }
    

    EventDispatcher
    public class EventDispatcher {
        ......
        // key     ,value      
        static final Map<Class<? extends AbstractEvent>, CopyOnWriteArrayList<AbstractEventListener>> LISTENER_MAP
            = new HashMap<Class<? extends AbstractEvent>, CopyOnWriteArrayList<AbstractEventListener>>();
        ......
    }
    

    ServerListManager
    // ServerListManager 
    public class ServerListManager {
        ......
        //     (     )
        private String serverAddrsStr;
        //      (  serverAddrsStr  )
        volatile List<String> serverUrls = new ArrayList<String>();
        //       (          )
        public String addressServerUrl;
        ......
    }
    

    ClientWorker
    // ClientWorker
    public class ClientWorker {
        //        ,key        ,value CacheData
        private final AtomicReference<Map<String, CacheData>> cacheMap = new AtomicReference<Map<String, CacheData>>(
            new HashMap<String, CacheData>());
    }
    

    CacheData
    // CacheData
    public class CacheData {
        //       
        private volatile String content;
        //      
        private final CopyOnWriteArrayList<ManagerListenerWrap> listeners;
    }
    

    CacheData 는 파일 캐 시 를 설정 합 니 다. CacheData 에서 파일 내용 을 가 져 옵 니 다. CacheData 는 클 라 이언 트 스 레 드 에서 업 데 이 트 를 계속 끌 어 옵 니 다.
    전형 적 인 장면
    프로필 내용 가 져 오기
    로 컬 캐 시 파일 에서 프로필 내용 을 우선 읽 고 실패 하면 서버 에서 가 져 오고 실패 하면 과거 기록 스냅 샷 파일 에서 가 져 옵 니 다.
        // NacosConfigService
        private String getConfigInner(String tenant, String dataId, String group, long timeoutMs) throws NacosException {
            ...
            //         
            String content = LocalConfigInfoProcessor.getFailover(agent.getName(), dataId, group, tenant);
            if (content != null) {
                ......
                configFilterChainManager.doFilter(null, cr);
                content = cr.getContent();
                ......
                return content;
            }
            //                   
            try {
                String[] ct = worker.getServerConfig(dataId, group, tenant, timeoutMs);
                cr.setContent(ct[0]);
    
                configFilterChainManager.doFilter(null, cr);
                content = cr.getContent();
    
                return content;            
            } catch (NacosException ioe) {
                if (NacosException.NO_RIGHT == ioe.getErrCode()) {
                    throw ioe;
                }
                LOGGER.warn("[{}] [get-config] get from server error, dataId={}, group={}, tenant={}, msg={}",
                    agent.getName(), dataId, group, tenant, ioe.toString());
            }
            //      
            LOGGER.warn("[{}] [get-config] get snapshot ok, dataId={}, group={}, tenant={}, config={}", agent.getName(),
                dataId, group, tenant, ContentUtils.truncateContent(content));
            content = LocalConfigInfoProcessor.getSnapshot(agent.getName(), dataId, group, tenant);
            cr.setContent(content);
            configFilterChainManager.doFilter(null, cr);
            content = cr.getContent();
            return content;
        }
    

    프로필 내용 발표
    API 를 호출 하여 프로필 내용 을 수정 합 니 다.
    프로필 감청 추가
    클 라 이언 트 가 지정 한 파일 내용 을 정시 에 끌 어 옵 니 다. 변화 가 발생 하면 설정 파일 내용 을 업데이트 하고 (cacheMap 에 저장) 감청 기 를 호출 하여 해당 하 는 처 리 를 합 니 다. 파일 모니터링 코드 를 추가 하면 다음 과 같 습 니 다.
        // ClientWorker
        public void checkConfigInfo() {
            //    
            int listenerSize = cacheMap.get().size();
            //        
            // ParamUtil.getPerTaskConfigSize()            ,       ,  cacheMap      
            int longingTaskCount = (int) Math.ceil(listenerSize / ParamUtil.getPerTaskConfigSize());
            if (longingTaskCount > currentLongingTaskCount) {
                for (int i = (int) currentLongingTaskCount; i < longingTaskCount; i++) {
                    //                    。           。         
                    executorService.execute(new LongPollingRunnable(i));
                }
                currentLongingTaskCount = longingTaskCount;
            }
        }
    

    파일 내용 을 끌 어 내 고 코드 를 다음 과 같이 업데이트 합 니 다.
        // ClientWorker
        class LongPollingRunnable implements Runnable {
            private int taskId;
    
            public LongPollingRunnable(int taskId) {
                this.taskId = taskId;
            }
    
            @Override
            public void run() {
    
                List<CacheData> cacheDatas = new ArrayList<CacheData>();
                List<String> inInitializingCacheList = new ArrayList<String>();
                try {
                    // check failover config
                    for (CacheData cacheData : cacheMap.get().values()) {
                        if (cacheData.getTaskId() == taskId) {
                            cacheDatas.add(cacheData);
                            try {
                                checkLocalConfig(cacheData);
                                if (cacheData.isUseLocalConfigInfo()) {
                                    cacheData.checkListenerMd5();
                                }
                            } catch (Exception e) {
                                LOGGER.error("get local config info error", e);
                            }
                        }
                    }
    
                    // check server config
                    List<String> changedGroupKeys = checkUpdateDataIds(cacheDatas, inInitializingCacheList);
                    LOGGER.info("get changedGroupKeys:" + changedGroupKeys);
    
                    for (String groupKey : changedGroupKeys) {
                        String[] key = GroupKey.parseKey(groupKey);
                        String dataId = key[0];
                        String group = key[1];
                        String tenant = null;
                        if (key.length == 3) {
                            tenant = key[2];
                        }
                        try {
                            String[] ct = getServerConfig(dataId, group, tenant, 3000L);
                            CacheData cache = cacheMap.get().get(GroupKey.getKeyTenant(dataId, group, tenant));
                            //         
                            cache.setContent(ct[0]);
                            if (null != ct[1]) {
                                cache.setType(ct[1]);
                            }
                            LOGGER.info("[{}] [data-received] dataId={}, group={}, tenant={}, md5={}, content={}, type={}",
                                agent.getName(), dataId, group, tenant, cache.getMd5(),
                                ContentUtils.truncateContent(ct[0]), ct[1]);
                        } catch (NacosException ioe) {
                            String message = String.format(
                                "[%s] [get-update] get changed config exception. dataId=%s, group=%s, tenant=%s",
                                agent.getName(), dataId, group, tenant);
                            LOGGER.error(message, ioe);
                        }
                    }
                    for (CacheData cacheData : cacheDatas) {
                        if (!cacheData.isInitializing() || inInitializingCacheList
                            .contains(GroupKey.getKeyTenant(cacheData.dataId, cacheData.group, cacheData.tenant))) {
                            //        
                            cacheData.checkListenerMd5();
                            cacheData.setInitializing(false);
                        }
                    }
                    inInitializingCacheList.clear();
    
                    executorService.execute(this);
    
                } catch (Throwable e) {
    
                    // If the rotation training task is abnormal, the next execution time of the task will be punished
                    LOGGER.error("longPolling error : ", e);
                    executorService.schedule(this, taskPenaltyTime, TimeUnit.MILLISECONDS);
                }
            }
        }
    

    프로필 감청 삭제
        // ClientWorker
        public void removeListener(String dataId, String group, Listener listener) {
            group = null2defaultGroup(group);
            CacheData cache = getCache(dataId, group);
            if (null != cache) {
                cache.removeListener(listener);
                if (cache.getListeners().isEmpty()) {
                    removeCache(dataId, group);
                }
            }
        }
    

    스 레 드 모델
    Nacos 서버 로그 인 라인
  • JVM 의 이름 은 com. alibaba. nacos. client. config. security. updater
  • 입 니 다.
  • 정기 적 으로 Nacos 서버 에 로그 인 요청 을 보 내 클 라 이언 트 의 합 법성 을 확보 합 니 다
  • 구현 클래스: ServerHttpAgent. 익명 클래스
  • Nacos 서버 목록 업데이트 스 레 드
  • JVM 의 이름 은 com. alibaba. nacos. client. Timer
  • 입 니 다.
  • 서버 목록 을 정기 적 으로 조회 합 니 다. (이 스 레 드 는 서버 목록 이 지정 되 지 않 았 을 때 만 시작 합 니 다) 서버 변경 이 있 으 면 클 라 이언 트 서버 목록 정 보 를 업데이트 하고 이 사건 의 모니터 (있 으 면)
  • 를 호출 합 니 다.
  • 구현 클래스: ServerListManager. GetServerListTask
  • 클 라 이언 트 작업 스 레 드
  • JVM 의 이름 은 com. alibaba. nacos. client. Worker. {agentName}
  • 새로 구독 한 프로필 이 있 는 지 정기 적 으로 확인 하고 있 으 면 스 레 드 를 시작 합 니 다
  • 구현 클래스: Client Worker. 익명 클래스
  • 파일 추출 스 레 드 설정
  • JVM 의 이름 은 com. alibaba. nacos. client. Worker. longPolling. {agentName}
  • 서버 설정 파일 내용 을 정시 에 끌 어 내 고 이 파일 의 모니터 를 순서대로 호출 합 니 다. 모니터 를 추가 할 때 실행 스 레 드 탱크 를 지정 하면 지정 한 스 레 드 탱크 호출 모니터
  • 를 사용 합 니 다.
  • 실현 유형: Client Worker. LongPollingRunnable
  • 판본
    본 고 는 Nacos 의 1.2.0 버 전 을 바탕 으로 한다.

    좋은 웹페이지 즐겨찾기