因为我们服务基本都是 Java 框架,所以当初也是想当然的用 Java 原生的图片编辑能力来画图实现需求,随着业务增长,性能越来越吃紧,而且需求也越来越复杂,需要画越来越复杂的图,Java 越来越难画了
求大家指教,有什么成熟的后端服务方案,画图又快,还能画一些复杂的海报图呢。可以考虑用别的语言

用前端画,吃用户手机 cpu

后端画图避免不了性能问题

哈哈,也考虑过。但是绝大多数需求是需要一下画出来好几张图,让前端画担心用户停留不了那么长时间

原生指的是 java.awt.Graphics2D 么?

海报用 H5 实现输出 html 文件,后台起一个 headless chrome 进程直接本地渲染最后调用 sdk 截图 api 就好了,封装成服务很方便

你如果实时显示,后端也要那么久,除非你挂异步任务提前生成

对就是挂的异步提前生成,用户进活动落地页就去生成了,等到他划到最后去预览海报都过去好几秒了

Chrome 并发也是一个很大的问题,内存大户

也考虑过用 puppeteer ,但是 pptr 太吃内存了,而且速度也没快多少。倒是解决了画复杂海报的痛点

前端画图,像素根据手机宽度生成低分辨率的,速度应该不慢

#8 #9 堆机器就好了啊,一个海报生成服务能有多高并发?

我甚至在想,能不能上一些 GPU 加速呢🤔🤔,稍微研究了一下,感觉上手成本都比较高😂

#9 封装成独立服务堆数量就是了,海报别再 java 画了这是条不归路,ui 同学走查能搞死你

现在已经部了 20 台了,业务还会有几倍的增长空间,所以还是想看看能不能找到性能更好的方案。。。另外现在业务想画一些复杂的,比如说画些饼图、曲线图,之前用 Java 写写字、拼拼图还行,但是让我生成饼图就有点功力不够了😂

一开始就是独立出来的。我也不想用 Java 了,所以这不出来请教大家嘛,用啥方案更合适些

考虑下把这个活儿胶水给其他适合做图像处理的语言搞吧

#14 另外就是纯 web 的方案了这个不太了解不过我之前有同事实现过,headless chrome 方案我之前做了一版上线稳如老狗,k8s hpa 一开不需要操啥心

前端画,前端也能异步提前生成,这不就省了 20 台服务器

你海报是什么类型的海报,这点你要说清楚,你生成的图片是底图加用户信息的这种,还是每次生成的图片都不一样?解决方案也都不一样的

考虑性能的话最佳选择就是 c++或 rust ,rs 的话这有个库 crates.io/crates/charts-rs ,支持 json 格式数据直接生成图表方便对接。或者是用 plotters 实现更复杂的操作。

不是太复杂的文字和图片的组合可以考虑直接用公有云的水印功能

我之前使用过 headless 浏览器导出过 pdf ,内存吃紧,不是个好方案。画图的话我之前写过类似用 Rust ssr 导出 echarts 为 svg 的功能,使用的是 github.com/yuankunzhang/charming 这个库改了下源码支持 html ,速度还挺快就几 ms ,导出为 png 的话稍微慢点,需要渲染图片。

既然服务端是异步生成的,考虑是不是可以客户端异步,盲猜应该是可以的

这会感觉性能压力更大

让客户端画,实时性要求不高就上队列一个一个处理吧,用户等一会

前端画图很快的, 用 rust 、c++ 等语言编译成 wasm 模块执行可以大大减少服务器的压力。现在 b 站 用 ffmpeg 在客户端处理视频比过去快了很多倍。webgl 和 wasm 比较成熟,推荐几个比如 www.scichart.com/blog/surpassing-limits-javascript-bigdata-webassembly/更新的技术比如 webgpu 通过直接调用 GPU 方式可以大大加速密集型计算,不过现在这个还处于浏览器实验性的 API

如果是因为机器性能和部署的原因的话,看了你的描述,我感觉可以试试把画图这部份抽出来部署到函数计算上。这样成本可能会比现在降低很多( 20 台服务器说多也不多,说少也不少了),性能的话可以写个 demo 测测看情况,实例数量可以随着并发增加而增加,而且不需要维护。

另外也是建议你先检查一下你这里说的”性能压力“是什么,看看具体性能的瓶颈在哪里,有时候一个代码上的小优化,就可以起到一个立竿见影的效果,也有时候调整一下服务器规格,比如增加内存使用读写更快的磁盘也能在某些情况下大大的缓解性能压力。

最优肯定是放前端来处理,web 端通过 html 转 canvas 再转 image ,所见即所得。如果是非前端即时生成或者非 web 端(小程序),通过后端(nodejs)调用 puppeteer 生成,为了提高效率肯定要加一层对象缓存。根据模板 html+渲染数据 json 计算出当次内容 hash 值,判断是否已在对象仓库中,有即返回资源的 CDN 地址,不存在再渲染上传到对象仓库返回对应资源地址。( bucket 根据需求设置过期时间,防止存量过大问题)

就没有人提到 serverless 吗? puppeteer 配合 aws lambda ,压测 QPS 有 120 ~ 160 ,针对大部分场景都足够了。

🤔个人觉得可以这样,4 步走:1.解决业务可扩展性问题:可以让前端使用图片编辑器生成图片信息,如果业务需求是后续不可编辑可以生成截图保存,如果是可编辑的可以把整个编辑后的图片 html 保存,建议把其上传到对象存储;2.前端将图片编辑结果提交给后端服务,后端将 html 信息+业务参数封装,丢到消息队列里面。3.html->图片,这一步可以考虑各种各样的处理方式,根据自己的要求(比如性能要求)去搜索相关的库,比如 html to image java/nodejs/c++/rust 等等,生产完将结果上传并丢回消息队列里面,这个胶水层服务提供:消息队列消费,生产;图片处理;图片上传的服务。4.后端服务消费胶水层服务产生的图片 url目的:1.解决扩展性; 2.吞吐量; 3.图片业务与主业务的解耦,数据量大时,图片业务硬件资源吃的较多,可以单独升级图片处理服务。

建议拆分成单独服务部署,任务调度好应该能缓解压力,然后就是优化代码。之前的公司做项目的时候,有个转图生成各种格式各种分辨率海报的功能,做微服务改造的时候就是拆分成了单个服务,部署了 10+台机器,然后优化了下代码,效率杠杠的。

不晓得你要画多复杂的图,但正常情况下前端画图都是瞬间完成的,不存在你说的等待,你可以留意你玩的游戏,普遍可以达到 64 帧/s 以上,而一个帧就是一次全屏绘图,你感觉到等待了吗?

改 c++,然后独立部署,外部调用

相当于写好 H5 模板,在服务器起一个 headless chrome 实现截图,然后将截图保存成 url ,通过接口方式回传给前端显示?

html 模板 填上动态的文字后, 直接渲染就行啊

是的,核心就是 headless chrome 来渲染 H5

用 wasm,让前端来画

而且现在 wasm 是支持多线程的 应该慢不了

让前端画呗

十分感谢大家的回复~~我已经有个大概的认知了,目前打算去探索一些让前端去画,再传到后端保存的方案。另外针对前端无法生成的需求场景,先用老场景进行兜底等有余力后,再考虑探索一下后端 html to image 的方案,看能不能做个后台可以用自己运营编辑海报样式并生成 html

截图的问题真的很多,奇奇怪怪的问题。特别是如果 html 里面有视频或者动图,但是如果静态的 html 很简单。