热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

高并发图片(缩略图)处理中间层服务架构设计

互联网公司经常会有大量原始图片上传,而且一个原图会在页面以不同尺寸缩略图显示,一般有两种策略生成缩略图,一种在上传图片时,生成需要的多张不同缩略图,另一种是请求指定尺寸的图片时实时生存缩略图片,第一种

互联网公司经常会有大量原始图片上传,而且一个原图会在页面以不同尺寸缩略图显示,一般有两种策略生成缩略图,一种在上传图片时,生成需要的多张不同缩略图,另一种是请求指定尺寸的图片时实时生存缩略图片,第一种方式有一定限制,就是需要提前知道所有尺寸的图片,做雍余存储,无形中增加大量文件数量,如果文件系统设计不好,还有可能形成大量文件碎片,而且会消耗大量存储空间,如果前端ui设计改变了图片大小,需要重新生成。而第二种方式更加灵活,但是更消耗cpu资源,属于cpu密集计算型 

 

大吞吐量服务端架构设计要考虑四个技术点 

 

1 编程语言和编译优化

技术选型,是单进程多线程模型(reactor事件机制),还是多进程模型.

 

2 图片压缩算法

高效分布式文件存储系统选型。

Linux系统中sysctl参数优化(TCP高级选项设置)

编程语言和编译优化

互联网行业用java开发语言比较多,而且开发人员成熟,而且经验丰富。

高性能网络框架:netty,mina等等,而且资料比较,社区比较活跃。而且有大量内置的图像处理API和算法直接使用.对于jdk自带的一套图片处理库,他的特点是稳定简单,但是对图片处理来说,性能确实很差!离实际线上要求差距很大。不过java方面也提供了类似jni方式支持GraphicsMagick+im4java处理图像,但是要原生态支持openmpi,tbb,opencv等就比较繁琐了,要用jni方式调用大量动态或静态库。一个性能问题,二是如果出现内存问题也不好控制。

C语言:

1.有成熟图像处理库GraphicsMagick和opencv,

2.有可以很容易实现多进程模式。

3.容易用其他编译器做优化,比如用intelicc编译,可以大幅度提高性能。

4.多进程中每个进程方面绑定到每个cpu核上,实现操作系统每个cpu核上队列相同,均衡调度,更容易发挥目前多核cpu性能!

 

下面说一下单进程多线程模型

主线程负责侦听listen,注册accept和新进来连接,然后把连接socket转交给workthreadpool进行读写事件注册,计算逻辑处理

reactor事件机制:

Reactor释义“反应堆”,是一种事件驱动机制。和普通函数调用的不同之处在于:应用程序不是主动的调用某个API完成处理,而是恰恰相反,Reactor逆置了事件处理流程,应用程序需要提供相应的接口并注册到Reactor上,如果相应的时间发生,Reactor将主动调用应用程序注册的接口,这些接口又称为“回调函数”.

Reactor模式的优点

Reactor模式是编写高性能网络服务器的必备技术之一,它具有如下的优点:1)响应快,不必为单个同步时间所阻塞,虽然Reactor本身依然是同步的;2)编程相对简单,可以最大程度的避免复杂的多线程及同步问题,并且避免了多线程/进程的切换开销;3)可扩展性,可以方便的通过增加Reactor实例个数来充分利用CPU资源;4)可复用性,reactor框架本身与具体事件处理逻辑无关,具有很高的复用性;

 

3 多进程服务器

1每个进程处理多个connection,使用epoll事件驱动来管理这些连接,多个worker进程之间是对等的,他们同等竞争来自客户端的请求,各进程互相之间是独立的。

2master由信号驱动,worker由epoll驱动(当然信号会让epoll_wait返回),有更好的容错性,如果其中一个进程挂了或产生core,master收到相关信号后,会同时重启一个进程,并同时发送出相关监控信息,也不会导致不能提供服务,。

3多进程用来利用多CPU硬件,所以按照业务边界来划分进程,或者就按CPU个数配置。

4每个进程是单线程的:所有IO相关操作都是全异步处理方式,避免多线程切换和锁机制开销。

5进程之间抢占epoll资源时,仅用一个轻量级的共享内存锁,循环依次把连接事件放入队列,然后循环处理每个客户端的连接请求和逻辑处理。

6高性能:服务器若支持多CPU或超线程,多线程无法完全利用机器性能,多进程则可以让服务器满载.

 

4 图片压缩算法(jpeg,png,gif)

目前图像压缩算法已经成型,而且基本上都是搞数学方面的大牛发明的,

关于图像处理方面可以参考如下:

图片压缩或处理是一个非常消耗cpu的操作计算量非常大,因为要进行大量矩阵,傅立叶变换、沃尔什变换、离散余弦变换,图像噪声处理等变换或计算.目前高性能图像处理开源软件有2种GraphicsMagick和opecv。

GraphicsMagick:

GraphicsMagick号称图像处理领域的瑞士军刀。短小精悍的代码却提供了一个鲁棒、高效的工具和库集合,来处理图像的读取、写入和操作,支持超过88种图像格式,包括重要的DPX、GIF、JPEG、JPEG-2000、PNG、PDF、PNM和TIFF等等。

通过使用OpenMP可是利用多线程进行图片处理,增强了通过扩展CPU提高处理能力。

注意:但是GraphicsMagick启动多线程时,处理速度虽然加快了,但是cpu确大幅飙升。

Opencv:

OpenCV于1999年由Intel建立,如今由WillowGarage提供支持。OpenCV是一个基于[1](开源)发行的跨平台计算机视觉库,可以运行在Linux、Windows和MacOS操作系统上。它轻量级而且高效——由一系列C函数和少量C++类构成,同时提供了Python、Ruby、MATLAB等语言的接口,实现了图像处理和计算机视觉方面的很多通用算法。[2]最新版本是2.4.5。

OpenCV拥有包括300多个C函数的跨平台的中、高层API。它不依赖于其它的外部库——尽管也可以使用某些外部库。

注意:opencv目前支持jpeg,tiff,png,但是由于版权和法律方面原因不支持gif图像处理,png只是有限支持,图像压缩时会变形或变模糊。

GraphicsMagick与Opencv比较优缺点:

GraphicsMagick支持图像多,覆盖面全,几乎所有常见图像格式.压缩质量高

Opencv支持有限的图像处理,覆盖面不全,经过大量压力测试综合比较,但是压缩性能确比GraphicsMagick快一倍多。

综合两者的优点:需要把两者结合起来混合处理不同图像,以达到图像处理最佳性能。

 

5 高效分布式文件存储系统选型

互联网图片文件存储,一般考虑带宽,存储空间方面压力,经过压缩大小不会2MB。因此存储方案就有多种选择,既可以选择传统mysql数据库,也可以用成熟的分布式文件系统.下面就来说说他们的不同和优缺点。

用mysql做存储:

1.互联网公司都用mysql的丰富经验,技术成熟,众多人都会用mysql,而且还有专业的DBA团队来维护。

2.Mysq性能稳定,单台机器加上内存,基本能满足QPS性能要求。

3.存储图片的表结构属性少,结构简单,一般访问时只需要查询主键就可以了,不需求简历额外的索引。

4.去中心化设计,两台服务器为一组,双写随机读(任意一台服务器),服务器为raid5模式。

5.系统扩容,每当当前服务器存储空间不足,需要增加服务器扩容时,都需要成倍增加服务器数量.

 

6 用分布式文件做存储

1.一般是直接使用成熟开源产品或自主研发,使用开源产品,开发成本低,学习成本高,需要专门花费一些进行研究或学习。还要自己来维护。自主研发,时间周期长,投入成本更高,但可控性更强。能进行大量性能优化和调整,或许能节省一些服务器资源。

2.同等条件下分布式文件系统性能一般会比mysql等关系型数据库高3-5倍,因为它不需求进行B+Tree(时间复杂度)分页查找,文件在上传时,其生成的文件名就包含了大量文件具体位置信息,一般o(1)时间就能准备定位。而且是顺序一次性读取。不想B+Tree按页式存储,可能要多次读取多页数据,而且每条记录需求存储额外信息,进行事物回滚处理,比较浪费存储空间。

3.中心化设计(一般为metaserver和dataserver两类服务器组集群),两或三台服务器为一组,双写随机读(任意一台服务器),可以不用raid5模式。

4.系统扩容,每当当前服务器存储空间不足,可以轻易做到线性扩展,只需要增加一组服务器就可以了。明显在成本上具有优势。

Linux系统中sysctl参数优化(TCP高级选项设置)

服务器在高并发时,会创建大量连接,这就需要设置TCP相关参数来提供服务器性能。

1.文件描述符最大数调整。

修改vi/etc/security/limits.conf值

在里面添加一行

*-nofile65535

保存重启,再用命令ulimit-n可发现文件描述符由默认变成65535了

2.高负载linux服务器的内核调优

vi/etc/sysctl.conf,修改内核参数:

kernel.shmall=268435456

net.ipv4.tcp_synCOOKIEs=1

net.ipv4.tcp_tw_reuse=1

net.ipv4.tcp_tw_recycle=1

net.ipv4.tcp_fin_timeout=30

net.ipv4.tcp_keepalive_time=1200

net.ipv4.ip_local_port_range=102465000

net.ipv4.tcp_max_tw_buckets=5000

net.ipv4.tcp_max_tw_buckets=5000

net.ipv4.tcp_fin_timeout=30

net.ipv4.tcp_keepalive_time=300

net.ipv4.tcp_synCOOKIEs=1

net.ipv4.tcp_tw_reuse=1

net.ipv4.tcp_tw_recycle=1

net.ipv4.ip_local_port_range=500065000

net.ipv4.tcp_mem=78643210485761572864

net.core.wmem_max=873200

net.core.rmem_max=873200

net.ipv4.tcp_wmem=8192436600873200

net.ipv4.tcp_rmem=32768436600873200

net.core.somaxcOnn=256

net.core.netdev_max_backlog=1000

net.ipv4.tcp_max_syn_backlog=2048

net.ipv4.tcp_retries2=5

net.ipv4.tcp_keepalive_time=500

net.ipv4.tcp_keepalive_intvl=30

net.ipv4.tcp_keepalive_probes=3

net.ipv4.conf.lo.arp_ignore=0

net.ipv4.conf.lo.arp_announce=0

net.ipv4.conf.all.arp_ignore=0

net.ipv4.conf.all.arp_announce=0

3.参数说明:net.ipv4.tcp_synCOOKIEs=1

#表示开启SYNCOOKIEs。当出现SYN等待队列溢出时,启用COOKIEs来处理,可防范少量SYN攻击,默认为0,表示关闭;

net.ipv4.tcp_tw_reuse=1

#表示开启重用。允许将TIME-WAITsockets重新用于新的TCP连接,默认为0,表示关闭;

net.ipv4.tcp_tw_recycle=1

#表示开启TCP连接中TIME-WAITsockets的快速回收,默认为0,表示关闭。

net.ipv4.tcp_fin_timeout=30

#表示如果套接字由本端要求关闭,这个参数决定了它保持在FIN-WAIT-2状态的时间。

net.ipv4.tcp_keepalive_time=1200

#表示当keepalive起用的时候,TCP发送keepalive消息的频度。缺省是2小时,改为20分钟。

net.ipv4.ip_local_port_range=102465000

#表示用于向外连接的端口范围。缺省情况下很小:32768到61000,改为1024到65000。

net.ipv4.tcp_max_tw_buckets=5000

#表示系统同时保持TIME_WAIT套接字的最大数量,如果超过这个数字,

#TIME_WAIT套接字将立刻被清除并打印警告信息。默认为180000,改为5000。

 

 

7 架构

整体架构如下:

高并发图片(缩略图)处理中间层服务架构设计,by 5lulu.com

可以看到,笔者采用了通用的分层架构设计模式。

  • file storage存放着原始的图片数据。
  • image server用于图片的处理,同时进行图片的cache。
  • nginx作为统一的入口,同时也作为cache。

当用户请求一张图片的缩略图的时候,如果该图片不存在于nginx的缓存中,则nginx根据图片的fileid 通过consistent hash路由到对应的image server上面去处理,如果image server仍然没有该图片,则会从file storage下载。

分层架构有一个很好的地方在于系统的可扩展性,同时我们也可以在加入一些中间层,提高cache的命中率,譬如我们就可以在image server与nginx之间引入一个cache层。不过鉴于我们的系统主要用于企业内部,不会出现图片数据量过大的情况,所以上面这套分层设计已经足够了。

nginx try_files

如果本地cache不存在,则去后台服务器取数据。对于这套逻辑,nginx可以通过try_files很好的处理,譬如:

location /abc.png {
    root /data/image/;
    try_files $uri @fetch;
}

location @fetch {
    proxy_pass http://up_imageserver$request_uri;
}

首先try_files会尝试在本地获取对应的文件,如果没有找到,则会内部跳转到fetch这个location去远程获取数据。

 

8 何时处理缩略图

既然是缩略图,那么何时生成缩略图就是需要考虑的问题了。通常来说,缩略图的生成会有两种方式:

  • 上传生成

    当用户上传一张图片之后,系统自动为该图片生成对应的固定格式缩略图,然后将原图与缩略图一起存放到file storage里面去。这方面主要有facebook的Haystack系统。

  • 实时生成

    当用户上传一张图片之后,只保留该图片的原始数据,当请求该图的缩略图时,如果cache中不存在,由image server动态生成。这方面可以参考淘宝的图片存储介绍。

对于笔者来说,实际使用的是第二种方法,主要有以下几个原因的考量:

  • 对于实时生成的缩略图我们可以灵活的指定其大小,而不像上传生成那样只有预先定义的width和height。
  • 存储成本,额外存储缩略图会占用很大的存储空间,而且存放到file storage里面还会有冗余备份的问题,更加浪费。
  • 协同图片的冷热性问题,最近最热的图片铁定是最频繁访问的,尤其是在多人协同情况下面,而这些图片缩略图是有缓存的,不需要每次都通过原图生成,性能有保证。

 

9 如何处理缩略图

既然选择实时生成缩略图,那么如何快速生成缩略图就是笔者需要考虑的问题了。这里笔者使用graphicsmagick来生成缩略图,网上有太多介绍,这里不再累述。

 

10 安全

生成缩略图之后,如何保证该图片的安全访问也是一个需要关注的问题。笔者考虑了如下解决方案:

  • 签名,任何缩略图的url都是经过签名,因为签名是通过登陆用户自身的access id和security key进行的,并且有时效性,所以外界很难伪造。或者,可以使用简单的HttpAccessKeyModule来进行访问控制。

  • nginx HttpRefererModule,只允许特定domain的请求访问。

 

11 存储

对于如何存储大量的图片小文件,笔者觉得可以如下考虑:

  • 对于文件最终存放的file storage,业界有很多好的分布式解决方案,譬如TFS,mogilefs等,如果想自己造一个轮子,也很不错。
  • 对于图片的cache,因为cache的存储文件量级我们是可以控制的,所以这里可以考虑直接使用通常的文件系统存储。

    但需要注意的是,单个目录下面文件数量不能过多,目录的层次也不能过深,不然会导致很严重的性能瓶颈。为了解决上述问题,笔者建立了三层目录结构,首层100个文件夹,以1 - 100命名,每个文件夹下面1000个文件夹,以1 - 1000命名,对于任意的图片文件,根据其实际的文件名通过两次hash到特定的目录下。

高并发图片(缩略图)处理中间层服务架构设计

本文链接 http://tec.5lulu.com/detail/105k2n1e6z65g8s6c.html


推荐阅读
  • 本文介绍了Python高级网络编程及TCP/IP协议簇的OSI七层模型。首先简单介绍了七层模型的各层及其封装解封装过程。然后讨论了程序开发中涉及到的网络通信内容,主要包括TCP协议、UDP协议和IPV4协议。最后还介绍了socket编程、聊天socket实现、远程执行命令、上传文件、socketserver及其源码分析等相关内容。 ... [详细]
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • 本文介绍了在Python3中如何使用选择文件对话框的格式打开和保存图片的方法。通过使用tkinter库中的filedialog模块的asksaveasfilename和askopenfilename函数,可以方便地选择要打开或保存的图片文件,并进行相关操作。具体的代码示例和操作步骤也被提供。 ... [详细]
  • Android中高级面试必知必会,积累总结
    本文介绍了Android中高级面试的必知必会内容,并总结了相关经验。文章指出,如今的Android市场对开发人员的要求更高,需要更专业的人才。同时,文章还给出了针对Android岗位的职责和要求,并提供了简历突出的建议。 ... [详细]
  • [译]技术公司十年经验的职场生涯回顾
    本文是一位在技术公司工作十年的职场人士对自己职业生涯的总结回顾。她的职业规划与众不同,令人深思又有趣。其中涉及到的内容有机器学习、创新创业以及引用了女性主义者在TED演讲中的部分讲义。文章表达了对职业生涯的愿望和希望,认为人类有能力不断改善自己。 ... [详细]
  • 本文详细介绍了Linux中进程控制块PCBtask_struct结构体的结构和作用,包括进程状态、进程号、待处理信号、进程地址空间、调度标志、锁深度、基本时间片、调度策略以及内存管理信息等方面的内容。阅读本文可以更加深入地了解Linux进程管理的原理和机制。 ... [详细]
  • 本文讨论了在手机移动端如何使用HTML5和JavaScript实现视频上传并压缩视频质量,或者降低手机摄像头拍摄质量的问题。作者指出HTML5和JavaScript无法直接压缩视频,只能通过将视频传送到服务器端由后端进行压缩。对于控制相机拍摄质量,只有使用JAVA编写Android客户端才能实现压缩。此外,作者还解释了在交作业时使用zip格式压缩包导致CSS文件和图片音乐丢失的原因,并提供了解决方法。最后,作者还介绍了一个用于处理图片的类,可以实现图片剪裁处理和生成缩略图的功能。 ... [详细]
  • 第四章高阶函数(参数传递、高阶函数、lambda表达式)(python进阶)的讲解和应用
    本文主要讲解了第四章高阶函数(参数传递、高阶函数、lambda表达式)的相关知识,包括函数参数传递机制和赋值机制、引用传递的概念和应用、默认参数的定义和使用等内容。同时介绍了高阶函数和lambda表达式的概念,并给出了一些实例代码进行演示。对于想要进一步提升python编程能力的读者来说,本文将是一个不错的学习资料。 ... [详细]
  • Android工程师面试准备及设计模式使用场景
    本文介绍了Android工程师面试准备的经验,包括面试流程和重点准备内容。同时,还介绍了建造者模式的使用场景,以及在Android开发中的具体应用。 ... [详细]
  • Linux的uucico命令使用方法及工作模式介绍
    本文介绍了Linux的uucico命令的使用方法和工作模式,包括主动模式和附属模式。uucico是用来处理uucp或uux送到队列的文件传输工具,具有操作简单快捷、实用性强的特点。文章还介绍了uucico命令的参数及其说明,包括-c或--quiet、-C或--ifwork、-D或--nodetach、-e或--loop、-f或--force、-i或--stdin、-I--config、-l或--prompt等。通过本文的学习,读者可以更好地掌握Linux的uucico命令的使用方法。 ... [详细]
  • 本文介绍了操作系统的定义和功能,包括操作系统的本质、用户界面以及系统调用的分类。同时还介绍了进程和线程的区别,包括进程和线程的定义和作用。 ... [详细]
  • Linux服务器密码过期策略、登录次数限制、私钥登录等配置方法
    本文介绍了在Linux服务器上进行密码过期策略、登录次数限制、私钥登录等配置的方法。通过修改配置文件中的参数,可以设置密码的有效期、最小间隔时间、最小长度,并在密码过期前进行提示。同时还介绍了如何进行公钥登录和修改默认账户用户名的操作。详细步骤和注意事项可参考本文内容。 ... [详细]
  • 基于layUI的图片上传前预览功能的2种实现方式
    本文介绍了基于layUI的图片上传前预览功能的两种实现方式:一种是使用blob+FileReader,另一种是使用layUI自带的参数。通过选择文件后点击文件名,在页面中间弹窗内预览图片。其中,layUI自带的参数实现了图片预览功能。该功能依赖于layUI的上传模块,并使用了blob和FileReader来读取本地文件并获取图像的base64编码。点击文件名时会执行See()函数。摘要长度为169字。 ... [详细]
  • Oracle优化新常态的五大禁止及其性能隐患
    本文介绍了Oracle优化新常态中的五大禁止措施,包括禁止外键、禁止视图、禁止触发器、禁止存储过程和禁止JOB,并分析了这些禁止措施可能带来的性能隐患。文章还讨论了这些禁止措施在C/S架构和B/S架构中的不同应用情况,并提出了解决方案。 ... [详细]
author-avatar
Z-RZI
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有