新闻详情

新闻详情

首页 / 资讯中心 / 详情

Redis游标分页:Feed流无限滚动架构实战

发布时间:2026/10/2 19:15:09来源:尧图网络
Redis游标分页:Feed流无限滚动架构实战
做社交产品或者资讯App的人应该都遇到过 feed 流分页让人挠头的时刻。早年我用 MySQL 的 offset 翻页数据量大起来之后页数越深接口越慢最气人的是用户明明刷过了一页等新数据插入后再翻下一页又看到重复的内容。后来我一直在打磨一套基于 Redis 的方案直到用 Redis 游标分页把这个问题彻底理顺。这篇就把我从踩坑到落地的完整思路写下来包括为什么不用 offset、Redis 数据类型怎么选、游标怎么设计、推拉模式怎么取舍以及线上排障时那些 Redis 命令和参数背后的门道。1. 分页为什么是 Feed 流里的老大难1.1 Feed 流和普通列表的本质区别普通的分页列表比如后台的订单列表、用户管理列表数据在用户翻页期间几乎不会发生变化第一页第一条就是他看到的全部翻到第 50 页还是那批数据。这类场景用 SQL 的 OFFSEF 分页是没问题的LIMIT 20 OFFSET (页数-1)*20简单又粗暴性能也能接受。Feed 流不同。它的本质是“一个持续追加、按时间倒序排列的动态列表”。用户今天发了帖子明天又发了帖子服务器上每时每刻都在插入新内容。这个特性带来两个硬约束顺序敏感用户必须按时间倒序看到动态增量无限我们永远无法把整个列表一次给到客户端只能像挤牙膏一样一页一页给。麻烦就在这儿——你不可能用一版静态的页码去处理一份随时会变长的动态列表。我见过不少团队第一版都是直接“MySQL ORDER BY create_time DESC LIMIT 20 OFFSET X”这么写到线上一开始用户少没感觉等 DAU 上来之后首页刷起来像开盲盒评论里全是“刷新之后又看到一样的动态”产品经理气得直跺脚。问题表面是体验不好根子其实是分页方案选错了。1.2 OFFSET 分页的性能与错位窘境先说性能。假设 Feed 表有千万级数据用户已经翻到第 1000 页每页 20 条偏移量就是 2 万条MySQL 需要在索引上扫描并丢弃前面 2 万条记录再返回后面的 20 条。偏移量越大扫描越多耗时几乎线性增长。稍微懂点 SQL 的人都知道OFFSET 不是“跳过去”而是“先读出来再扔”数据库付出的是大量无效扫描的成本。再说错位这是比性能更致命的问题。用户 A 正停留在第 5 页此时用户 B 发布了一条新动态新动态被插到列表头部那么第 6 页的内容整体往后移了一位。用户 A 再翻第 6 页时会发现自己明明刚看过的最后一条动态又出现了。如果中途还有置顶、删帖、重新编辑错位的情况会更离谱。为什么会有错位因为页码本身是一个“相对位置”。在数据不发生变化的静态列表里第 6 页永远指向前面的第 101120 条但在持续更新的动态列表里“第 6 页”这个位置的所指一直在变化。要么容忍重复要么容忍遗漏无论容忍哪一边都是产品体验在遭殃。1.3 游标分页出现把“第几页”换成“从哪继续”业界的标准解法是游标分页也叫 Keyset Pagination。核心思路就一句话客户端不再告诉服务端“我要第几页”而是告诉服务端“我上次看到的最后一条在哪里你从这里继续给我后面的内容”。在关系数据库里通常这么写WHERE create_time :last_create_time ORDER BY create_time DESC LIMIT :page_size这里的 last_create_time 就叫游标它是上一页最后一条记录的排序值。这个思路下新插入的数据不会影响当前用户继续往下翻新数据的 create_time 总是比游标新不可能被“小于游标”的分页条件捞出来所以不会出现重复也不会漏掉老数据。思路不难但落地在 MySQL 上又能感觉到两个压力一是深度游标时对 create_time 索引的访问频率很高二是热点用户读取频繁数据库连接会被打满。于是大家纷纷把目光投向 Redis——内存读写快、数据结构天然适合排序和区间截取尤其 ZSet 几乎是为游标分页量身定做的。后面我会用一整个章节来讲 Redis 到底怎么选型、怎么写。2. Redis 在 Feed 流中的角色定位与数据结构选型2.1 Redis 当的是“时间线主存储”不只是缓存很多刚接触这套设计的朋友会有一个疑问Redis 不是缓存吗怎么还能扛 Feed 流的主数据我先把这个概念掰清楚。在成熟的 Feed 架构里MySQL 仍然保存着全量动态数据但每个用户的“时间线”也就是他刷首页时看到的那个有序列表通常直接存在 Redis。这跟我们平时说的“给 MySQL 套一层缓存”是两码事因为时间线里的每个成员都直接服务于用户读取不存在“缓存未命中再回源”的说法。为什么敢这么做因为用户时间线的读路径极热。一个日活百万的产品热门网红的时间线每秒会有几百上千次读取如果每次都回源到 MySQL即使有索引连接池也扛不住。Redis 纯内存操作单实例轻松扛到十万级 QPS而且 ZSet 的区间查询是高度优化的时间复杂度在 O(log N M)M 是返回的条数一次取几十条就是几十毫秒级别。数据库在这个场景下既没有性能优势也没有功能性优势。用生活化一点的类比MySQL 像仓库管理员货架上成千上万件商品每次都要他按时间翻找出一小批Redis 更像一条设计好的传送带新货从头部上架任意位置截取一截都是顺滑的。选择用什么工具本质上是看工具和业务的形状匹不匹配。Redis 的形状就合适——数据量可控、读取高频、顺序敏感这就是它的主场。2.2 Redis 数据类型里真正值得考虑的是 List 和 ZSetRedis 有 String、Hash、List、Set、ZSet、Stream 这些数据类型很多人背八股文时都滚瓜烂熟但到了实际场景往往不知道怎么选。做 Feed 流时间线我的结论比较明确核心参考 List 和 ZSet偶尔看 Stream。List 天然适合做“时间线形态”发一条动态就往用户的 key 左侧 LPUSH用户刷新就用 LRANGE 取一段。命令少理解成本低中小规模场景很好用。但 List 有两个隐藏的硬伤。第一它没有天然的排序能力只认插入顺序你想“按时间倒序”没问题但以后如果想在时间线上夹杂运营置顶、热度加权List 就完全没法表达。第二删除一条具体动态很麻烦LREM 是按值删除需要遍历列表而且如果列表里有相同的 member 还容易误删。ZSet 就不一样了每个 member 可以带一个 score我们直接把发帖时间戳作为 score用 ZRANGEBYSCORE 按 score 区间截取天然支持倒序和“小于某个游标”的查询。member 的唯一性也解决了重复推送问题删除成员是 O(log N)。唯一代价是内存会多一些因为 ZSet 底层除了哈希表还有跳表索引但这点开销在 Feed 场景里完全值得。顺便说一句 Stream。Redis 5.0 引入的 Stream 也常被拿来讨论它有消费者组、ack、消息回溯等能力非常适合做消息队列语义。但对 Feed 流来说Stream 的消费语义是锦上添花不是必需品——Feed 流的核心需求是“保存 去重 排序 读取”ZSet 已经把这些覆盖了所以现实中用 Stream 做用户时间线的团队并不多。2.3 List 与 ZSet我直接用一张表给出结论维度ListZSet写入方式LPUSH/RPUSHZADD指定 score分页方式LRANGE基于下标ZRANGEBYSCORE基于游标排序能力仅插入顺序可按 score 自定义删除操作LREM 按值删除O(N)ZREM 按成员删除O(log N)去重能力天然不去重天然去重member 唯一内存开销小较大多跳表索引游标分页难以实现天然支持我的实践建议是C 端用户的时间线优先选 ZSet换来的是游标分页、去重、删除的全套便利List 更适合站内信、订单通知这类数据量不大、逻辑简单的消息流写起来最快也不用考虑深度分页。另外有一个细节特别容易被忽略因为 ZSet 的 member 是唯一的用户“取消关注再重新关注”时不会在时间线里产生重复 Feed省去了业务层的幂等设计。List 做不到这点你很可能得额外维护一个 Hash 来标记哪些 FeedId 出现过否则时间线里全是重复内容产品又要来吼你。如果你本地还没装 Redis先把环境搭好再试后面的代码。Mac 上两条命令的事brew install redis brew services start redisWindows 用 Redis 官方包或者 WSL 都行我更喜欢直接上 Dockerdocker run -d --name redis -p 6379:6379 redis日常排查 Key 的时候我用的是 Another Redis Desktop Manager跨平台还免费连接上去看 ZSet 的 score 分布、TTL、内存占用都特别方便。3. 基于 ZSet 的游标分页完整实现3.1 数据模型和写入链路设计工程上我的设计是每条动态在 MySQL 里存全量数据Redis 的时间线 key 只存 FeedIdscore 是发帖的毫秒级时间戳。key 的命名用 feed:{userId}member 是 feedIdscore 是发帖时间戳毫秒。feed:{userId} member: feedId score: 发帖时间戳毫秒如 1742981000123用户发帖的链路要考虑清楚否则后面会踩大坑。我的做法是主库写入成功后发一条 MQ 消息异步消费端拉取发帖人的粉丝列表再批量对这些粉丝的 feed key 执行 ZADD。注意这里必须是异步因为一个普通用户如果有几百个粉丝一次发帖就要写几百次 Redis如果同步执行接口延迟直接不可接受更别提大 V 上百万粉丝同步写就是事故。但这只是基础版本的推模式真正上线还要对写放大做收敛关于推拉结合的细节我放到下一章专门讲。先把单条链路的实现写清楚大家对“Redis 时间线”到底是什么形态有个直观认识就行。3.2 score 设计时间戳粒度太粗会漏 Feed这是新手最容易踩、又最难排查的一个坑score 直接存“秒级时间戳”。假设用户在同一个秒内连续发了两条动态两条的 score 就完全相等。上一页游标取到边界时你再用“小于这个 score”去查同秒内的另一条就会被漏掉而且怎么刷新都刷不出来只在日志里看到诡异的数据缺失。解决办法是让 score 在同一毫秒内也能区分排序。一个稳妥的做法是把 score 设计成多层score System.currentTimeMillis() * 1000 自增序号 % 1000这样做score 位数大约 16 位当前毫秒时间戳约 1.7e12乘 1000 后约 1.7e15再加 3 位序号后还是这个量级而 ZSet 的 score 是 double能精确表示的整数上限是 2^53 约等于 9.007e15所以完全不会触发精度丢失。同一个毫秒内最多能排到 1000 条不同序号的动态对绝大多数产品都够用了。这里有一个衍生问题值得提醒ZSet 的 score 是 double 浮点有些同学想着干脆用字符串存时间戳觉得这样更“直观”但 ZSet 排序是按 score 数值来排的字符串的字典序和时间序根本不是一回事一定要杜绝这种想法。3.3 分页接口实现cursor pageSize 组合游标分页的接口参数非常简单cursor上一页最后一条的 score和 pageSize。第一次进入页面前端不传 cursor服务端默认为 0也就是从最新开始取。下面是一段 Spring Boot RedisTemplate 的实现我把注释写细一点public ListLong getFeedPage(Long userId, long cursor, int pageSize) { String key feed: userId; SetString rawIds; if (cursor 0) { // 首次请求从最大的 score 开始倒序取 pageSize 条 rawIds redisTemplate.opsForZSet() .reverseRangeByScore(key, Double.POSITIVE_INFINITY, 0, 0, pageSize); } else { // 后续请求取 score 小于 cursor 的 pageSize 条 rawIds redisTemplate.opsForZSet() .reverseRangeByScore(key, cursor - 1, 0, 0, pageSize); } if (rawIds null || rawIds.isEmpty()) { return Collections.emptyList(); } return rawIds.stream().map(Long::parseLong).collect(Collectors.toList()); }这段代码的核心逻辑就一行reverseRangeByScore(key, cursor - 1, 0, 0, pageSize)意思是“从 score 小于 cursor 的最大值开始倒序取 pageSize 条”。这里不得不强调一定要用 cursor - 1 而不是 cursor否则上一页最后一条会被重复返回。前端拿到返回列表里的最后一条 score存起来作为下一次的 cursor循环下去就是完整的无限滚动。很多人会在这里怀疑每次都要算 cursor - 1会不会越取越少不会。ZSet 里的数据并不会因为你读完就消失除非业务上有明确的删除逻辑所以游标指向的位置一直在只要还有比它小的 score就可以继续往下取直到把所有历史动态看完为止。顺带说一句序列化这里的 RedisTemplate 我用的 value 序列化器是 StringRedisSerializer只存 Long 类型的 feedId完全不需要对象序列化如果你把它换成 JDK 默认序列化或 JSON 序列化存对象反而会白白多占用几倍内存而且读取时反序列化也是开销。存对象没太大必要真要存就确认一下 GenericJackson2JsonRedisSerializer 的配置。3.4 游标分页的边界条件与调参实录边界条件大多藏在一些不起眼的细节里。第一是游标溢出如果代码里用了 Long 型存 cursorcursor - 1 在极端情况下可能溢出我习惯在接口入口做校验cursor 1 直接返回空列表配合防御性编程能省很多线上事故。第二是 pageSize 限制客户端如果传个 100 万Redis 会一次性拉出大量数据直接堵死在序列化和网络传输上所以服务端一定要限定 pageSize比如最大 20 或者 50拒绝异常请求。还有一个反向操作要看清方向ZREVRANGEBYSCORE 是先 max 后 min。写 reverseRangeByScore(key, cursor - 1, 0, 0, pageSize) 的含义是从“小于 cursor 的最大 score”一直扫描到 0如果你把参数写反查出来的顺序就完全是乱的。我给团队建议是先在 redis-cli 里用一条示例数据验证好命令方向127.0.0.1:6379 ZADD feed:test 100 a 200 b 300 c 127.0.0.1:6379 ZREVRANGEBYSCORE feed:test 299 0 LIMIT 0 2 1) b 2) a看到输出结果是 300 以下最大的两条也就是 b 和 a说明命令用法对了再拿这个方向去写业务代码别一上来就在 Debugger 里翻白眼。4. 大规模 Feed 流下推拉模式与 Redis 集群实践4.1 推模式写扩散读取很爽写入是债现在我们把视角从单条链路拉远看整个系统。最常见的时间线实现是“推模式”也叫写扩散每个人都有自己的 feed key别人发帖后把内容推到所有粉丝的 feed key 里。用户刷新时只读自己的 key一次 ZRANGEBYSCORE 搞定响应又快又稳定。代价全部沉没在写侧。假设用户 A 有 500 个粉丝他发一条动态系统要往 500 个 feed key 里写入一个千万粉丝的明星发一条就要写一千万个 ZSet。这还只是一条动态如果明星一分钟发十条Redis 的写入量直接爆炸。所以纯推模式在工程上很难撑住大 V 场景。实践里通常做的是“阈值分割”普通用户走完整推模式确保读端体验粉丝数超过阈值比如 10 万的大 V 不再向所有粉丝推送而是走拉模式或者只推送给最近活跃的粉丝白名单。这样把写放大的规模从“粉丝总数”压缩成“活跃粉丝数 大 V 数量”才是可控的。4.2 拉模式读扩散代价换成读端的合并拉模式又叫读扩散思路反过来不主动推用户刷新时才去实时拉取所有关注对象最近的数据然后合并、排序、去重返回给客户端。Redis 里实现拉模式的原始姿势是用 pipeline 或者异步并发给关注列表里的每个用户 key 发 ZRANGEBYSCORE取每个用户最新的 N 条全部取回来后在一个归并排序里选出当前页的 pageSize 条。伪代码可以参考这种 pipeline 风格ListObject results redisTemplate.executePipelined((RedisCallbackObject) connection - { for (Long followeeId : followeeIds) { connection.zRevRangeByScore( (feed: followeeId).getBytes(), cursor - 1, 0, 0, pageSize); } return null; });拉模式的好处是大 V 发帖不会产生任何写放大适合头部用户。坏处是普通用户如果关注了 800 个人每次刷首页都要并发拉 800 次 Redis网络往返成本巨大而且如果要做游标分页每次都要带上“小于游标”的条件去重复拉取所有人的片段再裁剪出适合本页的数据CPU 消耗和网络消耗都很难看。所以拉模式在纯 Redis 场景下更适合“关注数较少”或者“内容是否需要精确排序要求不高”的业务否则读端会成为新的瓶颈。4.3 推拉结合线上最稳的折中方案线上真正扛得住高并发的方案基本都是推拉结合我把它拆成三个规则普通用户完全推模式新帖实时推给他们所有粉丝的 feed key头部大 V不向所有粉丝推送只推给最近有登录/互动的活跃粉丝其他粉丝阅读时走拉模式读端合流用户首页的 Redis 时间线直接读未推到的头部大 V 动态通过 RPC 或 Redis 再拉一次在上游合并排序后返回。这种做法的本质是“把写放大控制住”普通用户粉丝数有限写放大还在可接受范围大 V 的粉丝虽多但活跃粉丝往往只占一小部分推给这一部分后其他粉丝在打开 App 时再补拉一次整体读写压力都均衡了。我在一个日活百万级别的社区项目里落地过类似方案单机 Redis 写入峰值直接下降 60% 以上核心接口 P99 从 130ms 降到了 40ms 附近效果非常明显。4.4 Redis 集群、持久化与重建时间线的注意点当你的 Redis 从一两台变成一套集群第一个要注意的是 key 分布。Redis Cluster 按 key 哈希到槽位同一个用户的 feed key 会固定在一个节点上批量拉取时尽量使用 pipeline把多次读写请求合并在一个节点内处理减少跨节点跳数。如果你的业务要求拉模式频繁批量读取一批用户的时间线可以用 hash tag 的语法比如 feed:{userId}:{extra} 这种写法让相同字段进入同一槽位减少跨节点路由。另一个容易忽略的问题是持久化。Feed 数据对短时丢失容忍度偏高用户刷到缺失一两条动态体验影响不大所以一般不会开 AOF 的 everysec 同步写性能会明显下降通常就是 RDB 快照加主从热备。但 RDB 快照的恢复窗口可能导致大 V 刚发的动态在 Redis 重启后丢失因此更稳妥的做法是“MySQL 全量 Redis 热层”的结构Redis 重启后通过异步任务从 MySQL 拉取最近 12 小时的数据重新构建用户时间线保证最终一致。注意重建任务一定要分批错峰跑别让所有缓存节点同时回源扫 MySQL否则数据库会在几分钟内演变成一场“重建风暴”被拖垮。另外同一个用户的重建任务如果被多个节点同时消费可能会重复 ZADD 或者相互覆盖我习惯在任务入口用 Redis 的 SET NX EX 做一把简单的分布式锁保证同一个用户的重建任务同时只有一个在执行。5. 常见问题与排查技巧实录5.1 大 Key 问题时间线膨胀必须定期裁剪在推模式里如果大 V 直接完整推送给所有粉丝他的 feed key 里可能躺着几千万条 member这在 Redis 里就是大 Key。大 Key 的危害是内存膨胀、读取变慢严重时还会导致集群自动迁移卡顿线上数据倾斜。我的处理办法是给时间线设定一个“保鲜期”只保留最近 30 天或者最近 500 条动态。ZSet 天然支持裁剪一条命令就能删掉历史区间ZREMRANGEBYSCORE feed:{userId} -inf {maxScore}但如果每次发帖都在业务代码里顺手清理反而会增加写路径的复杂度。更好的做法是单独跑一个定时任务每天对热点用户的时间线执行区间裁剪低频、可控也不会阻塞正常的读写链路。5.2 缓存穿透空时间线也要兜底一个用户如果长时间不活跃他的 feed key 可能会被 Redis 淘汰。等他重新打开 App 刷首页时如果代码里查不到 key 就直接回源 MySQL那这个用户恰好还是个头部用户瞬间的穿透流量足以让数据库崩溃。解决思路很简单查不到也要缓存“空结果”。比如给 ZSet 写入一个空成员并设置 TTL让下一次请求走 Redis 而不是走 MySQL加一层布隆过滤器也行用 Redis 的 setbit 做一个最简单的过滤器把不存在的用户 ID 直接挡掉几百万人也就几 MB 内存效果立竿见影。5.3 数据一致性发帖后为什么首页看不到异步写 Redis 的链路天然有延迟极端情况下用户刚发完动态马上刷新自己的主页竟然看不到刚发的内容这种体验会非常伤。缓解的办法有两个层面。第一发帖时同步写入用户自己的 feed key只把“扩散给粉丝”的部分异步化这样创作者本人永远第一时间看到自己的动态。第二读接口做一点补偿逻辑如果本账号最近有发帖并且首页第一屏没有包含该帖子就允许回源 MySQL 兜底查一次把这个缺口补上。两招配合用户感知几乎为零。5.4 高频问题排查速查表现象可能原因建议解法翻页出现重复内容下一页游标没排除上一页最后一条检查游标是否用了 cursor-1同一秒内发帖漏刷score 时间戳粒度太粗毫秒时间戳乘 1000 加自增序号首页打开明显变慢拉模式并发拉取过多用户改推拉结合降低并发拉取数粉丝时间线缺记录异步队列积压或消费失败增加重试机制给队列加监控告警单个 key 占用内存过大时间线大 Key 膨胀定时执行 ZREMRANGEBYSCORE 裁剪Redis 重启后时间线缺失持久化窗口丢失RDB 主从配合 MySQL 重建任务排障时我会优先打开监控看三个指标Redis 的慢查询日志、实例的 keyspace 命中率、异步消费队列的积压量。大多数 feed 分页问题最终都能回归到这三个地方——要么是游标边界算错了要么是数据没写进去要么是写进去了又被清掉了。我这套方案做下来最深的一个体会是分页方案一定要在架构图上提前设计不能等到流量上来才补救。我第一次上生产就是直接用 List 存时间线觉得简单结果用户量上来后“取关再关注重复推送”“删帖后残留”“游标边界错乱”几个问题集中爆发排查了一整个下午才收场。后来升级成 ZSet 游标分页这些坑几乎绝迹。如果你正好要接 Feed 流强烈建议直接把游标分页作为默认方案把时间戳精度和键清理规则想清楚后面会省下很多让人失眠的深夜。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

工业Agent实时控制是伪命题?从工程实践看分层智能落地路径 2026/10/2 20:06:35

工业Agent实时控制是伪命题?从工程实践看分层智能落地路径

说实话,我第一次听到“实时控制的工业Agent”这个说法时,第一反应是:这又是哪个团队在做PR。但后来我发现,认真讨论这个问题的人并不少,甚至不少做工业互联网的朋友真的在思考要不要用大模型去顶替PID闭环里那一环。作…

阅读更多 →
新拟态计算器为何必须用CSS Grid布局实现 2026/10/2 20:06:35

新拟态计算器为何必须用CSS Grid布局实现

1. 为什么新拟态计算器非得用 Grid 布局不可?我第一次在设计稿里看到那个带“内凹阴影柔光边框”的计算器界面时,下意识就想用 Flex 去堆——毕竟按钮排成四行五列,Flex 的flex-wrap看似天然适配。结果写了三版,全卡在同一个地方&…

阅读更多 →
Easy-Test:接口自动化测试平台的元数据驱动架构 2026/10/2 20:06:35

Easy-Test:接口自动化测试平台的元数据驱动架构

1. Easy-Test不是又一个“跑个脚本”的工具,而是测试资产的中枢操作系统 你有没有遇到过这样的场景:团队里三个人写接口测试,用着三种不同风格的脚本——A用PostmanNewman导出JSON再改;B硬刚PythonRequestspytest,但每…

阅读更多 →
初等变换的本质:线性映射视角下的矩阵操作原理 2026/10/2 20:06:35

初等变换的本质:线性映射视角下的矩阵操作原理

1. 这不是“做题技巧”,而是打开线性代数底层逻辑的钥匙你翻过《线性代数》教材第几章了?是不是刚学到“矩阵”就卡在“初等变换”这一页——看着三类操作(交换、倍乘、倍加)觉得简单,可一到解方程组就手忙脚乱&#x…

阅读更多 →
SCMI协议详解:ARM芯片电源与性能管理的统一接口 2026/10/2 20:06:35

SCMI协议详解:ARM芯片电源与性能管理的统一接口

1. SCMI协议到底是什么?它和你每天用的手机、电脑电源管理有什么关系?很多人第一次看到“SCMI协议”这个词,下意识会联想到那些密密麻麻的英文缩写——比如HTTP、USB、I2C——觉得又是某种底层通信规范,离自己很远。但其实&#x…

阅读更多 →
Azure China预留实例API自动化购买实战:从认证到落地 2026/10/2 20:06:28

Azure China预留实例API自动化购买实战:从认证到落地

先说我为什么折腾这件事。前年我接了一个 Azure China 账号群的成本治理项目,几十个订阅里跑着上百台虚拟机,利用率参差不齐,账单却每个月都很好看地超预算。最标准的省钱手段就是买预留实例(RI),也就是提前…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉