Storm-源码分析-Topology Submit-Supervisor

简介:

mk-supervisor

(defserverfn mk-supervisor [conf shared-context ^ISupervisor isupervisor]
  (log-message "Starting Supervisor with conf " conf)
  (.prepare isupervisor conf (supervisor-isupervisor-dir conf)) ;;初始化supervisor-id,并存在localstate中(参考ISupervisor的实现)
(FileUtils/cleanDirectory (File. (supervisor-tmp-dir conf))) ;;清空本机的supervisor目录 (let [supervisor (supervisor-data conf shared-context isupervisor)
;;创建两个event-manager,用于在后台执行function [event-manager processes-event-manager :as managers] [(event/event-manager false) (event/event-manager false)] sync-processes (partial sync-processes supervisor) ;;partial sync-process ;;mk-synchronize-supervisor, mk-supervisor的主要工作,参考下面
synchronize-supervisor (mk-synchronize-supervisor supervisor sync-processes event-manager processes-event-manager) ;;定义生成supervisor hb的funciton
heartbeat-fn (fn [] (.supervisor-heartbeat! (:storm-cluster-state supervisor) (:supervisor-id supervisor) (SupervisorInfo. (current-time-secs) (:my-hostname supervisor) (:assignment-id supervisor) (keys @(:curr-assignment supervisor)) ;; used ports (.getMetadata isupervisor) (conf SUPERVISOR-SCHEDULER-META) ((:uptime supervisor)))))] ;;先调用heartbeat-fn发送一次supervisor的hb
    ;;接着使用schedule-recurring去定期调用heartbeat-fn更新hb
    (heartbeat-fn)
    ;; should synchronize supervisor so it doesn't launch anything after being down (optimization)
    (schedule-recurring (:timer supervisor)
                        0
                        (conf SUPERVISOR-HEARTBEAT-FREQUENCY-SECS)
                        heartbeat-fn))
 

mk-synchronize-supervisor

supervisor很简单, 主要管两件事, 
当assignment发生变化时, 从nimbus同步topology的代码到本地 
当assignment发生变化时, check workers状态, 保证被分配的work的状态都是valid

两个需求, 
1. 当assignment发生变化时触发 
    怎样通过zookeeper的watcher实现这个反复触发机制, 参考
Storm-源码分析- Storm中Zookeeper的使用

2. 因为比较耗时, 后台执行 
    创建两个event-manager, 分别用于后台执行mk-synchronize-supervisor和sync-processes

mk-synchronize-supervisor, 比较特别的是内部用了一个有名字的匿名函数this来封装这个函数体 
刚开始看到非常诧异, 其实目的是为了可以在sync-callback中将这个函数add到event-manager里面去 
即每次被调用, 都需要再一次把sync-callback注册到zk, 以保证下次可以被继续触发

 

(defn mk-synchronize-supervisor [supervisor sync-processes event-manager processes-event-manager]
  (fn this []
    (let [conf (:conf supervisor)
          storm-cluster-state (:storm-cluster-state supervisor)
          ^ISupervisor isupervisor (:isupervisor supervisor)
          ^LocalState local-state (:local-state supervisor) ;;本地缓存数据库
          sync-callback (fn [& ignored] (.add event-manager this)) ;;生成callback函数(后台执行mk-synchronize-supervisor)
          assignments-snapshot (assignments-snapshot storm-cluster-state sync-callback) ;;读取assignments,并注册callback,在zk->assignment发生变化时被触发
          storm-code-map (read-storm-code-locations assignments-snapshot) ;;从哪儿下载topology code
          downloaded-storm-ids (set (read-downloaded-storm-ids conf)) ;;已经下载了哪些topology
          all-assignment (read-assignments  ;;supervisor的port上被分配了哪些executors
                           assignments-snapshot
                           (:assignment-id supervisor)) ;;supervisor-id
          new-assignment (->> all-assignment ;;new=all,因为confirmAssigned没有具体实现,always返回true
                              (filter-key #(.confirmAssigned isupervisor %)))
          assigned-storm-ids (assigned-storm-ids-from-port-assignments new-assignment) ;;supervisor上被分配的topology id集合
           existing-assignment (.get local-state LS-LOCAL-ASSIGNMENTS)] ;;从local-state数据库里面读出当前保存的local assignments
      
      ;;下载新分配的topology代码
      (doseq [[storm-id master-code-dir] storm-code-map]
        (when (and (not (downloaded-storm-ids storm-id))
                   (assigned-storm-ids storm-id))
         (download-storm-code conf storm-id master-code-dir)))     
      (.put local-state     ;;把new-assignment存到local-state数据库中
            LS-LOCAL-ASSIGNMENTS
            new-assignment)
      (reset! (:curr-assignment supervisor) new-assignment) ;;把new-assignment cache到supervisor对象中
       
      ;;删除无用的topology code 
;;remove any downloaded code that's no longer assigned or active (doseq [storm-id downloaded-storm-ids] (when-not (assigned-storm-ids storm-id) (log-message "Removing code for storm id " storm-id) (rmr (supervisor-stormdist-root conf storm-id)) ))
      ;;后台执行sync-processes
      (.add processes-event-manager sync-processes)
      )))

sync-processes

sync-processes用于管理workers, 比如处理不正常的worker或dead worker, 并创建新的workers 
首先从本地读出workers的hb, 来判断work状况, shutdown所有状态非valid的workers 
并为被assignment, 而worker状态非valid的slot, 创建新的worker

(defn sync-processes [supervisor]
  (let [conf (:conf supervisor)
        ^LocalState local-state (:local-state supervisor)
        assigned-executors (defaulted (.get local-state LS-LOCAL-ASSIGNMENTS) {})
        now (current-time-secs)
        allocated (read-allocated-workers supervisor assigned-executors now) ;;1.读取当前worker的状况
        keepers (filter-val     ;;找出状态为valid的worker
                 (fn [[state _]] (= state :valid))
                 allocated)
        keep-ports (set (for [[id [_ hb]] keepers] (:port hb))) ;;keepers的ports集合
         ;;select-keys-pred(pred map), 对map中的key使用pred进行过滤
         ;;找出assigned-executors中executor的port, 哪些不属于keep-ports, 
        ;;即找出新被assign的workers或那些虽被assign但状态不是valid的workers(dead或没有start)
;;这些executors需要从新分配到新的worker上去
reassign-executors (select-keys-pred (complement keep-ports) assigned-executors) new-worker-ids (into {} (for [port (keys reassign-executors)] ;;为reassign-executors的port产生新的worker-id [port (uuid)])) ] ;; 1. to kill are those in allocated that are dead or disallowed ;; 2. kill the ones that should be dead ;; - read pids, kill -9 and individually remove file ;; - rmr heartbeat dir, rmdir pid dir, rmdir id dir (catch exception and log) ;; 3. of the rest, figure out what assignments aren't yet satisfied ;; 4. generate new worker ids, write new "approved workers" to LS ;; 5. create local dir for worker id ;; 5. launch new workers (give worker-id, port, and supervisor-id) ;; 6. wait for workers launch (doseq [[id [state heartbeat]] allocated] (when (not= :valid state) ;;shutdown所有状态不是valid的worker (shutdown-worker supervisor id))) (doseq [id (vals new-worker-ids)] (local-mkdirs (worker-pids-root conf id))) ;;为新的worker创建目录, 并加到local-state的LS-APPROVED-WORKERS中 (.put local-state LS-APPROVED-WORKERS ;;更新的approved worker, 状态为valid的 + new workers (merge (select-keys (.get local-state LS-APPROVED-WORKERS) ;;现有approved worker中状态为valid (keys keepers)) (zipmap (vals new-worker-ids) (keys new-worker-ids)) ;;new workers )) (wait-for-workers-launch ;;2.wait-for-workers-launch conf (dofor [[port assignment] reassign-executors] (let [id (new-worker-ids port)] (launch-worker supervisor (:storm-id assignment) port id) id))) ))

1. read-allocated-workers

(defn read-allocated-workers
  "Returns map from worker id to worker heartbeat. if the heartbeat is nil, then the worker is dead (timed out or never wrote heartbeat)"
  [supervisor assigned-executors now]
  (let [conf (:conf supervisor)
        ^LocalState local-state (:local-state supervisor)
;从local-state中读出每个worker的hb, 当然每个worker进程会不断的更新本地hb id->heartbeat (read-worker-heartbeats conf)
        approved-ids (set (keys (.get local-state LS-APPROVED-WORKERS)))] ;;从local-state读出approved的worker
    (into
     {}
     (dofor [[id hb] id->heartbeat] ;;根据hb来判断worker的当前状态
            (let [state (cond
                         (or (not (contains? approved-ids id))
                             (not (matches-an-assignment? hb assigned-executors)))
                           :disallowed  ;;不被允许
                         (not hb)
                           :not-started ;;无hb,没有start
                         (> (- now (:time-secs hb))
                            (conf SUPERVISOR-WORKER-TIMEOUT-SECS))
                           :timed-out  ;;超时,dead
                         true
                           :valid)]
              (log-debug "Worker " id " is " state ": " (pr-str hb) " at supervisor time-secs " now)
              [id [state hb]] ;;返回每个worker的当前state和hb
              ))
     )))

 

2. wait-for-workers-launch

对reassign-executors中的每个new_work_id调用launch-worker

最终调用wait-for-workers-launch, 等待worder被成功launch

逻辑也比较简单, check hb, 如果没有就不停的sleep, 至到超时, 打印failed to start

(defn- wait-for-worker-launch [conf id start-time]
  (let [state (worker-state conf id)]    
    (loop []
      (let [hb (.get state LS-WORKER-HEARTBEAT)]
        (when (and
               (not hb)
               (<
                (- (current-time-secs) start-time)
                (conf SUPERVISOR-WORKER-START-TIMEOUT-SECS)
                ))
          (log-message id " still hasn't started")
          (Time/sleep 500)
          (recur)
          )))
    (when-not (.get state LS-WORKER-HEARTBEAT)
      (log-message "Worker " id " failed to start")
      )))

(defn- wait-for-workers-launch [conf ids]
  (let [start-time (current-time-secs)]
    (doseq [id ids]
      (wait-for-worker-launch conf id start-time))
    ))

本文章摘自博客园,原文发布日期:2013-06-28
目录
相关文章
|
存储 缓存 网络协议
IPV6 的路径 MTU 发现
本文档是 Internet 工程任务组 (IETF) 的产品。它代表了 IETF 社区的共识。它已接受公众审查,并已获互联网工程指导小组 (IESG) 批准出版。有关 Internet 标准的更多信息,请参见 RFC 7841 的第 2 节。
1183 0
IPV6 的路径 MTU 发现
|
10月前
|
存储 人工智能 安全
深度揭秘 ooderAgent MIT 开源框架
在人工智能技术快速发展的今天,AI Agent系统已成为实现复杂任务协作的重要架构。ooderAgent(全称ooder SuperAgent)作为一套基于MIT协议的开源企业级AI能力分发与自动化协作框架,通过创新的Agent架构和SKILL管理机制,为企业提供了从简单任务到复杂流程的全场景自动化解决方案。该框架由ooder团队开发,采用SpringCloud分布式架构,于2026年1月发布最新版本v0.6.2,目前已在企业级AI应用领域展现出重要的技术价值。 本研究旨在全面剖析ooderAgent框架的技术特点与技术价值,重点关注其在技术架构设计、应用能力边界、技术创新突破以及商业价值创造
|
10月前
|
人工智能 关系型数据库 分布式数据库
多图,PolarDB 2026 开发者大会有感
解读阿里云PolarDB开发者大会上数据库的AI原生演进:从数据形态融合、模型算子化到湖库一体架构,PolarDB通过四大支柱构建面向智能体时代的统一数据基座,推动数据库向“AI in SQL”与自主治理的深度变革。
|
12月前
|
运维 监控 Devops
运维不是“救火队”:聊聊运维团队的组织、管理与成长之道
运维不是“救火队”:聊聊运维团队的组织、管理与成长之道
726 5
|
12月前
|
机器学习/深度学习 人工智能 自然语言处理
AI公有云第一,阿里云持续领跑
国际数据公司(IDC)发布《中国AI公有云服务市场份额,2024》,其中阿里云以24.6%的市场占比稳居全国第一,并在对话式AI和智能语音两大细分市场蝉联榜首。
|
JSON API 数据格式
阿里妈妈 item_search 接口对接全攻略:从入门到精通
阿里妈妈item_search接口(taobao.tbk.item.search)是淘宝客选品与推广核心工具,支持关键词、类目、价格等多维度筛选,返回商品信息及佣金、优惠券、推广链接等关键数据,适用于选品分析、推广平台搭建等场景。本文详解接口对接流程、参数配置、Python代码实现、分页策略与合规要点,助开发者高效构建“搜索-推广-变现”闭环系统,实现精准营销与稳定收益。
|
存储 机器学习/深度学习 安全
阿里云服务器2核4G租用价格:最新收费标准、可选实例规格与活动价格参考
目前阿里云的活动中2核4G配置的云服务器经济型e、通用算力型u1、计算型c8i、计算型c9i和计算型c8y实例可选,其中u1实例2核4G5M带宽有特惠,价格为199元1年,且续费价格不变。选择不同实例规格和带宽价格不一样,本文为大家介绍阿里云服务器2核4G配置的最新月付及年付活动价格,以及选择参考。
|
机器学习/深度学习 人工智能 PyTorch
《视频秒变艺术大片:Python+AI风格迁移的神级操作》
Python在AI艺术风格迁移视频制作中至关重要,其丰富的库资源和强大的生态系统为深度学习提供了支持。核心原理基于卷积神经网络(CNN),通过提取内容图像与风格图像的特征并融合,生成新风格图像。视频制作需对每帧进行处理,涉及复杂计算,Python的高效工具如TensorFlow和PyTorch助力模型构建与训练。使用预训练模型(如VGG19)提取特征,通过Gram矩阵捕捉风格信息。优化策略包括多线程处理、分块处理以提升效率,同时确保视频连贯性。这一技术实现艺术与技术的深度融合,赋予视频全新视觉体验。
442 1
|
SQL NoSQL 关系型数据库
超强数据库管理软件推荐-没有之一-还在用Navicat管理本地数据库的吗?还在为Navicat寻求绿色版或者购买正版的费用望而却步吗?DBeaver让你解决所有数据库本地编写问题-优雅草央千澈-DBeaver下载和安装
超强数据库管理软件推荐-没有之一-还在用Navicat管理本地数据库的吗?还在为Navicat寻求绿色版或者购买正版的费用望而却步吗?DBeaver让你解决所有数据库本地编写问题-优雅草央千澈-DBeaver下载和安装
1397 18
超强数据库管理软件推荐-没有之一-还在用Navicat管理本地数据库的吗?还在为Navicat寻求绿色版或者购买正版的费用望而却步吗?DBeaver让你解决所有数据库本地编写问题-优雅草央千澈-DBeaver下载和安装
|
域名解析 网络协议 安全
【域名解析DNS专栏】DNS递归查询与迭代查询的区别及影响
【5月更文挑战第24天】DNS的递归查询与迭代查询是域名解析的两种方式。递归查询由客户端发起,DNS服务器负责全程解析,速度快但可能增加服务器负载和安全风险。迭代查询则需客户端参与多次查询,虽慢但分散负载,提高安全性。理解两者差异有助于优化网站访问体验和安全性。
3948 0
【域名解析DNS专栏】DNS递归查询与迭代查询的区别及影响

热门文章

最新文章