
AI 应用媒体生成后端前端【免费下载链接】pollinationsYour Friendly Open-Source Gen-AI Platform项目地址https://gitcode.com/gh_mirrors/po/pollinations点击查看免费下载本篇指南围绕operations/infrastructure/gpu/dreamshaper/SERVERS.md展开讲清 Pollinations 平台上sana模型别名如何被保留并映射到 DreamShaper 8 LCM 的 Vast.ai 双 Worker 生产路由包括当前部署形态、注册表池键pool key的历史成因、Vast 实例与命名 Cloudflare Tunnel 的部署方式以及 gen Worker 侧的加权池选择、503 跨 Worker 重试与队列限流机制。读完本文你可以理解这条别名兼容路由从请求进入到图像返回的完整调用链并掌握扩容、替换 Worker 时的运维检查点。1. 路由背景SANA Sprint 退役后留下的sana别名SERVERS.md给出的第一条关键事实是SANA Sprint 已不在生产图像路由中。公开模型名sana被保留为dreamshaper的别名实际由 DreamShaper 8 LCM 服务部署在两台 Vast Worker 上同时内部注册表池键也继续叫sana以保持兼容。modelsana - registry alias dreamshaper - pool type sana - named Cloudflare tunnels - DreamShaper workers这条链路在仓库源码中有完整印证模型注册表中lykon/dreamshaper-8-lcm显式声明了别名列表见 shared/registry/image.tslykon/dreamshaper-8-lcm: { // sana is kept as an alias so existing callers and the legacy image // proxy worker keep working unchanged. aliases: [sana, dreamshaper], provider: vast, ... },gen Worker 的图像分发对lykon/dreamshaper-8-lcm走自托管池且注释明确指出池键仍是sana见 gen.pollinations.ai/src/image/createAndReturnImages.tscase lykon/dreamshaper-8-lcm: // pool key stays sana — see VALID_TYPES in availableServers.ts return await callSelfHostedServer(prompt, safeParams, sana);池键的白名单定义在 gen.pollinations.ai/src/image/availableServers.ts。源码注释解释了保留旧名的根本原因/register会拒绝未知类型如果直接改用dreamshaper作为池键Worker 就无法在路由变更部署之前先行注册进池会存在请求打向空池的窗口期。注意没有外部自动 fallback。文档明确写道There is no automatic external fallback. If no worker is registered, the model is down. 可用性完全依赖两台 Vast Worker 与跨 Worker 的 503 重试。2. 当前部署形态两台 Vast Worker 命名 TunnelSERVERS.mdLast updated: 2026-09-02记录的部署快照如下WorkerVast instanceMachine / regionGPUAll-in rateRegistered hostnamedreamshaper-vast-0149063196143507 / Mexico, MXRTX 3060$0.075556/hrdreamshaper-canary-49063196.myceli.aidreamshaper-vast-0247789794100803 / Romania, RORTX 4070$0.093889/hrdreamshaper-canary-47789794.myceli.ai更晚更新2026-09-26的 GPU_INSTANCES.md 记录了后续替换实例47789794Romania, RTX 4070已被人审批准的实例52741049machine35285USRTX 3060 12 GB$0.081481/hr all-in替换槽位成本从 $0.093889/hr 降至 $0.081481/hr两台 DreamShaper GPU 合计 $100.27/30d。因此排查当前sana路由时应以GPU_INSTANCES.md的最新记录为准SERVERS.md表格代表 2026-09-02 时的状态。文档同时给出两条硬性运维约束两台 Worker 都运行operations/infrastructure/gpu/dreamshaper/setup-vast.shVast 在容器重启后执行/root/onstart.sh恢复服务而非/workspace/onstart.sh实时舰队与合格性证据见 GPU_INSTANCES.md部署与 API 细节见 DreamShaper README。2.1 历史 Sana 基础设施已废弃文档最后一段明确划清了历史边界Vast instance30937024、Scaleway Sana workers 以及遗留的 SSH-tunnel 路由属于历史设施不参与生产分发。诊断当前sana别名时不要使用旧 runbook 里的旧 IP 地址或 SSH 命令。这一点有现实风险sana这个名字横跨了三个时代——GH200 上的 SANA-SprintGPU_INSTANCES.md 提到Replaced SANA-Sprint on the GH200、Lambda Labs 上的 Sana端口 8766systemdsana.service见 GPU_INSTANCES.md 的 Lambda Labs 章节、以及当前的 DreamShaper Vast 路由。只有最后一条是当前生产链路。3. Worker 模型配置三个静默失败的关键项DreamShaper README 定义了这个 FastAPI Worker 的核心配置且指出三项配置改错了不会抛异常只会出坏图——这属于典型的静默失败点值得逐条对照源码 operations/infrastructure/gpu/dreamshaper/server.py3.1 LCMScheduler 是强制项DreamShaper-8 仓库自带DEISMultistepSchedulersolver_order2、timestep_spacingleading。LCM 模型跑在这个调度器上会产出washed-out mush发虚的糊图且不抛异常。源码在管道装配处显式替换调度器server.py# MANDATORY: dreamshaper-8 ships DEISMultistepScheduler with solver_order2 # and timestep_spacingleading. Running an LCM model on that produces # washed-out mush with no exception raised. pipe.scheduler LCMScheduler.from_config(pipe.scheduler.config)3.2 guidance_scale0.0LCM-LoRA 已把 guidance 烘焙进模型。实测 cfg 1.5 与 cfg 0.0 视觉上无差异但 cfg 1 会开启 classifier-free guidance每步多跑一次无条件前向白白损失约 1.8× 吞吐。对应源码server.py# LCM-LoRA bakes guidance into the model. Measured: cfg 1.5 and cfg 0.0 are # visually identical, but cfg 1 turns on classifier-free guidance, which runs # a second unconditional pass per step and costs 1.8x throughput for nothing. GUIDANCE_SCALE float(os.getenv(GUIDANCE_SCALE, 0.0))3.3 peft 是必需依赖diffusers ≥0.30 移除了非 PEFT 的 LoRA 后端没有peft时fuse_lora()直接失败。requirements.txt 中peft与diffusers0.38.0、transformers5等并列diffusers0.38.0 transformers5 accelerate peft safetensors huggingface-hub fastapi uvicorn pydantic aiohttp pillow requests另外两点配置决策TAESD 微型解码器madebyollin/taesd替换标准 VAE在 RTX 3060 上端到端实测 3.9× 加速且无可见质量差异——低步数下瓶颈在 decode 而非 UNetserver.py采样步数取 33 是可用输出的下限。512×512、batch 1 的历史单客户端实测数据StepsQualityRTX 3090RTX 30601unrecoverable mush13.80 img/s9.04 img/s2holds up on portraits, soft on scenes and flat-vector8.795.453clean6.183.884marginally crisper5.063.01文档特别提醒这些是历史单客户端测量值而非生产能力历史需求峰值为5.72 img/s生产部署为 2 张 GPU、每张 3 个 Uvicorn 进程早期正是单客户端基准高估了可用容量导致生产队列持续增长。更大的卡也不见得更快RTX 4090 在 3 步下仅 4.99 img/s比 3090 还慢——因为共享的 64 核 EPYC 宿主机是 CPU-dispatch 瓶颈GPU 从未打满4090 只在 micro-batchingbatch 16 时 22.8 img/s才反超而该 Worker 不做批处理。4. 部署Vast 实例、setup-vast.sh 与重启恢复4.1 三级递进的部署命令README 给出的操作流程canary 隔离验证 → 公网路径 canary → 生产必须按顺序执行# 1) 租用 Vast SSH 实例至少 30 GB 磁盘rent 时配置启动钩子 vastai create instance OFFER \ --image nvidia/cuda:12.8.1-cudnn-runtime-ubuntu24.04 \ --disk 30 --ssh --label dreamshaper-vast-NN \ --onstart-cmd if [ -x /root/onstart.sh ]; then /root/onstart.sh; fi vastai attach ssh INSTANCE ~/.ssh/id_ed25519.pub # 2) Isolated canary默认不注册生产心跳、不起 tunnel。 PLN_GPU_TOKEN... PUBLIC_HOSTNAMEdreamshaper-canary.example.com \ GIT_BRANCHmain bash setup-vast.sh # 3) Public-path canary专用 canary tunnel仍不注册生产心跳。 PLN_GPU_TOKEN... CLOUDFLARED_TUNNEL_TOKEN... \ PUBLIC_HOSTNAMEdreamshaper-canary.example.com TUNNEL_ENABLEDtrue \ HEARTBEAT_ENABLEDfalse GIT_BRANCHmain bash setup-vast.sh # 4) 生产仅在命名晋升审批通过后。 PLN_GPU_TOKEN... CLOUDFLARED_TUNNEL_TOKEN... \ PUBLIC_HOSTNAMEdreamshaper-vast-NN.example.com TUNNEL_ENABLEDtrue \ HEARTBEAT_ENABLEDtrue GIT_BRANCHmain bash setup-vast.sh镜像选型有实战依据使用nvidia/cuda:12.8.1-cudnn-runtime-ubuntu24.04运行时镜像即可DreamShaper 只安装固定版本的 PyTorch CUDA wheel不编译 CUDA 扩展更大的开发镜像在 2026-08-19 的替换中曾反复卡在容器创建之前而运行时镜像启动成功。4.2 环境变量全集setup-vast.sh生成的.env.dreamshapersetup-vast.sh与 README 声明一致Worker 侧完整清单为变量默认值说明MODEL_IDLykon/dreamshaper-8基础模型LCM_LORAlatent-consistency/lcm-lora-sdv1-5LCM LoRA加载后 fuseTINY_VAEmadebyollin/taesd微型解码器NUM_INFERENCE_STEPS3采样步数服务端决定忽略调用方GUIDANCE_SCALE0.0关闭 CFGMAX_DIM768单边像素上限MAX_PIXELS512²总像素上限PORT8766服务端口REGISTER_URLhttps://gen.pollinations.ai/register心跳注册端点SERVICE_TYPEsana注册表池键兼容保留HEARTBEAT_ENABLED—是否发送注册心跳TUNNEL_ENABLED—是否启动 cloudflaredWORKERS3Uvicorn 进程数QUEUE_LIMIT2每进程每进程最多 1 运行 1 排队4.3 /root/onstart.sh重启恢复的关键细节Vast 在容器重启后执行的是/root/onstart.sh。setup-vast.sh 生成的脚本先做彻底清理再拉起服务这段逻辑解释了为什么只杀监听端口不够pkill -TERM -f /root/run-dreamshaper.sh 2/dev/null || true # 先杀 detached supervisor screen -S dreamshaper -X quit ... pkill -TERM -f $VENV/bin/python ... # Uvicorn 派生的 fuser -k -TERM \$PORT/tcp\ ... # worker 与 resource tracker fuser -k -KILL \$PORT/tcp\ ... # 可能比父进程活得久只杀端口监听者是不充分的spawn 出来的 worker 和 resource tracker 会存活并引发Address already in use死循环。清理完成后脚本用 screen 会话拉起server.py带 5 秒重启循环并在/health就绪后才启动 cloudflared 与 tunnel watchdog。4.4 替换排空drain时的检查点替换 GPU 前不能只看保存的HEARTBEAT_ENABLEDfalse设置而要核对运行中的进程旧部署的启动脚本可能没有上述清理逻辑会留下携带旧环境、持续发心跳的 Python 进程。正确做法是停掉那个陈旧的 supervisor/进程树、以禁用注册的方式恢复旧端点等它的 URL 从/register中消失后再销毁——注册表排除 180 秒无心跳的条目KV 条目 TTL 为 240 秒与 availableServers.ts 中SERVER_TIMEOUT 180000、REGISTRY_TTL_SECONDS 240一致。2026-09-26 的替换记录就实际踩到了这个坑旧主机遗留的启动脚本在标志位改变后仍让陈旧 Python 进程带着心跳运行被人工停掉后注册表条目才正常过期GPU_INSTANCES.md。5. 请求路径从modelsana到 Worker 的源码级链路5.1 gen 侧加权池选择与 503 跨 Worker 重试callSelfHostedServer组装请求体时硬编码steps 4createAndReturnImages.ts并携带x-backend-token: $PLN_GPU_TOKEN随后调用fetchFromWeightedServer(sana, ...)。池选择逻辑availableServers.ts按1/lastMs做加权随机——快后端按比例分到更多流量避免把慢 GPU 和快 GPU 平摊。fetchFromWeightedServer的重试语义是整条高可用链的支点availableServers.ts仅当请求未被接受时重试其他 WorkerHTTP 503队列满、Cloudflare 1033 disconnected-tunnel 错误、或已知的网络故障其他 5xx 可能已经开始推理不重试直接抛出成功的响应延迟会被recordLatency写入独立 KV 键供加权选择使用心跳写与延迟写分离防止陈旧心跳冲掉路由权重。这解释了 Worker 侧限流设计的动机Worker 快速 503 不是失败而是让 gen 立刻换另一台已注册 DreamShaper Worker 的重试信号。5.2 Worker 侧队列限流与多进程server.py中每个 Uvicorn 进程用BoundedSemaphore(QUEUE_LIMIT)实现1 运行 1 等待server.py# Per Uvicorn worker process: one request runs on the GPU while one may wait. # Further requests receive 503 so gen can retry another registered Vast worker. QUEUE_LIMIT int(os.getenv(QUEUE_LIMIT, 2))超出即503 Queue full。QUEUE_LIMIT是每进程的因此默认WORKERS3时单张 GPU 最多容纳 6 个 in-flight 请求而不是在一块 GPU 上堆出无界队列。为什么必须多进程server.py 的注释记录了生产实测单进程串行在generate_lock上时GPU 有约 60% 时间空闲GPU 占用仅 26–45%、单进程封顶约 4.3 img/s——瓶颈是 Python 路径GIL 下的 JPEG 编码、base64、HTTP不是 GPU 或步数。模型只占约 3 GB 显存多进程各自持有独立管道与锁后 GPU 工作与 Python 开销才能真正重叠。5.3 心跳注册30 秒一次池键固定为 sanasend_heartbeat每 30 秒向https://gen.pollinations.ai/registerPOST{url, type: sana}server.py。两个陷阱都写进了文档必须传PUBLIC_HOSTNAME否则 Worker 注册的是裸 VastIP:portgen Worker 根本取不到该源地址——而心跳仍会报告健康。这次故障在 rollout 中真实发生过池键写死sana源码注释与VALID_TYPES白名单相互印证/register拒绝未知类型所以 Worker 必须使用已部署的路由池键才能先注册、后切流。6. API 契约/generate 与 /healthWorker 对外契约与旧 sana Worker 相同DreamShaper README 的 API 章节6.1 POST /generate要求请求头x-backend-token: $PLN_GPU_TOKEN缺失或不匹配返回 403verify_backend_token校验见 server.py。请求体{ prompts: [a cat wearing sunglasses], width: 512, height: 512, steps: 3, seed: 42 }尺寸处理规则按MAX_DIM768与MAX_PIXELS512²钳制并使用同一缩放因子保持宽高比再向下取整到 /32。因此 1024×1024 会返回 512×5121280×720 会返回 672×384分别钳制两边曾把 1280×720 变成 512×480这是修复过的历史 bug。钳制逻辑与单测一一对应见 clamp_dims 和 test_server.pydef clamp_dims(w, h): w, h max(1, w), max(1, h) scale min(1.0, MAX_DIM / max(w, h), (MAX_PIXELS / (w * h)) ** 0.5) w max(32, int(w * scale) // 32 * 32) h max(32, int(h * scale) // 32 * 32) return w, hsteps字段被接受但刻意忽略——与 sana Worker 行为一致。原因gen 侧每个请求体都硬编码steps: 4若尊重调用方步数会覆盖服务端 3 步配置把 3090 的吞吐从 6.18 img/s 拉到 5.06 img/s低于该部署按峰值小时容量规划的水位。步数由 Worker 端的NUM_INFERENCE_STEPS唯一决定。响应是单元素数组含 base64 JPEG[{image: base64, has_nsfw_concept: false, concept: [], width: 512, height: 512, seed: 42, prompt: ...}]6.2 GET /health{status: healthy, model: Lykon/dreamshaper-8, lora: latent-consistency/lcm-lora-sdv1-5, steps: 3, guidance: 0.0}模型未加载完成时返回 503Not loaded。OOM 时进程直接sys.exit(1)由/root/onstart.sh的重启循环兜底拉起。7. 变更顺序与验证清单文档反复强调的操作纪律SERVERS.md与 README 中沉淀了多条顺序错了就出事的纪律汇总如下7.1 上线顺序QUEUE_LIMIT 的开启顺序不要在 gen 生产环境具备跨 Worker 503 重试之前给生产 Worker 启用QUEUE_LIMIT。正确顺序先把main同步到production、通过 GitHub Actions 部署 gen、确认重试已上线然后在两台 DreamShaper Worker 上重跑 setup。顺序颠倒会把饱和从静默排队变成用户可见的 503。替换 sana 的顺序改造前sana走的是绕过注册表池的硬编码后端 URL。必须先部署并确认 Worker 已注册再合并路由变更先合并会把所有流量打到空池。7.2 命名 Tunnel不要用 quick tunnel生产必须走命名Cloudflare Tunnel指向http://localhost:8766quick tunnel 曾直接造成事故 #12254free、限流、无 SLA 的trycloudflare.com地址在生产负载下劣化静态/docs抓取要 15–39 秒本机 1024×1024 渲染只要 3.9 秒请求超过 CloudFront 超时后用户看到的是无限挂起而非报错——而 Worker 的心跳全程是绿的。这引出一条普适结论心跳健康不能证明数据路径可用必须用真实生成请求验证。7.3 销毁旧 GPU 前的最终验证不能只看后端日志后端 200 不构成退役门槛还要看最终 API 结果。在 Tinybird 中按model_requested IN (dreamshaper, sana)与is_final过滤——注意resolved_model_requested里存的是规范名lykon/dreamshaper-8-lcm而非公开 slug2026-09-26 的退役检查就因按公开 slug 过滤而误查成空集。要对比替换前后的完成窗口、区分客户端 4xx 与最终 5xx、并覆盖代表性突发同次替换通过了 210-RPM canary却在随后 484 请求/分钟的舰队突发中出现了用户请求被丢弃——支持突发容量不足的判断属于事后需要跟进的回归文档要求用单独批准的候选实例恢复容量后再退役其他 Worker。7.4 别名路由的自动化测试锚点仓库测试对这条链路有两处直接锁定可作为回归依据模型列表断言/image/models返回的lykon/dreamshaper-8-lcm携带aliases: [sana, dreamshaper]与固定单图计价见 gen.pollinations.ai/test/index.test.ts端到端别名路由请求modelsana时x-model-used响应头必须为lykon/dreamshaper-8-lcm且 Tinybird 事件保留调用方实际使用的名称sana见 gen.pollinations.ai/test/generation-vcr.test.ts。8. 小结SERVERS.md的篇幅虽短但浓缩了这条路由的全部运维真相sana同时是公开别名模型注册表、池键VALID_TYPES白名单与Worker 心跳类型SERVICE_TYPE三处的一致残留其唯一目的是让 Worker 能在路由切换部署前先行注册、消灭空池窗口生产可用性由两台 Vast Worker、命名 Tunnel、每进程QUEUE_LIMIT2的快速 503 与 gen 侧跨 Worker 重试共同构成且没有外部 fallback。理解这些之后无论是诊断modelsana的请求为什么失败还是执行下一次 GPU 替换都应当以注册表池键是 sana、池内主机名以/register实时查询为准、历史 Sana/SSH-tunnel 资料一律弃用作为出发点并结合 GPU_INSTANCES.md 中最新的实例记录与 DreamShaper README 的部署契约执行变更。赞分享AI 应用媒体生成后端前端【免费下载链接】pollinationsYour Friendly Open-Source Gen-AI Platform项目地址https://gitcode.com/gh_mirrors/po/pollinations点击查看免费下载相关推荐Flutter-Notebook路由命名使用命名路由管理页面Flutter Notebook路由命名使用命名路由管理页面 在Flutter应用开发中页面跳转是核心功能之一。传统的路由管理方式需要手动构造 Materi示例工程移动开发gsy_github_app_flutter路由管理命名路由与参数传递gsy_github_app_flutter路由管理命名路由与参数传递 在移动应用开发中路由Route是连接不同页面的桥梁良好的路由管理能显著提升应用移动开发开发者工具Vitess 查询路由原理与实现解析从 SrvKeyspace 到 TabletGateway 的健康路由链路Vitess 查询路由原理与实现解析从 SrvKeyspace 到 TabletGateway 的健康路由链路 本篇技术指南以 Vitess 官方设计文档 d数据库分布式数据库云原生后端数据存储创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考