news 2026/9/17 3:17:18

Spark入门到实战:从RDD到DataFrame的分布式计算与性能优化

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Spark入门到实战:从RDD到DataFrame的分布式计算与性能优化

1. 先把概念捋清楚:Spark到底是个什么东西

1.1 一句话说清Spark的定位

Spark是一个分布式计算引擎,专门用来处理“单台机器搞不定”的数据计算问题。什么叫做单台机器搞不定?两个典型场景:一是数据量大到内存放不下,二是计算逻辑复杂到单机跑完要好几个小时甚至直接卡死。

你可能听说过Hadoop MapReduce,Spark和它的定位很像,都是做分布式计算,但Spark最大的杀手锏是“内存计算”。MapReduce每个步骤都要落盘,每一步读写硬盘都是一次IO开销,而Spark尽量把中间结果留在内存里,所以跑迭代式算法、交互式查询的时候速度能快出好几个数量级。

我用一个不太严谨但很好懂的类比:MapReduce像是去银行办事,每办一个窗口业务就要重新排一次队;Spark则是提前把所有材料准备好,进一个大厅就能连着把几件事办完。数据还在内存里热着,下一个算子直接用,不用反复冷启动加载。

我在实际带新人入门的时候发现,很多初学者一上来就盯着RDD、DataFrame、shuffle这些术语,结果看了一周概念还是不会动手。所以这篇教程的定位很简单——让你今晚就能在本机跑出一个真正的Spark程序,同时把背后的原理和常见的坑讲清楚。

1.2 Spark生态全景:这么多组件分别干嘛的

打开Spark官网或者看招聘JD,你会发现Spark从来不是一个光秃秃的计算引擎,它是一整套生态。先记住下面这张表,不用全懂,但至少面试和看文档时不至于懵。

组件作用类比
Spark Core基础计算引擎,负责任务调度、内存管理、容错操作系统内核
Spark SQL用SQL或DataFrame API做结构化数据处理数据库查询引擎
Spark Streaming / Structured Streaming处理实时流式数据,按微批次切分水龙头分段接水
MLlib机器学习算法库,包括分类、回归、聚类、推荐算法工具箱
GraphX图计算组件,处理社交网络、关系图谱等图数据库专用计算器

选择Spark的很大一部分原因,就是这个生态太全了。同一个集群上既能跑离线批处理,又能跑实时流,还能直接做机器学习模型训练前的特征工程,不用来回搬数据换技术栈。

1.3 你该用哪个版本、哪门语言入门

先说版本。现在稳定主线是Spark 3.x,3.5已经是比较成熟的版本。网上还能搜到Spark 2.0、2.4的源码下载和旧教程,但除非你维护的是老集群,否则别在版本上纠结太久,直接选3.3+以上的新版本。

再说语言。Spark支持Java、Scala、Python、R四种语言,我的建议很明确:

  • 如果你未来做偏数据工程、跑批、SQL类工作:Python + PySpark完全够用。
  • 如果你做偏底层调优、二次开发、写UDF:建议直接学Scala,因为Spark源码本身就是Scala写的,很多底层算子Scala才暴露完整能力。
  • 如果只是公司有现成集群,你只负责写分析任务:先用SQL + DataFrame解决问题,这是上手最快的路径。

我自己带过不少从零开始的人,绝大多数都是从PySpark入门的。语法简单、调试方便、本地装了Python就能折腾,不用像Scala那样先搞懂sbt编译、类型推断这些烦心事。等跑通了几个实战项目,再去补Scala,是性价比最高的路线。

2. 动手前的准备:装环境、跑起来的两种姿势

2.1 本地模式:最快速度验证“Spark能跑”

很多人一听到“Spark集群”就以为必须搞三台服务器,其实Spark最简单的运行方式就是本地模式。本地模式下,Spark用一台机器上的多线程来模拟分布式计算,不需要Hadoop、不需要YARN,非常适合学习和初步开发。

准备步骤非常简单:

第一步:安装JDK(8/11/17均可)

Spark是基于JVM的,无论你用Python还是Scala,JDK都是必须的。官方要求JDK 8/11/17,我用的是JDK 11,稳定没毛病。装完记得配置JAVA_HOME.

第二步:安装Python(3.8及以上)

我是直接装的Anaconda,好处是numpy、pandas这些常用库都一起带了,后续做数据处理样例时不用单独装包。

第三步:下载Spark安装包

从官网下载spark-3.5.x-bin-hadoop3.tgz,解压到一个没有空格的路径,比如/opt/spark或者D:\spark. 然后配置环境变量:

export SPARK_HOME=/opt/spark export PATH=$SPARK_HOME/bin:$PATH

Windows用户记得把%SPARK_HOME%\bin加到Path环境变量里。

第四步:验证安装

pyspark

看到SparkSession已经在localhost:4040启动,就说明本地环境OK了。整个安装过程熟练的话不到十分钟。

2.2 集群模式:从单机到一堆机器的思路

本地模式是学习用的,生产环境肯定还是集群模式。Spark常见的集群部署方式有三种:

  • Standalone模式:Spark自带的一套简单集群管理器,不需要额外组件就可以把多台机器组成集群,适合中小规模场景和测试环境。
  • YARN模式:大数据生态里最常用的资源管理器,如果你公司已经有Hadoop集群,Spark跑在YARN上最省事,因为资源和权限体系都统一管理。
  • Kubernetes模式:容器化部署中的主流方案(配套DGX这类GPU服务器做Spark部署时也会用),适合云原生环境、需要弹性伸缩的场景。

如果你现在只是个人学习,完全不需要着急搭集群。先把本地模式玩熟,理解了任务怎么提交、资源怎么分配,再去搭集群会顺畅得多。反过来说,连单机Spark都跑不起来,直接去搭集群大概率会被各种环境配置折腾到怀疑人生。

2.3 开发工具推荐与起步调试技巧

很多初学者用pyspark命令行一句一句地敲,这适合测试,但不适合写完整任务。我更推荐两个方案:

  • VS Code + Python插件:本地写.py文件,用spark-submit提交,或直接右键Run。
  • Jupyter Notebook:配合findspark可以很方便地在Notebook里初始化Spark环境,逐段调试非常直观。
import findspark findspark.init() from pyspark.sql import SparkSession spark = SparkSession.builder.appName("MyFirstApp").master("local[*]").getOrCreate()

注意local[*]这个参数,星号代表用本机所有可用的CPU核心数来跑。如果你是8核机器,Spark就会创建8个并发任务来模拟分布式并行计算。学习阶段这样设置就够了,别贪多去调local[1]local[2]这种手动控制,留到后面理解了并发模型再调整也不迟。

3. 核心概念一次讲透:RDD、DataFrame、Dataset

3.1 RDD:Spark最底层的抽象

RDD的全称是弹性分布式数据集(Resilient Distributed Dataset),它代表一个只读的、分区的记录集合。我从四个特性帮你理解:

  • 只读:RDD一旦创建就不能修改,要做变换只能生成新的RDD。这是为了容错方便,每个RDD都知道自己是由哪个父RDD演算来的。
  • 分区:一个RDD会被切分成多个分区,分布式地存储在不同Executor上,Spark任务就是针对每个分区并行计算的。
  • 容错(弹性):如果一个分区数据丢失了,RDD可以通过血缘关系重新计算出来,不需要像Hadoop那样做冗余备份。
  • 延迟计算:RDD上的mapfilter这类变换不会立即执行,只有遇到countcollectsaveAsTextFile这类行动操作时才会真正触发计算。

我把RDD类比成一张“菜谱”,你往里面加各种步骤(变换操作),但真正开火做菜要等你说“开饭”(行动操作)那一刻才发生。

但RDD有一个很不友好的点:它没有Schema,也就是告诉Spark“那一列是整数、这一列是字符串”的信息完全靠你自己管理。数据量大、列多的时候,用RDD写代码会非常痛苦。

3.2 DataFrame:让Spark真正“好用起来”的关键

DataFrame的出现解决了RDD“缺乏结构”的问题。你可以把它理解为一张带列名和类型的分布式表格,每一行数据都遵循相同的Schema。

DataFrame能让Spark变快的原因有两个:

第一,Catalyst优化器。你写的DataFrame代码会被自动转换为逻辑执行计划,优化器会帮你做谓词下推、列剪枝、常量折叠等优化。比如你只需要查两列,Spark会尽可能跳过其他列的读取和计算。这个优化对于RDD是做不到的。

第二,Tungsten执行引擎。Spark通过二进制存储和代码生成技术,让DataFrame的计算在底层被编译成高性能的Java字节码,避免对象序列化和反序列化的开销,内存利用率更高。

一个很典型的现象:同一个数据统计任务,RDD写法可能跑4分钟,DataFrame写法只要40秒。差距就是这么夸张。

3.3 到底选哪个API:我的建议

维度RDDDataFrameDataset
适用人群框架开发者、底层功能需求数据分析、ETL、报表开发Scala/Java用户、需要类型安全
Schema支持
性能高(有优化器)高(有优化器)
开发效率

如果你写Python,乖乖用DataFrame。如果你写Scala,优先用Dataset/DataFrame,结合类型安全用Case Class。至于RDD,了解它的特性和原理就够了,除非你要自定义分区器、操作非结构化数据,否则别直接拿RDD去写业务逻辑。

我见过很多从老教程学Spark的人,满脑子还是sc.textFile().flatMap().reduceByKey()这一套,结果同事用DataFrame写的同类任务执行效率高出一截。这年头入门Spark,直接拥抱DataFrame和Spark SQL,才是正道。

4. 从零到能跑:第一个WordCount实战

4.1 环境自检与数据准备

万事开头难,先验证环境是否一切正常。打开终端执行pyspark,如果能够看到SparkSession启动信息,说明环境已经就绪。

接着准备一个用于测试的文本文件,我用/tmp/hello.txt作为示例,内容放几行单词:

hello world spark hello spark hello spark is awesome word count example

学习阶段我建议用这种几百字节的小文件调通流程,别上来拿几个G的大文件跑,否则问题排查时单机和分布式混在一起,你根本分不清是代码问题还是环境问题。

4.2 逐步写出WordCount

我分三个级别来演示,你对比着看就明白RDD和DataFrame的差异了。

级别一:RDD版本(学习底层原理用)

from pyspark import SparkContext sc = SparkContext.getOrCreate() # 读文件,每行变成一个元素 lines = sc.textFile("file:///tmp/hello.txt") # 按空格拆成单词 words = lines.flatMap(lambda line: line.split(" ")) # 每个单词计数为1 pairs = words.map(lambda word: (word, 1)) # 按单词聚合求和 counts = pairs.reduceByKey(lambda a, b: a + b) # 触发执行并收集结果 for word, count in counts.collect(): print(f"{word}: {count}")

这段代码的每一步都有清晰的语义,也是理解Spark执行模型最好的教科书式示例。

级别二:DataFrame + SQL版本(实际开发推荐)

from pyspark.sql import SparkSession spark = SparkSession.builder.appName("WordCountDF").master("local[*]").getOrCreate() df = spark.read.text("file:///tmp/hello.txt") # 方法1:用DataFrame的API from pyspark.sql.functions import explode, split, col word_counts = df.select(explode(split(col("value"), " ")).alias("word")) \ .groupBy("word").count() # 方法2:直接注册成临时表,写SQL df.createOrReplaceTempView("lines") word_counts_sql = spark.sql(""" SELECT word, COUNT(*) as cnt FROM (SELECT explode(split(value, ' ')) AS word FROM lines) GROUP BY word """) word_counts.show()

注意用了file:///前缀,这是告诉Spark读取本地文件系统。如果不加这个前缀,Spark会默认走HDFS路径,单机模式下会报错找不到文件。这是初学者最容易踩的坑之一。

4.3 代码里这几个细节最容易踩坑

第一,collect()慎用collect()会把所有计算结果拉回到Driver端内存,结果集稍大一点就直接OOM。学习阶段无所谓,但生产环境里统计几十亿行数据时,你用了collect()就等着爆内存吧。要保存到文件用write.csv()write.parquet()才对。

第二,开多个SparkSession会冲突。有些同学在同一个Python进程里反复执行SparkSession.builder().getOrCreate(),最后报错Cannot call getOrCreate() after SparkSession was stopped或者端口冲突。原因是用完一个SparkSession后调用spark.stop(),然后又想重新创建,同一进程内这样操作很容易出问题。最简单的方式是每个脚本只创建一个SparkSession,别重复创建、重复关闭。

第三,文件路径别写错。Windows用户尤其小心,路径分隔符要用/而不是\,或者使用绝对路径。相对路径在不同工作目录下读取结果完全不一样,建议一开始就写死绝对路径。

5. 一个真实需求:用Spark分析用户复购率(附Redshift集成)

5.1 需求拆解:什么叫“复购率”

结构化的例子比WordCount更能让你感受到Spark在生产中的价值。我们拿电商场景的“用户复购率”来练手,这也是招聘和日常工作中很常见的分析需求。

复购率的口径要先明确。一般指的是:在某段时间内首次购买过的用户中,有多少比例的人再次购买了商品

计算公式:

复购率 = 至少购买两次的用户数 / 至少购买一次的用户数

这里的“两次”和“不同商品”还是“不同订单”要根据业务来定义。比如“用不同订单号算”还是“同一订单内不同商品算”,结果差异很大。我们在这里用最简单也最常用的口径:一个用户在两个不同的订单里出现,就算复购。

5.2 用DataFrame完成清洗、聚合、计算

先造一批模拟数据,两个CSV文件,一个用户表一个订单表:

orders.csv: order_id, user_id, order_time 1001, u001, 2024-01-05 1002, u001, 2024-02-10 1003, u002, 2024-01-08 1004, u003, 2024-01-15 1005, u003, 2024-02-20

完整代码如下:

from pyspark.sql import SparkSession from pyspark.sql.functions import col, count, countDistinct spark = SparkSession.builder \ .appName("RepeatPurchaseRate") \ .master("local[*]") \ .getOrCreate() # 读订单数据 orders = spark.read.option("header", True).csv("file:///tmp/orders.csv") orders.show() # 清洗:去空格、去空值、统一用户ID格式 orders_clean = orders.select( col("order_id").cast("string").alias("order_id"), col("user_id").cast("string").alias("user_id"), col("order_time").cast("string").alias("order_time") ).dropDuplicates(["order_id", "user_id"]) # 防止同订单重复记录 # 统计每个用户实际下单次数(拿不同订单号数量) user_orders = orders_clean.groupBy("user_id").agg( countDistinct("order_id").alias("order_cnt") ) user_orders.show() # 加一列标记是否复购 user_orders_with_flag = user_orders.withColumn( "is_repurchase", col("order_cnt") >= 2 ) # 计算复购率 total_users = user_orders_with_flag.count() repurchase_users = user_orders_with_flag.filter(col("is_repurchase") == True).count() repeat_rate = repurchase_users / total_users print(f"总购买用户数: {total_users}") print(f"复购用户数: {repurchase_users}") print(f"复购率: {repeat_rate:.2%}")

这个例子虽然数据量很小,但完整走了一遍“读数据 -> 清洗 -> 去重 -> 聚合 -> 业务计算”的流程。实际生产环境里,这几张表的数据量可能是几亿行,Spark并行处理的能力就在这里体现出来了。

5.3 JDBC读写Redshift的思路

热词里出现了“用户复购率 spark 脚本 redshift”,这其实是很典型的数据管道场景:原始数据在Redshift数据仓库里,你要用Spark做复杂加工,处理完再写回Redshift供BI报表查询。

Spark读写Redshift的常见方式是JDBC:

# 从Redshift读数据 df = spark.read \ .format("jdbc") \ .option("url", "jdbc:redshift://your-cluster.redshift.amazonaws.com:5439/yourdb") \ .option("dbtable", "public.orders") \ .option("user", "your_user") \ .option("password", "your_password") \ .option("driver", "com.amazon.redshift.jdbc.Driver") \ .load() # 处理逻辑... # 写回Redshift df.write \ .format("jdbc") \ .option("url", "jdbc:redshift://your-cluster.redshift.amazonaws.com:5439/yourdb") \ .option("dbtable", "public.user_repurchase_result") \ .option("user", "your_user") \ .option("password", "your_password") \ .mode("overwrite") \ .save()

这里的核心坑点有三个:

  1. 司机会冲突。如果你项目里同时有PostgreSQL JDBC驱动和Redshift驱动,注意别把两个相关的包都扔进去,因为Redshift驱动和PostgreSQL驱动的类名容易冲突,导致各种奇怪的ClassNotFoundException。
  2. 写入性能。通过JDBC逐条写回Redshift非常慢,要对大数据量写回时建议把数据先落成S3上的Parquet,再用COPY命令导入Redshift,速度能差出几十倍。
  3. 分区数匹配。写入Redshift前,把DataFrame重分区到合理的并行度(比如16-32个分区),减少数据库连接压力。别用默认的200个分区去写,Redshift会被打崩。

6. 内存、shuffle和任务调优:入门到进阶的必经之路

6.1 Spark为什么总报内存不足

初学Spark的人一定会遇到这个报错:

java.lang.OutOfMemoryError: Java heap space

或者:

Container killed by YARN for exceeding memory limits

先说Spark的内存模型。Spark的Executor内存分为三块:

  • Storage内存:用来缓存RDD/DataFrame数据。
  • Execution内存:用来存shuffle、join、aggregation等过程中的临时数据。
  • Reserved内存:保留给系统使用。

默认情况下,Storage和Execution是动态共享的,比例为spark.memory.fraction=0.6,也就是Executor堆内存的60%用于这两块,剩下40%留给用户代码和元数据。

出现OOM通常有三种原因:

  1. Driver端OOM:你用了collect()take()这类拉取全部数据的操作。
  2. Executor端OOM:单个分区内的数据量太大,或者shuffle的数据量超过了Executor内存限制。
  3. 元数据OOM:表太多、分区太多、Schema太复杂,导致Driver端需要维护的元数据暴增。

调优方向不是一味加大内存,更核心的是减少单个Executor需要处理的数据量,也就是合理分区。

6.2 shuffle是性能杀手,怎么降低开销

shuffle这个词几乎是Spark性能优化的核心议题。简单理解,shuffle就是数据在集群里重新分布的过程,比如groupByKeyjoinreduceByKey这些操作,都需要把相同key的数据拉到同一个节点处理。

shuffle慢的原因在于:数据要从当前Executor写出到磁盘,然后通过网络传到其他Executor,再读入内存。涉及磁盘IO + 网络IO,是Spark作业中最昂贵的操作。

我在实际项目中踩过一个印象很深的坑:一条join语句处理不到1亿行的数据,跑了一个多小时。后来排查发现,两个表都发生了严重的shuffle,数据在集群里来回倒腾了几轮。后来改用Broadcast方式,把小表广播到大表所在节点,避免彻底shuffle,作业直接缩短到3分钟。

优化shuffle的思想总结起来有三板斧:

  1. 减少shuffle数据量:在shuffle之前先filter、先做列裁剪,尽可能减小单个分区的数据体积。
  2. 合理设置shuffle分区数spark.sql.shuffle.partitions默认是200。如果你数据量很小,200个分区纯属浪费;如果数据量巨大,200个分区又不够并行。经验法则:每个shuffle分区处理128MB到256MB的数据比较合适。
  3. 尽可能避免shuffle:能用map、filter、broadcast join解决的就别用wide dependency。

6.3 先学会这几招再谈优化

给初学者一个可以立即执行的优化清单:

  1. 设置合理的内存和并行度参数

    spark.conf.set("spark.executor.memory", "2g") spark.conf.set("spark.executor.cores", "2") spark.conf.set("spark.sql.shuffle.partitions", "8")
  2. 用缓存加速重复使用的数据

    df.cache() df.count() # 触发缓存 # 后续多次使用 df 时不用重算
  3. 用Broadcast Join处理小表关联

    from pyspark.sql.functions import broadcast result = large_df.join(broadcast(small_df), "key", "left")
  4. 避免写.show()在生产任务里show()会触发一次action,如果被反复调用在循环里,会导致重复计算。

  5. 优先使用Parquet列式存储。读写Parquet比CSV快得多,特别是做列裁剪查询时,Parquet可以直接跳过无关列。

这些优化策略核心是理解一点:Spark任务尽量在内存里完成,尽量不让数据频繁跨节点移动

7. 常见问题与排查技巧实录

7.1 我踩过的5个典型坑

报错或现象原因解决方案
Could not find or load main class org.apache.spark.launcher.MainSPARK_HOMEJAVA_HOME没配置好检查环境变量,确保Spark解压路径和JDK路径正确
读取文件后数据都是nullCSV文件没设置header=True,或者分隔符不对确认表头参数和文件实际格式,必要时指定option("delimiter", "\t")
PySpark提示Python worker failed to connect backPython路径找不到,Spark启动的Worker无法连接Python进程在代码里显式指定Python解释器:spark.conf.set("spark.pyspark.python", "/usr/bin/python3")
java.io.IOException: No space left on device临时目录(通常是/tmp/spark-*)被写满修改spark.local.dir指向有足够空间的目录
作业进度卡在Running jobs...不动某个Executor死了,或者Driver和Executor之间连接丢失查看4040端口Spark UI,定位是哪个Stage卡住,检查是否Executor内存不够导致频繁GC

7.2 几个实用排查命令与工具

排查问题最核心的工具就是Spark自带的Web UI,默认地址是http://localhost:4040.

打开后重点看三个标签页:

  • Jobs页面:看到当前作业的整体进度,以及每个Job的耗时分布。
  • Stages页面:如果某个Stage的shuffle读或写数据量特别大,说明shuffle优化没做好。
  • Executors页面:看每个Executor的GC时间和内存使用,如果某个Executor的GC时间占比很高,说明内存配置不合理。

日志排查的通用流程是:先看Driver端日志 -> 看出错的是哪个Stage -> 点进对应Stage看任务日志 -> 定位是数据倾斜还是OOM

还可以用spark-submit --verbose查看提交的详细参数,确认配置是否生效。

7.3 学了这些下一步学什么

到这里,你已经能写一个能跑的Spark程序,也能理解它的核心概念和常见调优手段。接下来往哪个方向深入,我根据自己的经历给三条路线:

  1. 数据倾斜深入排查:当你的join结果出现某些任务要跑很久、其他任务很快完成时,大概率是数据倾斜。学习加盐、两阶段聚合等高级玩法。
  2. Structured Streaming流式计算:学会用同样的DataFrame API处理Kafka中的实时数据。
  3. SQL优化与源码理解:用explain()看懂执行计划,自己判断哪些SQL写法效率低;想更深入的可以下Spark源码,编译跑通后在本地断点调试看执行流程。

我个人在实际学习中的体会是:Spark入门最大的障碍不是概念复杂,而是“看得多、跑得少”。很多知识点非要写到代码里、跑到报错、翻到报错原因,才会真正变成你自己的经验。所以看这篇文章的时候,最好电脑就在手边,把前面几个例子亲手敲一遍,遇到报错再回来看对应章节的排查方法,一步一个脚印,比什么都管用。

最后再分享一个小技巧:学习阶段如果你遇到奇怪的环境问题,搜索时别老盯着 “Spark xxx 教程” 这类泛泛的标题,试着直接把报错原文贴到搜索引擎里,往往一搜就中。很多牛人已经把这些坑的记录发布在各个社区了,你看到的报错,大概率别人早就踩过、修过了。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/17 3:16:45

功能值不值得做?Free AI Courses 影响估算框架量化 ROI 教程

功能值不值得做?Free AI Courses 影响估算框架量化 ROI 教程 【免费下载链接】free-ai-courses Interactive course teaching Product Managers how to use Claude Code effectively 项目地址: https://gitcode.com/GitHub_Trending/cl/free-ai-courses Free…

作者头像 李华
网站建设 2026/9/17 3:16:12

智能座舱芯片横评:高通8155、联发科MT8676、华为麒麟990A谁更值?

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/17 3:15:42

海光DCU接入Kubernetes实战:从整卡到vDCU虚拟化与DeepSeek部署

我在给客户做 AI 平台适配的时候,经常要回答同一个问题:手里有海光 DCU 这种国产加速卡,到底怎么接进 Kubernetes,怎么让平台上的训练和推理任务真正用起来?这个问题看着像是“装个驱动、写个 Device Plugin”的功夫活…

作者头像 李华
网站建设 2026/9/17 3:15:38

CPU信息获取全指南:从CPUID指令到Windows命令的工程实践

1. 先搞清楚要拿什么:CPU Info、CPUID、CPU ID不是一回事做Windows平台开发或者搞运维资产盘点,最常遇到的一个需求就是“把机器的CPU信息拿回来”。我见过太多人在这个问题上栽跟头:拿着CPU-Z截图当交付物,不知道系统里其实藏着好…

作者头像 李华
网站建设 2026/9/17 3:14:36

Jetson eFuse烧录:生产预置安全的硬件锚点

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/17 3:14:08

Velero 开发指南:生成文件、单元测试与依赖管理实战

Velero 开发指南:生成文件、单元测试与依赖管理实战 【免费下载链接】velero Backup and migrate Kubernetes applications and their persistent volumes 项目地址: https://gitcode.com/GitHub_Trending/ve/velero Velero(VMware Tanzu Velero&…

作者头像 李华