汕尾海湾 发表于 2024-10-26 07:50:41

1024征文活动 - 企业级互联网全栈体系全链路架构优化方案落地实施方案

https://i-blog.csdnimg.cn/direct/f7ece1e55b6b4b17b0f8b249804eccf0.jpeg
   一年一度的步伐员节来啦,当然大家期待的 10·24征文活动也随之而来喽,现在来分享一下我在公司性能优化落地的一些实践,希望能资助大家。
一、前言:

从刚结业到现在也有近4个年头,最开始接触的是PHP + jQuery的开发,到后面的SOA分布式、K8s微服务,目最新团队使用了一段时间AI辅助开发,接触的业务规模也是越来越大,在不断的项目驱动学习与自我技能提高中,在应对越来越复杂的项目,做了很多全链路的优化。
https://i-blog.csdnimg.cn/direct/c967194636a24d69abd18a9399597ba7.png
阶段一(全栈开发工程师):

就职于一家外包公司,公司发展的初级阶段,人比较少,对产品迭代速度的要求较高,此时更多的需要一些全栈的工程师,一个人开发从前到后全搞定,主要是做一些CMS、写一些官网、一些jQuery H5的页面,Laravel Blade模板+ Bootstrap的后台管理体系模板,所用的技术相对比较落后,而且每天都是比较重复工作,外包的业务量较小,也不需要考虑并发、事务场景,往往索引都不需要加。如下为经常使用的Bootstrap的后台管理体系模板,基本上靠开发“3板斧头闯天下”。
https://i-blog.csdnimg.cn/direct/47e7de2b31cf47bcac0063cb15010177.png
阶段二(开发组长 -> 技术经理):

进入一家初创企业公司,公司人员配置还是比较正规的,前后端分离的工作模式,有专业的运维岗位,相对于全栈开发,虽然增长了些沟通成本比,但是对于产品迭代的质量还是有所包管的,从某些角度来看,其实还是提高了效率,前后端分离后可以使前后端工程师分工更加明白,大家各司其职,提高工作效率,充分发挥各自的优点。


[*]让后端工程师专注于业务逻辑的实现以及性能优化、安全。
[*]前端工程师专注于用户体验,交互模式。
公司也是逐渐规模越来越大,也碰到了很多问题,现在就跟大家一起来分享一下,在企业内部落地的一些优化方案的最佳实践。性能优化的关键在于从多个角度和层面进行综合优化,包括但不限于代码优化、数据库优化、服务器优化、前端优化等。
二、全栈工程化体系 – 最佳实践落地优化方案:

https://i-blog.csdnimg.cn/direct/c316f8aa9e28495e80013504c5d03f07.png
三、【场景一】:前端工程化体系一:Webpack打包方案优化:

1. 问题点描述:

项目使用是Vue开发的后台管理体系,随着项目逐渐增长新功能,没有做一定的优化策略,项目打包越来越慢了,而且网站的首屏白屏加载时间也越来越多,用户体验越来越差了,同时,也遭到业务的各个部分的投诉,技术团队内部告急办理这个问题。
https://i-blog.csdnimg.cn/direct/a5876aee78d44de1bfce834a290808f5.png
2. 缘故原由分析:

打包的文件太多,有序号的文件就快要733个chunk文件,总的巨细也快接近50Mb的巨细,如许会导致文件加载越来越慢,而且每次发版本的时候,都需要重新革新一下整个hash值的文件。
https://i-blog.csdnimg.cn/direct/1049f407d2fa45dd8000cf4a51113cb1.png
3. 办理思绪分析:

4. 技术点思绪分析:

可视化打包体积巨细分析插件:webpack-bundle-analyzer。
(1). 作用:

检察打包后的文件巨细与其中组成因素,可以检察哪些文件占用较大。


[*]①. 打包后全部组件与组件间的依赖关。
[*]②. 针对多余的包文件过大,对初次影响加载的效率问题进行剔除修改。
[*]③. 将捆绑内容表示为方便的交互式可缩放树形图【可视化试图】。
(2). 模块功能:



[*]①. 文件打包压缩后中真正的内容。
[*]②. 找出哪些模块组成最大的巨细。
[*]③. 找到错误的模块。
[*]④. 支持缩小捆绑,会解析它们现实巨细的捆绑模块、gzipped巨细。
(3). 实现:

起首进行“webpack-bundle-analyzer”这个插件的安装,使用npm install和yarn install都可以,看本身的需求进行安装,可以根据本身的webpack版本来决定安装的版本(webpack@3.8.1)。
yarn add webpack-bundle-analyzer@ 4.10.2
https://i-blog.csdnimg.cn/direct/0820f688bc9e4ace961ca882ade903ae.png
修改“webpack.prod.config.js”文件中,增长引入“webpack-bundle-analyzer”这个插件,在Plugins插件属性中,增长“new BundleAnalyzerPlugin()”实例化的对象,可以使用默认的配置即可。
https://i-blog.csdnimg.cn/direct/c8e20561159443009543d6e63a0bea29.png
const webpack = require('webpack');
...
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin

module.exports = merge(webpackBaseConfig, {
    output: {
      publicPath: '/dist/',
      filename: '..js',
      chunkFilename: '..chunk.js'
    },
    plugins: [
      new BundleAnalyzerPlugin(),// 使用默认配置
      ......
    ]
});
不过,需要配合 webpack 和 webpack-cli 一起使用,运行“yarn build”命令后,打包完成会自动在在网页上表现一个report.html的文件项目资源包的交互式可视化树形分析图,可以直观地分析打包出的文件有哪些,及它们的巨细、占比情况、各文件 Gzipped 后的巨细、模块包含关系、依赖项等,对应做出优化,从而资助提拔代码质量和网站性能。
https://i-blog.csdnimg.cn/direct/32270cfdb374438c84a32f0e1097f445.png
可以看到上面的可视化树形分析图,有些Chunk文件很大,占面积越大的文件,其文件的巨细越大,最大的到达了4.22MB,摆设到服务器之后,在欣赏器中加载的时间越长,鼠标移动到相对应的板块上,就可以直接检察各个文件的巨细,得到可视化的分析结果之后,接下来就对占比比较大大概依赖程度比较高的文件进行优化了。
通过上述的分析图可以资助我们得到一些项目存在的问题点信息:


[*]①. 相识Chunk包中的真正内容,以及打包后天生了哪些文件
[*]②. 找出哪些Chunk包模块尺寸最大,哪些文件会存在复重(如图中Tinymce富文本),看起来是每个文件夹都有一套代码,没有公用起来
[*]③. 查找误引入的模块,比如说有些模块根据在项目中没有使用到,大概使用过了,在后续的迭代项目中更换了功能,但是代码还在。
[*]④. 通过“Gzipped”选项,可以检察Chunk包文件压缩之后的巨细,并且与原始文件现实巨细进行比较,压缩率是多少。
   当然,此时,在生产流水线打包,肯定会报错的,可以作为CLI的一个工具来使用,直接可以打包为一个json文件用于分析,可以在package.json中scripts命令中增长一条命令:
"build:chart": "vue-cli-service build --profile --json > stats.json",
具体的参数介绍:
new BundleAnalyzerPlugin({
// 可接受字符串,用来指定报告生成的格式和渠道。可以是'server','static',或者'disabled'。
// 'server'会启动一个HTTP服务器来提供报告的互动查看,默认为localhost:8888。
// 'static'会生成单个HTML文件来描述报告。
// 'disabled'在有些场景中可能很有用,你可以用于临时禁用插件,但保留配置代码。
analyzerMode: 'server',

// 在'server'模式下,定义HTTP服务器的主机名。
analyzerHost: '127.0.0.1',

// 在'server'模式下,定义HTTP服务器的端口号。
analyzerPort: 8888,

// 在'static'模式下,定义报告生成的文件名。
reportFilename: 'report.html',

// 定义模块大小的计算方式。定义为'stat','parsed'或者'gzip'。
// 'stat'描述所有未解析代码的大小之前的大小(模块间关联的尺寸)。
// 'parsed'描述所有已被解析的代码的大小(只有已经经过loaders处理和解析的代码)。
// 'gzip'则会描述所有解析代码的gzip大小(如果这个值被定义的话)。
defaultSizes: 'parsed',

// 一个模块是否应该被展示出来。你可以通过这个选项来隐藏那些非必要的模块。
// 你可以传入一个函数,这个函数接收一个模块作为参数,然后返回一个布尔值。
filterModules: false,

// 如果你想要生成的报告文件的内容是一个自定义的数据结构,你可以传入一个函数,这个函数会接收一个stats数据作为参数。
// 你的函数需要返回一个序列化的JSON对象,或者一个Promise,这个Promise在resolve时需要返回这个序列化的JSON对象。
generateStatsFile: false,

// 如果你想要自定义生成的stats文件的文件名,你可以修改这个选项。
statsFilename: 'stats.json',

// 定义在生成stats文件时,是否也生成报告。
statsOptions: null,

// 定义一个日志函数。
logLevel: 'info'
})
5. 落地方案实施一(Gzip压缩):

Gzip是一种 http 哀求优化方式,一种用来改进web应用步伐性能的技术,gzip压缩比率在3到10倍左右,可以大大节省服务器的网络带宽。


[*]①. 通过镌汰文件体积来提高加载速度。
[*]②. 对于用户量多的网站,开启 gizp 压缩会大大低落服务器压力,提高加载速度、低落服务器流量成本。
[*]③. 节省了服务器的网络带宽,节约的流量非常可观。
[*]④. 必须欣赏器与服务器都支持Gzip。
[*]⑤. Gzip算法特性,代码相似率越大压缩效率越高(风浪越大,鱼越贵)。
如下左图描述了Gzip的工作原理图:


[*] ①. 欣赏器发送哀求:

[*]a. 在 request header 中设置属性 accept-encoding:gzip。
[*]b. 表示欣赏器支持 gzip。

[*] ②. 服务器收到哀求后:

[*]a. 判断欣赏器是否支持 gzip:

[*](1). 假如支持 gzip,则向欣赏器传送压缩过的内容。
[*](2). 不支持则向欣赏器发送未经压缩的内容。

[*]b. Response headers返回包含 content-encoding:gzip。

[*] ③. 欣赏器吸收相应后判断内容是否被压缩,假如被压缩则解压缩表现页面内容,欣赏器先解压再使用,对于用户是无感知的。
https://i-blog.csdnimg.cn/direct/d359d1daa8ef4e61b2f4c6ce09e11d4f.png
从右侧的可视化树形分析图中可以看到,原始的文件巨细是47.74MB,通过Gzipped压缩之后的代码是5.75MB,相当于节省了88%的空间巨细,可以大大的加速了长途资源的加载,同时也节省了带宽,所以说导入Gzip压缩是快速体现加载速度最快捷,收益也是最大的方式。
两种 Gzip 实现的压缩方式:



[*] ①. webpack打包天生 .gz 文件【推荐】:

[*]a. 通过 webpack 配置天生对应的 .gz 文件。
[*]b. 欣赏器哀求 xx.js/css 等文件时,服务器返回对应的 xxx.js.gz 文件。

[*] ②. 服务器实时在线将哀求 xx.js 文件进行gzip压缩后传输给欣赏器:

[*]a. 压缩文件过程本身有额外开销。
[*]b. 服务器压缩的时间开销和 CPU 开销(及欣赏器解析压缩文件的开销)为代价【重点】,来节省传输过程中的时间开销。

方案一:Nginx服务器Gzip压缩方案:

https://i-blog.csdnimg.cn/direct/71e9ccdf8c9f41558e54607a9fbb4122.png
server {
        ...
    gzip on;
    gzip_buffers 4 16K;
    gzip_comp_level 6;
    gzip_min_length 100k;
    gzip_types text/plain application/x-javascript application/javascript application/json text/css application/xml text/javascript application/x-httpd-php;
    gzip_disable "MSIE .";
    gzip_http_version 1.1;
gzip_vary on;
...
}
参数解释:

// 是否开启gzip
gzip on|off;
// 压缩的页面最小字节数,超出进行压缩
// 页面字节数从header头中的Content-Length中进行获取,默认值是0.
// 太小就不要压缩了,意义不大
gzip_min_length 100k;
// 缓冲区(压缩在内存中缓冲几块?每块多大?)
// 获取多少内存用于缓存压缩结果:'4 16k'表示以16k*4为单位获取
gzip_buffers 4 16k;
// 压缩级别(压缩比1-9,级别越高,压的越小,越浪费CPU计算资源)
// 越小压缩效果越差,但是越大处理越慢,一般取中间值(官网建议6)
gzip_comp_level 6;
// 对哪些类型的文件用压缩,如txt、xml、html、css、js等
// 对特定的MIME类型生效,其中'text/html'被系统强制启用
gzip_types text/plain;
// 识别http协议的版本,不支持gzip自解压的浏览器,用户会看到乱码
gzip_http_version 1.1  
// 是否传输gzip压缩标志
// 和http头有关系,加个vary头,给代理服务器用的,有的浏览器支持压缩,有的不支持
// 避免不支持的也压缩,根据客户端的HTTP头来判断,是否需要压缩
gzip_vary on|off;
// nginx做为反向代理时启用,off(关闭所有代理结果的数据的压缩),expired(启用压缩,如果header头中包括"Expires"头信息),no-cache(启用压缩,header头中包含"Cache-Control:no-cache"),no-store(启用压缩,header头中包含"Cache-Control:no-store"),private(启用压缩,header头中包含"Cache-Control:private"),no_last_modefied(启用压缩,header头中不包含"Last-Modified"),no_etag(启用压缩,如果header头中不包含"Etag"头信息),auth(启用压缩,如果header头中包含"Authorization"头信息)
gzip_proxied off
// IE5.5和IE6 SP1使用msie6参数来禁止gzip压缩
// 指定哪些不需要gzip压缩的浏览器(将和User-Agents进行匹配),依赖于PCRE库
gzip_disable "MSIE ."
注意事项:



[*] ①. 图片/mp3的二进制文件:

[*]a. 不必压缩,由于压缩率比较小,同时会泯灭CPU资源的。
[*]b. 图片压缩并不能现实镌汰文件巨细,反而会导致打包后天生很多同巨细的gz文件。

[*] ②. 比较小的文件不必压缩。
方案二:Webpack前端Gzip压缩方案【推荐】:

Webpack前端Gzip压缩插件:compression-webpack-plugin
安装 compression-webpack-plugin插件:
yarn add compression-webpack-plugin@6.1.1 -D
   注:新版本 7.x 会报错,Cannot read property ‘tapPromise’ of undefined
在 vue.config.js 中配置:
const CompressionPlugin = require('compression-webpack-plugin');

module.exports = {
    chainWebpack(config) {
      ...
      // 方式一【本文使用】:
      config
            .when(process.env.NODE_ENV === 'production',
                config => {
                  config
                        .plugin('compression')
                        .use(CompressionPlugin)
                        .tap(() => [{
                            test: /\.js$|\.html$|\.css$/, // 匹配文件名,开启js、css压缩
                            filename: '.gz', // 压缩后的文件名(保持原文件名,后缀加.gz)
                            minRatio: 1, // 压缩率小于1才会压缩
                            threshold: 10240, // 对超过10k的数据压缩
                            deleteOriginalAssets: false // 是否删除未压缩的源文件(不设置或设置为false)
                            // 保留非gzip的资源,删除打包后的gz后还可以加载到原始资源文件,建议不要设置为true
                        }])
                }
            )

      // 方式二:
      if (process.env.NODE_ENV === 'production') {
            config.plugin('compression-webpack-plugin')
                .use(new CompressionPlugin({
                  test: /\.js$|\.html$|\.css/,
                  threshold: 10240,
                  deleteOriginalAssets: false
                }))
      }
    }
}
使用“yarn build”打包后目次会多出 .gz 文件,需要注意的假如没有设置filename的话,打包的目次会只有一个没有名称的 .gz 文件,并提示“Conflict: Multiple assets emit different content to the same filename static/js/.gz”。
https://i-blog.csdnimg.cn/direct/6a33091b6a994e7a9c8292d01ed09ae6.png
当然,Nginx服务器也是需要开启 Gzip的功能,“gzip_static”参数开启后,Nginx就会读取预先压缩的gz文件,可以镌汰每次哀求进行Gzip压缩的CPU资源斲丧。
server {
    // 表示静态加载本地的gz文件
    // 浏览器请求xx.js/css等文件时,服务器返回对应的xxx.js.gz文件
    // 服务器会根据Request Headers的Accept-Encoding标签进行鉴别,如果支持gzip就返回.gz文件.
    // gzip_static开启后,nginx就会读取预先压缩的gz文件,可以减少每次请求进行gzip压缩的CPU资源消耗
    gzip_static on;
    gzip_http_version 1.1;
}
https://i-blog.csdnimg.cn/direct/60fc1464bb654a9f9fe4bfa559efb7b3.png
这是我们在其它项目上的应用截图,可以看到加载速度还是有所提高,这个项目是3.2MB,大概性价比看不出来太高,但是假如50MB、100MB的话,性价比的上风非常显着。
可以通过CURL的命令来,检查是否开启Gzip乐成,假如content-encoding返回的值是“gzip”就可以证明已经是被Gzip压缩过了。
curl -I -H "accept-encoding: gzip, deflate" "https://xxxx/static/css/chunk-elementUI.a8b08852.css"
https://i-blog.csdnimg.cn/direct/c1d0552a156e465fa985ccd6f263b38a.png
也可以通过F5,检察Network的情况,通过勾选“Big request rows”选项,来检察未压缩的资源巨细的比对,假如发现两个巨细不一样,同样,也可以表示Gzip压缩过。
https://i-blog.csdnimg.cn/direct/1a0894f1cda14f30aafa9a24bd5b5c7c.png
以下是增长Gzip 压缩的一个现实效果对比的结果,我们可以找了其中的一个js文件“chunk-elementUI.71006ee3.js”来做一下比较,看看Gzip 压缩前后有没有什么大的变化:


[*]①. 压缩前:在压缩之前这个js文件的加载时间是8.31s,文件的传输巨细为593kB。
[*]②. 压缩后: 在压缩之前这个js文件的加载时间是1.75s,文件的传输巨细为146kB。
[*]③. Gzip的压缩比率在4倍左右。
https://i-blog.csdnimg.cn/direct/c2a7c7dbbcb64cc4b23cf5035264610e.png
可以通过Url的哀求来对Request、Response 进行比对:
https://i-blog.csdnimg.cn/direct/0c167da62ad047f09f8aa3fb48a0e363.png


[*] ①. Request Headers:

[*]a. Accept-Encoding: gzip, deflate:

[*](1). 表示用户欣赏器支持二种压缩,包括 gzip 的压缩方式。
[*](2). deflate 与 gzip 使用的压缩算法几乎相同。


[*] ②. Response Headers:

[*]a. Accept-Ranges: bytes:

[*](1). 是用来告诉客户端,服务器是否能处理范围哀求,以指定获取服务器端某个部分的资源。
[*](2). 表示能处理客户端发过来的范围哀求。

[*]b. 静态加载 gz 文件的相应头:Content-Encoding: gzip

注意事项:


[*]①. Nginx服务器配置了静态 gz 加载后,哀求文件变小不会导致哀求卡线程。
[*]②. 保留了源文件,当删除 gz 后,欣赏器会自动去哀求原始文件,不会导致界面出现任何问题。
四、【场景二】:前端工程化体系二:图片Webp导入方案优化:

1. 问题点描述:

项目在早期使用的过程中,存在大量的png和jpeg类型图片,类似H5的下单页面会有大量的图片表现,比如商品的描述,商品的介绍、商品的规则参数、商品的头图等等,而首页是一个门户,假如打开经常延迟、卡顿,白屏时间过长,容易导致用户不好的体验,就不会来购买下单,可以看一下我们早期网站加载的问题点:
https://i-blog.csdnimg.cn/direct/b3e66ee4a6b04e968e3647018cf6d554.png


[*]①. 加载的图片最大的巨细是1.4MB,200KB以上的图片占60%。
[*]②. 加载的图片最长时间是9.93s,凌驾3s钟加载的占40%。
[*]③. 总体首页加载的资源是12.7MB,加载完成的时间为12s。
2. 缘故原由分析:

在当今互联网数字化的期间,图片在网页筹划和内容通报中扮演着至关重要的角色。为了提供更好的用户体验和更佳的网页性能,互联网图片格式从最早期的 BMP、PCX全面升级到JPG、PNG 等主流格式,而 WebP 作为一种新兴的图像格式,正以其众多上风在行业中崭露头角。
https://i-blog.csdnimg.cn/direct/9f2db32aec4c4283bf7345793d28b379.png
现在对于JPEG、PNG、GIF等常用图片格式的优化已几乎到达极致,因此Google于2010年提出了一种新的图片压缩格式 — WebP,WebP为网络图片提供了无损和有损压缩能力,使用无损压缩后的WebP比PNG文件少了26%的体积,有损压缩后的WebP图片相比于等效质量指标的JPEG图片镌汰了25%~34%的体积。
3. 办理思绪分析:

   WebP最初在2010年发布,目标是镌汰文件巨细,但到达和JPEG格式相同的图片质量,希望能够镌汰图片档在网络上的发送时间。2011年11月8日,Google开始让WebP支持无损压缩和透明色(alpha通道)的功能,而在2012年8月16日的参考实做libwebp 0.2.0中正式支持。
WebP 是一种由 Google 开发的现代图像格式,旨在提供高质量的图像压缩,同时保持较小的文件巨细,WebP 支持有损和无损压缩,以及透明度(alpha 通道),并且它特殊适合用于网络上的图像传输,由于它可以资助镌汰带宽斲丧和加速页面加载速度。
https://i-blog.csdnimg.cn/direct/9f7472359fea4bc6aee47ec28520f730.png
虽然 WebP 具有这些上风,但由于一些老旧的欣赏器大概不支持该格式,因此在使用 WebP 时需要确保目标受众的欣赏器兼容性。别的,对于不支持 WebP 的欣赏器,可以提供回退方案,如使用 JPEG 或 PNG 格式的图像。
https://i-blog.csdnimg.cn/direct/b709cfe2921c4b56a45dbe66324e80f4.png
4. 技术点思绪分析及落地实践:

以下在蓝湖上进行切图时,默认一般是使用png大概jpg格式,现在可以增长webp格式,点击下载后,可以同时放到文件夹下面。
https://i-blog.csdnimg.cn/direct/dde88d586dac44c49a1f9dec422f3ece.png
可以通过Picture标签可以通过包含一个或多个元素来使用,根据屏幕匹配的差别尺寸表现差别图片,假如没有匹配到或欣赏器不支持 picture 属性则使用 img 元素,用法如下,标签包含了三个元素:
<picture>
<source srcset="~images/index/product.webp" type="image/webp">
<source srcset="~images/index/product.png" type="image/png">
<img src="~images/index/product.jpg" alt="Picture">
</picture>


[*]①. 多个图片源:可以指定多个图片源,根据欣赏器的支持情况来选择最合适的图片格式,在上面例子中,起首尝试加载product.webp,假如欣赏器不支持webp格式,则加载product.png,最后再加载product.jpg。
[*]②. 标签的默认内容:它会在没有匹配的标签时被加载。
[*]③. src属性:用于指定默认情况下要加载的图片地点。
[*]④. alt属性:用于指定图片的替代文本,当图片无法加载时会表现这个文本。
[*]⑤.
使用Picture标签可以提供更好的图片适配性,根据差别装备和欣赏器的支持情况加载差别的图片格式,从而提高页面的性能和用户体验。
https://i-blog.csdnimg.cn/direct/f995530eff36495f96845f6f5aab0dd0.png
以上通过Picture标签方案,在H5的项目的落地实施,可以看到空间压缩率平均可以镌汰到达72%左右,加载的时间平均可以低落70%左右,通过比较发现:


[*]加载体积最大的图片1.4MB,转换为webp格式图片巨细为526kb。
[*]加载耗时最大的图片9.03s,转换为webp格式图片时间为1.41s。
五、【场景三】:前端工程化体系三:图片压缩方案优化:

   在日常的Web开发或筹划工作中,经常需要处理大量的图像文件,图片巨细直接影响页面加载速度,进而影响用户体验。
1. 问题点描述:

承上启下,页面的图片越大那么网站的打开速度也就会越慢,所以在包管图片的清楚度的同时我们也要适当的压缩图片的巨细来包管网站的打开速度,提高网站的质量得分。
根据Google较早的测试,WebP的无损压缩比网络上找到的PNG档少了45%的文件巨细,即使这些PNG档在使用pngcrush和PNGOUT处理过,WebP还是可以镌汰28%的文件巨细。
2. 技术点思绪分析:

TinyPng 使用了先进的压缩算法,对PNG和JPEG图片进行智能优化,其主要采用了以下技术:
https://i-blog.csdnimg.cn/direct/b2db23062fbb4630b8efab9b02e7f085.png
TinyPng可广泛应用于以下几个场景:


[*]①. Web开发:优化网站上的图片资源,加速页面加载速度。
[*]②. 移动应用:镌汰安装包巨细,提高用户下载与更新的效率。
[*]③. 图形筹划:在不影响视觉效果的条件下,减小筹划作品的存储需求。
[*]④. 云服务:与图像处理服务结合,提拔服务质量。
3. 落地实践【方案一】在线网站压缩:

在项目开发的前期,维护同砚是在TinyPng在线的网站上进行上传图片,压缩完成后,再下载更换到项目中,可以看到png、webp、jpeg等主要使用的图片格式都能进行压缩:
以某一张图片来讲,最开始的png巨细为1.2MB,转为webp格式图片巨细为737KB,再进行webp图片压缩,可以到达66KB。
https://i-blog.csdnimg.cn/direct/8488fe873b884ee5a801a27f62cd5eaf.png
不过,如许做的话,有一个缺点,就是每次有图片更新话,都需要人工手动去进行上传压缩,想想该如何进行自动化压缩图片呢?
4. 落地实践【方案二】开发压缩CLI小工具:

上面也提到了TinyPng是可以进行API访问的,基于API的情势,开发了一个CLI的小工具,在webpack构建之前,会先去运行这个CLI的命令来进行图片的文件压缩,实现自动化进行压缩图片,如下CLI工具会把一些主要的信息在控制台命令中进行表现:


[*]①. Webp在压缩后,可以节省近70%的空间巨细
[*]②. Webp在压缩后,可以加速近33%的时间巨细
https://i-blog.csdnimg.cn/direct/b1907e5742a445908be2ecb2f4532899.png
以下为CLI相关的主要代码:
#!/usr/bin/env node
const inquirer = require('inquirer')
const ora = require('ora')
const cluster = require('cluster')
import chalk from 'chalk'
import fs from 'fs'
import Ora from 'ora'
import { resolve } from 'path'
let spinner: Ora.Ora // ora载体
let inputSize = 0 // 输入总体积
let outputSize = 0 // 输出总体积
let ratio = 0 // 压缩比

/**
* 程序入口
*/
interface importData {
name?: string
}
const test = (): void => {
inquirer
    .prompt([
      {
      type: 'input',
      message: ' 请输入当前目录下需要压缩的 (文件夹名称)?',
      name: 'name'
      }
    ])
    .then((res: importData) => {
      const folderName = res.name
      const spinner = ora(`正在检查文件夹[${folderName}]是否存在......`)
      spinner.start()
      console.log(res)
      // 找出所有目标文件夹
      const targetFolder = resolve(process.cwd() + "/" +folderName)
      const isTargetFolder = fs.existsSync(targetFolder);
      if (isTargetFolder) {
      mapFolder(targetFolder)
      } else {
      console.log("目录不存在")
      }
      spinner.stop()
    })
}

test()


/**
* 递归找出所有图片
* @param { string } path
* @returns { Array<imageType> }
*/
export type imageType = {
path: string
file: Buffer
}
interface IdeepFindImg {
(path: string): Array<imageType>
}
let deepFindImg: IdeepFindImg = (path: string) => {
const content = fs.readdirSync(path)
let images: Array<imageType> = []
content.forEach(folder => {
    const filePath = resolve(path, folder)
    const info = fs.statSync(filePath)
    if (info.isDirectory()) {
      images = [...images, ...deepFindImg(filePath)]
    } else {
      const fileNameReg = /\.(jpe?g|png|svga)$/
      const shouldFormat = fileNameReg.test(filePath)
      if (shouldFormat) {
      const imgData = fs.readFileSync(filePath)
      if (filePath && imgData) {
          images.push({
            path: filePath,
            file: imgData
          })
      }
      }
    }
})
return images
}

/**
* 遍历处理每个目标文件
* @param { Array<string> } folderList
*/
interface ImapFolder {
(folderPath: string): void
}
const mapFolder: ImapFolder = async (folderPath: string) => {
// 查找目标文件夹内的图片资源
const targets = deepFindImg(folderPath)
folderList.forEach(path => {
    target = [...target, ...deepFindImg(path)]
})
if (target.length) {
    const noCompressList: Array<imageType> = [] // 未压缩列表
    const hasCompressList: Array<imageType> = [] // 已压缩列表
    let len = 0

    while (len < target.length) {
      const { path } = target
      let data = ''
      const curBuf: Buffer = await new Promise((resolve, reject) => {
      const readerStream = fs.createReadStream(path)
      readerStream.setEncoding('utf8')
      readerStream.on('data', chunk => {
          data += chunk
      })
      readerStream.on('end', () => {
          const buf = Buffer.alloc(data.length, data, 'binary')
          resolve(
            Buffer.from(
            toArrayBuffer(buf).slice(buf.length - tagLen, buf.length)
            )
          )
      })
      readerStream.on('error', err => {
          reject(err.stack)
      })
      })
      try {
      if (curBuf.compare(tagBuf) !== 0) {
          noCompressList.push(target)
      } else {
          hasCompressList.push(target)
      }
      } catch (err) {
      spinner.fail(`读取 ${path} 资源失败!`)
      }
      len++
    }

    // 未压缩的svga数量
    const noCompressSvgaNum = noCompressList.filter(ele =>
      /\.(svga)$/.test(ele.path)
    ).length
    // 未压缩的图片数量
    const noCompressImageNum = noCompressList.length - noCompressSvgaNum

    // 已压缩的svga数量
    const hasCompressSvgaNum = hasCompressList.filter(ele =>
      /\.(svga)$/.test(ele.path)
    ).length
    // 已压缩的图片数量
    const hasCompressImageNum = hasCompressList.length - hasCompressSvgaNum

    CG({
      options: {
      headerVisible: true
      },
      columns: ['类型', '可压缩', '已压缩', '总数'],
      rows: [
      [
          '图片',
          chalk.red(noCompressImageNum),
          chalk.green(hasCompressImageNum),
          chalk.blue(noCompressImageNum + hasCompressImageNum)
      ],
      [
          'SVGA',
          chalk.red(noCompressSvgaNum),
          chalk.green(hasCompressSvgaNum),
          chalk.blue(noCompressSvgaNum + hasCompressSvgaNum)
      ]
      ]
    })

    if (!noCompressList.length) {
      spinner.fail(`「目标文件夹内」找不到「可压缩」的资源!`)
      spinner.stop()
      return
    }
    inquirer
      .prompt([
      {
          type: 'list',
          message: chalk.green('') + ' 请选择压缩模式?',
          name: 'compressType',
          choices: [
            {
            value: 'all',
            name: '全量'
            },
            {
            value: 'diy',
            name: '自定义'
            }
          ],
          pageSize: 2
      },
      {
          type: 'checkbox',
          message: chalk.green('') + ' 请选择需要压缩的图片?',
          name: 'compressList',
          choices: target.map(img => ({ value: img, name: img.path })),
          pageSize: 10,
          when: function ({ compressType }: { compressType: 'diy' | 'all' }) {
            return compressType === 'diy'
          }
      }
      ])
      .then(
      async ({
          compressType,
          compressList
      }: {
          compressType: 'diy' | 'all'
          compressList: Array<imageType>
      }) => {
          // 根据用户选择处理对应的资源
          const list = compressType == 'all' ? noCompressList : compressList
          if (!list.length) {
            spinner.fail(`请至少选择一个!`)
            spinner.stop()
            return
          }

          //开始时间
          const dateStart = +new Date()

          cluster.setupPrimary({
            exec: resolve(__dirname, 'features/process.js')
          })

          // 若资源数小于则创建一个进程,否则创建多个进程
          const works: Array<{ work: any; tasks: Array<imageType> }> = []
          if (list.length <= cpuNums) {
            works.push({ work: cluster.fork(), tasks: list })
          } else {
            for (let i = 0; i < cpuNums; ++i) {
            const work = cluster.fork()
            works.push({ work, tasks: [] })
            }
          }

          // 平均分配任务
          let workNum = 0
          list.forEach(task => {
            if (works.length === 1) {
            return
            } else if (workNum >= works.length) {
            works.tasks.push(task)
            workNum = 1
            } else {
            works.tasks.push(task)
            workNum += 1
            }
          })

          // 用于记录进程完成数
          let pageNum = works.length
          let succeedNum = 0 // 成功资源数
          let failNum = 0 // 失败资源数
          const failMsg: Array<string> = [] // 失败列表
          let outputTabel: Idetail[] = []
          // 初始化进度条
          bar.render({
            current: 0,
            total: list.length,
            token: `${chalk.green(0)} 个成功${chalk.red(0)} 个失败`
          })
          works.forEach(({ work, tasks }) => {
            // 发送任务到每个进程
            work.send(tasks)
            // 接收任务完成
            work.on('message', (details: Idetail[]) => {
            outputTabel = outputTabel.concat(details)

            // 统计 成功/失败 个数
            details.forEach((item: Idetail) => {
                if (item.output) {
                  inputSize += item.input
                  outputSize += item.output
                  ratio += item.ratio
                  succeedNum++
                } else {
                  failNum++
                  if (item.msg) failMsg.push(item.msg)
                }
                // 更新进度条
                bar.render({
                  current: succeedNum + failNum,
                  total: list.length,
                  token: `${chalk.green(succeedNum)} 个成功${chalk.red(
                  failNum
                  )} 个失败`
                })
            })
            pageNum--
            // 所有任务执行完毕
            if (pageNum === 0) {
                if (failMsg.length) {
                  failMsg.forEach(msg => {
                  spinner.fail(msg)
                  })
                }

                CG({
                  options: {
                  headerVisible: true
                  },
                  columns: [
                  '名称',
                  '原体积',
                  '现体积',
                  '压缩率',
                  '耗时',
                  '状态'
                  ],
                  rows: [
                  ...outputTabel.map((item: any) => [
                      chalk.blue(filterFileName(item.path)),
                      chalk.red(byteSize(item.input)),
                      chalk.green(byteSize(item.output)),
                      !item.ratio
                        ? chalk.red('0 %')
                        : chalk.green((item.ratio * 100).toFixed(4) + ' %'),
                      chalk.cyan(item.time + ' ms'),
                      item.output ? chalk.green('success') : chalk.red('fail')
                  ])
                  ]
                })

                const totalRatio = ratio / succeedNum

                spinner.succeed(
                  `资源压缩完成! \n原体积: ${chalk.red(
                  byteSize(inputSize)
                  )}\n现体积: ${chalk.green(byteSize(outputSize))}\n压缩率: ${
                  totalRatio
                      ? chalk.green((totalRatio * 100).toFixed(4) + ' %')
                      : chalk.red('0 %')
                  }\n成功率: ${chalk.green(
                  ((succeedNum / list.length) * 100).toFixed(2) + ' %'
                  )}\n进程数: ${chalk.blue(works.length)}\n总耗时: ${chalk.cyan(
                  +new Date() - dateStart + ' ms'
                  )}\n`
                )

                cluster.disconnect()
            }
            })
          })
      }
      )
} else {
    spinner.fail(`找不到可压缩资源!`)
    spinner.stop()
}
}
六、【场景四】:前端工程化体系四:上传图片压缩方案优化:

1. 问题点描述:

很多场景中需要照相上传图片,比如业务有用到案件,需要拍高清的图片上传用来考核,但是高分辨率的照片文件在存储和传输过程中占用较多的空间,并且会增长上传和下载的时间成本。在以下情况下,对照片进行巨细压缩尤为重要:
https://i-blog.csdnimg.cn/direct/9ed7aa2a1b8f40bab69b37aab38c55ed.png
通过对照片进行巨细压缩,可以有用地节省存储空间并提高上传速度,假如我们直接将原图片上传,可以图片体积比较大,一是上传速度较慢,二是前端进行渲染时速度也比较慢,比较影响客户的体验感。所以在不影响清楚度的情况下,前端可以在上传前对图片的巨细体积进行压缩,压缩到一个比较合适的巨细进行上传。为什么需要压缩照片巨细,并介绍了压缩方法和最佳实践。
2. 技术点思绪分析:

js-image-compressor是一个第三方npm库,用来图像压缩是一种减小图像文件巨细的方法,从而镌汰加载时间和带宽斲丧的技术,并优化网站加载速度,可以在不丧失图像质量的条件下,优化图片文件的巨细。


[*]①. 可以压缩图片到指定的压缩率或特定的巨细(兆字节、千字节或字节)。
[*]②. 支持主流的无损和有损格式图片上传,并可以下载压缩后的JPEG、PNG和WEBP格式图片。
[*]③. 可以批量压缩多张图片,将图片巨细从MB敏捷压缩至KB,节省时间。
https://i-blog.csdnimg.cn/direct/3ddb1b58bc75475e8903efb5b8e83575.png
4. 落地实践【方案】js-image-compressor库:

安装“js-image-compressor”库,这个库可以资助前端进行图像压缩:
npm i js-image-compressor
这个组件允许用户上传图像,并在前端进行压缩,然后表现压缩后的图像,可以根据需要调整maxWidth、maxHeight和quality、checkOrientation等选项来控制压缩的质量和巨细、图片翻转功能。
import ImageCompressor from 'js-image-compressor'

methods: {
compressFile(file) {
      return new Promise((resolve, reject) => {
      new ImageCompressor(file.file, {
          quality: 0.6, // 压缩质量
          checkOrientation: false, // 图片翻转,默认为false
          success(result) {
            var reader = new FileReader();
            var imageItem = ''
            reader.readAsDataURL(result); // readAsDataURL方法可以将上传的图片格式转为base64,然后在存入到图片路径,
            reader.onload = function () {
            imageItem = reader.result;// image即base64格式,后面调用后端请求传入image
            resolve(reader.result)
          },
          error(e) {
            console.log(e)
            reject()
          }
      })
      })
    },
}
在上传后端OSS的时候的方法中使用即可:
methods: {
        uploadImg (file) {
      return new Promise(async (res, rej) => {
      let compressFile = await this.compressFile(file)
      let formData = new FormData()
      formData.append('file', compressFile)
      uploadFile(formData).then(result => {
          // 判断是否是数组
          file.status = 'success';
          file.message = '';
          file.url = result
      }).catch((e) => {
          console.log('错误', e)
          file.status = 'failed'
          file.message = '上传失败'
          file.url = ''
      })
      })
    },
}
由于公司的业务较为特殊,案件需要上传很多差别类型的报告,一个案件,最少9张,最大支持96张图片,在没有压缩之前,用户反馈这个界面操作很慢、很卡,查询了一下缘故原由:


[*]高清照相图片巨细非常大,IOS高清的偶然候能到达20MB,安卓P60照相也有10几MB。
[*]业务图片会先上传到后端,后端再上传到OSS云存储,如许会产生2倍带宽。
[*]后台管理有批量下载这个案件的全部图片,比较浪费带宽和下载时间。
https://i-blog.csdnimg.cn/direct/05cfdc2377fa4aa59bdf6688c595c563.png
通过安装并使用“js-image-compressor”库,在不影响画质的底子上,可以压缩图片巨细,节省存储空间,并且取得很好的结果,可以看到5.3MB的图片可以压缩到745KB,压缩率到达70%,可以很好的节省OSS的存储空间、带宽流量、下载速度。
七、【场景七】:服务器工程化体系一:HTTP/2方案与OSS方案优化:

1. 缘故原由分析:

HTTP/1.1的协议哀求,并不能很好地地使用带宽,比如,一个 TCP 毗连同时只能有一个 HTTP 哀求和相应,假如正在发送一个 HTTP 哀求,那其它的 HTTP 哀求就得列队。
很多欣赏器对同一域名下差别哀求的并发数量都有限定,以平常经常使用的Chrome欣赏器为例,当前同一个域名下,最大的并发哀求限定数量为6个,假如需要等待相应的哀求数量凌驾6个以上,那么,后面这个域名的其它哀求,就会进入等待队列,只有当前面的哀求完成后,才会再被执行。
https://i-blog.csdnimg.cn/direct/16e4e4b182394ff3b82d6c23b2936fb5.png
2. 办理思绪:

   HTTP2的多路复用代替了 HTTP1.x 的序列和阻塞机制,全部的相同域名哀求都通过同一个 TCP 毗连并发完成,通过这个技术,可以制止 HTTP 旧版本中的队头阻塞问题,极大的提高传输性能。
HTTP2的多路复用技术,为了办理网络中带宽越来越大而时延也居高不下,理想的消息通报方式,只要在 TCP 滑动窗口和拥塞窗口的处理范围内,发送端就应当源源不断的发送,吸收端则源源不断的吸收,HTTP2的多路复用代替原来的序列和阻塞机制,全部就是哀求的都是通过一个 TCP 毗连并发完成:


[*]①. 同时也很好的办理了欣赏器限定同一个域名下的哀求数量的问题。
[*]②. 同域名下全部通讯都在单个毗连上完成,同个域名只需要占用一个 TCP 毗连,使用一个毗连并行发送多个哀求和相应。
[*]③. 单个毗连可以承载任意数量的双向数据流,单个毗连上可以并行交织的哀求和相应,之间互不干扰。
3. 【落地方案一】Nginx配置Http/2:

要让 Nginx 支持 HTTP/2,需要确保您的 Nginx 版本是 1.9.5+,由于这是引入 HTTP/2 支持的版本。别的,HTTP/2 需要 SSL/TLS 支持,因此,还需要配置 SSL 证书。
以下是一个基本的 Nginx 配置示例,展示了如作甚 HTTP/2 启用 SSL:
server {
listen 443 ssl;
// 告诉 Nginx 在 443 端口上以 SSL 加密的方式启用 HTTP/2
http2 on;
    server_name example.com;
       
// ssl_certificate 和 ssl_certificate_key 指令指定了 SSL 证书和私钥的路径,确保替换 example.com、证书路径和网站根目录路径。
    ssl_certificate /path/to/test.pem;
    ssl_certificate_key /path/to/ test.pem;

    # 其他配置...
}
https://i-blog.csdnimg.cn/direct/bfc7beaf96f24d35999e32a5533a71d8.png
在配置好 SSL 和 HTTP/2 之后,重启 Nginx 以应用新的配置:
sudo service nginx restart
Nginx配置Http/2落地实践比较:

网页使用了很多静态资源文件,如HTML、css样式表、js脚本、图片、视频等。在HTTP1.1中由于同一个域名最多同时哀求6个,导致后续的哀求都在等待,网络经常是空闲的和未充分使用的,可以看到他是一个阶梯式的一个加载的过程。
而HTTP2.0可以很好的办理这个问题,同域名下全部通讯都在单个毗连上完成,同个域名只需要占用一个 TCP 毗连,使用一个毗连并行发送多个哀求和相应,所以可以进行多路复用进行文件的加载,多个文件是同时进行加载,理论上带宽充足,就能传多快。
https://i-blog.csdnimg.cn/direct/c5de97f2d514484882c3a8a328236f97.png
4. 【落地方案二】静态资源分散差别OSS域名加载方案:

   如今互联网期间在高速发展,对网站的访问速度越来越高了,往往在图片加载的时候,会碰到卡顿、超时、缓慢的情况产生,从而需要将大量的文本类资源(如css、html、图片、txt文本)都可以通过云储存为商户实现了快捷稳定的服务。
但随着云计算,大数据,微服务技术的日趋盛起,在近几年的开发过程中,存储数据的样式种类越来越多,对数据的安全和性能的平衡等,我们需要的文件体系的特性也越来越多,不在局限于当地的文件体系存储。
https://i-blog.csdnimg.cn/direct/42bb0be7d2f049a19f8e48794a8c4dbd.png
随着项目的不断增长,图片或视频等文本类型的资源,也渐渐由存在当地演进到存放到本身的文件服务器,后面托管到到第三方的云平台。
https://i-blog.csdnimg.cn/direct/c9df0c1964dc47b3ac3b16f6c153aa14.png
现在公司的项目中,全部应用于阿里云的云对象存储OSS,是一款海量、安全、低成本、高可靠的云存储服务,提供最高可达 99.995 % 的服务可用性,多种存储类型供选择,全面优化存储成本,OSS可用于图片、音视频、日志等海量文件的存储,各种终端装备、Web网站步伐、移动应用可以直接向OSS写入或读取数据。
https://i-blog.csdnimg.cn/direct/b1515340688f4bfe9ee911384ec4ee1b.png
最重要的一点是:使用海量互联网带宽,OSS可以实现网页大概移动应用的静态和动态资源分离,提供原生的传输加速功能,支持上传加速、下载加速,结合CDN产品,提供静态内容存储、分发到边沿节点的办理方案,使用CDN边沿节点缓存的数据,提拔访问的速度。
https://i-blog.csdnimg.cn/direct/ad3650d3657f49c98b27609adf7ee928.png
优化一:HPPT/2 + OSS云存储 + CDN:

比如像图片服务器,我们大概会按功能分为差别的OSS进行CDN加速,再使用CNAME映射多个域名,如许,就可以防止同一个域名最大6个的并发数据限定,另外,再加上CDN的可以分担源网站压力、制止网络拥塞,确保在差别区域、差别场景下加速网站内容的分发,提高资源访问速度。
https://i-blog.csdnimg.cn/direct/672fae7c576e4ce28d1b31c3557ca895.png
将差别业务的静态资源分散差别OSS域名加载,再加上服务器Nginx开启了HTTP/2,可以看到差别的类型的资源,如图片、CSS、JS资源都是在同一个时间节点加载,并没有阶梯式的加载资源,同时,再配合CDN缓存在离用户更近的服务器节点上,如许可以加速低落数据传输的延迟,提高访问速度。
https://i-blog.csdnimg.cn/direct/792458500b3242338d120ada5dfca1e2.png
优化二:小步伐分包与资源OSS迁移:

微信小步伐的分包是指将小步伐的差别功能模块分别打包成独立的代码块,以便于分布式摆设和加载,对于提拔小步伐性能、优化用户体验至关重要。


[*]①. 通过分包,小步伐可以按照功能、页面等维度进行拆分,使得代码结构更清楚、维护更便捷。
[*]②. 分包还可以有用镌汰小步伐的加载时间和网络流量,提拔用户体验。
最开始由于业务的需求,需要开发小步伐,一些静态资源如图片、CSS、js文件是在当地存储,在最开始的小步伐主包巨细限定为2MB,功能是完全够用的,也没有出现问题。
https://i-blog.csdnimg.cn/direct/26c832f4daf3403eab56704e1038ce99.png
但是,随着公司的业务不断的发展,功能的不断完善,功能模块的不断增长,到后面2MB肯定是不够的。
https://i-blog.csdnimg.cn/direct/3ac0dc5ef1e441a7b6157bf188919f5d.png
此时,将小步伐的静态资源全部迁移到OSS上,再配合CDN的加速,将一些不常用的模块进行分包处理,在小步伐启动时,默认会下载主包并启动主包内页面,当用户用户进入分包内某个页面时,客户端会把对应分包下载下来,下载完成后再进行展示。
优化三: OSS缩略图增效:

   项目中经常会碰到加载多张图片的场景,用户不想下载每张图片的原图,假如只想大概预览这些图形的样子,还是进行原图加载,即占用带宽,又泯灭用户大把时间。
在列表中使用原图加载会很卡,乃至闪退,偶然候需要10几分钟才气加载完成,导致业务工作效率低下,缩略图是大图片的缩小版,即可以节省带宽,用户又可以预览缩略图来找想要的那一张图片,不用点击全部的图片,比如一些场景:


[*]①. 商品列表中需要展示10几个商品,不需要表现原图。
[*]②. 海报列表中需要表现全部的海报图片(往往一张海报就是10几MB),所以,只需要大概知道长什么样子的小图片代替即可,等用户真的需要下载,可以点击“海报详情”进行下载。
[*]③. 后管体系欣赏一个案件上传的图片,往往需要大量的照相图片来证明用于案件的考核。
[*]④. 后管列表中,商品的详情图片假如需要修改,不需要把原图表现出来,只需要表现对应的小图,由于操作人员不是每张都要编辑,只需要更换有问题的图片即可。
https://i-blog.csdnimg.cn/direct/81df138d8e684800bd250de5bca4221d.png
当用户上传到OSS上,可以通过添加后缀的情势来天生多个缩略图,这些缩略图可以用于差别的用途,如在文章列表中表现缩略图、在文章内部表现缩略图等。
将图片放到阿里云OSS上,加载列表时在图片后拼接,可以根据本身的需求选择并使用适当巨细的缩略图,列表中使用缩略图加载图片会流畅很多,点击图片可以检察大图就可以了:
// 参数拼接
?x-oss-process=image/resize,m_fill,h_100,w_100

// 缩略图文件URL举例
https://oss-console-img-demo-cn-hangzhou.oss-cn-hangzhou.aliyuncs.com/example.jpg?x-oss-process=image/resize,w_300/quality,q_90。


[*] ①. 回源原图:对原图example.jpg添加图片缩放resize不会影响原图的任何信息。
[*] ②. 回源处理后的图片:对原图example.jpg添加图片缩放resize以及质量变更quality参数后。
   针对OSS内存储的图片文件(Object),还可以在GetObject哀求中携带图片处理参数对图片文件进行处理,比方添加图片水印、转换格式等。
将需要加速加载时间、节省存储空间、镌汰带宽费用大概以合适的尺寸出现图片时,需要进行图片缩放,OSS支持通过图片缩放参数,调整Bucket内存储的图片巨细。
https://i-blog.csdnimg.cn/direct/ae3a600387cb4b158c56a99c9b254845.png
通过上面案例展示,可以得到以下的结论:


[*]①. 单张图片原图是平均2MB左右,加上缩略图后平均在5KB左右。
[*]②. 单张图片原图加载时间是平均15s左右,加上缩略图后平均在300ms左右。
[*]③. 团体图片原图加载是73.4MB,加上缩略图后是1.6MB,空间节省了97%左右。
[*]④. 团体图片原图加载时间1.6min,加上缩略图后6.41s,时间加速了93%左右。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: 1024征文活动 - 企业级互联网全栈体系全链路架构优化方案落地实施方案