Spark实战:从数据处理到性能调优的完整指南
1. 项目概述从概念到实战的Spark旅程如果你正在处理的数据量已经让传统的单机工具比如Pandas开始“力不从心”或者你每天需要面对的是来自多个业务系统的TB级日志文件那么Apache Spark这个名字你一定不陌生。它早已不是那个仅仅存在于Hadoop生态圈里的“下一代MapReduce”而是成为了现代大规模数据处理和分析事实上的标准引擎。我接触Spark有七八年了从最早在实验室里折腾几个节点的集群到后来在真实的生产环境中处理每天数PB的实时用户行为数据踩过的坑和获得的效率提升同样深刻。今天我想抛开那些教科书式的架构图直接从一个实战者的视角和你聊聊当我们谈论“Spark数据分析及处理”时我们到底在做什么以及如何把它真正用起来。简单来说Spark是一个开源的、统一的分布式计算框架。它的核心魅力在于“统一”二字你可以用同一套API主要是Scala、Java、Python和R来完成批处理、交互式查询、实时流处理、机器学习和图计算等几乎所有常见的数据任务。这极大地简化了数据平台的架构复杂度。更重要的是它通过将数据尽可能多地保留在内存中进行计算获得了比传统基于磁盘的MapReduce快出数十倍甚至百倍的性能。对于数据分析师、数据工程师和算法工程师而言掌握Spark意味着你拥有了处理海量数据的能力能将分析洞察从样本扩展到全量将模型训练从几天缩短到几小时。那么这个实战分析项目适合谁呢首先是那些已经熟悉Python特别是Pandas或SQL进行数据分析但受限于单机性能想要迈向大数据处理的数据分析师。其次是负责构建和维护企业级数据管道需要高效、稳定地完成数据清洗、转换和加载ETL任务的数据工程师。最后对于正在学习分布式系统的开发者通过Spark实战来理解分区、容错、惰性求值等概念也是一个绝佳的途径。接下来我将从设计思路、核心细节、实操过程到避坑经验为你完整拆解一个Spark数据分析项目的生命周期。2. 核心设计思路为何是Spark以及如何规划你的作业当你决定启动一个Spark项目时第一个问题往往是为什么是Spark而不是Flink、Hive或者继续用Pandas加数据库我的选择逻辑通常基于以下几个考量点数据规模、处理范式和团队技能栈。如果你的数据量在GB到TB级别且处理逻辑复杂需要多次迭代比如特征工程、机器学习Spark的内存计算优势会非常明显。如果你的业务以实时流处理为核心且对延迟有毫秒级要求那么Flink可能是更专精的选择但如果你的场景是准实时秒到分钟级或批处理为主Spark Structured Streaming的微批处理模型以其与批处理API的高度一致性能显著降低开发维护成本。至于团队技能如果成员普遍熟悉Python和SQL那么PySpark和Spark SQL的低门槛会让你快速上手。确定了使用Spark后一个清晰的顶层设计至关重要。切忌一上来就开始写代码。我的习惯是遵循“目标驱动分而治之”的原则。首先明确本次分析或处理的核心目标是什么是生成一份每日销售报表还是构建一个用户画像标签体系或者是训练一个推荐模型目标决定了数据的输入、转换逻辑和最终输出。其次将这个大目标分解为若干个可独立验证的步骤。一个典型的数据处理管道通常包括数据源接入 - 原始数据解析与清洗 - 多表关联与维度补全 - 业务指标计算/特征提取 - 结果持久化或可视化。为每个步骤设计好输入输出的Schema数据结构并思考它们之间的依赖关系。在架构层面你需要决定运行模式。对于学习和中小型任务Local模式单机多线程模拟分布式是最快的起点。对于生产环境Standalone、YARN或Kubernetes是主要的集群管理器。目前随着云原生的发展Kubernetes模式越来越流行它提供了更灵活的资源调度和弹性伸缩能力。资源规划是另一个关键你需要预估数据量为Driver和Executor配置合适的内存与CPU核心。一个常见的“踩坑点”是低估了Shuffle操作如groupBy、join带来的网络和磁盘IO压力这可能导致作业运行缓慢甚至OOM内存溢出。因此在设计阶段就要尽量避免会产生巨大Shuffle的宽表关联优先考虑广播小表Broadcast Join或调整分区策略。3. 环境搭建与核心API初探工欲善其事必先利其器。虽然生产环境多在集群但本地开发环境是学习和调试的基石。我推荐使用Conda来管理Python环境并结合PySpark进行开发这对数据分析师最为友好。你可以通过pip install pyspark直接安装Spark会自动下载所需的依赖。一个更可控的方式是去Apache官网下载预编译的Spark包然后设置SPARK_HOME环境变量。这里有个小技巧在本地测试时可以通过设置spark.sql.shuffle.partitions为一个较小的值比如你的CPU核心数来避免生成大量小文件提升测试速度。Spark的核心抽象是弹性分布式数据集RDD但对于数据分析而言我们更常用的是构建在RDD之上的高级APIDataFrame和Dataset。你可以把DataFrame想象成一个分布式的、带有Schema的表格它提供了丰富的结构化数据处理接口并且经过Catalyst优化器的优化执行效率很高。Dataset是类型安全的主要在Scala和Java中使用。对于Python用户我们操作的就是DataFrame。让我们从一个最简单的例子开始感受一下Spark的编程模型。假设我们有一个CSV格式的销售日志sales.csv。from pyspark.sql import SparkSession # 1. 创建SparkSession入口 spark SparkSession.builder \ .appName(MyFirstSparkAnalysis) \ .config(spark.sql.shuffle.partitions, 200) \ .getOrCreate() # 2. 读取数据 df_sales spark.read \ .option(header, true) \ .option(inferSchema, true) \ .csv(path/to/sales.csv) # 3. 查看数据 df_sales.printSchema() df_sales.show(5) # 4. 执行一个简单的聚合按产品类别统计销售额 df_summary df_sales.groupBy(product_category) \ .agg({sales_amount: sum, order_id: count}) \ .withColumnRenamed(sum(sales_amount), total_sales) \ .withColumnRenamed(count(order_id), order_count) df_summary.show()这段代码体现了Spark的核心思想声明式编程和惰性求值。我们定义了一系列的转换操作read,groupBy,agg但直到show()这个动作Action被调用时Spark才会真正开始执行计算。这允许优化器对整个计算图进行全局优化。spark.read是极其强大的数据入口除了CSV它还直接支持JSON、Parquet、ORC、JDBC数据库、Hive表等多种数据源。注意在生产环境中慎用.option(“inferSchema”, “true”)。虽然方便但遍历数据推断类型有开销且可能不准。最佳实践是显式定义Schema使用StructType和StructField这能提升读取性能并保证数据一致性。4. 数据处理实战清洗、转换与关联真实世界的数据从来都不是干净的。数据处理的核心阶段就是将这些“原始数据”转化为“可用数据”。这一阶段会消耗一个数据项目约70%的时间和精力。4.1 数据清洗与质量检查清洗的第一步是了解数据全貌。除了printSchema()和show()我习惯使用df.describe().show()来查看数值列的统计信息计数、均值、标准差、最小最大值快速发现异常值。对于空值处理Spark提供了灵活的方法# 删除包含空值的行谨慎使用可能丢失大量数据 df_cleaned df_sales.na.drop() # 填充空值 df_filled df_sales.na.fill({sales_amount: 0, city: Unknown}) # 更复杂的填充使用均值 from pyspark.sql import functions as F mean_val df_sales.select(F.mean(df_sales.sales_amount)).collect()[0][0] df_filled_mean df_sales.na.fill(mean_val, subset[sales_amount])重复数据也是常见问题。使用df.dropDuplicates()可以基于所有列或指定列子集去重。对于数据格式错误比如日期字符串不统一可以使用F.to_date()函数配合指定的格式进行转换。4.2 复杂转换与用户自定义函数UDFSpark SQL内置了上百个函数能满足大部分需求如字符串处理、日期运算、数学计算等。例如我们想从timestamp列中提取小时和星期几df_with_features df_sales.withColumn(sale_hour, F.hour(F.col(timestamp))) \ .withColumn(sale_day_of_week, F.dayofweek(F.col(timestamp)))当内置函数不够用时就需要用到UDF。但要注意UDF特别是Python UDF会涉及数据在JVM和Python进程间的序列化与反序列化性能开销较大应优先考虑使用内置函数或Scala UDF。如果必须使用建议使用pandas UDF也称为向量化UDF它利用Apache Arrow进行高效的数据传输性能比逐行处理的普通Python UDF好得多。from pyspark.sql.functions import pandas_udf from pyspark.sql.types import DoubleType import pandas as pd # 定义一个pandas UDF计算某个值的平方 pandas_udf(DoubleType()) def squared(s: pd.Series) - pd.Series: return s ** 2 df_sales.withColumn(amount_squared, squared(F.col(sales_amount))).show()4.3 表关联与性能优化数据关联是数据分析的基石。Spark支持多种Join类型inner,outer,left,right,left_semi,left_anti等。关联的性能是最大的挑战。# 假设有另一个产品维度表df_product df_joined df_sales.join(df_product, onproduct_id, howleft)这个简单的join可能引发巨大的Shuffle。优化策略如下广播小表如果有一个表足够小通常小于10MB可通过spark.sql.autoBroadcastJoinThreshold配置Spark可以自动或手动将其广播到所有Executor节点避免Shuffle。from pyspark.sql.functions import broadcast df_joined df_sales.join(broadcast(df_product), onproduct_id)调整Shuffle分区数通过spark.sql.shuffle.partitions控制Shuffle后数据的分区数量默认200。对于数据量很大的作业适当增加此值如1000可以让任务更并行对于数据量小的作业减少此值可以避免过多小任务的开销。使用相同的分区器如果两张表需要频繁按照相同键进行Join或聚合可以在最初就使用相同的分区器如repartition对它们进行分区这样后续操作可以避免Shuffle。避免数据倾斜这是生产环境最常见的“杀手”。如果某个product_id对应的订单量特别大会导致某个Task处理时间极长。应对方法包括过滤掉异常的热点key将热点key拆分如加上随机前缀使用“倾斜连接”的特殊技巧。5. 聚合、窗口函数与高级分析清洗和转换后的数据就进入了核心的分析阶段。基础的聚合操作groupBy().agg()大家都很熟悉。这里我想重点介绍两个更强大的工具窗口函数和多维聚合。5.1 窗口函数在组内进行计算窗口函数允许你在一个数据行的“窗口”与当前行相关的一组行上进行计算而不必将数据折叠到一行。这对于计算排名、移动平均、累计求和等场景不可或缺。例如计算每个产品类别内按销售额排名的产品from pyspark.sql.window import Window window_spec Window.partitionBy(product_category).orderBy(F.col(total_sales).desc()) df_ranked df_summary.withColumn(rank_in_category, F.rank().over(window_spec)) df_ranked.filter(F.col(rank_in_category) 3).show() # 显示每个类别的前三名再比如计算每个用户最近3次消费的移动平均金额user_window Window.partitionBy(user_id).orderBy(order_time).rowsBetween(-2, Window.currentRow) df_sales.withColumn(moving_avg_3, F.avg(sales_amount).over(user_window))5.2 多维聚合与旋转对于制作交叉报表groupBy的pivot功能非常方便。它可以将某一列的唯一值转换为新的列。# 计算每个城市行、每个产品类别列的总销售额 df_pivot df_sales.groupBy(city).pivot(product_category).agg(F.sum(sales_amount)).fillna(0) df_pivot.show()对于更复杂的多维分析OLAP可以使用cube或rollup操作它们能一次性计算所有维度组合的聚合结果。df_cube df_sales.cube(city, product_category).agg(F.sum(sales_amount).alias(total)) # 结果将包含(cityA, categoryX), (cityA, 所有category), (所有city, categoryX), (所有city, 所有category) 的聚合值6. 性能调优与故障排查实录即使逻辑正确一个未经调优的Spark作业也可能慢得无法接受。性能调优是一个结合了监控、分析和经验的过程。6.1 监控你的作业Spark UISpark Web UI是你最好的朋友。在作业运行时通过4040端口或配置的端口访问Driver节点的UI界面。你需要重点关注Stages和Tasks哪个Stage耗时最长是否有Task执行时间远高于其他数据倾斜StorageRDD/DataFrame是否被缓存缓存级别是什么Environment确认你的配置参数是否生效。ExecutorsExecutor的数量、内存使用情况、GC时间是否健康6.2 核心调优参数以下是一些关键配置需要根据你的集群资源和作业特点调整参数默认值说明与调优建议spark.executor.memory1gExecutor内存。通常设为容器/节点总内存的75%左右留一部分给操作系统和HDFS。例如在4核16G的节点上可设为10g。spark.executor.cores1每个Executor的CPU核心数。通常与节点核心数匹配或略少。spark.executor.instances(动态)Executor数量。在YARN/K8s上常动态分配Standalone需指定。总核心数 instances * cores。spark.sql.shuffle.partitions200Shuffle后的分区数。这是最常调整的参数之一。数据量大则调高如1000-10000数据量小则调低。spark.sql.autoBroadcastJoinThreshold10MB小于此大小的表会自动广播。可酌情调大如50MB但需确保广播表不会撑爆Driver内存。spark.default.parallelism(取决于集群)未指定分区数时的默认并行度。通常设为集群总核心数的2-3倍。spark.serializerJavaSerializer使用KryoSerializerspark.kryo.registrator需配置序列化更快、更紧凑。6.3 常见问题与排查技巧作业卡在某个Stage如99%只有少数几个Task没跑完现象这是数据倾斜的典型症状。少数几个Task处理的数据量远大于其他。排查在Spark UI的Stage详情页查看Task的“输入数据量”和“耗时”。解决加盐对倾斜的Key添加随机前缀打散到一个聚合子阶段然后再合并。# 假设user_id存在倾斜 df_with_salt df.withColumn(“salted_key”, F.concat(F.col(“user_id”), F.lit(“_”), (F.rand()*10).cast(“int”))) # 先对salted_key聚合 df_first_agg df_with_salt.groupBy(“salted_key”).agg(F.sum(“amount”).alias(“partial_sum”)) # 去掉盐二次聚合 df_final df_first_agg.withColumn(“original_user_id”, F.split(F.col(“salted_key”), “_”)[0]) \ .groupBy(“original_user_id”).agg(F.sum(“partial_sum”).alias(“total_sum”))过滤如果热点数据是异常数据如测试账号、爬虫直接过滤掉。广播如果倾斜发生在Join且其中一个表很小尝试广播小表。Executor Lost / OOM内存溢出现象任务失败日志显示java.lang.OutOfMemoryError。排查检查是堆内存Heap还是堆外内存Off-Heap溢出。查看Executor日志。解决增加spark.executor.memory。调整内存比例spark.memory.fraction默认0.6和spark.memory.storageFraction默认0.5。对于堆外内存常用于Shuffle、PySpark通信调整spark.executor.memoryOverhead通常设为Executor内存的10%以上。检查代码中是否有收集大量数据到Driver的操作如collect()避免之。作业运行极其缓慢但没有明显错误排查检查是否频繁发生Full GC垃圾回收或者Shuffle读写量巨大。解决减少Shuffle优化groupBy和join逻辑使用广播。使用缓存对需要多次使用的中间结果进行缓存df.cache()或df.persist()并选择合适的存储级别如MEMORY_AND_DISK。选择高效的文件格式将中间数据保存为Parquet或ORC格式它们具有列式存储、压缩和谓词下推等优点能极大提升IO性能。调整并行度确保分区数df.rdd.getNumPartitions()与可用计算资源匹配避免过多小分区任务调度开销大或过少大分区无法并行。7. 结果输出与数据持久化策略分析计算完成后的结果需要输出到某个地方供下游使用。Spark支持多种输出方式。7.1 输出到文件系统这是最常见的方式支持多种格式。# 写入为Parquet格式推荐 df_result.write \ .mode(“overwrite”) \ # 模式overwrite, append, ignore, error .parquet(“hdfs:///output/path/”) # 写入为带分区的Parquet便于后续按分区查询 df_result.write \ .partitionBy(“date”, “city”) \ .mode(“append”) \ .parquet(“hdfs:///output/path/”) # 写入为CSV适合与人交互查看 df_result.write \ .option(“header”, “true”) \ .mode(“overwrite”) \ .csv(“/local/path/output.csv”)实操心得写入文件时控制输出文件的数量很重要。过多的碎小文件会给HDFS Namenode带来压力也会降低下游读取如Hive查询的性能。可以通过在写入前使用df.coalesce(N)或df.repartition(N)来将数据重分区到指定数量N从而控制输出文件数。N的大小通常与总数据量和期望的单个文件大小如128MB或256MB有关。7.2 输出到数据库使用JDBC连接器可以将结果写入关系型数据库。df_result.write \ .mode(“append”) \ .format(“jdbc”) \ .option(“url”, “jdbc:mysql://host:port/db”) \ .option(“dbtable”, “result_table”) \ .option(“user”, “username”) \ .option(“password”, “password”) \ .save()7.3 输出到Hive表如果你的Spark集成了Hive可以直接创建或写入Hive表。# 将DataFrame保存为Hive托管表 df_result.write.saveAsTable(“my_db.my_result_table”) # 或者写入到指定的Hive外部表路径 df_result.write \ .mode(“overwrite”) \ .option(“path”, “/user/hive/warehouse/my_db.db/my_table”) \ .saveAsTable(“my_db.my_table”)8. 从批处理到流处理Structured Streaming初探现代数据分析对实时性的要求越来越高。Spark Structured Streaming让你能用处理批数据相同的API来处理流数据概念上的无缝切换降低了学习成本。其核心思想是将连续的数据流视为一张不断追加的表。一个基础的流处理作业示例如下我们假设从Kafka读取JSON格式的订单流进行实时聚合from pyspark.sql.types import StructType, StructField, StringType, TimestampType, DoubleType # 定义输入数据的Schema order_schema StructType([ StructField(“order_id”, StringType()), StructField(“product_id”, StringType()), StructField(“user_id”, StringType()), StructField(“amount”, DoubleType()), StructField(“order_time”, TimestampType()) ]) # 从Kafka读取流 df_stream spark \ .readStream \ .format(“kafka”) \ .option(“kafka.bootstrap.servers”, “host1:port,host2:port”) \ .option(“subscribe”, “order_topic”) \ .load() # 将Kafka的value字段二进制转为字符串再解析JSON df_parsed df_stream.select( F.from_json(F.col(“value”).cast(“string”), order_schema).alias(“data”) ).select(“data.*”) # 进行窗口聚合每10分钟统计过去1小时的销售额 windowed_counts df_parsed \ .withWatermark(“order_time”, “10 minutes”) \ # 定义水印处理延迟数据 .groupBy( F.window(F.col(“order_time”), “1 hour”, “10 minutes”), # 窗口长度1小时滑动间隔10分钟 F.col(“product_id”) ) \ .agg(F.sum(“amount”).alias(“hourly_sales”)) # 定义输出以“update”模式输出到控制台调试用和文件系统生产用 query windowed_counts \ .writeStream \ .outputMode(“update”) \ # 也可以是“complete”或“append” .format(“console”) \ .option(“truncate”, False) \ .trigger(processingTime“10 seconds”) \ # 每10秒触发一次微批处理 .start() # 写入到文件系统如Parquet # query windowed_counts \ # .writeStream \ # .outputMode(“append”) \ # .format(“parquet”) \ # .option(“path”, “/streaming_output/”) \ # .option(“checkpointLocation”, “/streaming_checkpoint/”) \ # **必须提供检查点目录用于容错** # .trigger(processingTime“1 minute”) \ # .start() query.awaitTermination() # 等待查询终止流处理的关键概念输出模式append只输出新增行、update输出有更新的行、complete输出完整结果适用于有界聚合。水印用于处理延迟数据系统会根据事件时间和指定的延迟阈值如“10 minutes”来清理旧的聚合状态防止状态无限增长。检查点checkpointLocation是必须设置的。它保存了查询的进度信息和中间状态当查询因故障重启时可以从断点恢复保证端到端恰好一次的语义。注意事项流处理作业的监控更为重要。你需要关注处理延迟Processing Delay和背压Backpressure。在Spark UI的“Streaming”标签页下可以清晰地看到这些指标。如果输入速度持续高于处理速度需要考虑调整触发间隔、优化处理逻辑或扩容资源。

相关新闻

ESP32C3实战:基于HTTPClient库调用ChatGPT API构建智能对话终端

ESP32C3实战:基于HTTPClient库调用ChatGPT API构建智能对话终端

1. 项目概述:当ESP32C3遇见ChatGPT 最近在捣鼓Seeed Studio的XIAO ESP32C3这块小板子,发现不少朋友拿到手后,除了点个灯、连个Wi-Fi,就不知道下一步该玩什么了。其实,它的潜力远不止于此。今天,我就想分享一…

2026/10/6 22:40:07 阅读更多 →
柏翠以赛事级产品实力,重塑国产商用咖啡机的专业高度

柏翠以赛事级产品实力,重塑国产商用咖啡机的专业高度

2026 CBCC中国咖啡师巅峰挑战赛(拉花赛),柏翠旗下天工Plus(PE3966)双头商用咖啡机凭借卓越的稳定性与专业表现,经过组委会层层实测筛选,成功斩获唯一指定官方用机资格。这不仅是一纸认证&#x…

2026/9/23 15:27:33 阅读更多 →
PHP反序列化漏洞实战:从原理到Getshell的完整利用链分析

PHP反序列化漏洞实战:从原理到Getshell的完整利用链分析

1. 项目概述:一次经典的PHP反序列化漏洞实战复盘 最近在整理CTF(Capture The Flag)题目和渗透测试的实战笔记时,翻到了一个非常经典的靶场环境——“BugKu-new_php”。这个题目虽然名字简单,但它几乎囊括了PHP反序列化…

2026/10/7 4:12:50 阅读更多 →

最新新闻

openrig:Claude Code与Codex的本地配置编排实战

openrig:Claude Code与Codex的本地配置编排实战

1. 从 openrig 这个标题说起:它到底想解决什么问题第一次看到openrig这个名字,我脑子里蹦出来的第一反应是“open rig”,也就是“开放式的设备/工具架”。结合热搜词里那一串Claude Code、Codex、YAML、Node.js,基本可以判断出&a…

2026/10/9 5:39:43 阅读更多 →
【ENSP】DHCP 基础实验(路由器作为 DHCP 服务器,接口地址池模式)

【ENSP】DHCP 基础实验(路由器作为 DHCP 服务器,接口地址池模式)

实验任务 搭建拓扑,连线并启动所有设备在路由器 G0/0/0 配置 IP,开启 DHCP 全局功能接口启用 DHCP 接口地址池,配置 DNS、排除静态保留 IPPC 改为 DHCP 自动获取,验证 IP 分配与连通性 AR 路由器 G0/0/0 → S3700 交换机 → PC1、…

2026/10/9 5:39:43 阅读更多 →
MCGS6.2删除负责人登录密码:燃气锅炉仿真程序解锁指南

MCGS6.2删除负责人登录密码:燃气锅炉仿真程序解锁指南

最近在处理一个燃气锅炉热力系统MCGS6.2仿真程序时,卡在了一个特别尴尬的点上——负责人登录密码。工程是从另一组人手里接过来的,仿真界面、控制逻辑都调完了,结果负责人账号带着密码,运行环境一启动就弹登录框,进不了…

2026/10/9 5:39:43 阅读更多 →
context-mode:上下文感知模式如何重塑编辑器与AI提示词工程

context-mode:上下文感知模式如何重塑编辑器与AI提示词工程

这个命令我第一次看到的时候,第一反应是“又一个奇葩缩写”。但等真正用上之后,才意识到它是个被名字耽误了的好牌。context-mode,字面意思是“上下文模式”,放在编辑器、命令行工具、甚至 AI 辅助编程的场景里,它的核…

2026/10/9 5:39:43 阅读更多 →
Spring Boot 实战:从零搭建到多商户商城与推荐系统

Spring Boot 实战:从零搭建到多商户商城与推荐系统

Spring Boot 封神之路,说白了就是一条从“先跑起来”到“跑得明白”的路。早在 2014 年 Spring Boot 1.0 发布之前,Java Web 开发可不是现在这个画风。搞一个 SSM 项目,光 XML 配置就能把人写吐:web.xml、spring-mvc.xml、spring-…

2026/10/9 5:39:43 阅读更多 →
工业无机盐科普:无水硫酸钠理化特性与工业应用介绍丨广东大小化工有限公司

工业无机盐科普:无水硫酸钠理化特性与工业应用介绍丨广东大小化工有限公司

无水硫酸钠,是工业生产中非常常见的无机盐原料,属于基础性化工辅料。因为稳定性好、适用性广、杂质可控,被大量应用在轻工、化工、建材、印染等行业。很多工厂日常使用频繁,但对其完整特性与正确储存方式了解不多。一、无水硫酸钠…

2026/10/9 5:38:42 阅读更多 →

日新闻

Java时间API实战:LocalDate、Date与ZonedDateTime的转换与避坑指南

Java时间API实战:LocalDate、Date与ZonedDateTime的转换与避坑指南

Java时间API这个话题,隔三差五就会在群里被翻出来讨论一次。上周还有个同事线上处理一个订单超时问题,排查到最后发现是ZonedDateTime序列化后时区丢了,用户在下单当天晚上看到的时间整整差了8个小时。这类问题几乎每个做Java开发的人都遇到过…

2026/10/9 0:00:49 阅读更多 →
EasyTier实践:从NAT穿透到子网代理的异地组网部署与排错

EasyTier实践:从NAT穿透到子网代理的异地组网部署与排错

前几个月我手头有好几台机器需要互相访问:办公室台式机、家里 NAS、还有一台云主机。如果只是偶尔传个文件倒还好,问题是工作场景经常要在几处环境之间来回切换,每次都先登录跳板机再层层代理,实在折腾。我先后试过端口映射、自建…

2026/10/9 0:00:49 阅读更多 →
AI Agent工程实战:从七要素到七个决策点的系统设计指南

AI Agent工程实战:从七要素到七个决策点的系统设计指南

AI Agent 这个词在过去一年里被反复提及,但真正动手搭过一套能跑起来的 Agent 系统的人都知道,从"知道它是什么"到"让它稳定干活"之间隔着一整套工程决策。我前后参与过几个 Agent 项目的落地,从最初用现成框架拼装&…

2026/10/9 0:01:50 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

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

2026/10/8 15:26:32 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

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

2026/10/8 15:26:40 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

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

2026/10/8 10:10:36 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

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

2026/10/8 21:13:17 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

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

2026/10/8 15:26:17 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

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

2026/10/7 13:34:55 阅读更多 →