新闻详情

新闻详情

首页 / 资讯中心 / 详情

在线教育多级缓存架构设计:Caffeine+Redis+数据库三级联动复盘

发布时间:2026/10/2 8:42:46来源:尧图网络
在线教育多级缓存架构设计:Caffeine+Redis+数据库三级联动复盘
当时接手“天机学堂”这个在线教育项目的时候最让我头疼的并不是业务逻辑而是课程详情页的流量。大促期间几十万人同时刷首页、刷课程目录数据库即使做了主从和读写分离还是被压得喘不过气。明明Redis已经上了而且缓存命中率也不低但每次请求都要走一次网络Redis的连接池和带宽开始变成新的瓶颈。那时候我意识到单靠Redis这一层缓存在高并发场景下真的不够。所以后来我们把缓存体系升级成了“本地缓存 Redis 数据库”的多级缓存架构这套方案跑了大半年效果非常明显。这篇文章就把整个设计和落地过程完整复盘出来包括参数调优、一致性处理、防击穿方案和日常运维中踩过的坑。1. 天机学堂为什么要上多级缓存1.1 业务场景与性能瓶颈天机学堂是一个典型的在线教育平台核心业务包括课程展示、视频点播、题库练习和学习记录。用户行为高度集中在课程详情页和首页推荐位上这意味着大部分流量都打在少数几个数据对象上课程信息、老师信息、章节列表、评论前几页。上线初期我们用了一张非常标准的缓存方案先查Redis查不到再查数据库然后回填。这个方案在日活几十万的时候没什么问题但遇到节假日促销或者热门课程上新曲线明显不对了。首先是Redis的访问量上去了每秒几万次GET请求单节点CPU接近70%网络带宽也接近饱和。其次是数据库虽然压力不大但偶尔会有慢查询冒出来基本都集中在评论统计和课程下架状态更新这些场景。说白了问题不是Redis不够快而是“每次请求都要通过网络去取数据”这件事本身就慢了。局域网内Redis延迟一般是0.5到1毫秒听起来很低但当一个请求要取三次缓存课程、老师、章节列表延迟就到了2到3毫秒再算上对象序列化和连接池排队接口平均耗时在高峰期能超过50毫秒。对于课程页这种用户感知极高的场景这个数字不能接受。1.2 单级缓存为什么不够Redis不是万能解药很多团队把Redis当成高性能的万金油确实Redis单实例QPS可以轻松破10万但它有物理上限和网络损耗。而且在高并发下Redis的瓶颈往往不是QPS而是连接数和带宽。我们当时做过一个很直观的测试同样的课程详情数据直接从Redis取P99延迟大约3毫秒但如果多个字段分散存储、需要三次GET再经过JSON反序列化P99就变成8毫秒左右。你再把这个时间乘以核心接口的调用量Redis连接池很快就被占满了。另一个问题是热点Key。一门爆款课程上线后它的课程详情Key短时间内可能有几十万次访问Redis单Key的查询是串行的虽然内存查询很快但网络包处理还是会形成热点导致这个Redis节点CPU飙高。所以单级缓存的本质缺陷是所有流量都汇总到一层上无论这一层多快都存在网络IO成本和集中热点风险。本地缓存的存在意义就是在应用进程内直接命中连网络都不用走。1.3 多级缓存的总体思路本地缓存兜底Redis汇总数据库最后防线我们最终落地的多级缓存分三层。第一层是应用本地缓存也就是JVM内的Caffeine它的访问延迟是纳秒级基本在0.1毫秒以内第二层是Redis负责集群内所有实例共享的缓存数据第三层才是数据库。读请求过来后先查本地缓存本地没有就查RedisRedis也没有就查数据库然后把数据逐级回填。这套架构带来的第一个好处是同一个应用实例上对同一个热点数据的重复请求会在本地直接命中Redis的QPS能下降百分之七八十。第二个好处是即使Redis短暂不可用或者发生网络抖动本地缓存依然可以扛住主要流量给数据库和Redis恢复争取时间。第三个好处是从系统整体来看数据库承担的压力被降到了极低绝大多数请求都不会穿透到最底层。当然多级缓存不是无脑叠加它带来了一个经典问题一致性怎么保证。我在下一节详细拆解我们的设计方案。2. 多级缓存设计与一致性方案选择2.1 缓存层级规划Caffeine、Redis、数据库各自扮演什么角色在设计缓存层级之前我们先明确了每一层的边界。Caffeine作为一级缓存保存的是当前实例高频访问的数据它的容量有限通常我们只放热点课程、章节列表和全局配置。Redis作为二级缓存保存的是全量需要缓存的数据容量可以撑到几十G它承担“数据汇总”和“多实例共享”的职责。数据库就是最终的一致性来源。实际分层的时候我们对数据做了分类。课程详情这种读多写少、实时性要求适中的数据适合走完整三级缓存。学习进度、即时消息这类用户维度强、更新频繁的数据只走Redis不走本地缓存否则用户在一台机器上更新后另一个台机器上的本地缓存还是旧值重试逻辑会变得很复杂。评论、公告这种写多读少的数据一律直接写数据库加Redis不做本地缓存。这里的核心原则是只有所有人都看同一份数据并且实时性要求没那么苛刻时才适合放在一级缓存里。凡是和用户个人状态强相关的数据放到本地缓存里就是给自己挖坑。2.2 更新链路的选型为什么坚持Cache Aside模式多级缓存的一致性问题说到底就是缓存和数据库之间怎么同步。市面上有很多方案更新数据库后直接删缓存、延迟双删、订阅binlog异步更新、用消息队列广播失效消息等。我们在天机学堂里选择的主链路是Cache Aside也就是业务侧先更新数据库再删除缓存下次读请求再回填新数据。这个模式简单有效出错概率低。为什么没有选“更新数据库后同步更新缓存”因为并发情况下同步更新缓存容易出现旧值覆盖新值的竞态问题而删除缓存即使删多了也只是多一次回查数据库不会产生数据错乱。对于延迟双删我们并没有在核心链路用。原因是它实现起来很别扭第二次延迟删除的间隔不好把握且部署在多实例环境下还要考虑每个实例的本地缓存。我们最终用MQ广播的方式替代了第二次延迟删除数据库更新成功后发送一条缓存失效消息各个应用实例收到消息后分别删除自己的本地缓存然后Redis里的Key也会被删除。这套方案比睡几秒再删更可靠也更容易排查。2.3 三个典型一致性场景修改课程、下架课程、更新学习进度场景一修改课程信息。运营后台改课程标题后数据库先更新然后发一条课程变更消息。消息内容包括课程ID和一个版本号。所有在线实例订阅到消息后删除本地缓存中对应的课程Key同时删除Redis中的课程Key。后续请求查到最新值后回填一致性窗口控制在消息传递耗时内。场景二课程下架。这个场景比较特殊因为涉及权限判断。下架后详情页不能显示但已购买用户还要继续学习。我们的做法是给缓存里的课程对象增加一个status字段下架时更新数据库然后主动推送状态变更到Redis里不动业务数据本身的Key让已缓存的数据保留但状态字段立即更新。这个方案避免了删除Key后的大量缓存穿透也让用户端感知很迅速。场景三学习进度。这类数据更新非常频繁属于典型的用户私有数据。我们只将它们放在Redis里写入时直接覆盖不走本地缓存。因为用户分布在不同实例上本地缓存反而会造成数据串不回去的问题。2.4 失效通知机制Redis PubSub配合应用内消息广播多级缓存一致性最难处理的是本地缓存怎么及时失效。如果只有一台实例直接删本地缓存就好但天机学堂是一个多实例部署的微服务集群某个实例收到运营请求更新数据库后其他实例并不知道要清空各自JVM里的那份缓存。我们最终的技术方案是组合使用Redis PubSub和应用内事件监听。数据库变更后当前实例发送一条Redis Channel消息所有实例都会订阅同一个Channel收到消息后在自己的本地Cache里执行删除。由于Redis PubSub是异步的整体性能损耗很低且不依赖额外的消息队列组件。这里要提醒一句Redis PubSub有“消息丢失”的风险如果某个实例短暂断线这个期间的消息会直接丢弃。所以这个机制只能保证最终一致性的概率收敛不能保证100%。对于极少数不一致场景我们还加了一个兜底策略每条缓存数据带一个短过期时间即使推消息失败最多几秒后也会强制回源。这个兜底看起来笨但非常有效。3. 关键参数与代码级落地3.1 缓存Key设计与过期时间的权衡多级缓存的Key设计直接决定了后续排查成本和热点分布。我们采用“业务域 对象类型 ID 版本”的拼接方式比如course:detail:1001:v2。版本号主要用于应对数据结构升级比如课程详情从V1变成V2只要加上版本后缀业务代码里可以平滑切换不用上线时手动清一大片Key。过期时间需要精心衡量。过长会导致数据长期不一致过短会导致缓存命中率下降。我们给课程详情设置的过期时间是30分钟再加一个随机浮动值。章节列表设置1小时老师信息2小时全局配置类数据永久缓存但监听配置变更消息。随机浮动值不是为了好看是为了避免同一批Key同时过期造成缓存雪崩。另外本地缓存和Redis的过期时间通常需要一致或者本地缓存时间略短于Redis。因为本地缓存的淘汰是进程内行为不会通知外部设置短一点可以让本地缓存更快感知远端数据变化。我们一般把Caffeine的过期时间设为Redis的一半比如Redis 30分钟Caffeine 15分钟。3.2 Caffeine配置实战maximumSize和expireAfterWrite怎么配Caffeine是当前Java生态里性能最强的本地缓存库没有之一。它提供了基于频率和容量相结合的淘汰策略比传统LRU更聪明。我们最开始用Guava Cache后来替换成Caffeine性能提升非常明显尤其是大量读操作场景下。配置上最核心的是maximumSize和expireAfterWrite。我们先根据实例的内存规格估算可用的堆外空间比如一台4G内存的应用实例堆内2G缓存最多分配300M左右。然后统计业务对象平均大小比如课程详情JSON序列化后大约 5KB那么300M可以放下约6万个对象所以我们把maximumSize设置为50000留出余量。expireAfterWrite设置为15分钟结合上面提到的版本号兜底这个时间足够缓存大多数热点数据又能保证变更后最长15分钟内必然回源。Caffeine还支持refreshAfterWrite但我们没启用因为担心后台异步刷新会打到数据库反而增加不可控的流量。以下是一份比较合理的配置样例CacheString, CourseDetail localCache Caffeine.newBuilder() .maximumSize(50_000) .expireAfterWrite(15, TimeUnit.MINUTES) .recordStats() .build();recordStats()这个开关我强烈建议从一开始就打开后面做命中率监控的时候全靠它拿数据不用它的话Graphite/Spring Boot Actuator都看不到缓存指标。3.3 Redis序列化与存储结构选择Redis层我们刚开始用了JDK原生序列化后来果断换成了JSON字符串。原因是JDK序列化出来的数据体积大、跨语言差、排查问题时肉眼完全看不懂而且会引入反序列化漏洞风险。用JSON后整个Key是一个可读的字符串Value也直观。存储结构上课程详情我们直接用普通的String结构序列化后的JSON整体存储。章节列表因为要支持按序读取开始用List结构但后来发现更新成本太高而且在并发修改时容易乱最终也用String存储整个列表JSON。这里要特别提醒不要为了节省存储而把多个字段拆成多个Key。天机学堂早期有个同事把课程名称、价格、老师ID分别存确实省了一些重复数据但读的时候需要多次GET网络成本翻了好几倍。对于这种读多写少的场景宁可让数据冗余一点也要保证一次GET拿全。Redis侧我们启用了内存淘汰策略allkeys-lru因为多级缓存架构里Redis只是二级缓存不是唯一存储即使热点数据被淘汰了也无非是回源数据库一次完全可控。这样Redis内存使用率可以长期维持在70%左右不用担心Memory爆炸。3.4 多级缓存存取代码示例一级二级三级这样打通读取链路的伪代码大概是这样本地Caffeine - Redis - DB - 回填。核心逻辑很直接但细节要注意熔断、超时和空值处理。public CourseDetail getCourseDetail(Long courseId) { // 1. 查本地缓存 String localKey course:detail: courseId; CourseDetail detail localCache.getIfPresent(localKey); if (detail ! null) return detail; // 2. 查Redis缓存 String redisKey course:detail: courseId; String json redisTemplate.opsForValue().get(redisKey); if (json ! null) { detail JSON.parseObject(json, CourseDetail.class); localCache.put(localKey, detail); return detail; } // 3. 查数据库并逐级回填 detail courseDetailMapper.selectById(courseId); if (detail ! null) { // 本地缓存回填 localCache.put(localKey, detail); // Redis回填并加入随机过期时间 int expire 1800 new Random().nextInt(300); redisTemplate.opsForValue().set(redisKey, JSON.toJSONString(detail), expire, TimeUnit.SECONDS); } return detail; }这段代码有两个关键点第一Redis查询结果可能是一致的旧值但我们允许短时间内的不一致第二如果返回空结果一定要额外处理不能直接return null否则会引发缓存穿透。空值处理我们在下一章会专门讲。3.5 缓存预热与启动加载避免上线瞬间打崩数据库每次发布新版本后应用实例重启JVM本地缓存全部清空。如果Redis里也没有对应数据大量请求就会直接打到数据库。为此我们做了一个预热任务在应用启动阶段读取一批热门课程ID主动查询数据库并回填两级缓存。热门课程ID的来源是上个周期的访问日志统计我们每天凌晨跑一个离线任务统计课程页面PV排名前500的ID。预热的时候不阻塞应用启动用单独的线程池异步执行每个Key之间间隔几十毫秒避免集中打数据库。启动后本地缓存命中率能直接恢复到百分之六七十数据库基本无感。预热还有一个额外好处JIT热点代码会被提前编译用户请求进来时方法调用链路已经被预热过性能更稳定。这个细节很多团队会忽略但对大促前发布而言非常重要。4. 缓存异常场景防护4.1 穿透问题布隆过滤器与空值缓存双重方案缓存穿透指的是请求的数据在缓存和数据库中都不存在每次请求都会打到数据库如果这种请求量很大数据库会被恶意或非恶意的无效请求拖垮。天机学堂最典型的就是用户访问一个已经被逻辑删除的课程或者爬虫遍历不存在的课程ID。我们做了两道防线。第一道是布隆过滤器提前把有效课程ID全量加载到布隆过滤器里查询时先判断ID是否存在如果不存在直接返回默认值数据库根本不会收到请求。布隆过滤器允许误判但不会出现漏判所以这层损失可控。第二道防线是空值缓存即使某个ID在布隆过滤器里误判为存在或者本身就是正常ID但数据库查询结果为空我们也会把空值写进Redis过期时间设为5分钟。这样同样的无效请求在5分钟内不会再次穿透。空值缓存会造成Key数量增长但5分钟过期对内存压力很小。4.2 击穿问题互斥锁和逻辑过期哪个更适合缓存击穿是单个热点的Key在过期的一瞬间大量请求同时涌入数据库。天机学堂的典型场景是首页推荐位上的爆款课程它的缓存过期瞬间可能带来几千个并发请求。传统的解决办法是互斥锁也就是在回源之前尝试获取一个分布式锁只有一个线程能去查数据库其他线程等待结果。但互斥锁有一个副作用同步等待会增加接口延时极端情况下会阻塞线程池。所以我们最终采用“逻辑过期”方案也就是缓存数据里不设物理过期时间而是保存一个逻辑过期时间戳。读请求发现当前时间超过逻辑过期时间后先返回旧值再去后台异步重建缓存。这个方案的好处是用户永远能秒回不会因锁等待而卡顿坏处是数据会短暂过期但对课程详情这种低强一致场景完全够用。需要留意的是逻辑过期方案必须搭配“重建锁”否则多个线程同时发现过期后会重复查库。我们用的是Redisson的tryLock等待时间为200ms如果获取不到锁就直接返回旧值避免重建风暴。4.3 雪崩问题过期时间抖动与多级缓存天然抗性缓存雪崩的经典原因是大量缓存同时过期导致请求穿透到数据库。解决方案很直观过期时间加随机抖动。我们所有Redis Key的过期时间基本都是“基础时间 random(0,300秒)”课程详情是1800到2100秒章节列表是3600到3900秒。这样即使同一批课程同时写入它们的失效时间也不会集中。多级缓存架构带来的另一个抗性来自本地缓存。当Redis里某个Key过期的瞬间大多数请求其实会先在本地缓存命中真正回源到数据库的只是很小一部分。因为本地缓存和Redis的过期时间不同步本地缓存往往是优先失效但紧接着Redis可能还扛着或者反过来。在两级缓存交叉作用下数据库暴露的流量冲击被极大削弱。我见过不少项目为了省内存把本地缓存容量配得特别小结果基本起不到保护作用。容量只要不是特别夸张尽量让它能覆盖核心热点的请求量否则一级缓存形同虚设。4.4 热点Key治理本地副本扩容与热点探测热点Key是Redis层面最容易被打爆的因素。某个商品或课程的Key过于集中会让单分片节点CPU飙升。多级缓存已经能缓解一部分但当一个Key在每台实例上都会被本地缓存命中时其实压力已经分散了。真正的风险在于不同实例同时失效导致所有流量同时打到Redis同一个Key上。我们的做法是在应用内做热点识别。每台实例的Caffeine记录访问次数如果一个Key在短时间内本地访问次数超过阈值就把它的本地缓存过期时间临时延长并主动通知Redis侧不需要淘汰这个Key。热点识别其实不需要特别复杂的算法用Caffeine自带的Policy就能实现监听recordStats的hitCount和missCount。另外我们给所有缓存操作都加了降级开关。如果Redis访问出现超时或连接池等待就直接跳过Redis只依赖本地缓存和数据库。这个降级在极端场景下非常关键宁可让Redis短暂无数据也不能让整个接口雪崩。5. 性能数据与常见问题排查5.1 上线后的性能变化从50毫秒到5毫秒多级缓存上线后我们做了一轮完整的压测和线上对比。线上真实流量下课程详情接口的平均响应时间从之前的48毫秒降到了6毫秒P99从82毫秒降到了18毫秒。Redis的QPS从高峰期每秒5.6万次降到了1.2万次下降了接近80%。数据库的QPS几乎可以忽略只有缓存回源时偶尔出现个位数请求。印象最深的是大促当天的表现。往年一到整点流量峰值Redis水位会上到85%以上偶尔触发慢查询升级后即使流量再涨30%Redis水位也只是勉强到40%数据库主库的CPU全程没有超过15%。这种“数据库无感”的状态才是多级缓存真正想要的收官效果。当然性能提升不是单纯靠本地缓存带来的。Caffeine的内存访问延迟大约50纳秒Redis网络访问大约1毫秒这两者差距是四个数量级。当请求命中本地缓存的比例达到85%以上时接口整体耗时就趋近于业务代码本身和外部依赖基本解耦。5.2 常见问题本地缓存不更新、命中率低、Redis连接打满先说不一致性。上线初期我们遇到一个诡异问题运营后台改完课程介绍页面一直显示旧值。排查发现是本地缓存没有收到订阅消息。原因是发布系统在发送MQ前出了问题数据库更新成功但消息发送失败而且没有重试机制。后面我们用消息表加定时补偿对账解决了这个问题核心逻辑是变更记录先落库然后由定时任务扫描未发送成功的记录重新投递。再看命中率低。刚开始我们把本地缓存过期时间设得太短只有3分钟导致本地命中率只有40%左右。后来逐步调到15分钟命中率稳定在85%以上。如果你的本地缓存命中率长期低于60%先别急着加缓存容量先看是不是过期时间设置不合理或者Key的粒度太粗。Redis连接打满的情况多半是应用侧没做连接复用或者没有配置合理的连接池大小。我们把lettuce的连接池最大连接数从默认调到了64最小空闲连接数调到16同时开启空闲回收。另外所有Redis调用都加了超时时间读超时200毫秒连接超时100毫秒避免连接池被慢请求占满。5.3 排查工具与日志埋点让问题不再靠猜多级缓存链路变长后排查问题不能靠直觉。我们在关键路径上加了大量的日志埋点和数据上报。每次读请求的缓存层级命中情况都会打印一行日志格式类似hitLevellocal、hitLevelredis、hitLeveldb。大促时按命中层级做聚合能快速判断哪一层没有发挥作用。Caffeine的recordStats开启后通过Spring Boot Actuator的/metrics端点就能实时拿到缓存命中数、未命中数、加载次数、淘汰数量。Reids侧用INFO命令看命中率其实不太准所以我们在业务层做了一个计数器每访问一次Redis里的Key就增加命中次数最后看业务命中率而不是Redis的全局命中率。日志埋点最容易被忽视的是耗时。我们在“查本地缓存”、“查Redis”、“查数据库”、“回填缓存”这四个阶段分别打了计时点一旦某个接口变慢直接看是哪个阶段耗时异常。实践证明大多数性能问题都卡在Redis序列化和数据库慢SQL上本地缓存极少成为瓶颈。5.4 避坑经验这套方案在什么场景下不适合多级缓存不是银弹。我踩过的坑里最大的一个是在用户维度的数据上强行使用本地缓存结果多个实例之间的数据互相覆盖漏掉了本地缓存没有失效的问题造成用户看到自己的学习进度在不同端上不一致。最后我们只能把用户数据从一级缓存中剥离只保留Redis。另外如果你们的应用实例数量非常大且每个实例的本地缓存都存同一批全量数据内存消耗会成倍增长这时候需要谨慎评估到底哪些数据值得进本地缓存。热点数据适合全量数据不适合。对于那种数据总量很小又需要频繁读取的配置类数据我们反而是直接全部加载进每台实例内存里用消息通知更新这样比“查一次加载一次”更高效。如果你所在团队的研发资源很紧不建议一开始就上三级缓存。先做好Redis缓存和异常防护等流量真的上来后再加本地缓存这样维护成本会低很多。但架构上一定要提前预留多级缓存的接入点比如缓存管理器接口和Key命名规范否则后面改造时会非常痛苦。最后分享一个我个人特别坚持的习惯每次上线缓存相关的改动一定要准备一份“缓存清理手册”。多级缓存意味着即使你写了很好的删除逻辑也总会有漏网之鱼。线上应急时能一键清空本地缓存、按前缀清理Redis缓存比临时写代码快得多。天机学堂这套多级缓存能稳定运行这么久靠的不仅是设计和代码还有一套顺手可用的运维工具。希望这份复盘能帮正在做缓存改造的同学少走几步弯路。
网站建设高端定制企业官网
RELATED

相关资讯

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

较早相关资讯

最新相关资讯

AI日报制作全流程:从信息筛选到知识库的工程实践 2026/10/2 11:04:47

AI日报制作全流程:从信息筛选到知识库的工程实践

1. 一份“AI 日报”到底在记录什么每天早上打开电脑,我的第一件事不是看邮件,而是花二十分钟把过去二十四小时里 AI 圈发生的事过一遍。这个习惯坚持了快三年,从最开始只是自己记备忘录,到后来整理成固定的格式发给团队&#xff0…

阅读更多 →
Python实现多AGV路径规划与调度优化实战解析 2026/10/2 11:04:47

Python实现多AGV路径规划与调度优化实战解析

简介:面向智能物流装备、仓储管理与智能制造领域的科研人员和开发工程师,该资源提供了一份基于Python的多AGV路径规划与调度优化方案,完整复现了“订单拣选系统中多AGV路径规划与调度研究”论文的关键方法。内容以栅格地图环境建模为起点&…

阅读更多 →
Kali Linux root登录配置全攻略:从锁定到解锁的完整说明 2026/10/2 11:04:47

Kali Linux root登录配置全攻略:从锁定到解锁的完整说明

不少朋友刚把Kali装起来,第一件事就是想在登录界面敲个root,结果输完密码直接被打回来,或者在终端里执行个su -,密码怎么输都不对,心里就开始犯嘀咕:是不是我哪里配置错了?其实你大概率没配错&a…

阅读更多 →
AI Agent实战:用命令和日志诊断外接屏HDMI无信号 2026/10/2 11:04:46

AI Agent实战:用命令和日志诊断外接屏HDMI无信号

周一早上 9 点还差几分钟,我照例把笔记本推进底座准备开始干活。外接屏电源灯亮了,黑屏上却只有“HDMI 无信号”几个字。上周它已经闹过一次情绪,当时我花了整个上午逛搜索引擎,“换线、更新驱动、重置显示器、重装系统”挨个试了…

阅读更多 →
多AGV路径规划与调度论文复现:订单分批、模拟退火与A*的Python实现 2026/10/2 11:04:46

多AGV路径规划与调度论文复现:订单分批、模拟退火与A*的Python实现

简介:面向物流自动化与智能仓储领域研究者和Python开发工程师的完整复现资源包,围绕订单拣选系统中多自动导引运输车路径规划与调度问题,提供可运行的Python实现与详细讲解。方案覆盖环境建模与数据预处理、基于节省算法的动态订单分批、模拟…

阅读更多 →
ComfyUI+PS高效AI绘画工作流:从节点搭建到商业落地 2026/10/2 11:04:40

ComfyUI+PS高效AI绘画工作流:从节点搭建到商业落地

1. 为什么是 ComfyUI PS:这套组合解决了我什么痛点1.1 从 WebUI 转向 ComfyUI 的心路历程先说结论:如果你只是想随便玩两下出几张图,WebUI(也就是 Stable Diffusion WebUI)完全够用。但如果你想认认真真把 AI 绘画做成…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

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

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