Flink SQL实时计算性能优化实战:状态管理、数据倾斜与资源配置

1. 从一条慢查询说起:为什么Flink SQL优化值得单独拎出来讲

第一次在实时数仓项目里用Flink SQL,很多人都会经历一个相似的阶段:SQL写得飞快,上线之后任务跑得也飞快——不过是反方向的快,延迟高、反压严重、Checkpoint频繁超时。我印象很深的一次,一个看似简单的双流JOIN,在数据量上来之后直接把整个作业拖垮,TaskManager的CPU打满,背压指标一路飘红。当时排查了大半天,最后发现问题出在状态后端配置和JOIN的TTL没设,状态无限膨胀,内存被吃干净了。

这件事让我意识到,Flink SQL虽然把流处理的开发门槛降得很低,但"能跑"和"跑得好"之间隔着一整套优化方法论。SQL语法帮你屏蔽了DataStream API的复杂度,可它并没有帮你屏蔽状态管理、算子链、并行度、数据倾斜这些底层问题。恰恰相反,因为SQL把细节藏起来了,出问题的时候反而更难定位。

这篇内容面向的是已经在用或者准备用Flink SQL做实时计算的开发同学,尤其是那些任务已经上线、但遇到了性能瓶颈的团队。我会围绕实时JOIN、状态管理、数据倾斜、资源配置、SQL写法这几个最容易出问题的方向,把优化思路和实操细节讲透。不会只告诉你"要设TTL",而是会讲清楚为什么状态会膨胀、TTL设多少合适、设了之后有什么副作用。这些都是在实际项目里反复踩坑之后总结出来的东西,希望能帮你少走弯路。

2. 双流JOIN的状态膨胀:最容易被忽视的性能杀手

2.1 状态为什么会无限增长

Flink SQL里的双流JOIN,底层实现是把它拆成两个流分别存到状态里,一条流的数据来了就去另一条流的状态里查匹配。这个设计本身没问题,问题在于:默认情况下,这些状态永远不会被清理。

举个例子,你有一个订单流和一个支付流做JOIN,订单流每天新增500万条,支付流每天新增480万条。如果没设状态TTL,那么订单流的状态里会一直累积所有历史订单,支付流的状态里也会累积所有历史支付记录。跑一个月下来,状态大小可能就是几十GB甚至上百GB。这带来的连锁反应是:Checkpoint越来越大、越来越慢,恢复时间越来越长,最终可能导致Checkpoint超时失败,作业直接挂掉。

注意:状态膨胀不是线性增长的,它跟数据的基数(key的数量)和更新频率都有关系。key越多、更新越频繁,状态增长越快。

2.2 状态TTL的正确设置方式

Flink SQL提供了table.exec.state.ttl参数来控制状态的存活时间。这个参数的单位是毫秒,默认值是0,表示状态永不过期。

-- 在SQL中设置状态TTL为24小时 SET 'table.exec.state.ttl' = '86400000'; -- 或者在Flink配置文件中全局设置 -- table.exec.state.ttl: 86400000

但这里有个关键问题:TTL设多少合适?设太短,可能导致本该匹配上的数据因为状态过期而丢失;设太长,状态还是很大。我的经验是,TTL应该略大于业务上两个流之间最大的合理延迟。

比如订单和支付,正常情况下支付会在订单创建后30分钟内完成,极端情况可能延迟几小时。那TTL设24小时是比较稳妥的,既能覆盖绝大多数场景,又不会让状态无限增长。如果业务上允许少量数据丢失(比如对账场景可以离线补),TTL可以设得更短,比如2小时。

还有一个容易踩的坑:TTL是针对每个key独立计算的。也就是说,每个key的状态从最后一次更新开始计时,超过TTL没有更新才会被清理。所以如果你的数据里有些key是"热点key",频繁更新,那这些key的状态实际上永远不会过期。这一点在设计方案时要有预期。

2.3 用Interval JOIN替代Regular JOIN

如果你的JOIN条件里包含时间范围的约束,比如"订单创建后1小时内的支付记录",那强烈建议用Interval JOIN而不是Regular JOIN。

-- Regular JOIN:状态无限保留 SELECT o.order_id, o.amount, p.pay_time FROM orders o JOIN payments p ON o.order_id = p.order_id; -- Interval JOIN:只保留时间窗口内的状态 SELECT o.order_id, o.amount, p.pay_time FROM orders o JOIN payments p ON o.order_id = p.order_id AND p.pay_time BETWEEN o.create_time AND o.create_time + INTERVAL '1' HOUR;

Interval JOIN的好处是,Flink知道只需要保留时间窗口内的状态,超出窗口的数据可以安全清理。这比手动设TTL更精确,也更高效。实测下来,同样的数据量,Interval JOIN的状态大小可能只有Regular JOIN的十分之一甚至更少。

但Interval JOIN也有局限:它要求JOIN条件里必须有一个时间字段的范围比较,而且两个流都需要有事件时间或处理时间属性。如果你的JOIN条件不满足这个要求,那就只能回到Regular JOIN加TTL的方案。

2.4 状态后端的选型对JOIN性能的影响

状态后端的选择直接影响JOIN的性能。Flink目前主流的状态后端是HashMapStateBackend和EmbeddedRocksDBStateBackend。

状态后端适用场景优点缺点
HashMapStateBackend状态较小(GB级别以内)读写快,纯内存操作状态受内存限制,大了会OOM
EmbeddedRocksDBStateBackend状态较大(TB级别)支持超大状态,可溢写到磁盘读写有序列化开销,比内存慢

对于双流JOIN这种状态容易膨胀的场景,如果状态确实很大,RocksDB是更稳妥的选择。但要注意,RocksDB的性能调优本身也是个话题,比如state.backend.rocksdb.block.cache-size、state.backend.rocksdb.writebuffer.size这些参数都需要根据实际情况调整。我一般会先把block cache设大一些(比如256MB),writebuffer设到64MB,然后再根据监控指标微调。

3. 数据倾斜:并行度再高也救不了热点key

3.1 怎么判断是不是数据倾斜

数据倾斜的典型表现是:作业整体并行度不低,但个别SubTask的吞吐量远高于其他SubTask,导致这些SubTask成为瓶颈,反压一路向上传导。在Flink Web UI里,你可以通过查看每个SubTask的Records Sent/Received和CPU使用率来判断。如果发现某个SubTask的处理量是其他SubTask的几倍甚至几十倍,那基本可以确定是数据倾斜。

另一个判断方法是看Checkpoint的耗时。如果Checkpoint的各个SubTask完成时间差异很大,慢的那些往往就是数据量大的SubTask。

3.2 热点key的常见来源

数据倾斜的根源是key的分布不均匀。在实时场景里,常见的热点key来源有几种:

  • 业务上的大客户:比如某个大商户的订单量占了总量的30%,那按商户ID做key的时候,这个商户就是一个巨大的热点。
  • null值或默认值:如果某个字段大量为null,而你又用这个字段做key,那所有null值都会落到同一个SubTask上。
  • 时间戳做key:用时间戳做key的时候,同一秒的数据会全部落到一个SubTask上,造成瞬时热点。

3.3 两阶段聚合:打散热点key的经典方案

两阶段聚合是解决数据倾斜最常用的方案。核心思路是:先给key加一个随机前缀,做一次局部聚合,然后把前缀去掉,再做一次全局聚合。

-- 第一阶段:加随机前缀,局部聚合 SELECT key, SUM(cnt) as partial_cnt FROM ( SELECT CONCAT(key, '_', CAST(RAND() * 10 AS INT)) as key, COUNT(*) as cnt FROM source_table GROUP BY CONCAT(key, '_', CAST(RAND() * 10 AS INT)) ) GROUP BY key; -- 第二阶段:去掉前缀,全局聚合 SELECT SUBSTRING(key, 1, LENGTH(key) - 2) as original_key, SUM(partial_cnt) as total_cnt FROM partial_result GROUP BY SUBSTRING(key, 1, LENGTH(key) - 2);

这个方案的关键在于随机前缀的数量。前缀太少,打散效果不够;前缀太多,会增加第二阶段聚合的压力。我一般会从10开始试,根据SubTask的负载情况调整。如果倾斜特别严重,可以加到100甚至更多。

提示:两阶段聚合会增加一次数据shuffle,所以它会带来额外的网络开销。如果倾斜不严重,可能不值得这么做。先用监控数据判断倾斜程度,再决定是否采用。

3.4 用LocalGlobal优化聚合

Flink SQL有一个内置的优化策略叫LocalGlobal,它会在数据shuffle之前先做一次本地聚合,减少网络传输的数据量。这个优化默认是开启的,但在某些情况下可能需要手动确认。

-- 确认LocalGlobal优化是否开启 SET 'table.optimizer.agg-phase-strategy' = 'AUTO'; -- 或者强制开启 SET 'table.optimizer.agg-phase-strategy' = 'TWO_PHASE';

LocalGlobal对于聚合类的倾斜有很好的缓解作用,但它对JOIN类的倾斜帮助有限。JOIN的倾斜还是需要靠两阶段聚合或者key的重设计来解决。

3.5 从业务层面重新设计key

有时候,技术层面的优化到头了,就需要回到业务层面重新思考key的设计。比如,如果按商户ID做key导致倾斜,能不能改成按商户ID+订单ID的哈希做key?这样同一个商户的订单会被分散到多个SubTask上。代价是后续如果需要按商户维度做聚合,还得再做一次shuffle。

还有一种做法是给大客户的key单独加盐,让小客户走正常路径,大客户走特殊路径。这种方案实现起来复杂一些,但在极端倾斜的场景下效果最好。

4. 资源配置:并行度和内存不是越大越好

4.1 并行度的确定逻辑

并行度的设置是Flink SQL优化里最容易被拍脑袋决定的事情。很多人觉得并行度越高越好,实际上并行度太高会带来几个问题:一是每个SubTask处理的数据量太少,反而增加了调度和协调的开销;二是状态会被分散到更多的SubTask上,每个SubTask都要维护一份状态,总的状态开销反而可能增加。

并行度的合理值应该根据数据量和单个SubTask的处理能力来估算。一个经验公式是:

并行度 = 峰值QPS / 单个SubTask的处理能力

单个SubTask的处理能力跟算子的复杂度有关。简单的filter/map算子,单并行度每秒处理几万条没问题;复杂的JOIN或聚合,可能只有几千条。我一般会先设一个保守的并行度(比如Source的并行度跟Kafka分区数一致),然后根据反压情况逐步调整。

4.2 内存配置的坑

Flink的内存模型比较复杂,有Framework Heap、Task Heap、Managed Memory、Network Memory等多个部分。对于Flink SQL作业来说,最容易出问题的是Managed Memory和Network Memory。

Managed Memory主要用于RocksDB状态后端和批处理算子。如果状态很大,Managed Memory要相应调大。Network Memory用于数据shuffle的缓冲区,如果shuffle量大(比如有大量的JOIN或聚合),Network Memory不够会导致反压。

# flink-conf.yaml中的内存配置示例 taskmanager.memory.process.size: 4096m taskmanager.memory.managed.fraction: 0.4 taskmanager.memory.network.fraction: 0.2

taskmanager.memory.managed.fraction默认是0.4,如果状态很大可以调到0.5甚至0.6。taskmanager.memory.network.fraction默认是0.1,如果shuffle量大可以调到0.2。但要注意,这些内存是从总内存里分的,调大了一个部分,其他部分就会变小,需要权衡。

4.3 Checkpoint配置的优化

Checkpoint的频率和超时时间直接影响作业的稳定性。频率太高,会影响正常的数据处理;频率太低,故障恢复时需要重放的数据就多。

# Checkpoint配置 execution.checkpointing.interval: 3min execution.checkpointing.timeout: 10min execution.checkpointing.min-pause: 1min execution.checkpointing.max-concurrent-checkpoints: 1

execution.checkpointing.interval是Checkpoint的触发间隔,我一般设3到5分钟。execution.checkpointing.timeout是单次Checkpoint的超时时间,如果状态很大,这个值要设大一些,否则Checkpoint还没做完就超时了。execution.checkpointing.min-pause是两次Checkpoint之间的最小间隔,防止Checkpoint过于密集。

还有一个重要的配置是execution.checkpointing.tolerable-failed-checkpoints,它决定了连续多少次Checkpoint失败后作业才会失败。设一个合理的值(比如3到5次)可以避免因为偶发的Checkpoint失败导致作业重启。

5. SQL写法里的那些"隐形陷阱"

5.1 避免使用SELECT *

SELECT *在Flink SQL里看起来很方便,但它有两个问题:一是会读取所有字段,包括你不需要的,增加了IO和序列化的开销;二是当表结构变化时,SELECT *的结果会跟着变,可能导致下游处理出错。我一般建议明确列出需要的字段,既提升性能,又增加代码的稳定性。

5.2 维表JOIN的缓存策略

维表JOIN是实时数仓里的常见操作,比如订单流关联商品维表获取商品名称。维表JOIN的性能关键在于缓存策略。

-- 维表JOIN示例 SELECT o.order_id, o.product_id, p.product_name, o.amount FROM orders o JOIN products FOR SYSTEM_TIME AS OF o.proc_time AS p ON o.product_id = p.product_id;

Flink提供了几种维表缓存策略:

缓存策略说明适用场景
None不缓存,每条数据都查维表维表数据变化极频繁
LRU最近最少使用缓存维表数据量大,但热点集中
ALL全量缓存维表数据量小,变化不频繁

LRU缓存是最常用的,需要设置缓存大小和过期时间。缓存大小根据维表的数据量和内存情况来定,过期时间根据维表的更新频率来定。如果维表每天更新一次,过期时间可以设几小时;如果维表实时更新,过期时间要设短一些,比如几分钟。

5.3 窗口聚合的提前触发

窗口聚合默认是在窗口结束时才输出结果。如果窗口比较大(比如1小时),那结果要等1小时才能看到。对于需要近实时查看的场景,可以配置提前触发。

-- 配置窗口提前触发 SET 'table.exec.emit.early-fire.enabled' = 'true'; SET 'table.exec.emit.early-fire.delay' = '10s';

这样每10秒就会输出一次当前窗口的中间结果。但要注意,提前触发会产生大量的中间结果,下游需要能够处理这种重复数据。一般会配合table.exec.emit.late-fire.enabled一起使用,处理迟到数据。

5.4 去重场景的优化

实时去重是另一个常见场景,比如同一订单的重复消息只处理一次。Flink SQL里可以用ROW_NUMBER()来实现去重。

SELECT * FROM ( SELECT *, ROW_NUMBER() OVER (PARTITION BY order_id ORDER BY proc_time ASC) as rn FROM source_table ) WHERE rn = 1;

这个写法的性能关键在于状态的大小。如果order_id的基数很大,状态会很大。优化思路是配合TTL使用,只保留最近一段时间的去重状态。另外,如果去重的时间窗口是固定的(比如只去重最近1小时的数据),可以用Interval JOIN或者窗口来限定范围,减少状态。

6. 监控与调优:用数据说话而不是凭感觉

6.1 必看的几个监控指标

Flink Web UI提供了丰富的监控指标,但有几个是调优时必须关注的:

  • BackPressure:反压指标,如果某个算子显示HIGH,说明它是瓶颈。
  • Records Sent/Received:每个SubTask的吞吐量,用来判断数据倾斜。
  • Checkpoint Duration:Checkpoint耗时,如果持续增长,说明状态在膨胀。
  • State Size:状态大小,直接反映状态管理的效果。

除了Web UI,还可以通过Metrics Reporter把指标推到外部监控系统,做长期的趋势分析。我一般会用Prometheus+Grafana来搭建监控面板,把关键指标都展示出来,方便随时查看。

6.2 火焰图定位CPU热点

如果CPU使用率很高但吞吐量上不去,可以用火焰图来定位CPU热点。Flink支持通过REST API触发火焰图采样。

# 触发火焰图采样 curl -X POST http://jobmanager:8081/jobs/:jobid/flamegraph

火焰图会显示每个方法调用的CPU占用比例,帮助你找到最耗CPU的代码路径。常见的热点包括序列化/反序列化、正则表达式匹配、字符串操作等。找到热点之后,就可以针对性地优化,比如换更高效的序列化器、预编译正则表达式、减少不必要的字符串拼接。

6.3 迭代调优的方法论

调优不是一次性的工作,而是一个迭代的过程。我的做法是:

  1. 建立基线:在优化之前,先记录当前的吞吐量、延迟、状态大小、Checkpoint耗时等指标。
  2. 定位瓶颈:通过监控和火焰图找到最影响性能的环节。
  3. 实施优化:针对瓶颈采取优化措施,比如调整并行度、设置TTL、优化SQL写法。
  4. 验证效果:对比优化前后的指标,确认优化是否有效。
  5. 重复迭代:解决了一个瓶颈之后,可能会有新的瓶颈出现,继续下一轮优化。

这个过程中最重要的是每次只改一个变量,这样才能准确判断每个优化的效果。如果一次改了好几个地方,效果好了不知道是哪个起了作用,效果不好也不知道是哪个拖了后腿。

7. 一些踩坑之后的经验之谈

做Flink SQL优化这几年,踩过的坑确实不少,有几个经验我觉得值得单独拿出来说。

第一个是关于TTL的。我见过有团队为了保险起见,把TTL设得特别长,比如7天。结果状态还是很大,Checkpoint还是超时。后来发现,虽然TTL是7天,但数据里有很多key是持续更新的,这些key的状态永远不会过期。所以TTL不是万能的,关键还是要理解数据的更新模式。如果热点key持续更新,TTL帮不了你,得从key的设计或者业务逻辑上想办法。

第二个是关于并行度的。很多人觉得并行度设成跟Kafka分区数一样就行了,其实不一定。如果Kafka有100个分区,但数据量很小,设100个并行度就是浪费资源。反过来,如果数据量很大,100个并行度可能还不够。并行度应该根据实际的数据量和处理能力来定,而不是简单地跟Source的分区数对齐。

第三个是关于SQL可读性和性能的平衡。有些优化手段(比如两阶段聚合)会让SQL变得很复杂,可读性下降。我的建议是,如果倾斜不严重,优先保证SQL的可读性;如果倾斜严重到影响作业稳定性,那该复杂就复杂,但一定要写好注释,说明为什么要这么写。毕竟代码是给人看的,性能优化也要考虑维护成本。

第四个是关于测试的。Flink SQL的优化效果很难在开发环境完全验证,因为开发环境的数据量和生产环境差很多。我的做法是,在开发环境做功能验证,在生产环境做性能验证,但生产环境的优化要谨慎,最好先在预发布环境跑一段时间,确认稳定后再上生产。另外,优化上线后要密切监控,一旦发现异常,要能快速回滚。

最后说一个我觉得挺有用的技巧:用EXPLAIN来看执行计划。Flink SQL支持EXPLAIN语句,可以看到SQL被转换成了什么样的算子拓扑。通过执行计划,你可以看到哪些地方做了shuffle、哪些地方用了状态、算子的并行度是多少。这对于理解SQL的实际执行方式非常有帮助,也是定位性能问题的重要手段。

EXPLAIN SELECT o.order_id, p.pay_time FROM orders o JOIN payments p ON o.order_id = p.order_id;

执行计划会显示这个JOIN是用了Regular JOIN还是Interval JOIN、状态是否设置了TTL、并行度是多少。养成看执行计划的习惯,很多问题在写SQL的时候就能发现,不用等到上线之后才暴露。

相关新闻

从零上手Claude Code:终端AI编程助手的安装实战与避坑指南

从零上手Claude Code:终端AI编程助手的安装实战与避坑指南

前一阵子给自己定了个小目标:把 Claude Code 从零完整学一遍,边学边记,最后整理成这份 S01 学习记录。Claude Code 说白了就是一个跑在终端里的 AI 编程助手,它能在命令行里读你的项目代码、改文件、跑命令,甚至代替你…

2026/10/20 13:53:30 阅读更多 →
开源AI智能体OpenClaw实操指南:普通人也能轻松部署

开源AI智能体OpenClaw实操指南:普通人也能轻松部署

说真的,能让“普通人也值得拥有”这七个字同时出现在标题里的AI项目,最近只有一个——OpenClaw,也就是被大家在聊天群里喊成“龙虾”的那个开源AI智能体。这个外号没啥高深来头,项目形象是一只举着钳子、看起来不太好惹的红色小龙…

2026/10/20 13:52:16 阅读更多 →
自适应哈夫曼编码:流式数据压缩中的动态树与同步机制

自适应哈夫曼编码:流式数据压缩中的动态树与同步机制

简介:这是一份自适应哈夫曼编码的C完整实现,适合正在学习数据压缩算法、哈夫曼树与动态编码原理的开发者。与静态哈夫曼编码不同,自适应版本在编码过程中根据字符频率变化实时更新哈夫曼树,特别适合流式数据或字符分布动态变化的场…

2026/10/20 13:52:16 阅读更多 →

最新新闻

OSG项目GIF插件编译失败怎么办?giflib 4.1.6 64位静态库接入与避坑指南

OSG项目GIF插件编译失败怎么办?giflib 4.1.6 64位静态库接入与避坑指南

简介:面向需要在 OpenSceneGraph 3.2.1 中启用 GIF 插件编译的开发者,这份资源提供 giflib 4.1.6 的 64 位静态链接库及配套头文件,可解决 osg 的 Plugin gif 链接依赖问题,省去自行构建 giflib 的环节。压缩包共 3 个文件&#x…

2026/10/20 14:34:30 阅读更多 →
微电网两阶段鲁棒优化调度:CCG算法应对风光不确定性

微电网两阶段鲁棒优化调度:CCG算法应对风光不确定性

1. 微电网优化调度为什么要考虑不确定性 做园区级微电网调度的人应该都有过这种体会:今天光伏预测曲线明明很漂亮,上午十点突然飘来一片云,出力直接砍半;或者风电场那边预报微风,结果下午风速爬升,风机满发…

2026/10/20 14:34:30 阅读更多 →
AI气象数据融合实现流感提前两周预警的完整实践

AI气象数据融合实现流感提前两周预警的完整实践

流感预警这件事,难点从来不在“发现”,而在“提前”。我在复现某区域流感预警Demo系统时,核心目标只有一个:在流感监测曲线还没来得及明显抬头之前,用AI气象数据融合的方式提前两周给出区域风险判断。很多人问我&#…

2026/10/20 14:34:30 阅读更多 →
深入理解TensorFlow 2.x自动求导:GradientTape原理、实践与排坑指南

深入理解TensorFlow 2.x自动求导:GradientTape原理、实践与排坑指南

很多人从 TensorFlow 1.x 迁移过来,第一件事就是找tf.gradients,然后一脸懵:没了,取而代之的是一个叫tf.GradientTape的东西。更懵的是,新写的训练代码里看不到"计算图"这种概念,梯度就像变魔术一…

2026/10/20 14:34:30 阅读更多 →
用Qt+Windows API打造远程控制软件:架构、协议与实战

用Qt+Windows API打造远程控制软件:架构、协议与实战

简介:基于Qt框架实现的Windows远程控制软件资源,包含服务器端(被控端)与客户端(主控端)两部分,附完整源码与可直接运行的编译程序。服务器端以进程形式后台运行,客户端为图形界面程序…

2026/10/20 14:34:30 阅读更多 →
OpenCV 2.4.13 安装指北:源码编译、环境配置与五条血泪排错记录

OpenCV 2.4.13 安装指北:源码编译、环境配置与五条血泪排错记录

简介:面向计算机视觉与图像处理开发者,该zip压缩包提供的是OpenCV 2.4.13.3经典旧版安装资源,适合需要维护旧项目、复现历史算法或学习传统视觉知识的用户;相比高版本OpenCV,2.4.x在函数命名与调用方式上存在差异&…

2026/10/20 14:33:27 阅读更多 →

日新闻

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

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

2026/10/20 1:01:30 阅读更多 →
ESP32舵机控制指南:原理、多路驱动与避坑实战

ESP32舵机控制指南:原理、多路驱动与避坑实战

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

2026/10/20 1:01:30 阅读更多 →
位移法实现一阶低通滤波:单片机ADC采样降噪实战

位移法实现一阶低通滤波:单片机ADC采样降噪实战

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

2026/10/20 1:01:30 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/20 10:02:13 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/19 17:32:41 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/20 2:50:50 阅读更多 →

月新闻

我发现了一个新思路:用 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/20 10:02:08 阅读更多 →
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/20 9:50: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/20 9:50:45 阅读更多 →