V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
alwayshere
V2EX  ›  程序员

高并发下 php 输出图像对性能开销大不大?

  •  
  •   alwayshere · 2016-12-30 19:41:46 +08:00 · 3085 次点击
    这是一个创建于 2896 天前的主题,其中的信息可能已经有所发展或是发生改变。

    目前服务器是这样的: cpu 太差,是 ATOM 的 cpu ,带宽是 100M 独享,硬盘太小,而且是机械硬盘,内存 4G 。 服务器需要裁剪图像(平均 4M 大小)输出到浏览器端,因为硬盘太小,如果把每个图片都裁剪成各种分辨率存到硬盘的话,硬盘装不下,我目前想到两种方案:

    1.客户端浏览器 canvas 裁剪:

    输出原始图像到客户端,用 js 配合 canvas 最终生成 base64 图像。

    优点:不费硬盘、不费内存

    缺点:带宽估计消耗很大,用户等待时间较长,即使一个 100x100 的图像都要等很长,搜索引擎抓取不到这张图像

    2.php 动态输出:

    php 在客户端进行裁剪,rewrite伪装成静态地址如www。abc。com/images/little-cat-480x800.jpg:

    //php 裁剪原始图像得到$content;

    header('Content-Type:image/jpeg');

    //输出裁剪后的图片内容$content;

    这样做的好处:不费硬盘、不费带宽

    缺点:费内存和 cpu ,在高并发下不知道表现如何?

    项目实际经验太少,求教 V 站高手解疑一下,哪种更好?或者有更好的方案?谢谢

    第 1 条附言  ·  2016-12-30 20:27:38 +08:00
    上面打错了,“ php 在客户端”=>“ php 在服务器端”,目前服务器只有 1T 大小,如果加上各种裁剪后的各种分辨率的图片的话,还要增加好多倍的硬盘,感觉有点贵了
    11 条回复    2016-12-31 21:36:30 +08:00
    duola
        1
    duola  
       2016-12-30 19:47:57 +08:00
    这是硬伤,寄硬盘跟 CPU 吧,这是最好的解决方案,反正再在硬盘和 CPU 也不贵。
    incompatible
        2
    incompatible  
       2016-12-30 19:48:55 +08:00 via iPhone
    用七牛之类的云存储,可以以很低的成本解决你的问题。
    alwayshere
        3
    alwayshere  
    OP
       2016-12-30 19:49:32 +08:00
    @incompatible 自己算了下,还是自己搭建图片服务器更实惠点
    alwayshere
        4
    alwayshere  
    OP
       2016-12-30 19:53:16 +08:00
    @duola 目前硬盘只有 1T ,裁剪成各种分辨率再拿其他服务器来装,花销挺大的
    gouchaoer
        5
    gouchaoer  
       2016-12-30 20:12:19 +08:00 via Android
    php 有 glide 专门裁剪图片,其实图片如果反复访问的话第一次裁剪才耗 cpu ,第 n 次访问直接 nginx 读文件输出就完了
    pubby
        6
    pubby  
       2016-12-30 21:29:38 +08:00
    2006 年我也是用你的方案,存的是原图, php 动态裁剪,前面加 squid 缓存
    2009 年改成 fastcgi
    2014 年用 go 重写,改成分布式处理
    z5864703
        7
    z5864703  
       2016-12-30 22:25:10 +08:00
    动态裁剪+缓存。这样不用所有图都进行裁剪存储,然后缓存可以设置有效期。过期自动删除缓存,这样磁盘利用率就可以提高很多了
    mko0okmko0
        8
    mko0okmko0  
       2016-12-31 00:58:23 +08:00   ❤️ 3
    如果是 JPG 就可以用贱招.
    首先你只要存原始尺寸图片.但一定要是 JPG 渐进式格式.存档品质不要超过 85 比较好.这个 php 本身就有支援.
    然后重点.输出的时候用串流输出. 意思就是 php 读取图片用串流(BYTE)的.不要解读图片
    然后 php 控制输出也是串流的.但输出多少要自己控制.
    例如你只要 4 分之 1 的大小=长宽减半的大小.
    你就先取得整个档案的大小.计算 4 分之一的档案长度.
    然后串流输出的时候.到达 4 分之 1 的输出后.直接截断.关闭串流.
    用户端需要稍微用 html 控制一下.直接指定显示的长宽.
    因为实际上你输出的还是原始尺寸.
    而对方收到的图片清晰度却没有达到全部.但一定超过 4 分之一的需求.
    所以看不出有问题.但计算消耗只有第一次的存档.输出频宽消耗也只有 4 分之 1.
    验证方法是随便产出一些 渐进式品质 75~85 的 JPG 图片.直接用档案切割软体或是 16 进制的编辑软体截断档案.
    然后将截断的前面用看图软体打开.
    用 4 分之一大小看基本上没问题.但用原始尺寸看就可以看到破损.
    有研究 JPEG 格式就知道.渐进式的话.他有一个一个的段落.每个段落都会让图片慢慢清晰.而且后面的不存在也没关系.只是解码会终止.但可以正常显示前面.
    如果有搭配 imagemagick 或类似的软体存档.可以给他更多参数.

    例如黑白灰(YUV 的亮度 Y)正确性比彩色(UV 部分)重要.下参数让 Y 全部在前然后才是 UV.
    他就会变成 YYYYUUUUVVVV(第一层.最模糊) YYYYUUUUVVVV (第 2 层某一块.是第 1 层的局部补正) YYYYUUUUVVVV (第 2 层某一块.是第一层的局部补正) YYYYUUUUVVVV (第 3 层某一块.是第 2 层的局部补正) YYYYUUUUVVVV (第 3 层某一块.是第 2 层的局部补正) .....直到最后一层.

    如过颜色比较重要那就下参数让 YUV 混合.就变成 YUVYUVYUVYUV(第 1 层) YUVYUVYUVYUVYUVYUVYUVYUV(第 2 层)....以此类推.

    每一层有几块是编码器决定的.而且还分算数二进算法或是金字塔算法.所以不好计算你要的尺寸要切到哪一层.干脆直接截断.
    金字塔算法是预设的因为效率更高但较复杂难预测. 算数二进比较简单.可预测但档案较大.

    以上就是不换设备但有高解析度到低解析度需求的解决方案.
    缺点是用户很喜欢你的图片存下来看原图他会翻白眼.因为截断的瑕疵就会露出来.
    这里的补充解法是. 图片旁边写 JS 下载语法.
    参考范例(繁)
    http://www.ladesign.tw/paper/info/jquery_html2canvas_download
    他是按照标签产图.你就选图片的那个标签名称就可以.他会产生"用户看见"的大小的图片.
    等于是用户浏览器自己重新编码一个图片了.大小比用户看见的小一些(我也不懂原因哈哈哈).
    但是不会有破图瑕疵.

    以上是我的自建图床解.
    mko0okmko0
        9
    mko0okmko0  
       2016-12-31 01:06:05 +08:00
    补充 JPEG 格式
    https://zh.wikipedia.org/zh-cn/JPEG
    YUV
    https://zh.wikipedia.org/zh-cn/YUV

    建议参数是
    Q75~85.
    YUV420(颜色解析度较低.预设值) 或是 YUV444(颜色解析度跟 Y 一样)
    float(慢速编码但品质优). 如果 CPU 不够力用 int(预设的整数编码)
    YYYYUUUUVVVV.(每层的黑白灰优先).
    fhefh
        10
    fhefh  
       2016-12-31 10:51:10 +08:00
    nice 先 mark
    lecher
        11
    lecher  
       2016-12-31 21:36:30 +08:00 via Android   ❤️ 1
    如果没有高并发的压力,可以先不考虑这个问题,图像处理极其耗费 CPU 资源,纯靠堆机器解决,基本上做不了高并发方案。

    我遇到过的,调用网站验证码的功能,没有考虑到并发量的问题,在任何嵌入验证码需求的页面都直接把验证码生成接口嵌入在 IMG 标签中。导致无登录状态的用户在访问任何页面都请求一次验证码的接口,单台服务器 8 核 CPU 的情况下,日均 PV 到 400w 就在高峰期频繁出现 100%CPU 的情况了,后来改动了调用方式,只有确认用户主动点击登录之类的活动触发了验证码才会填充 URL 到 IMG 标签中。

    这只是一个 CPU 消耗比较小,在 100ms 内就能处理完的图像处理请求,如果是大图像裁剪,性能会更差,如果真的有访问量比较大的峰值,建议买硬盘扩容,硬盘的成本是最低的,可以靠堆硬盘解决的问题,不要心疼钱。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1046 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 32ms · UTC 20:05 · PVG 04:05 · LAX 12:05 · JFK 15:05
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.