为什么性能会是一个新需求
因为传统的开发,并不会将性能作为一个必选的需求来做,因此,很多时候在项目发布的时候,会发现允许各种卡顿与缓慢。所以解决这个的方法,就是在项目的初始阶段,把性能问题作为一个必选的特性来做。
常见的性能问题
选择开发语言注意事项
书里第一个介绍了语言需要注意的地方,基本上就是常识,越低级的语言(汇编,C)允许速度会快,越高级的语言,特别是解释型的语言(Ruby,Python,JavaScript)会更慢。不过,就目前开发环境来说,慢的语言都有各种优化方案,Ruby不清楚,但是Python和JavaScript可以使用C\C++来对写一个热点函数,解决了一些热点问题,基本上在做业务开发上,性能都不会是太大问题了。
常见的性能分类
- 延迟
- 内存延迟
- 网络延迟
- 磁盘和I/O延迟
- 通信量/应答
- 带宽
- 数据过载
- 未经优化数据
- 压缩
- 计算
- 处理的数据太多
- 计算不必要的结果
- 包含暴力算法
- 响应
- 同步操作与可以脱机的操作
- 状态数据的缓存和复制
文章列举了上面的性能常见的分类,实际上,碰上问题后,按照上述的问题思考下去,也很容易定位到要修改的地方。不过就算了解分类,在实际解决问题的过程中,也还是一个依靠经验的过程。而且很多时候,我们不能只靠看到的现象后,凭直觉去修改,而是要数据说话。特别得是生产环境的数据。同样的一个方法,在生产环境,因为自身的数据量很大,会将问题放大。一般的开发环境下的性能测试不一定能反映出来。
所以我们在开发阶段,就应该提前考虑到,如何对执行的代码做性能测量。并且,这个测量时一直持续到软件生命周期结束的。
了解硬件
文章里主要介绍了各种硬件设备对资源(数据)获取上的速度差异。
- CPU 缓存和寄存器
- L1 cache
- L2 cache
- L3 cache
- RAM
- 存储
- 本地(SSD)
- 本地(HDD)
- 网络
- 局域网
- 区域网
- 广域网
上面的速度差异,基本上按照顺序从上到下递增。差距不是倍数的差距,是指数级别的差距。
不过,网络访问和本地存储访问还需要特别说明,如果是局域网,并且局域网另外一段的数据源是内存,那么,从它获得数据,不一定比从本地存储慢多少。恩,memcache,redis存在的依据。
再次,本地存储还需要区分本地物理存储和本地云存储。目前的云服务器都是多个虚拟机共享一个物理硬件,那么就会存在争用问题,导致磁盘IO相当的不稳定。如果云服务商提供的是SSD还好,如果没指明存储类型,那么,就小心一点吧:(
工具和成本
书里没有介绍太多与性能相关的工具,相关的介绍可以参考《编写高性能的.NET代码》
成本的话,自然是指花了多少$$$,所以,为了节约成本,需要尽量选择免费和开源的工具。
设置你的开发环境
Windows
这个,没有什么好说的,只有vs2017,虽然也可以用vs code,但我通常也只那它来开发web前端。不过现在偶尔也拿vs写前端了,现在vs对js的支持也很好了,不像2010/2012版本那样(公司的主力开发环境)。
Mac
没有机器,书里介绍的是Visual Studio for Mac,是基于Xamarin开发的。如果不是为了写.net 代码,也可以用VS Code。
Linux
如果要使用IDE,只有VS Code可选了。控制台的的linux,也只能安装.net core sdk进行代码编译了。不过,现在都流行使用Docker来发布.net core。所以,在linux编译项目的情况应该不多。
测评应用的性能瓶颈
一些常用的工具,可以从《编写高性能的.NET代码》书里找。
针对SQL,介绍了SQL Server Profiler。这个是SQL Server里安装的组件。如果你用的是MySQL,一些Mysql的第三方工具也会带有针对sql的探查器。Oracle应该也有对应的工具,但那个有点高端,我是用不起的了。
针对Asp.Net core的性能分析工具,还有MiniProfiler和Glimpse,书里着重介绍了Glimpse。它们都是通过依赖注入的方式注入到asp.net core执行框架下,在返回的前端页面里带出一个脚本,显示着本次调用的耗时,如果使用了EF,着还可以看到EF执行sql的耗时。当然也可以在自己的方法里,加入一些自定义的配置,这样也可以在每次页面返回时,将自定义的数据执行时间返回。但这两个工具,可以开发用,也可以生产用,但更多的时候,应该是开发阶段时使用。生产环境需要关闭。
针对HTTP,那就是各自浏览器自带的的工具了。不需要多介绍。
针对网络监控,可以选择Wireshark,软件支持Windows,Mac,Linux,这个就针对存储的网络数据包的监控了。
Science 说的是,选择工具做测试的时候,应该尽量的保证每次测试结果都是可复现的。不要一次前后两次测试得到的结果差别太大。
修复常见的性能问题
延迟
延迟主要是说当你发起一个请求操作后,很久才能得到反馈信息。书里讨论的延迟主要是网络延迟和磁盘延迟。这些延迟都是会导致数据库访问的延迟,解决方案,减少数据查询量(减少返回的记录数和数据集的列数),以及更换更高校的磁盘(SSD)。
异步操作
对于客户端来说,用户发起请求后,如果不是可以立即返回的操作,那么就需要把业务逻辑切换到后台执行了。开线程或者用异步Task。如果是web应用,则想办法通知用户等待,然后刷状态了。
查询的N+1问题
查询的N+1问题,是指先查询出来一个列表数据,然后再根据列表项里的ID,查询到与之关联的数据。
举一个栗子
PT希望在首页里,显示前10个blog文章,每篇文章下面还要有最新的10条评论。那么常见的方法就是先一个SQL查询blog的文章,然后循环blog文章,再查询对应的前10条评论。
发现问题了吧,第二次查询评论可能会发起10次sql请求。
所以,正确的方法是,拿到blog文章Id列表,然后一次SQL查询出关联的评论,再和现在的blog文章组合返回给前端。
当然,书里针对blog提出了个解决方案,就是将页面静态化。
硬件的解决方案
说到硬件,不就是更快的cpu,更大的内存,以及高速的SSD。
过大的图片
简单的说,就是对最终使用的图片,缩小分辨率,改用高压缩比的格式。现在的各种云应用都集成了类似的功能,可以将你上传到对象云里的图片进行分辨率调整与加水印。一些CDN也可以附带调整分辨率的功能。