RocketMQ源码 Broker-FilterServerManager 过滤服务器管理组件源码分析

前言

FilterServerManager 负责维护过滤服务器长连接 与 过滤服务器信息映射关系,并且内部有定时调度线程,不断检查过滤服务器实际数量和配置数量是否一致,如果不一致,就根据配置构建命令行命令,执行命令启动 FilterServer 过滤服务器进程。

过滤服务器实例,是RockerMQ的高级功能,复制支持更复杂的过滤条件。

源码版本:4.9.3

源码架构图

核心数据结构

java 复制代码
// 过滤服务器管理组件
public class FilterServerManager {

    // 过滤服务器最大空闲时间,30秒
    public static final long FILTER_SERVER_MAX_IDLE_TIME_MILLS = 30000;
    private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.BROKER_LOGGER_NAME);
    // 过滤服务器长连接 与 过滤服务器信息映射关系
    private final ConcurrentMap<Channel, FilterServerInfo> filterServerTable =
        new ConcurrentHashMap<Channel, FilterServerInfo>(16);
    private final BrokerController brokerController;

    // 过滤服务器定时调度线程池
    private ScheduledExecutorService scheduledExecutorService = Executors
        .newSingleThreadScheduledExecutor(new ThreadFactoryImpl("FilterServerManagerScheduledThread"));
}
java 复制代码
    static class FilterServerInfo {
        // 过滤服务器地址
        private String filterServerAddr;
        // 最后更新时间戳
        private long lastUpdateTimestamp;
    }

核心行为方法

java 复制代码
// 过滤服务器管理组件
public class FilterServerManager {

    // 过滤服务器最大空闲时间,30秒
    public static final long FILTER_SERVER_MAX_IDLE_TIME_MILLS = 30000;
    private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.BROKER_LOGGER_NAME);
    // 过滤服务器长连接 与 过滤服务器信息映射关系
    private final ConcurrentMap<Channel, FilterServerInfo> filterServerTable =
        new ConcurrentHashMap<Channel, FilterServerInfo>(16);
    private final BrokerController brokerController;

    // 过滤服务器定时调度线程池
    private ScheduledExecutorService scheduledExecutorService = Executors
        .newSingleThreadScheduledExecutor(new ThreadFactoryImpl("FilterServerManagerScheduledThread"));

    public FilterServerManager(final BrokerController brokerController) {
        this.brokerController = brokerController;
    }

    public void start() {

        // 注册调度任务,每隔30秒扫描一次过滤服务器
        this.scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                try {
                    FilterServerManager.this.createFilterServer();
                } catch (Exception e) {
                    log.error("", e);
                }
            }
        }, 1000 * 5, 1000 * 30, TimeUnit.MILLISECONDS);
    }

    // 创建过滤服务器
    public void createFilterServer() {
        int more =
            this.brokerController.getBrokerConfig().getFilterServerNums() - this.filterServerTable.size();
        String cmd = this.buildStartCommand();
        for (int i = 0; i < more; i++) {
            // 启动过滤服务器
            FilterServerUtil.callShell(cmd, log);
        }
    }

    // 构建过滤服务器启动命令
    private String buildStartCommand() {
        String config = "";
        if (BrokerStartup.configFile != null) {
            config = String.format("-c %s", BrokerStartup.configFile);
        }

        if (this.brokerController.getBrokerConfig().getNamesrvAddr() != null) {
            config += String.format(" -n %s", this.brokerController.getBrokerConfig().getNamesrvAddr());
        }

        if (RemotingUtil.isWindowsPlatform()) {
            return String.format("start /b %s\\bin\\mqfiltersrv.exe %s",
                this.brokerController.getBrokerConfig().getRocketmqHome(),
                config);
        } else {
            return String.format("sh %s/bin/startfsrv.sh %s",
                this.brokerController.getBrokerConfig().getRocketmqHome(),
                config);
        }
    }

    public void shutdown() {
        this.scheduledExecutorService.shutdown();
    }

    // 注册过滤服务器
    public void registerFilterServer(final Channel channel, final String filterServerAddr) {
        FilterServerInfo filterServerInfo = this.filterServerTable.get(channel);
        if (filterServerInfo != null) {
            filterServerInfo.setLastUpdateTimestamp(System.currentTimeMillis());
        } else {
            filterServerInfo = new FilterServerInfo();
            filterServerInfo.setFilterServerAddr(filterServerAddr);
            filterServerInfo.setLastUpdateTimestamp(System.currentTimeMillis());
            this.filterServerTable.put(channel, filterServerInfo);
            log.info("Receive a New Filter Server<{}>", filterServerAddr);
        }
    }

    // 扫描过期的过滤服务器
    public void scanNotActiveChannel() {

        Iterator<Entry<Channel, FilterServerInfo>> it = this.filterServerTable.entrySet().iterator();
        while (it.hasNext()) {
            Entry<Channel, FilterServerInfo> next = it.next();
            long timestamp = next.getValue().getLastUpdateTimestamp();
            Channel channel = next.getKey();
            // 过滤服务器超过30秒没有更新,则删除
            if ((System.currentTimeMillis() - timestamp) > FILTER_SERVER_MAX_IDLE_TIME_MILLS) {
                log.info("The Filter Server<{}> expired, remove it", next.getKey());
                // 删除内存中的过滤服务器信息
                it.remove();
                // 关闭过滤服务器连接
                RemotingUtil.closeChannel(channel);
            }
        }
    }

    // 过滤服务器连接关闭事件
    public void doChannelCloseEvent(final String remoteAddr, final Channel channel) {
        FilterServerInfo old = this.filterServerTable.remove(channel);
        if (old != null) {
            log.warn("The Filter Server<{}> connection<{}> closed, remove it", old.getFilterServerAddr(),
                remoteAddr);
        }
    }

    // 构建新的过滤服务器列表
    public List<String> buildNewFilterServerList() {
        List<String> addr = new ArrayList<>();
        Iterator<Entry<Channel, FilterServerInfo>> it = this.filterServerTable.entrySet().iterator();
        while (it.hasNext()) {
            Entry<Channel, FilterServerInfo> next = it.next();
            addr.add(next.getValue().getFilterServerAddr());
        }
        return addr;
    }

    static class FilterServerInfo {
        // 过滤服务器地址
        private String filterServerAddr;
        // 最后更新时间戳
        private long lastUpdateTimestamp;

        public String getFilterServerAddr() {
            return filterServerAddr;
        }

        public void setFilterServerAddr(String filterServerAddr) {
            this.filterServerAddr = filterServerAddr;
        }

        public long getLastUpdateTimestamp() {
            return lastUpdateTimestamp;
        }

        public void setLastUpdateTimestamp(long lastUpdateTimestamp) {
            this.lastUpdateTimestamp = lastUpdateTimestamp;
        }
    }
}
相关推荐
programhelp_8 分钟前
Pinterest OA 题库大公开|Programhelp 独家整理(最新高频)
java·开发语言
likerhood1 小时前
Fastjson中的JSON.parseObject()详细讲解
java·json
KNeeg_1 小时前
黑马点评完整代码(RabbitMQ优化)+简历编写+面试重点 ⭐
java·redis·后端·spring·面试·职场和发展·黑马点评
铁皮哥1 小时前
【后端/Agent 开发】给你的项目配置一套 .claude/ 工作流:别再裸用 Claude Code 了!
java·windows·python·spring·github·maven·生活
乐之者v1 小时前
AI编程 -- codex添加代码,在intellij Idea中没有显示,如何处理?
java·ide·intellij-idea
2401_878820472 小时前
Sa-Token基础篇
java·spring boot·后端·sa-token
2301_816374332 小时前
Nginx下构建PC站点
java·运维·nginx
无所事事O_o2 小时前
JAVA应用不定时卡顿问题排查过程记录
java·优化
幸福巡礼2 小时前
【LangChain 1.2 实战(八)】Agent Middleware 实战 —— 动态路由、监控、安全与容错
java·安全·langchain
Byron__3 小时前
Java JVM核心知识点复习笔记
java·jvm·笔记