随着互联网时代的发展, 用户量自增迅猛, 应用程序性能要求日益增大. 如果一个页面用户打开需要超过 3 秒, 大部分用户等待的意愿减少, 等待的时间越长, 减少的用户量也会越多. 所以我们应用程序的性能, 调优变得越来越重要. 这里介绍应用程序性能调优相关方案.
调优从宏观的思维来看, 分为网络, 应用程序, 数据库. 这篇文章不会介绍应用程序代码上的调优, 因代码及其使用框架上有很大的区别.
性能优化的想法
在介绍具体操作性能优化前, 需要给大家理清一下思路. 性能优化是很大很复杂的东西, 如果要做到极致, 没有一个专业化的团队是根本不可能的, 在绝大部分公司来说是很难有经费去支撑这一个团队. 而且性能优化的人懂得的东西不仅要全面, 而且又要有深度, 这些人大部分都是一些民间高手.
我们首先理清性能优化的目标, 目标是优化到什么程度. 如做一些活动, 用户量最高峰大约在 10w 的并发访问, 那么性能优化一般都需要做到比 2-3 倍的用户量优化. 比如并发访问达到 20w-30w 之间, 这样系统性能才会有保障.
然后根据实际情况, 来确定性能优化怎么做. 因为有些系统单机的性能瓶颈就在那里, 再怎么优化都是浪费时间. 第一种是整个系统重构广度的优化, 如你的系统吞吐量是 1000/S, 如果要达到 10W/S, 那么可能再深入性能优化就浪费时间, 因为你的单机系统最高吞吐量是 1W/S, 如果要增加 10 倍, 只能改造程序, 分布式处理. 再来第二种是深度的优化, 如果你的系统吞吐量是 100/S, 要提升到 300/S, 那么通常是可以的, 通过网络, 数据库, 前后端, 系统思路去优化即可.
这篇文章更多讲的是深度的优化, 广度的优化网络上很多, 分布式, 微服务等.
确定好优化怎么做后, 我们需要短板木桶原理, 优化导致性能最慢的. 即把最短的木板优化, 加长, 再找最短的再优化加长.
总的一点来说, 性能优化的想法的流程是: 理清优化的目标 ->确定怎么做 ->短木板原理优化最慢的.
网络
网络的性能优化可以分为多方面, 可分为应用程序外网, 应用程序内网. 如图:
程序外网
程序外网可通过 PC, 手机等不同的客户终端发起访问, 经过外部网络最终落入到程序内部. 如上图的灰色区域以外的部分表示外网, 灰色区域表示内部局域网, 下面分别列出外网带宽需要考虑的点.
1)外网首先要考虑的是带宽, 带宽越大才能经过更多的数据包, 更多的数据量. 这里要注意带宽的单位: Mbps,MB/S.Mbps*8=MB/S, 即 1MB/S=8Mbps.
2)DNS. 在前后端分离的应用程序中, 前端发起请求填写相关的域名即可. 我们也知道, 域名要通过 DNS 解析找到相应的 IP 才能把数据包发送到相应的服务器, 因为在 TCP/IP 协议传输过程中, 网络层需要 IP 地址. 那么 DNS 就为我们提供了 IP 与域名的映射关系, 通过域名找到相应的 IP 地址.
在程序发起请求解析映射的过程中, 优先级是这样的: 程序 (浏览器, 服务器等) 找到内部域名与 IP 的映射或代理 -> 本机 Host 文件 -> 局域网 DNS 服务器 -> 英特网 DNS 服务器, 如下图.
所以在 DNS 优化上面, 可在局域网中建立 DNS, 用来映射 IP 与域名.
3)尽量减少数据包大小. 在网络传输中, 免不了发送数据包. 减少数据包的大小可增加网络传输效率.
4)允许的话, 可使用 HTTP2.0, 并且不要使用 HTTP1.0.HTTP2.0 带来的极致的性能优化, HTTP 经过 1.0->1.1 的发展. HTTP1.1 比 1.0 加了长连接与 keepalive 方式, 连接过程中无需每次都中断. 而 HTTP2.0 加了多路复用, 让所有数据流可公用同一个连接, 大大提升连接效率, 很适合目前大用户量的程序. 鉴于目前客户端, 浏览器支持不足, 大部分在默认是使用 HTTP1.1, 或者更旧的 1.0.
程序内网
一般在服务化程序中, 或者一些中间件都会使用到内网程序的访问. 内网的带宽一般无问题, 至少可达 GB 级别. 在 Linux 环境中, 发起网络请求有文件读取数量, 也有 maxconn 的限制, 加相应的配置即可.
应用程序
现今的应用程序一般都是前后端分离, 这里的性能优化包括前端应用程序及后端应用程序. 应用程序优化有很多方面, 有很多是代码死循环或底层了解不透彻引起的, 也有是其它方面.
前端应用程序
首先前端的性能优化代码上不做讨论. 代码上有很多的优化地方, 如渲染页面的优化. 前端除了代码上的优化, 还有缓存与压缩.
1)缓存.
B/S 应用中, 用户第一次访问我们的应用程序时, 会默认把静态文件如 JS,CSS 等文件保存在浏览器中, 无需下次再打开浏览器时再获取服务器的静态文件. 浏览器的缓存分为强缓存与协商缓存, 一般的静态文件如 CSS,html 等都是强缓存. 强缓存与协商缓存都是服务器指定的, 区别在于协商缓存请求一次服务器来证明是否获取浏览器缓存, 而强缓存没过期的话都会获取浏览器本地缓存. 所以要把文件的缓存归类好, 哪些是基本不会变化的, 哪些是变化很大的, 最后做出相应的缓存处理.
然后是 CDN. 一般部署用户量大的应用都需要把前端部署到 CDN 上面, 以减轻服务器压力及快速响应页面到用户终端.
最后是后端缓存. 后端缓存主要是通过反向代理服务器来缓存, 如闻名的 Nginx. 当前端需要请求后端时, 后端首先经过 Nginx 等反代, 然后判断是否需要向下一层请求. 这里的 Nginx 会判断服务器有无更改过内容, 如果无则从 Nginx 直接返回, 无需经过下层的服务器.
2)压缩.
压缩最直接的做法. 通过压缩 JS,CSS 等文件, 以达到减少网络上的数据传输的目的.
后端应用程序
1)工具.
可通过一些工具上的使用, 分析代码有哪些值得优化的地方. 这些工具包括 C# 的 dotTrace,PrefCollect,VTune 等, java 的 JProfiler,ZProfiler 等.
能使用工具最好是使用工具分析出来, 使用这些工具是最直观快捷的做法, 有时候这些工具直接分析出代码的不足地方, 问题也就帮助你解决了.
2)中间件, SLB, 缓存.
有时候, 你会遇到 API 访问慢的问题. 此 API 可能是需要大量耗时, 也可能是用户量访问大引起的. 这时候你可以通过异步处理的方式来进行优化. 这里的异步处理通常是用中间件来解决, 如队列.
我们经常访问数据库都知道, 数据库的请求压力一般都是很大的. 如果多人同时请求数据库可能发生拥挤的情况, 并且一般服务器的性能瓶颈都在数据库. 如何优化数据库呢? 这个下一点做讨论, 我们可以从减少数据库访问的方向来入手, 可以通过缓存的方式来减少数据库的访问. 即在数据库访问上面加一层一级缓存来做处理, 减少直接访问数据库的压力.
有时候是应用瓶颈性能到了, 这时候我们就需要部署多个应用实例了, 通过负载均衡 SLB 来分发请求到应用, 加大应用的访问力.
3)CPU, 内存.
应用程序的 CPU 与内存分析, 通过上面介绍的工具分析即可. 一般工具可以看出上下文的切换, 减少这种不必要的切换能大大提升程序的性能. 有时候单线程比多线程性能更优.
内存通过分析可以得到哪些对象是释放不了的, 通过减少内存的使用来提高应用的稳定性.
4)业务调优.
最后在后端优化上说的是应用上的调优. 业务上的调优是很关键的因素, 可以通过与客户, 产品经理的沟通, 来达到业务调优的目的. 有些功能是边界功能, 会影响应用性能的话那么建议是去掉; 有些功能绕了几圈, 程序处理性能很低, 那么简化其功能. 很多时候通过业务上沟通, 加快程序上的性能, 减轻技术人员的压力.
5)接口合并
有些页面, 因为多次的请求而导致后端请求过多. 所以我们在页面上, 尽量的就行接口的合并. 一个简单的页面, 应该就对应一个接口即可. 如有些页面根据用户体验的不同而需要不同的加载方式, 即有些元素需要先加载, 有些是后加载, 则这些页面可多个接口.
6)分治
在后端的应用程序中, 单体应用是有瓶颈的. 在单体应用中, 部署在一台机器, 机器的性能包括 CPU, 网络读取, 内存都有相应的瓶颈. 所以要使用分治的思想, 把系统拆分成多个子系统或服务, 如现流行的微服务或者服务化. 至少让高并发的应用服务化.
7)keepalive
上述也介绍过, keepalive 是 http1.1 固有的, 用来保持连接, 减少重新请求的握手动作. 对于经常发起请求的, 考虑用长连接的方式.
数据库
性能优化上, 先优化最慢的效果是最明显的, 往往是最慢的影响着性能. 在应用程序中, 数据库是性能提升的关键因素.
1)配置优化.
数据库的提升, 首先是配置上的优化. 数据库很耗内存及 CPU,CPU 与内存上去了那么你的数据库性能档次也会相应地得到提升.
2)索引及慢 SQL.
然后是建立合适的索引及避免慢 SQL 的查询. 索引从来都是直接提升查询的方法, 所以不是建立得越多越好, 越多的索引会导致硬盘空间占用过大并且写性能低下. 合适的在表中建立查询较多字段的索引是关键.
其次要避免慢 sql 的查询. 慢 sql 可通过 explain 关键字就行 sql 的调优, 也可根据经验来避免全表的扫描. 经常是因为写慢 sql 导致全表的扫描, 最终导致性能的低下.
3)数据清理
一个表的数据量有它的极限, 太大的数据量为以后数据的读写埋下炸弹. 无用的数据需要定时地做清理. 这里的清理不是说数据删除了即可, 不同的数据库规则不同, 大部分直接 delete from 表是删除了表的数据, 这是表面上的删除, 硬盘空间还会占用着. 需要做数据的定时清理, 清理硬盘空间. 办法有很多, 最简单粗暴的方法是建立临时表与原表的数据做临时迁移.
4)分表分库
分表分库是很大众的做法, 目前的公司数据量过大的情况下都会使用到. 在数据量过多的情况下, 会导致性能的低下, 这时候分表分库虽然会用一些中间件多一层的方式, 但是性能比原来的也会好很多. 分表分库这里不详细讨论, 可上网搜索一些使用方法.
操作系统
操作系统的优化, 主流是 Linux 开源系统的优化, Windows 一般很少做优化. 所以这里只介绍 Linux 的优化. 会分为 CPU, 内存, 磁盘, 内核参数, 文件系统方面优化.
1)CPU
CPU 是系统运行效率的保障, 市面上的 CPU 一般都是多核的, 效率也得到大大提升. 在 Linux 上多核的 CPU 会看成一个一个核. 例如你的 CPU 是四核, 那么在 Linux 上看成是四个单核 CPU.
据权威报告, CPU 多核分开比整合在一起性能快 20% 左右. 即一个四核的 CPU 比四个 1 核的 CPU 慢 20%.
2)内存
内存分两种, 分别为物理内存, 虚拟内存. 在以前配置虚拟内存一般为物理内存的两倍, 因物理内存容量比较小. 现在随着物理内存费用不再像以前那么高, 很多机器的内存都可以升到很高了, 所以建议高内存的服务器不开通虚拟内存. 例如流行的 k8s 就禁止用虚拟内存.
在系统方面, 一般安装 64 位的操作系统, 因为 32 位的操作系统有内存的限制. 8G 左右的内存已经是 32 位操作系统的上限, 如果内存再多也无用. 而 64 位的无限制. 在应用程序方面, 32 位操作系统每个应用程序内存支持最大 4G, 而 64 位的没有限制.
这些内存都需要理解好, 因为配置部署系统时很关键, 大内存的应用尤为关键, 如 MongoDB,Redis.
3)磁盘
磁盘是影响着 IO 读写的关键, 有些应用的 IO 读写很重要. 提升磁盘性能的有 RAID 等. 在市场上买磁盘时有固态, 磁盘. 有些应用比较依赖磁盘, 这种一般都采用固态硬盘, 如数据库都比较依赖硬盘.
4)内核参数
内核参数包括共享段, 文件句柄等. 网上很多这方面的调优, 这里不详细介绍.
5)文件系统
其实文件系统是一个很重要的东西, 因为不同的文件系统性能是不同的. 较流行的有 EXT4,XFS.
总结
我们分析了性能优化的一些思路, 这些思路是你应用程序遇到瓶颈时都可思考. 我们从大方向上分别是网络, 应用程序, 数据库, 操作系统分析了性能优化的思路, 最后从这些方面入手细分. 下图是我们这篇文章性能优化思路的脑图, 可供参考.
可以关注本人的公众号, 多年经验的原创文章共享给大家.
来源: http://www.bubuko.com/infodetail-3474735.html