IM开发基础知识补课(二):如何设计大量图片文件的服务端存储架构?

简介: 友情提示:正文内容整理自架构师丁浪的技术分享,部分观点可作抛砖引玉之用,可能并非最佳实践,欢迎留言指正。1、前言一个完善的IM系统中通常充斥着大量的图片内容,包括:用户头像、图片消息、相册、图片表情等等,那么在做服务端架构设计时该如何存储这些图片呢?本文分享的是典型Web应用中大量图片的服务端存储加构的演进过程,但基本的技术原理和架构思路对于IM系统而言同样适用,所以在阅读时可以根据自已IM的实际架构情况,酌情吸取适合您的内容即可。

友情提示:正文内容整理自架构师丁浪的技术分享,部分观点可作抛砖引玉之用,可能并非最佳实践,欢迎留言指正。

1、前言

一个完善的IM系统中通常充斥着大量的图片内容,包括:用户头像、图片消息、相册、图片表情等等,那么在做服务端架构设计时该如何存储这些图片呢?

本文分享的是典型Web应用中大量图片的服务端存储加构的演进过程,但基本的技术原理和架构思路对于IM系统而言同样适用,所以在阅读时可以根据自已IM的实际架构情况,酌情吸取适合您的内容即可。文中部分观点可作抛砖引玉之用,可能并非最佳实践,请勿迷信之。

实际上:旧式的PC端IM中,诸如图片消息这种业务形态,可能是通过长连接直接推送过去(所谓的实时图片传输嘛),这种情况理论上是不需要服务端存储的。但现今的主流移动端IM,基于移动网络抖动大、 不稳定的特性和随时随地社交分享的现实,已很少使用实时传输这种技术手段。现在主流IM都是本文所述的这种:通过Http短连接从云(也就是服务端)“拉取”,这种方式的好处是:随时随地分享、对网络稳定性要求低(只要上传者一次上传,服务端可长时间存储,下一个阅读者通过URL按需随读随取即可,再次分享时只要分享URL而无需再次完整传输整个图片)。

以此类推:IM系统中,实际上还存在其它类似于图片的小文件存储需求,比如:语音留言消息中的AMR短音频文件(有些IM中为了音质可能使用的是AAC音频格式,比如易信)、短视频功能中的小视频文件等,这些文件的存储和使用跟图片文件基本类似,所以考虑到通用性,如果能把这些小文件存储也纳入到图片的存储架构中,对于整体系统架构来说(尤其存储部分)就显的更通用。所以本文中虽然以图片存储为切入点,但您实际上完全可以套用到基它小文件的存储上哦。

学习交流:

- 即时通讯开发交流群:320837163[推荐]

- 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端IM

(本文同步发布于:http://www.52im.net/thread-1356-1-1.html

2、相关文章

▼ 跟IM数据存储架构有关的文章,有如下几篇,或许对你有用:

腾讯原创分享(一):如何大幅提升移动网络下手机QQ的图片传输速度和成功率

微信海量用户背后的后台系统存储架构(视频+PPT) [附件下载]

微信后台基于时间序的海量数据冷热分级架构设计实践

现代IM系统中聊天消息的同步和存储方案探讨

▼ IM开发干货系列文章适合作为IM开发热点问题参考资料(本文是其第11篇):

IM消息送达保证机制实现(一):保证在线实时消息的可靠投递

IM消息送达保证机制实现(二):保证离线消息的可靠投递

如何保证IM实时消息的“时序性”与“一致性”?

IM单聊和群聊中的在线状态同步应该用“推”还是“拉”?

IM群聊消息如此复杂,如何保证不丢不重?

一种Android端IM智能心跳算法的设计与实现探讨(含样例代码)

移动端IM登录时拉取数据如何作到省流量?

通俗易懂:基于集群的移动端IM接入层负载均衡方案分享

浅谈移动端IM的多点登陆和消息漫游原理

IM开发基础知识补课(一):正确理解前置HTTP SSO单点登陆接口的原理

IM开发基础知识补课(二):如何设计大量图片文件的服务端存储架构?》(本文)

如果您是IM开发初学者,强烈建议首先阅读《新手入门一篇就够:从零开发移动端IM》。

3、单机时代的图片服务器架构(集中式)

初创时期由于时间紧迫,开发人员水平很有限。

所以通常就直接在website文件所在的目录下,建立1个upload子目录,用于保存用户上传的图片文件:

[1] 如果按业务再细分,可以在upload目录下再建立不同的子目录来区分,例如:upload\QA,upload\Face等

[2] 在数据库表中保存的也是“upload/qa/test.jpg”这类相对路径;

[3] 用户的访问方式如下:http://www.yourdomain.com/upload/qa/test.jpg

程序上传和写入方式:

程序员A通过在web.config中配置物理目录D:\Web\yourdomain\upload  然后通过stream的方式写入文件;

程序员B通过Server.MapPath等方式,根据相对路径获取物理目录  然后也通过stream的方式写入文件。

结果就是:

优点:实现起来最简单,无需任何复杂技术,就能成功将用户上传的文件写入指定目录。保存数据库记录和访问起来倒是也很方便;

缺点:上传方式混乱,严重不利于网站的扩展。

针对上述最原始的架构,主要面临着如下问题:

随着upload目录中文件越来越多,所在分区如果出现容量不足,则很难扩容。只能停机后更换更大容量的存储设备,再将旧数据导入;

在部署新版本(部署新版本前通过需要备份)和日常备份website文件的时候,需要同时操作upload目录中的文件,如果考虑到访问量上升,后边部署由多台Web服务器组成的负载均衡集群,集群节点之间如果做好文件实时同步将是个难题。

4、集群时代的图片服务器架构(实时同步)

一个传统的Web服务端站点下面,新建一个名为upload的虚拟目录,由于虚拟目录的灵活性,能在一定程度上取代物理目录,并兼容原有的图片上传和访问方式。

用户的访问方式依然是:

http://www.yourdomain.com/upload/qa/test.jpg

优点:配置更加灵活,也能兼容老版本的上传和访问方式。因为虚拟目录,可以指向本地任意盘符下的任意目录。这样一来,还可以通过接入外置存储,来进行单机的容量扩展。

缺点:部署成由多台Web服务器组成的集群,各个Web服务器(集群节点)之间(虚拟目录下的)需要实时的去同步文件,由于同步效率和实时性的限制,很难保证某一时刻各节点上文件是完全一致的。

基本架构如下图所示:

从上图可看出,整个Web服务器架构已经具备“可扩展、高可用”了,主要问题和瓶颈都集中在多台服务器之间的文件同步上。

上述架构中只能在这几台Web服务器上互相“增量同步”,这样一来,就不支持文件的“删除、更新”操作的同步了。

早期的想法是,在应用程序层面做控制,当用户请求在web1服务器进行上传写入的同时,也同步去调用其它web服务器上的上传接口,这显然是得不偿失的。所以我们选择使用Rsync类的软件来做定时文件同步的,从而省去了“重复造轮子”的成本,也降低了风险性。

同步操作里面,一般有比较经典的两种模型,即推拉模型:所谓“拉”,就是指轮询地去获取更新,所谓推,就是发生更改后主动的“推”给其它机器。当然,也可以采用加高级的事件通知机制来完成此类动作。

在高并发写入的场景中,同步都会出现效率和实时性问题,而且大量文件同步也是很消耗系统和带宽资源的(跨网段则更明显)。  

5、集群时代的图片服务器架构改进(共享存储)

沿用虚拟目录的方式,通过UNC(网络路径)的方式实现共享存储(将upload虚拟目录指向UNC)。

用户的访问方式1:

http://www.yourdomain.com/upload/qa/test.jpg

用户的访问方式2(可以配置独立域名):

http://img.yourdomain.com/upload/qa/test.jpg

支持UNC所在server上配置独立域名指向,并配置轻量级的web服务器,来实现独立图片服务器。

优点: 通过UNC(网络路径)的方式来进行读写操作,可以避免多服务器之间同步相关的问题。相对来讲很灵活,也支持扩容/扩展。支持配置成独立图片服务器和域名访问,也完整兼容旧版本的访问规则。   

缺点:但是UNC配置有些繁琐,而且会造成一定的(读写和安全)性能损失。可能会出现“单点故障”。如果存储级别没有raid或者更高级的灾备措施,还会造成数据丢失。

基本架构如下图所示:

在早期的很多基于Linux开源架构的网站中,如果不想同步图片,可能会利用NFS来实现。事实证明,NFS在高并发读写和海量存储方面,效率上存在一定问题,并非最佳的选择,所以大部分互联网公司都不会使用NFS来实现此类应用。当然,也可以通过Windows自带的DFS来实现,缺点是“配置复杂,效率未知,而且缺乏资料大量的实际案例”。另外,也有一些公司采用FTP或Samba来实现。

上面提到的几种架构,在上传/下载操作时,都经过了Web服务器(虽然共享存储的这种架构,也可以配置独立域名和站点来提供图片访问,但上传写入仍然得经过Web服务器上的应用程序来处理),这对Web服务器来讲无疑是造成巨大的压力。所以,更建议使用独立的图片服务器和独立的域名,来提供用户图片的上传和访问。

6、独立图片服务器/独立域名的好处

图片访问是很消耗服务器资源的(因为会涉及到操作系统的上下文切换和磁盘I/O操作)。分离出来后,Web/App服务器可以更专注发挥动态处理的能力。

独立存储,更方便做扩容、容灾和数据迁移;

浏览器(相同域名下的)并发策略限制,性能损失;

访问图片时,请求信息中总带cookie信息,也会造成性能损失;

方便做图片访问请求的负载均衡,方便应用各种缓存策略(HTTP Header、Proxy Cache等),也更加方便迁移到CDN;

......

我们可以使用Lighttpd或者Nginx等轻量级的web服务器来架构独立图片服务器。

7、我们当前的图片服务器架构

当前图片服务器架构采用分布式文件系统+CDN。

在构建当前的图片服务器架构之前,可以先彻底撇开web服务器,直接配置单独的图片服务器/域名。

但面临如下的问题:

旧图片数据怎么办?能否继续兼容旧图片路径访问规则?

独立的图片服务器上需要提供单独的上传写入的接口(服务API对外发布),安全问题如何保证?

同理,假如有多台独立图片服务器,是使用可扩展的共享存储方案,还是采用实时同步机制?

直到应用级别的(非系统级) DFS(例如FastDFS HDFS MogileFs MooseFS、TFS)的流行,简化了这个问题:执行冗余备份、支持自动同步、支持线性扩展、支持主流语言的客户端api上传/下载/删除等操作,部分支持文件索引,部分支持提供Web的方式来访问。

考虑到各DFS的特点,客户端API语言支持情况(需要支持C#),文档和案例,以及社区的支持度,我们最终选择了FastDFS来部署。

唯一的问题是:可能会不兼容旧版本的访问规则。如果将旧图片一次性导入FastDFS,但由于旧图片访问路径分布存储在不同业务数据库的各个表中,整体更新起来也十分困难,所以必须得兼容旧版本的访问规则。架构升级往往比做全新架构更有难度,就是因为还要兼容之前版本的问题。(给飞机在空中换引擎可比造架飞机难得多)

解决方案如下:

首先,关闭旧版本上传入口(避免继续使用导致数据不一致)。将旧图片数据通过rsync工具一次性迁移到独立的图片服务器上(即下图中描述的Old Image Server)。在最前端(七层代理,如Haproxy、Nginx)用ACL(访问规则控制),将旧图片对应URL规则的请求(正则)匹配到,然后将请求直接转发指定的web 服务器列表,在该列表中的服务器上配置好提供图片(以Web方式)访问的站点,并加入缓存策略。这样实现旧图片服务器的分离和缓存,兼容了旧图片的访问规则并提升旧图片访问效率,也避免了实时同步所带来的问题。

整体架构如图:

8、使用第3方CDN的方案

基于FastDFS的独立图片服务器集群架构,虽然已经非常的成熟,但是由于国内“南北互联”和IDC带宽成本等问题(图片是非常消耗流量的),我们最终还是选择了商用的CDN技术,实现起来也非常容易,原理其实也很简单,我这里只做个简单的介绍。

将img域名cname到CDN厂商指定的域名上,用户请求访问图片时,则由CDN厂商提供智能DNS解析,将最近的(当然也可能有其它更复杂的策略,例如负载情况、健康状态等)服务节点地址返回给用户,用户请求到达指定的服务器节点上,该节点上提供了类似Squid/Vanish的代理缓存服务,如果是第一次请求该路径,则会从源站获取图片资源返回客户端浏览器,如果缓存中存在,则直接从缓存中获取并返回给客户端浏览器,完成请求/响应过程。

由于采用了商用CDN服务,所以我们并没有考虑用Squid/Vanish来自行构建前置代理缓存。

上面的整个集群架构,可以很方便的做横向扩展,能满足一般垂直领域中大型网站的图片服务需求(当然,像taobao这样超大规模的可能另当别论)。经测试,提供图片访问的单台Nginx服务器(至强E5四核CPU、16G内存、SSD),对小静态页面(压缩后大概只有10kb左右的)可以扛住几千个并发且毫无压力。当然,由于图片本身体积比纯文本的静态页面大很多,提供图片访问的服务器的抗并发能力,往往会受限于磁盘的I/O处理能力和IDC提供的带宽。Nginx的抗并发能力还是非常强的,而且对资源占用很低,尤其是处理静态资源,似乎都不需要有过多担心了。可以根据实际访问量的需求,通过调整Nginx的参数,对Linux内核做调优,加入分级缓存策略等手段能够做更大程度的优化,也可以通过增加服务器或者升级服务器配置来做扩展,最直接的是通过购买更高级的存储设备和更大的带宽,以满足更大访问量的需求。

值得一提的是,在“云计算”流行的当下,也推荐高速发展期间的网站,使用“云存储”这样的方案,既能帮你解决各类存储、扩展、备灾的问题,又能做好CDN加速。最重要的是,价格也不贵。

总结,有关图片服务器架构扩展,大致围绕这些问题展开:

容量规划和扩展问题;

数据的同步、冗余和容灾;

硬件设备的成本和可靠性(是普通机械硬盘,还是SSD,或者更高端的存储设备和方案);

文件系统的选择。根据文件特性(例如文件大小、读写比例等)选择是用ext3/4或者NFS/GFS/TFS这些开源的(分布式)文件系统;

图片的加速访问。采用商用CDN或者自建的代理缓存、web静态缓存架构;

旧图片路径和访问规则的兼容性,应用程序层面的可扩展,上传和访问的性能和安全性等。

附录:更多IM开发文章

[1] 有关IM架构设计:

浅谈IM系统的架构设计

简述移动端IM开发的那些坑:架构设计、通信协议和客户端

一套海量在线用户的移动端IM架构设计实践分享(含详细图文)

一套原创分布式即时通讯(IM)系统理论架构方案

从零到卓越:京东客服即时通讯系统的技术架构演进历程

蘑菇街即时通讯/IM服务器开发之架构选择

腾讯QQ1.4亿在线用户的技术挑战和架构演进之路PPT

微信后台基于时间序的海量数据冷热分级架构设计实践

微信技术总监谈架构:微信之道——大道至简(演讲全文)

如何解读《微信技术总监谈架构:微信之道——大道至简》

快速裂变:见证微信强大后台架构从0到1的演进历程(一)

17年的实践:腾讯海量产品的技术方法论

移动端IM中大规模群消息的推送如何保证效率、实时性?

现代IM系统中聊天消息的同步和存储方案探讨

IM开发基础知识补课(二):如何设计大量图片文件的服务端存储架构?

>> 更多同类文章 ……

[2] 有关IM安全的文章:

即时通讯安全篇(一):正确地理解和使用Android端加密算法

即时通讯安全篇(二):探讨组合加密算法在IM中的应用

即时通讯安全篇(三):常用加解密算法与通讯安全讲解

即时通讯安全篇(四):实例分析Android中密钥硬编码的风险

即时通讯安全篇(五):对称加密技术在Android平台上的应用实践

即时通讯安全篇(六):非对称加密技术的原理与应用实践

传输层安全协议SSL/TLS的Java平台实现简介和Demo演示

理论联系实际:一套典型的IM通信协议设计详解(含安全层设计)

微信新一代通信安全解决方案:基于TLS1.3的MMTLS详解

来自阿里OpenIM:打造安全可靠即时通讯服务的技术实践分享

简述实时音视频聊天中端到端加密(E2EE)的工作原理

移动端安全通信的利器——端到端加密(E2EE)技术详解

Web端即时通讯安全:跨站点WebSocket劫持漏洞详解(含示例代码)

通俗易懂:一篇掌握即时通讯的消息传输安全原理

>> 更多同类文章 ……

[3] IM开发综合文章:

IM开发基础知识补课:正确理解前置HTTP SSO单点登陆接口的原理

移动端IM中大规模群消息的推送如何保证效率、实时性?

移动端IM开发需要面对的技术问题

开发IM是自己设计协议用字节流好还是字符流好?

请问有人知道语音留言聊天的主流实现方式吗?

IM消息送达保证机制实现(一):保证在线实时消息的可靠投递

IM消息送达保证机制实现(二):保证离线消息的可靠投递

如何保证IM实时消息的“时序性”与“一致性”?

一个低成本确保IM消息时序的方法探讨

IM单聊和群聊中的在线状态同步应该用“推”还是“拉”?

IM群聊消息如此复杂,如何保证不丢不重?

谈谈移动端 IM 开发中登录请求的优化

移动端IM登录时拉取数据如何作到省流量?

浅谈移动端IM的多点登陆和消息漫游原理

完全自已开发的IM该如何设计“失败重试”机制?

通俗易懂:基于集群的移动端IM接入层负载均衡方案分享

微信对网络影响的技术试验及分析(论文全文)

即时通讯系统的原理、技术和应用(技术论文)

开源IM工程“蘑菇街TeamTalk”的现状:一场有始无终的开源秀

QQ音乐团队分享:Android中的图片压缩技术详解(上篇)

QQ音乐团队分享:Android中的图片压缩技术详解(下篇)

腾讯原创分享(一):如何大幅提升移动网络下手机QQ的图片传输速度和成功率

腾讯原创分享(二):如何大幅压缩移动网络下APP的流量消耗(上篇)

腾讯原创分享(二):如何大幅压缩移动网络下APP的流量消耗(下篇)

如约而至:微信自用的移动端IM网络层跨平台组件库Mars已正式开源

基于社交网络的Yelp是如何实现海量用户图片的无损压缩的?

>> 更多同类文章 ……

(本文同步发布于:http://www.52im.net/thread-1356-1-1.html

目录
相关文章
|
17天前
|
API 数据库 开发者
构建高效可靠的微服务架构:后端开发的新范式
【4月更文挑战第8天】 随着现代软件开发的复杂性日益增加,传统的单体应用架构面临着可扩展性、维护性和敏捷性的挑战。为了解决这些问题,微服务架构应运而生,并迅速成为后端开发领域的一股清流。本文将深入探讨微服务架构的设计原则、实施策略及其带来的优势与挑战,为后端开发者提供一种全新视角,以实现更加灵活、高效和稳定的系统构建。
23 0
|
5天前
|
消息中间件 监控 持续交付
构建高效微服务架构:后端开发的进阶之路
【4月更文挑战第20天】 随着现代软件开发的复杂性日益增加,传统的单体应用已难以满足快速迭代和灵活部署的需求。微服务架构作为一种新兴的分布式系统设计方式,以其独立部署、易于扩展和维护的特点,成为解决这一问题的关键。本文将深入探讨微服务的核心概念、设计原则以及在后端开发实践中如何构建一个高效的微服务架构。我们将从服务划分、通信机制、数据一致性、服务发现与注册等方面入手,提供一系列实用的策略和建议,帮助开发者优化后端系统的性能和可维护性。
|
26天前
|
监控 Java 开发者
构建高效微服务架构:后端开发的新范式
在数字化转型的浪潮中,微服务架构以其灵活性、可扩展性和容错性成为企业技术战略的关键组成部分。本文深入探讨了微服务的核心概念,包括其设计原则、技术栈选择以及与容器化和编排技术的融合。通过实际案例分析,展示了如何利用微服务架构提升系统性能,实现快速迭代部署,并通过服务的解耦来提高整体系统的可靠性。
|
2天前
|
监控 API 持续交付
构建高效微服务架构:后端开发的新趋势
【4月更文挑战第23天】 随着现代软件开发实践的不断演进,微服务架构已经成为企业追求敏捷、可扩展和弹性解决方案的首选。本文深入探讨了如何构建一个高效的微服务架构,涵盖了关键的设计原则、技术选型以及实践建议。通过分析微服务的独立性、分布式特性和容错机制,我们将揭示如何利用容器化、服务网格和API网关等技术手段,来优化后端系统的可维护性和性能。文章旨在为后端开发人员提供一套全面的指南,以应对不断变化的业务需求和技术挑战。
|
7天前
|
监控 持续交付 开发者
构建高效微服务架构:后端开发的新趋势
【4月更文挑战第18天】在数字化转型的浪潮中,微服务架构已成为企业提升系统灵活性、加速产品迭代的关键。此文深入探讨了构建高效微服务架构的实践方法,包括服务划分原则、容器化部署、持续集成/持续部署(CI/CD)流程以及监控与日志管理等关键技术点。通过分析具体案例,揭示了微服务在提高开发效率、降低维护成本及促进团队协作方面的显著优势。
|
10天前
|
监控 负载均衡 API
构建高性能微服务架构:后端开发的最佳实践
【4月更文挑战第14天】 在当今快速发展的软件开发领域,微服务架构已成为构建可扩展、灵活且容错的系统的首选方法。本文深入探讨了后端开发人员在设计和维护高性能微服务时需要遵循的一系列最佳实践。我们将从服务划分原则、容器化部署、API网关使用、负载均衡、服务监控与故障恢复等方面展开讨论,并结合实际案例分析如何优化微服务性能及可靠性。通过本文的阅读,读者将获得实施高效微服务架构的实用知识与策略。
|
14天前
|
存储 算法 安全
微信团队分享:来看看微信十年前的IM消息收发架构,你做到了吗
好的架构是迭代出来的,却也少不了良好的设计,本文将带大家回顾微信背后最初的也是最核心的IM消息收发技术架构,愿各位读者能从中获得启发。
36 1
|
23天前
|
Kubernetes API 开发者
构建高效微服务架构:后端开发的新范式
在数字化转型的浪潮中,微服务架构已成为许多企业追求敏捷开发、持续交付和系统可维护性的关键解决方案。本文将深入探讨微服务架构的设计原则、技术选型以及实践案例,为后端开发者提供一套构建和维护微服务系统的实用指南。
|
3月前
|
自然语言处理 监控 数据可视化
海拍客与瓴羊达成合作,通过智能客服系统提升员工内部服务体验
海拍客与瓴羊达成合作,通过智能客服系统提升员工内部服务体验
|
3月前
|
自然语言处理 监控 机器人
中国联通济南分公司与瓴羊达成合作,以智能客服系统提升员工内部服务体验
中国联通济南分公司与瓴羊达成合作,以智能客服系统提升员工内部服务体验

热门文章

最新文章