server 保留 2 份配置文件,一份在 mysql,一份在本地磁盘,同时在内存中缓存配置文件的 md5 值。当客户端获取配置时,server 直接返回本地磁盘文件,使用的是 sendFile api

FileInputStream fis = null;
fis.getChannel().transferTo(0L, fis.getChannel().size(), Channels.newChannel(response.getOutputStream()));

用户发布配置
ConfigController#publishConfig

// 更新数据库
persistService.insertOrUpdate(srcIp, srcUser, configInfo, time, configAdvanceInfo, false);
// 发布事件
EventDispatcher.fireEvent(new ConfigDataChangeEvent(false, dataId, group, tenant, time.getTime()));

整个事件流

public class EventDispatcher {

    /**
     * add event listener
     */
    static public void addEventListener(AbstractEventListener listener) {
        for (Class<? extends Event> type : listener.interest()) {
            getEntry(type).listeners.addIfAbsent(listener);
        }
    }

    /**
     * fire event, notify listeners.
     */
    static public void fireEvent(Event event) {
        if (null == event) {
            throw new IllegalArgumentException();
        }

        for (AbstractEventListener listener : getEntry(event.getClass()).listeners) {
            try {
                listener.onEvent(event);
            } catch (Exception e) {
                log.error(e.toString(), e);
            }
        }
    }

    /**
     * For only test purpose
     */
    static public void clear() {
        LISTENER_HUB.clear();
    }

    /**
     * get event listener for eventType. Add Entry if not exist.
     * 获取事件监听器,如果没有则新建 Entry
     */
    static Entry getEntry(Class<? extends Event> eventType) {
        for (; ; ) {
            for (Entry entry : LISTENER_HUB) {
                if (entry.eventType == eventType) {
                    return entry;
                }
            }

            Entry tmp = new Entry(eventType);
            /**
             *  false means already exists
             */
            if (LISTENER_HUB.addIfAbsent(tmp)) {
                return tmp;
            }
        }
    }

    // 把事件和监听器关联起来
    static private class Entry {
        final Class<? extends Event> eventType;
        final CopyOnWriteArrayList<AbstractEventListener> listeners;

        Entry(Class<? extends Event> type) {
            eventType = type;
            listeners = new CopyOnWriteArrayList<AbstractEventListener>();
        }

        @Override
        public boolean equals(Object obj) {
            if (null == obj || obj.getClass() != getClass()) {
                return false;
            }
            if (this == obj) {
                return true;
            }
            return eventType == ((Entry)obj).eventType;
        }

        @Override
        public int hashCode() {
            return super.hashCode();
        }

    }

    static private final Logger log = LoggerFactory.getLogger(EventDispatcher.class);

    static final CopyOnWriteArrayList<Entry> LISTENER_HUB = new CopyOnWriteArrayList<Entry>();

    public interface Event {
    }

    static public abstract class AbstractEventListener {

        public AbstractEventListener() {
            // 执行 AsyncNotifyService 构造函数,把事件和监听器关联起来
            EventDispatcher.addEventListener(this);
        }

        /**
         * 感兴趣的事件列表
         *
         * @return event list
         */
        abstract public List<Class<? extends Event>> interest();

        /**
         * 处理事件
         *
         * @param event event
         */
        abstract public void onEvent(Event event);
    }

}

AsyncNotifyService

@Service
public class AsyncNotifyService extends AbstractEventListener {

    @Override
    public List<Class<? extends Event>> interest() {
        List<Class<? extends Event>> types = new ArrayList<Class<? extends Event>>();
        // 触发配置变更同步通知
        types.add(ConfigDataChangeEvent.class);
        return types;
    }
    
    @Override
    public void onEvent(Event event) {

        // 并发产生 ConfigDataChangeEvent
        if (event instanceof ConfigDataChangeEvent) {
            ConfigDataChangeEvent evt = (ConfigDataChangeEvent) event;
            long dumpTs = evt.lastModifiedTs;
            String dataId = evt.dataId;
            String group = evt.group;
            String tenant = evt.tenant;
            String tag = evt.tag;
            List<?> ipList = serverListService.getServerList();

            // 其实这里任何类型队列都可以
            Queue<NotifySingleTask> queue = new LinkedList<NotifySingleTask>();
            for (int i = 0; i < ipList.size(); i++) {
                queue.add(new NotifySingleTask(dataId, group, tenant, tag, dumpTs, (String) ipList.get(i), evt.isBeta));
            }
            EXECUTOR.execute(new AsyncTask(httpclient, queue));
        }
    }
}

由以上可见,ConfigDataChangeEvent 事件由 AsyncNotifyService.onEvent 负责

向集群中所有节点(包括自己)发送请求

/v1/cs/communication/dataChange?dataId=oo.yml&group=xx&tenant=dev

节点处理配置变更请求

CommunicationController#notifyConfigInfo

用数据库中的数据更新磁盘上的文件缓存

dumpService.dump(dataId, group, tenant, tag, lastModifiedTs, handleIp);
// DumpService#dump
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));
}
@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);
        dumpTaskMgr = new TaskManager("com.alibaba.nacos.server.DumpTaskManager");
        // 设置默认处理器
        dumpTaskMgr.setDefaultTaskProcessor(processor);
    }
}

TaskManager

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();
}


class ProcessRunnable implements Runnable {

    @Override
    public void run() {
        while (!TaskManager.this.closed.get()) {
            try {
                Thread.sleep(100);
                TaskManager.this.process();
            } catch (Throwable e) {
            }
        }

    }

}

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 {
            // 获取任务
            task = entry.getValue();
            if (null != task) {
                if (!task.shouldProcess()) {
                    // 任务当前不需要被执行,直接跳过
                    continue;
                }
                // 先将任务从任务Map中删除
                this.tasks.remove(entry.getKey());
                MetricsMonitor.getDumpTaskMonitor().set(tasks.size());
            }
        } finally {
            this.lock.unlock();
        }

        if (null != task) {
            // 获取任务处理器
            TaskProcessor processor = this.taskProcessors.get(entry.getKey());
            if (null == processor) {
                // DumpTask 使用的是默认处理器,即 DumpProcessor
                processor = this.getDefaultTaskProcessor();
            }
            if (null != processor) {
                boolean result = false;
                try {
                    // 处理任务
                    result = processor.process(entry.getKey(), task);
                } catch (Throwable t) {
                    log.error("task_fail", "处理task失败", t);
                }
                if (!result) {
                    // 任务处理失败,设置最后处理时间
                    task.setLastProcessTime(System.currentTimeMillis());

                    // 将任务重新加入到任务Map中
                    this.addTask(entry.getKey(), task);
                }
            }
        }
    }

    if (tasks.isEmpty()) {
        this.lock.lock();
        try {
            this.notEmpty.signalAll();
        } finally {
            this.lock.unlock();
        }
    }
}

因此执行的是 DumpProcessor#process,读取数据库中的配置,更新本地磁盘文件,同时生成 LocalDataChangeEvent 事件。

处理 LocalDataChangeEvent 事件

// com.alibaba.nacos.config.server.service.LongPollingService#onEvent
public void onEvent(Event event) {
    if (isFixedPolling()) {
        // ignore
    } else {
        if (event instanceof LocalDataChangeEvent) {
            LocalDataChangeEvent evt = (LocalDataChangeEvent)event;
            scheduler.execute(new DataChangeTask(evt.groupKey, evt.isBeta, evt.betaIps));
        }
    }
}

取消线程池中的定时任务,发送响应(变化的配置文件 id)给客户端

com.alibaba.nacos.config.server.service.LongPollingService.DataChangeTask#run

 

 

客观地讲,nacos 的代码细节不优雅,还在发展中。

posted on 2019-10-12 16:27  偶尔发呆  阅读(2939)  评论(0编辑  收藏  举报