order
This paper mainly studies the notifyConfigInfo of nacos
CommunicationController
nacos-1.1.3/config/src/main/java/com/alibaba/nacos/config/server/controller/CommunicationController.java
@Controller @RequestMapping(Constants.COMMUNICATION_CONTROLLER_PATH) public class CommunicationController { private final DumpService dumpService; private final LongPollingService longPollingService; private String trueStr = "true"; @Autowired public CommunicationController(DumpService dumpService, LongPollingService longPollingService) { this.dumpService = dumpService; this.longPollingService = longPollingService; } /** * Notification of configuration information changes */ @RequestMapping(value = "/dataChange", method = RequestMethod.GET) @ResponseBody public Boolean notifyConfigInfo(HttpServletRequest request, HttpServletResponse response, @RequestParam("dataId") String dataId, @RequestParam("group") String group, @RequestParam(value = "tenant", required = false, defaultValue = StringUtils.EMPTY) String tenant, @RequestParam(value = "tag", required = false) String tag) { dataId = dataId.trim(); group = group.trim(); String lastModified = request.getHeader(NotifyService.NOTIFY_HEADER_LAST_MODIFIED); long lastModifiedTs = StringUtils.isEmpty(lastModified) ? -1 : Long.parseLong(lastModified); String handleIp = request.getHeader(NotifyService.NOTIFY_HEADER_OP_HANDLE_IP); String isBetaStr = request.getHeader("isBeta"); if (StringUtils.isNotBlank(isBetaStr) && trueStr.equals(isBetaStr)) { dumpService.dump(dataId, group, tenant, lastModifiedTs, handleIp, true); } else { dumpService.dump(dataId, group, tenant, tag, lastModifiedTs, handleIp); } return true; } //...... }
- The notifyConfigInfo method mainly executes the dumpService.dump method, but whether the dump method called by beta is different
DumpService
nacos-1.1.3/config/src/main/java/com/alibaba/nacos/config/server/service/dump/DumpService.java
@Service public class DumpService { @Autowired private Environment env; @Autowired PersistService persistService; @PostConstruct public void init() { LogUtil.defaultLog.warn("DumpService start"); DumpProcessor processor = new DumpProcessor(this); DumpAllProcessor dumpAllProcessor = new DumpAllProcessor(this); DumpAllBetaProcessor dumpAllBetaProcessor = new DumpAllBetaProcessor(this); DumpAllTagProcessor dumpAllTagProcessor = new DumpAllTagProcessor(this); dumpTaskMgr = new TaskManager( "com.alibaba.nacos.server.DumpTaskManager"); dumpTaskMgr.setDefaultTaskProcessor(processor); dumpAllTaskMgr = new TaskManager( "com.alibaba.nacos.server.DumpAllTaskManager"); dumpAllTaskMgr.setDefaultTaskProcessor(dumpAllProcessor); //...... } /** * Full dump interval */ static final int DUMP_ALL_INTERVAL_IN_MINUTE = 6 * 60; /** * Full dump interval */ static final int INITIAL_DELAY_IN_MINUTE = 6 * 60; private TaskManager dumpTaskMgr; private TaskManager dumpAllTaskMgr; private static final Logger log = LoggerFactory.getLogger(DumpService.class); static final AtomicInteger FINISHED = new AtomicInteger(); static final int INIT_THREAD_COUNT = 10; int total = 0; private final static String TRUE_STR = "true"; private final static String BETA_TABLE_NAME = "config_info_beta"; private final static String TAG_TABLE_NAME = "config_info_tag"; Boolean isQuickStart = false; private int retentionDays = 30; //...... public void dump(String dataId, String group, String tenant, long lastModified, String handleIp, boolean isBeta) { String groupKey = GroupKey2.getKey(dataId, group, tenant); dumpTaskMgr.addTask(groupKey, new DumpTask(groupKey, lastModified, handleIp, isBeta)); } public void dump(String dataId, String group, String tenant, String tag, long lastModified, String handleIp) { dump(dataId, group, tenant, tag, lastModified, handleIp, false); } public void dump(String dataId, String group, String tenant, String tag, long lastModified, String handleIp, boolean isBeta) { String groupKey = GroupKey2.getKey(dataId, group, tenant); dumpTaskMgr.addTask(groupKey, new DumpTask(groupKey, tag, lastModified, handleIp, isBeta)); } //...... }
- The dump method finally adds DumpTask to dumpTaskMgr; the defaultTaskProcessor of dumpTaskMgr is dumpProcessor
TaskManager
nacos-1.1.3/config/src/main/java/com/alibaba/nacos/config/server/manager/TaskManager.java
public final class TaskManager implements TaskManagerMBean { private static final Logger log = LogUtil.defaultLog; private final ConcurrentHashMap<String, AbstractTask> tasks = new ConcurrentHashMap<String, AbstractTask>(); private final ConcurrentHashMap<String, TaskProcessor> taskProcessors = new ConcurrentHashMap<String, TaskProcessor>(); private TaskProcessor defaultTaskProcessor; Thread processingThread; private final AtomicBoolean closed = new AtomicBoolean(true); private String name; class ProcessRunnable implements Runnable { @Override public void run() { while (!TaskManager.this.closed.get()) { try { Thread.sleep(100); TaskManager.this.process(); } catch (Throwable e) { } } } } ReentrantLock lock = new ReentrantLock(); Condition notEmpty = this.lock.newCondition(); public TaskManager() { this(null); } public AbstractTask getTask(String type) { return this.tasks.get(type); } public TaskProcessor getTaskProcessor(String type) { return this.taskProcessors.get(type); } @SuppressWarnings("PMD.AvoidManuallyCreateThreadRule") public TaskManager(String name) { this.name = name; if (null != name && name.length() > 0) { this.processingThread = new Thread(new ProcessRunnable(), name); } else { this.processingThread = new Thread(new ProcessRunnable()); } this.processingThread.setDaemon(true); this.closed.set(false); this.processingThread.start(); } //...... /** * Add task to task Map * * @param type * @param task */ public void addTask(String type, AbstractTask task) { this.lock.lock(); try { AbstractTask oldTask = tasks.put(type, task); MetricsMonitor.getDumpTaskMonitor().set(tasks.size()); if (null != oldTask) { task.merge(oldTask); } } finally { this.lock.unlock(); } } protected void process() { for (Map.Entry<String, AbstractTask> entry : this.tasks.entrySet()) { AbstractTask task = null; this.lock.lock(); try { // Getting tasks task = entry.getValue(); if (null != task) { if (!task.shouldProcess()) { // Task does not need to be executed at present, skip directly continue; } // Remove the task from the task Map first this.tasks.remove(entry.getKey()); MetricsMonitor.getDumpTaskMonitor().set(tasks.size()); } } finally { this.lock.unlock(); } if (null != task) { // Get task processor TaskProcessor processor = this.taskProcessors.get(entry.getKey()); if (null == processor) { // If there is no processor set according to the task type, use the default processor processor = this.getDefaultTaskProcessor(); } if (null != processor) { boolean result = false; try { // Processing tasks result = processor.process(entry.getKey(), task); } catch (Throwable t) { log.error("task_fail", "Handle task fail", t); } if (!result) { // Task processing failed, set the last processing time task.setLastProcessTime(System.currentTimeMillis()); // Add tasks back to task Map this.addTask(entry.getKey(), task); } } } } if (tasks.isEmpty()) { this.lock.lock(); try { this.notEmpty.signalAll(); } finally { this.lock.unlock(); } } } //...... }
- The addTask method of TaskManager adds AbstractTask to tasks; its constructor starts ProcessRunnable, and its run method is mainly to execute TaskManager.this.process(); this method will traverse tasks, take out tasks, and then execute tasks through the process method of TaskProcessor.
DumpProcessor
nacos-1.1.3/config/src/main/java/com/alibaba/nacos/config/server/service/dump/DumpTask.java
class DumpProcessor implements TaskProcessor { DumpProcessor(DumpService dumpService) { this.dumpService = dumpService; } @Override public boolean process(String taskType, AbstractTask task) { DumpTask dumpTask = (DumpTask)task; String[] pair = GroupKey2.parseKey(dumpTask.groupKey); String dataId = pair[0]; String group = pair[1]; String tenant = pair[2]; long lastModified = dumpTask.lastModified; String handleIp = dumpTask.handleIp; boolean isBeta = dumpTask.isBeta; String tag = dumpTask.tag; if (isBeta) { // If the beta is released, dump the data and update the beta cache. ConfigInfo4Beta cf = dumpService.persistService.findConfigInfo4Beta(dataId, group, tenant); boolean result; if (null != cf) { result = ConfigService.dumpBeta(dataId, group, tenant, cf.getContent(), lastModified, cf.getBetaIps()); if (result) { ConfigTraceService.logDumpEvent(dataId, group, tenant, null, lastModified, handleIp, ConfigTraceService.DUMP_EVENT_OK, System.currentTimeMillis() - lastModified, cf.getContent().length()); } } else { result = ConfigService.removeBeta(dataId, group, tenant); if (result) { ConfigTraceService.logDumpEvent(dataId, group, tenant, null, lastModified, handleIp, ConfigTraceService.DUMP_EVENT_REMOVE_OK, System.currentTimeMillis() - lastModified, 0); } } return result; } else { if (StringUtils.isBlank(tag)) { ConfigInfo cf = dumpService.persistService.findConfigInfo(dataId, group, tenant); if (dataId.equals(AggrWhitelist.AGGRIDS_METADATA)) { if (null != cf) { AggrWhitelist.load(cf.getContent()); } else { AggrWhitelist.load(null); } } if (dataId.equals(ClientIpWhiteList.CLIENT_IP_WHITELIST_METADATA)) { if (null != cf) { ClientIpWhiteList.load(cf.getContent()); } else { ClientIpWhiteList.load(null); } } if (dataId.equals(SwitchService.SWITCH_META_DATAID)) { if (null != cf) { SwitchService.load(cf.getContent()); } else { SwitchService.load(null); } } boolean result; if (null != cf) { result = ConfigService.dump(dataId, group, tenant, cf.getContent(), lastModified); if (result) { ConfigTraceService.logDumpEvent(dataId, group, tenant, null, lastModified, handleIp, ConfigTraceService.DUMP_EVENT_OK, System.currentTimeMillis() - lastModified, cf.getContent().length()); } } else { result = ConfigService.remove(dataId, group, tenant); if (result) { ConfigTraceService.logDumpEvent(dataId, group, tenant, null, lastModified, handleIp, ConfigTraceService.DUMP_EVENT_REMOVE_OK, System.currentTimeMillis() - lastModified, 0); } } return result; } else { ConfigInfo4Tag cf = dumpService.persistService.findConfigInfo4Tag(dataId, group, tenant, tag); // boolean result; if (null != cf) { result = ConfigService.dumpTag(dataId, group, tenant, tag, cf.getContent(), lastModified); if (result) { ConfigTraceService.logDumpEvent(dataId, group, tenant, null, lastModified, handleIp, ConfigTraceService.DUMP_EVENT_OK, System.currentTimeMillis() - lastModified, cf.getContent().length()); } } else { result = ConfigService.removeTag(dataId, group, tenant, tag); if (result) { ConfigTraceService.logDumpEvent(dataId, group, tenant, null, lastModified, handleIp, ConfigTraceService.DUMP_EVENT_REMOVE_OK, System.currentTimeMillis() - lastModified, 0); } } return result; } } } final DumpService dumpService; }
- DumpProcessor implements the TaskProcessor interface. Its process method is to execute ConfigService.dump or remove method according to different conditions.
Summary
The notifyConfigInfo method mainly executes the dumpService.dump method, but whether the dump method called by beta is different