记一次高性能 I/O 调试:Agent 给出满分优化,却说错了底层原理

在线体验各类最新模型,更有模型 免费Token 额度领取!
立即体验
简介: 系统真正的瓶颈不是 I/O,而是CPU 在扫内存时的地址翻译成本

本文经 叉鸽 授权,由七牛开发者账号翻译。叉鸽 也是七牛开发者 Router 内容计划的第 6 位作者。

Router 内容计划是由七牛开发者发起的 AI Coding 实践分享计划。我们希望成为连接开发者与开发者的“路由器”:持续收集、整理并分享一线开发者在 AI Coding 中的真实经验,包括工具选择、工作流改造、踩坑复盘和效率实践,让更多人的实践被看见,也让更多开发者可以从中获得参考。

作者叉鸽,活跃在开源社区的程序员,Foyer 项目作者。关注开源与高性能基础设施开发。喜欢看看电影喝喝啤酒,希望能为开源社区做更多贡献。

foyer 是一个用 Rust 编写的高效、用户友好的 Hybrid Cache 库,它将内存缓存和磁盘缓存无缝集成,旨在提供高并发、低延迟的数据存储与读取能力。GitHub 地址:github.com/foyer-rs/foyer

任务失败得很成功:把网卡和磁盘带宽跑满

AI 时代来得比我们大多数人预想得更快。Agentic coding 彻底改变了我的日常工作方式。老实说,我已经有一段时间没有在工作里亲手写过一行代码了。是的,这是真的,一行都没有!!虽然但是这并不影响“我的”代码在几百台 HPC 服务器组成的集群上以峰值性能运行。

当然,我们不写代码,甚至没有完整 review 每一行代码,并不代表我们就真在乱点一通,像猴子打字一样碰运气。需求还是要分析,设计得和 agent 一起细化,demo 要搭,模拟实验要跑,小规模测试结果要看,发现问题之后还要继续迭代,完整可靠的测试流程也要维护。诸如此类,该做的事一样都少不了。

图注:敲键盘的猴 🐒

不过,有了 AI 和 agentic coding,很多事情确实变快了。有时,代码产出的速度会快过我们理解它的速度,甚至快过 AI 自己理解它的速度。没错,你没看错。这篇文章就来自这样一个例子。

我给 agent 发了一个 prompt,让它帮我优化系统性能。AI 很快就把系统吞吐从大约一半提升到了接近跑满。问题是,它对“为什么能生效”的解释完全错了。换句话说,这是一次非常典型的 task failed successfully。

图注:任务失败得很成功

这篇文章不讨论 AI 为什么会“失败得很成功”。它主要记录这次系统性能优化背后的分析和调试过程。

用 1 张网卡和 8 块盘优化一个 Demo

为了把注意力放在性能优化上,我们先把复杂业务抽象成一个简单模型:

一个单线程向 8 块 NVMe 盘发起 1 MiB 的随机 Direct I/O 读请求,然后通过 RDMA WRITE 操作把数据发送到远端主机。现在的目标很直接:把网卡带宽跑满。

具体来说,每块 NVMe 硬盘最高可以提供 7 GiB/s 的读取吞吐,网卡提供 400 Gb/s 的网络带宽。所有相关设备都连接在同一个 NUMA 节点上。worker 线程被固定绑定到一个 CPU 核心上,而且这个核心不是 CPU0。主机的 IOMMU 运行在 passthrough 模式,这次涉及的 I/O 设备都没有经过 IOMMU 做地址转换。

具体实现上,我(其实是我的 AI agent)搭了一个很简单的事件循环:client 向 server 发送读请求;server 轮询 RDMA CQ,接收传入的请求,然后通过 io_uring 提交读操作,再轮询对应的 CQE,最后通过 RDMA WRITE 把数据发回去。

这个 demo 的设计很简单,也基本排除了大部分干扰因素。除了我们要跑满的网卡,其他组件都有足够余量:网卡的理论最大吞吐是 46.6 GiB/s;每块盘的平均读取吞吐低于 6 GiB/s;总 IOPS 保持在 50,000 以下;CPU 也还有充足空间。

环境准备好了,接下来看看测试结果。

结果有点出乎意料。系统在 I/O depth 只有 16 时就已经撞上瓶颈,总吞吐只达到网卡带宽的大约一半。同时,CPU 利用率已经到了 100%。

这里肯定有什么地方不对劲。于是,我在 I/O depth 为 16 的情况下用 perf 做了 profiling。下面是火焰图。

图注:Simple Demo 火焰图,iodepth=16

从火焰图可以看到,大部分 CPU 时间都花在了 io_submit_sqes 上,它占到了总 CPU 开销的 81.62%。因为这个 demo 使用的是 Direct I/O,所以每次提交 I/O 时,内核都要根据用户态 buffer 构造一份给块设备使用的 DMA 元数据。这条路径里最耗时的部分主要有:

  • __bio_iov_iter_get_pages:把 iov 转成 bio pages。

    • pin_user_pages_fast:把一段用户空间虚拟地址转换成一组 struct page 指针,并把这些页面 pin 住。这样设备执行 DMA 时,这些页面就不会被回收、迁移或换出。
  • bio_set_pages_dirty:把 buffer pages 标记为 dirty。使用 Direct I/O 时,NVMe 设备会通过 DMA 直接把数据写进用户空间 buffer 背后的页面里。之后,这些页面需要被标记为 dirty,避免 VM 把它们当成 clean pages 处理。

  • folio_*:更新和 folio 相关的 VM 状态,包括引用计数、dirty 状态、mapping、locking,以及和回收相关的状态。在 Linux VM 里,folio 是一组物理连续页面的统一抽象。

简单来说,io_submit_sqes 那个很宽的栈帧,代表的是为 Direct I/O DMA 准备用户内存时,一路累积下来的成本。每个 SQE 里只有一个用户空间指针和长度。内核必须遍历页表,找到并 pin 住背后的 struct page,构造 bio_vec 条目,更新 folio 状态,最后提交生成的 bio

这些工作大多是按内存页来计费的。一个由 4 KiB 页支撑的 1 MiB 读请求,大约会涉及 256 个页。于是,一次逻辑读请求就会变成几百次页表查找、page pin、folio 更新和 bio-vector 操作。每秒 20,000 到 50,000 次读取时,系统每秒要通过 GUP,也就是 Get User Pages,处理大约 500 万到 1300 万个页。

如果这段虚拟地址背后的物理内存碎片很多,还可能带来同等规模的 folio 元数据更新、原子 refcount / pincount 更新,以及潜在的跨核心 cache line 争用。

所以,如果能避免每次 I/O 都重新处理一遍用户空间 buffer,性能应该就能上去。幸运的是,liburing 正好提供了这样的办法。io_uring_register_buffers(3) 允许我们提前注册 I/O buffer,把这部分元数据准备工作从每次 I/O 的路径里挪出去。

具体来说,io_uring_register_buffers(3) 会提前完成下面这些工作:

  • 提前校验 iovecs,检查地址范围、长度、对齐方式和数量限制。

  • 对这些 buffer 执行 GUP,把用户空间虚拟地址转换成对应的 struct pages / folios,并在注册有效期内 pin 住这些页面。

  • 构造并保留内核侧的 buffer 元数据,为每个注册的 buffer 建好 io_mapped_ubuf

这些正好就是我们刚才在火焰图里看到的主要开销。现在我们来试试看效果:

在这个 demo 中,我们引入了一块 64 MiB 的 read arena,并把它切成一个个 1 MiB 的 slot,刚好和 I/O size 对齐。启动时,我们通过 io_uring_register_buffers(3),把这块包含 64 个 slot 的 read arena 注册成 64 个 io_uring 固定缓冲区,每个 slot 对应一个 iovec

每次读取时,我们把 opcode 从 opcode::Read 换成 opcode::ReadFixed,并把 buf_index 设置成对应的 slot。这样一来,I/O 路径就可以直接使用注册好的 buffers。

下面是测试结果:

随着 I/O depth 增加,吞吐继续上升。在 I/O depth 为 64 时,它已经接近跑满网卡带宽。

和 baseline 相比,在较低的 I/O depth 下,两者吞吐差不多,因为这时 CPU 还没有成为瓶颈。到了 I/O depth 16,baseline 已经开始明显感受到 CPU 压力;再往后,每次 I/O 都要处理 buffer,这部分开销就彻底被 CPU 卡住了。

READ_FIXED 去掉了这个瓶颈,让吞吐可以继续往上扩展,直到把网卡带宽跑满。

火焰图也能佐证这一点。

图注:READ_FIXED 的 Simple Demo 火焰图,iodepth=16

扩展到更大的部署规模

Simple Demo 这边处理完之后,我们可以继续看一个更大规模的 demo。这个版本会更接近真实部署环境。

在这个大规模 demo 里,client 是一台单节点机器,上面配了 8 张 400 Gb/s 的 NIC。server 端由 4 台节点组成。每台 server 有 2 个 NUMA 节点;每个 NUMA 节点上有 1 张 400 Gb/s NIC,以及 8 块和前面 demo 相同的 NVMe 盘。

I/O size 也从 1 MiB 增加到了 1,028 KiB,因为还需要额外 4 KiB 来存放元数据。

事件循环和前面的版本差不多。不过,为了更接近真实负载,server 在每次读完之后,会先校验这次读取数据的 CRC,再通过 RDMA WRITE 发回去。CRC 计算用的是 crc-fast 这个 crate,里面包含了用 AVX-512 VPCLMULQDQ 指令优化过的实现。单核上,它大约可以提供 50 GiB/s 的 checksum 吞吐。

单看 CRC 计算,这个吞吐刚好够应付当前负载。但一个 CPU 核还要跑事件循环,还要处理其他应用逻辑,所以每个 NUMA 节点只放一个 worker 线程就不太够了。于是这里改成:每个 NUMA 节点由多个 worker 线程共同服务,这些 worker 线程共享同一个 index 和本地 8 块 NVMe 盘。index 本身也做了分片,避免全局 index 锁变成性能瓶颈。

每个 worker 线程都会和 client 节点上的每一张 NIC 建立连接。每条连接都有一个独立的 QP;而同一个 worker 线程拥有的所有 QP,会共享一个 CQ,用来处理 completion。

为了让后面的讨论更清楚,我会用下面几个词描述 server 端不同层级的分片:

现在,我们对这个大规模 demo 的结构已经比较清楚了,至少希望如此。接下来给它上压力!

下面是测试结果。这里的 T 代表每个 shard 的 worker 线程数,所有吞吐数字单位都是 GiB/s。

理论上,系统应该能在所有 8 张网卡上达到 372.5 GiB/s 的总吞吐。但实际结果只有大约一半。

新的瓶颈来了!

接下来,我们一步步看火焰图,找出瓶颈在哪里。

排除 iou-wrk 的影响

为了定位瓶颈,我们先看新的火焰图。它来自一次 T=8、I/O depth 为 64 的运行。

提示:完整火焰图太大,无法直接嵌入这里。可以下载 SVG 后在浏览器里打开,方便看细节。

[图:Large Demo Flamegraph,T=8,iodepth=64]

虽然多 shard 的火焰图看起来比较复杂,但它其实很清楚地分成了两块:左边是 16 个 iou-wrk 线程,右边是 16 个 worker 线程。

前面给 Simple Demo 抓火焰图时,系统里只有一个 worker 线程,所以我们只 profile 了那个线程,没有把 iou-wrk 线程算进去。再加上 Simple Demo 当时已经能把 NIC 跑满,这也让我们很容易忽略 iou-wrk 可能带来的影响。

这个瓶颈会不会是 iou-wrk 的开销造成的?要回答这个问题,先看一下 iou-wrk 线程是从哪里来的。

iou-wrk 是 io_uring 使用的内核 worker 线程。当提交 I/O 的线程没办法立刻完成一个请求时,io_uring 就会把这个请求交给 iou-wrk,让它沿着内核提交路径,或者可能阻塞的路径,继续异步执行。

那为什么我们的读请求会被 offload 到 iou-wrk 呢?

大规模 demo 沿用了 Simple Demo 里的 read arena 设计:buffer 会提前注册到 io_uring,读取时使用 READ_FIXED。这样可以避开每次 I/O 都做页表遍历和 page pinning 的成本,但底层物理内存依然是由分散的 4 KiB 页支撑的。

在构造 bio 和 request 时,如果支撑一个 1,028 KiB buffer 的 257 个 4 KiB 页,对应的 PFN 并不连续,它们就没法合并成更大的物理连续区间。于是,从 block layer 和 DMA engine 的视角看,这次 I/O 大概就会表现为 257 个 scatter-gather segments。

但硬件和系统都有各自的限制,没办法把这 257 个 segment 全部塞进同一个 bio 里。下面这些参数,都可能导致一个 bio 被拆分:

在 server 上,这些参数配置如下:

> dev=nvme0n1
> for f in \
  max_segments \
  max_segment_size \
  max_sectors_kb \
  max_hw_sectors_kb \
  nr_requests
do
  printf "%-24s " "$f"
  cat "/sys/block/$dev/queue/$f"
done

max_segments             128
max_segment_size         4294967295
max_sectors_kb           1280
max_hw_sectors_kb        4096
nr_requests              1023

因为 257 除以 128 还会多出 1,所以每个 1,028 KiB 请求会被拆成 3 个 bio:前两个 bio 各包含 128 个 segment,也就是 512 KiB;最后一个 bio 只包含 1 个 4 KiB segment。算下来,平均 bio size 就是 342.67 KiB。

这一点也可以通过 iostat 里的 rareq-sz 指标确认:

> iostat -x -d /dev/nvme0n1
Device  ... rareq-sz ...
nvme0n1 ... 342.65 ...

所以,一个 1,028 KiB 请求的触发链路大致是这样:

1,028 KiB buffer,没有使用 hugepage
  → 257 个物理 4 KiB segment
  → 超过 max_segments = 128
  → 进入 multi-bio / split 路径
  → io_uring 先用 NOWAIT 提交
  → block Direct I/O 路径发现 iterator 里还有数据要处理,无法继续 inline 执行
  → 返回 -EAGAIN
  → io_uring 调用 io_queue_async / io_queue_iowq
  → iou-wrk 接手

到这里,我们已经知道是什么触发了 iou-wrk。接下来的问题是:iou-wrk 本身到底是不是那个让吞吐继续上不去的瓶颈?

有点遗憾,答案是 NO。几个额外实验可以把它排除掉。在运行大规模 demo 的时候,我还单独做了一组关闭 CRC 的实验。结果如下,单位是 GiB/s。

结果可以看到,即使 bio split 和 iou-wrk 仍然存在,关闭 CRC 之后,性能还是有了明显提升。Simple Demo 也指向同一个结论:它完全没有把 iou-wrk 的开销算进去,却能很轻松地跑满了 NIC。

还有几个额外观察,也支持这个判断。

我追踪了从 io_uring_queue_async_workio_wq_submit_work 的交接过程,发现排队延迟只有几微秒级别:

把 Little’s Law 应用到 io-wq 队列上:

Lq = λ × Wq

算下来,平均队列深度低于 1。换句话说,平均来看,io-wq 队列里甚至连一个等待中的 disk read 都不到。

这是一个很有力的反证:如果 iou-wrk 的 backlog 真的是那堵吞吐墙,队列不可能一直这么浅。

worker pool 这边也不是线程不够。系统在饱和状态下确实会创建很多临时的 iou-wrk 线程,但真正处于 runnable 状态的几乎没有:

所以,这也不是 worker pool 被耗尽的问题。磁盘队列同样没有跑满:每块盘的 aqu-sz 大约是 3,而 nr_requests 是 1023。

最后,为了单独看 split 操作本身的影响,我们又做了一组对照实验:只降低 block queue 的 max_sectors_kb

更低的 rareq-sz 说明,请求确实被拆得更细了,从 342.67 KiB 降到了 205.60 KiB。也就是说,这个对照实验真的把 split 数量从每个 GET 3 个 request 增加到了 5 个 request。但吞吐没有变化:

这就排除了几个可能性:request splitting 本身、每次 split 带来的 CPU 开销,以及 async 和 inline 路径之间的切换,都不足以解释这段吞吐差距。

它们确实都会产生影响,但单独看,谁都不是那堵真正的墙。

排除 fget 的影响

在 Simple Demo 和大规模 demo 的 per-shard 火焰图里,我们还发现 io_uring_enter 里有另一块主要开销,其中大部分来自 fget。这里可以拿大规模 demo 某次运行里的 shard 48 举个例子。

图注:Large Demo 火焰图,shard=48

fget 可能来自两个地方:一是在 disk SQE 路径上查找目标文件描述符,也就是每次真实 disk I/O 都要查一次;二是在每次调用 io_uring_enter 时,查找 ring 文件描述符本身。那 fget 会不会就是性能瓶颈的来源?

READ_FIXED 类似,io_uring 也提供了机制,可以把这两类开销都消掉:registered files 可以去掉 disk-I/O 路径上的 fd lookup;registered ring fd 则可以去掉每次 io_uring_enter 调用时对 ring fd 本身的查找。两者合起来,就能消掉这两类 fget

图注:Large Demo 火焰图,shard=48,regfiles=on,regring=on

从火焰图可以确认,fget 开销现在几乎完全消失了。然而,瓶颈依然还在。下面的吞吐数字单位是 GiB/s:

这说明,fget 并不是性能瓶颈的来源。火焰图里还有一个现象:虽然 fget 已经消失了,但 io_uring_enter 的开销还在。为什么?

剩下的这部分开销,来自我们的 busy-polling loop:当没有 I/O 完成,而 CPU 也暂时没别的事情可做时,io_uring 的 poll 路径就会一直 spin。

这也从侧面说明,当前瓶颈并不是被 CPU 算力卡住的。

排除 CRC 计算的影响

虽然上一个章节的实验足够说明瓶颈并没有卡在 CPU 算力上,但为了稳妥起见,我们还是继续排除 CRC 计算这个可能的竞争来源。毕竟前面的实验里,关掉 CRC 之后,性能确实突破了那堵瓶颈。

这一次,我们用三种配置更仔细地验证这个假设:

  1. 开启 CRC

  2. 关闭 CRC

  3. 关闭 CRC,但每次读完之后,以 64 B 的步长 touch 一遍 read buffer

这里的 touch=on 指的是一次 cache line 粒度的扫描:每次读完后,worker 会在整个 1,028 KiB buffer 上,每隔 64 B 做一次 load,但不做 CRC 计算。

有意思的事情出现了:完全关闭 CRC 时,性能确实突破了瓶颈。但如果只是关闭 CRC 计算,同时在 read buffer 上每隔 64 B 做一次 load,性能又撞回了同一个瓶颈。

这已经足够说明,CRC 计算本身并不是瓶颈来源。更关键的是,我们似乎找到了那个能复现瓶颈的关键操作。

真正的瓶颈:TLB Miss

在上面章节中,我们观察到了一个有意思的现象:只要读完之后,以 64 B 的步长 touch 一遍 buffer,即使完全不做任何计算,系统还是会撞上瓶颈。

再回头看 Simple Demo 和「排除 iou-wrk 的影响」的实验,我们已经不止一次遇到 4 KiB 页带来的问题。那么,这里的瓶颈会不会其实没有卡在计算上,也没有卡在 I/O 上,而是卡在 4 KiB 页的地址转换停顿上?

为了验证这个假设,我们把原来由 4 KiB 页支撑的 64 MiB read arena,换成由 1 GiB hugepage 支撑的 read arena,然后对比测试结果。下面的吞吐数字单位是 GiB/s。

结果显示,开启 hugepage 之后,即使 CRC 仍然打开,在 T=8 的配置下,系统也已经几乎可以把 NIC 跑满。

这足以确认,hugepage 确实能有效解决这个瓶颈。同时也说明,「扩展到更大的部署规模」里被我们排除掉的那三个因素,都不是根因。

不过,瓶颈虽然已经被消掉了,但我们还不能就此断定它一定来自地址转换。还需要更硬的证据。于是,我重新跑了一次实验,并用 perf stat 统计 CPU 的 L1D miss 和 dTLB miss。

结果已经很清楚了。使用 4 KiB 页时,无论是开启 CRC 的运行,还是关闭 CRC、但以 64 B 步长扫描 read buffer 的运行,平均每个 GET 都会产生 80 多次 dTLB miss。

一旦开启 hugepage,dTLB miss 数量就会降到和完全关闭 CRC 时差不多的水平。这给出了直接证据:dTLB miss 才是吞吐瓶颈的根因。

相比之下,在所有测试配置里,L1D miss 数量变高,并没有和吞吐下降形成对应关系。这也排除了 L1D miss 作为瓶颈的可能。

为什么 TLB miss 会带来这么大的性能下降?

TLB 可以理解成 CPU 的地址转换缓存:它保存最近用过的虚拟页到物理页的映射关系。CPU 在从内存里 load 数据,或者向内存 store 数据之前,得先知道这个虚拟地址背后对应的是哪个物理页。TLB hit 很快;一旦 miss,CPU 就得去走页表。

TLB miss 之所以重要,是因为它会在真正访问数据之前让执行停下来。对于 4 KiB 页里的一个地址,转换过程可能需要多级页表遍历,比如经过 PGD、PUD、PMD 和 PTE 这些条目。而这些页表项本身也要从 cache 或内存里取出来,过程中还可能继续引发 cache miss。

对于一条连续扫描 1,028 KiB value 的路径来说,CPU 会一边读取 cache line,一边不断跨过 4 KiB 页边界。一个 1,028 KiB value 会横跨 257 个 4 KiB 页。只要当前活跃的地址转换装不进 dTLB,CPU 就会反复执行 page walk,吞吐也就被直接拉低了。

hugepage 有用,是因为它把地址转换的粒度变大了。使用 4 KiB 页时,一个 1,028 KiB value 需要 257 次页转换;使用 1 GiB hugepage 时,同样这段 1,028 KiB 区域,通常只需要一个 large-page translation 就能覆盖。这样一来,少量 TLB entry 就能覆盖更多数据,dTLB miss 和 4 KiB page-walk reload 也会明显减少。

到这里,整条线终于串起来了。READ_FIXED 去掉了内核侧反复发现并 pin 用户页的成本,但它没有改变应用后续扫描数据时 CPU 需要付出的代价。使用 4 KiB 页时,每个 1,028 KiB value 仍然会逼着 CPU 跨过几百次页转换;CRC 只是把这种扫描显性化了,touch=on 则在完全不做 checksum 计算的情况下,复现了同样的压力。

hugepage 补上了缺的那一环,让数据路径对地址转换也更友好。这个瓶颈没有落在磁盘、NIC、io_uring offload、fd lookup 或 CRC 算术计算上。真正拖慢系统的,是这些组件共同经过的那段内存地址转换成本。

X. “A Planet Upside Down”

事实上,最早用 AI 调这个性能瓶颈时,它一开始就建议我用 hugepage 来优化 read arena,而且这确实足够把 NIC 跑满。

但它没有找到真正的底层原因:TLB miss。相反,它一直在围绕前面已经发现的那些问题打转。

对于有 HPC 和存储性能优化经验的工程师来说,这类问题也许凭经验就能闻出一点味道。但这次调试过程中留下的线索可能太稀疏,AI 没有足够证据把那条推理路径完整还原出来。它给出了答案,却没有给出通向答案的完整推理链。

我想,这大概也是这篇博客值得写下来的原因之一。

说实话,当 AI 完成最初那次性能优化时,我的工作本来就该结束了。讽刺的是,弄清楚这次优化为什么能生效,最后花掉的时间远远超过了原任务本身。随着 AI 模型能力越来越强,它们即使没有真正理解底层原理,也能搭出相当不错的系统。

但把这些原理追清楚,一直是我作为程序员的一点小执念。在 AI 的浪潮里,这也许也是我避免自己滑向无意义感的一种方式。

最后,我想分享几句最近常听的一首歌里的歌词。敬这个时代里,仍然努力让自己脚踩实地的人。

图:A Planet Upside Down - Pearl & The Oysters

原文链接:blog.mrcroxx.com/posts/task-failed-successfully-saturating-nic-and-disk-bandwidth/

相关文章
|
6天前
|
人工智能 JSON 自然语言处理
让教学更智慧:用阿里云百炼工作流,自动生成中小学教材内容#小有可为#有温度的AI
通过可视化工作流编排,将大模型推理能力转化为标准化的教学内容生成引擎。教师只需输入教材标题和适用学段,即可自动获得结构完整、符合课程标准的章节内容,大幅降低备课门槛,助力教育资源均衡化。
463 123
|
8天前
|
人工智能 定位技术 SEO
我学 GEO 第 15 天:终于知道AI GEO该如何做?
我是暴走的莉莉酱,边旅行边研究AI GEO的数字游民。专注普通人如何提升“AI可见度”——让AI在回答用户问题时准确识别、理解并推荐你。不讲玄学,只做可测、可调、可持续的GEO实践。
444 127
|
10天前
|
机器学习/深度学习 人工智能 调度
🐴 HappyHorse 1.1 现已上线阿里云百炼!快来查收模型使用指南,现在调用享 6 折~
HappyHorse 1.1 是新一代视频生成大模型,全面升级动态表现力、角色一致性、指令遵循、视觉质感与音画协同能力。支持I2V/T2V/R2V三类生成,适配短剧、电商广告、品牌营销等场景,提供高质、流畅、可控的AI视频生产力。
758 5
🐴 HappyHorse 1.1 现已上线阿里云百炼!快来查收模型使用指南,现在调用享 6 折~
|
2天前
|
消息中间件 存储 Kafka
Kafka 原生消息入湖能力上线!一键打通实时流与数据湖
阿里云消息队列 Kafka 版正式上线原生消息入湖能力。
216 121
|
2天前
|
人工智能 安全 Cloud Native
Higress 新发布:AI Gateway 能力增强,Gateway API 及其推理扩展持续打磨
增强 AI 网关能力,持续打磨 Gateway API 及其推理扩展。
263 122
|
8天前
|
缓存 人工智能 运维
阿里云618百炼大模型Qwen3.7-Max功能、免费试用、订阅计费、配置接入详解
Qwen3.7-MAX是阿里云百炼平台推出的通义千问3.7系列旗舰大语言模型,专为智能体时代复杂任务打造,依托阿里云全域算力与自研技术,在逻辑推理、长文本处理、代码工程、长周期自主执行等领域达到行业顶尖水平。2026年618期间,该模型推出多重免费试用权益、按量计费5折、订阅套餐优惠等专属福利,覆盖个人开发者、团队与企业全场景需求,以下从核心功能、免费试用、订阅计费、配置接入四方面展开详细解析。
453 123
|
6天前
|
人工智能 自然语言处理 API
阿里云Token Plan团队版解析:功能、三档套餐与省钱订阅指南
阿里云百炼平台推出的Token Plan团队版,是面向企业与团队的AI大模型订阅服务,以Credits为统一计量单位,整合文本与图像生成模型,提供团队管理、数据安全、多工具兼容等核心能力,解决团队零散订阅AI服务的管理混乱、成本失控、数据安全等痛点。本文将从核心定位、套餐详情、计费规则、团队管理、工具兼容、便宜订阅技巧等方面,全面解析Token Plan团队版,帮助企业与团队高效、低成本地使用AI服务。
332 108
|
15天前
|
Linux 程序员 数据格式
【2026最新】Notepad++下载、安装和使用一篇搞定(附中文版安装包)
Notepad++ 是一款免费开源、轻量高效的 Windows 文本编辑器,支持 C/Python/HTML 等 80+ 语言语法高亮、代码折叠、正则替换、编码转换及插件扩展,专为程序员与文本处理用户打造,完美替代系统记事本。(239字)