deepseek-ai_开源smallpond的源码分析

Smallpond

Smallpond 的设计目标是简化大规模数据处理流程,降低 AI 开发者的技术门槛
  轻量级数据处理框架,专注于 PB 级数据的高效处理
     "--num_executors_per_task",default=5,
      "mode", choices=["executor", "scheduler", "ray"], default="executor"  
    args.mode == "ray":   DataFrame(sp, plan.root_node).compute()
	args.mode == "executor"
	        runtime_ctx: RuntimeContext = load(args.runtime_ctx_path)
		    exec_procs = [Process(target=run_executor,args=(runtime_ctx, args.exec_id, numa_node_id), )
			              for numa_node_id in range(runtime_ctx.numa_node_count)]
						  
	args.mode == "scheduler"
                jobmgr = JobManager(
                exec_plan = jobmgr.run(	
    DataFrame 将逻辑计划(plan.root_node)包装成一个分布式数据处理任务

两套API

01.Ray Core as the task scheduler.
     api/dataframe
	       from smallpond.execution.task import Task
		   from smallpond.logical.node import
		   from smallpond.logical.optimizer import Optimizer
		   from smallpond.logical.planner import Planner
		   from smallpond.session import SessionBase
		class DataFrame :封装了 wrapper around a `Node` and a `Session` required for execution  
		   Session   封装 JobId, RuntimeContext  import ray
		   Node
		   
		   task 也调用了 import ray  
02. built-in scheduler and only supports one-time execution of static data flow graphs
       01.nodes` to construct static data flow graphs.submit them to smallpond
	   02.tasks` and wait for all tasks to complete.
	api/execution
     	dataset = CsvDataSet(paths, OrderedDict(schema), delim)
        plan = DataSourceNode(self._ctx, dataset)	

示例1-High-level API

Initialize smallpond environment.
sp = smallpond.init()
df = sp.read_parquet("path/to/dataset/*.parquet")
df.write_parquet("path/to/output")
    init --  a local ray cluster as worker node
       data_root 
       job_id  job_time  job_name
	      job的名称默认是当前脚本的文件名
       bind_numa_node num_executors 
	       ray cluster
    session = Session(
	  atexit.register可以确保在程序退出时执行必要的清理工作,如关闭文件、释放资源等,从而避免资源泄露或其他潜在问题

示例2-Low-level API

    driver = Driver()	
    ctx = Context()
    dataset = ParquetDataSet(input_paths)
    node = DataSourceNode(ctx, dataset)
    node = DataSetPartitionNode(ctx, (node,), npartitions=npartitions)
    node = SqlEngineNode(ctx, (node,), "SELECT * FROM {0}")	
    plan = LogicalPlan(ctx, node)
    driver.run(plan)
	  
	Driver 是对 JobManager的封装 ,读取来自命令的参数并把参数值传给JobManger 
	Scheduler and Executor  是底层的API, 来调度和执行task--  scheduling and executing tasks
	node: 封装数据处理的工作流--A typical workflow 
	         # Create a global context 创建一个全局的上下文
                创建数据集
                创建数据源的node,创建执行引擎,创建逻辑执行计划

数据目录

Data Root https://github.com/deepseek-ai/smallpond/blob/main/docs/source/internals.rst

data_root
└── 2024-12-11-12-00-28.2cc39990-296f-48a3-8063-78cf6dca460b # job_time.job_id
    ├── config  # configuration and state
    │   ├── exec_plan.pickle
    │   ├── logical_plan.pickle
    │   └── runtime_ctx.pickle
    ├── log     # logs
    │   ├── graph.png
    │   └── scheduler.log
    ├── queue   # message queue between scheduler and workers
    ├── output  # output data
    ├── staging # intermediate data
    │   ├── DataSourceTask.000001
    │   ├── EvenlyDistributedPartitionProducerTask.000002
    │   ├── completed_tasks  # output dataset of completed tasks
    │   └── started_tasks    # used for checkpoint
    └── temp    # temporary data
        ├── DataSourceTask.000001
        └── EvenlyDistributedPartitionProducerTask.000002	

核心组件:

  查询引擎:基于 DuckDB,提供高效的 SQL 查询能力。
  存储适配层:与 3FS 集成,负责数据读写和缓存管理。
  任务调度:轻量级调度器,支持并行处理和流水线优化。
  扩展接口:支持插件机制,可添加新数据源或自定义处理逻辑
   dataset  plan
   
提交plan-- 方式一:  the JobManager to create a Job in the cluster to execute it
           方式二:  Driver 来执行     

dataframe

dataframe.py   
               Session   类 继承自 SessionBase,用于管理数据处理会话  class Session(SessionBase)
               DataFrame 类   代表一个分布式数据集合,是数据处理的核心类。
			      	    	 
	                ray.wait(
	                ray.get(dataset_refs, timeout=0)  
			   
			    使用了   dataset
				使用了   plan     plan: Node SqlEngineNode  ShuffleNode  HashPartitionNode  EvenlyDistributedPartitionNode
				使用了   LogicalPlan Optimizer  optimized_plan
				          planner.node_to_tasks  planner.visit(self.optimized_plan)
						  
						  
session.py    SessionBase 类  负责初始化数据处理环境,包括配置管理、任务调度、日志输出等
   class SessionBase:	
         from smallpond.logical.node import Context
	     from smallpond.execution.task import JobId, RuntimeContext
	     self._ray_address = ray.init(	 address="local", )
		 
worker.py  ,这个文件是 SmallPond 工作节点的入口脚本。它负责解析命令行参数、启动 Ray 进程

任务调度

Driver作为入口点,解析参数后根据模式调用不同的执行逻辑。Driver 是对 JobManager的封装 ,读取来自命令的参数并把参数值传给JobManger 
     JobManager负责作业的整体管理,创建执行计划并启动Scheduler。
	 Scheduler 分配任务给 Executor,
	 Executor实际执行具体的Task
	     args.mode == "executor":
		    runtime_ctx: RuntimeContext = load(args.runtime_ctx_path)
		    run_executo		
		      executor = Executor.create(runtime_ctx, exec_id) 
			  executor.run()
   通过逻辑计划(Logical Plan)和执行计划(Execution Plan)描述数据处理流程	
       "-e", "--engine_type", default="duckdb", choices=("duckdb", "arrow")	
smallpond/execution/driver.py
   
	"--tags", nargs="*", default=[], help="Tags for submitted platform task"

manager.py     JobManager   类负责作业的整体管理,包括创建执行计划、启动调度器和执行器
    保存逻辑计划、执行计划和调度状态,调用了调度器scheduler,使用观察者模式
	以及使用配置文件的方式来执行  executor
       初始化运行时上下文( RuntimeContext)
	   	execution/manager.py
        from smallpond.execution.task import ExecutionPlan, JobId, RuntimeContext		
            class JobManager(object)   def run(
			sched_state_observers: Optional[List[Scheduler.StateObserver]] = None
			sched_state_exporter = SchedStateExporter(runtime_ctx.sched_state_path)
			sched_state_observers.insert(0, sched_state_exporter)
	    class SchedStateExporter(Scheduler.StateObserver)
		
	 dump(runtime_ctx, runtime_ctx.runtime_ctx_path, atomic_write=True)	
scheduler.py   Scheduler类 是任务调度的核心,负责将任务分配给可用的执行器(Executor),并监控任务的状态。
    Scheduler 维护任务队列,处理任务的重试和失败,确保作业的顺利完成
        维护任务队列和执行器状态(RemoteExecutor/LocalExecutor)
	 smallpond/execution/scheduler.py
	    ExecutorState(Enum)
		RemoteExecutor  LocalExecutor(RemoteExecutor):
	  class Scheduler(object):
	    class StateObserver(object):
        from smallpond.execution.workqueue import (
            StopExecutor,
            StopWorkItem,
            WorkItem,
            WorkQueue,
            WorkQueueInMemory,
            WorkQueueOnFilesystem,
        )
    self.running_works: Dict[str, WorkItem]
	
	
executor.py,其中定义了 Executor 类,负责实际执行任务。
     它使用工作队列(WorkQueue)来处理工作项(WorkItem),并管理任务的执行,通过 SimplePool 实现多进程并发。
	通过底层的3FS进行exeutor服务发现和task分发的 
  --runtime_ctx_path  通过配置文件路径--pickle来关联
      help="The path of pickled runtime context passed from scheduler to executor",	  
  	  runtime_ctx: RuntimeContext = load(args.runtime_ctx_path)
	   for output_name, nodes in nodes_groupby_output_name.items(): 
	 
	class Executor(object):
	task = SimplePoolTask(func, args, name)
    from smallpond.execution.workqueue import (
        StopExecutor,
        StopWorkItem,
        WorkItem,
        WorkQueue,
        WorkQueueOnFilesystem,
        WorkStatus,
    )
    self.running_works: Dict[str, Tuple[SimplePoolTask, WorkItem]] 
task.py定义了各种任务类型,如DataSourceTask、MergeDataSetsTask、PartitionProducerTask等
	    RuntimeContext
    调用了 duckdb

logical

###逻辑计划和执行计划的分离,实现了系统的模块化和可扩展性。	   
	node.py 这是整个系统的核心之一。  Node 类的定义,它是所有逻辑节点的基类 
	     DataSourceNode 和 DataSinkNode
		 PythonScriptNode、ArrowComputeNode 和 SqlEngineNode
    		create_task 方法,它用于创建任务,这是执行计划的基础 使用 DuckDB 引擎来执行查询 
            LogicalPlanVisitor 类,它使用了访问者模式来遍历逻辑计划	
         全局上下文类,用于管理逻辑计划的用户定义函数(UDF)
		      create_function 和 create_duckdb_extension 用于注册 UDF 或 DuckDB 扩展。	
	optimizer.py 。这里定义了一个 Optimizer 类,它的作用是优化逻辑计划 
	planner.py  。这个文件定义了一个 Planner 类,它负责将逻辑计划转换为执行计划


 exec_plan = ExecutionPlan(self.runtime_ctx, root_task, logical_plan)

### 支持插件机制,可添加新数据源或自定义处理逻辑	
 dataset.py,对不同数据集类型的定义和处理逻辑
	    load_partitioned_datasets 
		RowRange 类  
		Dataset 是所有数据集的基类,提供了数据集的基本功能  
		ParquetDataSet 类 继承自 Dataset,专门处理 Parquet 文件。
		   CsvDataSet  ArrowTableDataSet
 udf.py 定义了 UDF(用户自定义函数)相关的类型和工具,用于扩展系统的功能
	   UDFType 是一个枚举类,它包装了 DuckDB 的数据类型 UDFContext 和其子类,它们负责管理 UDF 的上下文和绑定逻	

IO-文件系统

arrow.py 中定义了一个 RowRange 数据类, 帮助管理数据文件中的行范围,可能用于分片或并行处理数据集。	
        需要将数据均匀分配到多个任务或线程中进行处理的场景	
         PyArrow 的小字符串和小二进制类型转换为大字符串和大二进制类型
filesystem.py	
        测路径是否属于 HF3FS 文件系统,并提取挂载点路径
        包括路径管理、对象序列化和反序列化,特别支持 HF3FS 文件系统和 Zstandard 压缩。			

platform-集群环境

  通过 Platform 抽象层支持不同集群环境(如 MPI)
    class Platform: 
	    定义了一些默认值和日志记录功能。
 		start_job  stop_job  default_job_id
		    进程管理--popen = subprocess.Popen    os.kill  uuid.uuid4()
			Grafana | 查询、可视化、警报观测平台
    class MPI(Platform):
	
架构特点 
     清晰的架构设计:
	     通过 抽象基类提供的默认实现和统一接口,减少了重复代码,提高了代码的可维护性
	     通过抽象基类和具体平台实现的分层设计,使得代码结构清晰,易于理解和维护	
	 支持多种平台的实现和扩展,可以根据需求快速添加新的平台支持--插件机制

contrib

 contrib 模块包含了一系列附加的、可选的扩展功能,如数据类型、函数、工具和插件等 
    动态加载模块 实验性的功能和特性
    CopyArrowTable 和 StreamCopy。测试或验证数据传输完整性的
	   ArrowComputeNode 和 ArrowStreamNode,这意味着它们是基于 Apache Arrow 的计算和流式处理节点  

   log_dataset.py 日志来监控数据处理的各个阶段  LogDataSet
        通过继承 PythonScriptNode 和 PythonScriptTask,展示了如何将自定义任务集成到数据处理框架中
        添加各种各样的自定义逻辑 

    WARC(Web ARChive)格式是网络资源存档中使用的常见文件格式,全称为Web Archive File Format, 网站归档	
	  OFD格式在电子文件管理和档案信息化	OFD是自主可控的版式格式-网页归档
        ImportWarcFiles 类中使用了 warcio.ArchiveIterator 来解析 WARC 文件

高阶的API的流程

smallpond init 
     api/dataframe
	       from smallpond.execution.task import Task
		   from smallpond.logical.node import
		   from smallpond.logical.optimizer import Optimizer
		   from smallpond.logical.planner import Planner
		   from smallpond.session import SessionBase
	DataFrame is the main class in smallpond  
	    功能: Loading Data  Partitioning Data  Transformations
		       Consuming Data  Execution
		class DataFrame :封装了 wrapper around a `Node` and a `Session` required for execution  
		   Session   封装 JobId, RuntimeContext  import ray
		   Node
		   
		 调度:  import ray
		           ray.wait(tasks, timeout=0)
				   ray.get([task.run_on_ray() for df in dfs for task in df._get_or_create_tasks()])
		 计划     node    optimizer   planner   session 
		 数据:from smallpond.logical.dataset import * 
    Task--涉及到数据-调度
	     import duckdb 
		 import ray
		 from smallpond.execution.workqueue import WorkItem, WorkStatus

参考

   https://github.com/deepseek-ai/smallpond
  https://github.com/deepseek-ai/smallpond/blob/main/docs/source/api.rst
posted @ 2025-03-03 18:04  辰令  阅读(313)  评论(0)    收藏  举报